Skip to main content

gemachain_bpf_loader_program/
syscalls.rs

1use crate::{alloc, BpfError};
2use alloc::Alloc;
3use gemachain_program_runtime::InstructionProcessor;
4use gemachain_rbpf::{
5    aligned_memory::AlignedMemory,
6    ebpf,
7    error::EbpfError,
8    memory_region::{AccessType, MemoryMapping},
9    question_mark,
10    vm::{EbpfVm, SyscallObject, SyscallRegistry},
11};
12#[allow(deprecated)]
13use gemachain_sdk::sysvar::fees::Fees;
14use gemachain_sdk::{
15    account::{AccountSharedData, ReadableAccount, WritableAccount},
16    account_info::AccountInfo,
17    blake3, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
18    clock::Clock,
19    entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
20    epoch_schedule::EpochSchedule,
21    feature_set::{
22        allow_native_ids, blake3_syscall_enabled, check_seed_length,
23        close_upgradeable_program_accounts, demote_program_write_locks, disable_fees_sysvar,
24        libsecp256k1_0_5_upgrade_enabled, mem_overlap_fix, return_data_syscall_enabled,
25        secp256k1_recover_syscall_enabled, sol_log_data_syscall_enabled,
26    },
27    hash::{Hasher, HASH_BYTES},
28    ic_msg,
29    instruction::{AccountMeta, Instruction, InstructionError},
30    keccak,
31    message::Message,
32    native_loader,
33    process_instruction::{self, stable_log, ComputeMeter, InvokeContext, Logger},
34    program::MAX_RETURN_DATA,
35    pubkey::{Pubkey, PubkeyError, MAX_SEEDS, MAX_SEED_LEN},
36    rent::Rent,
37    secp256k1_recover::{
38        Secp256k1RecoverError, SECP256K1_PUBLIC_KEY_LENGTH, SECP256K1_SIGNATURE_LENGTH,
39    },
40    sysvar::{self, Sysvar, SysvarId},
41};
42use std::{
43    alloc::Layout,
44    cell::{Ref, RefCell, RefMut},
45    cmp::min,
46    mem::{align_of, size_of},
47    rc::Rc,
48    slice::from_raw_parts_mut,
49    str::{from_utf8, Utf8Error},
50};
51use thiserror::Error as ThisError;
52
53/// Maximum signers
54pub const MAX_SIGNERS: usize = 16;
55
56/// Error definitions
57#[derive(Debug, ThisError, PartialEq)]
58pub enum SyscallError {
59    #[error("{0}: {1:?}")]
60    InvalidString(Utf8Error, Vec<u8>),
61    #[error("BPF program panicked")]
62    Abort,
63    #[error("BPF program Panicked in {0} at {1}:{2}")]
64    Panic(String, u64, u64),
65    #[error("Cannot borrow invoke context")]
66    InvokeContextBorrowFailed,
67    #[error("Malformed signer seed: {0}: {1:?}")]
68    MalformedSignerSeed(Utf8Error, Vec<u8>),
69    #[error("Could not create program address with signer seeds: {0}")]
70    BadSeeds(PubkeyError),
71    #[error("Program {0} not supported by inner instructions")]
72    ProgramNotSupported(Pubkey),
73    #[error("{0}")]
74    InstructionError(InstructionError),
75    #[error("Unaligned pointer")]
76    UnalignedPointer,
77    #[error("Too many signers")]
78    TooManySigners,
79    #[error("Instruction passed to inner instruction is too large ({0} > {1})")]
80    InstructionTooLarge(usize, usize),
81    #[error("Too many accounts passed to inner instruction")]
82    TooManyAccounts,
83    #[error("Overlapping copy")]
84    CopyOverlapping,
85    #[error("Return data too large ({0} > {1})")]
86    ReturnDataTooLarge(u64, u64),
87}
88impl From<SyscallError> for EbpfError<BpfError> {
89    fn from(error: SyscallError) -> Self {
90        EbpfError::UserError(error.into())
91    }
92}
93
94trait SyscallConsume {
95    fn consume(&mut self, amount: u64) -> Result<(), EbpfError<BpfError>>;
96}
97impl SyscallConsume for Rc<RefCell<dyn ComputeMeter>> {
98    fn consume(&mut self, amount: u64) -> Result<(), EbpfError<BpfError>> {
99        self.try_borrow_mut()
100            .map_err(|_| SyscallError::InvokeContextBorrowFailed)?
101            .consume(amount)
102            .map_err(SyscallError::InstructionError)?;
103        Ok(())
104    }
105}
106
107/// Program heap allocators are intended to allocate/free from a given
108/// chunk of memory.  The specific allocator implementation is
109/// selectable at build-time.
110/// Only one allocator is currently supported
111
112/// Simple bump allocator, never frees
113use crate::allocator_bump::BpfAllocator;
114
115pub fn register_syscalls(
116    invoke_context: &mut dyn InvokeContext,
117) -> Result<SyscallRegistry, EbpfError<BpfError>> {
118    let mut syscall_registry = SyscallRegistry::default();
119
120    syscall_registry.register_syscall_by_name(b"abort", SyscallAbort::call)?;
121    syscall_registry.register_syscall_by_name(b"gema_panic_", SyscallPanic::call)?;
122    syscall_registry.register_syscall_by_name(b"gema_log_", SyscallLog::call)?;
123    syscall_registry.register_syscall_by_name(b"gema_log_64_", SyscallLogU64::call)?;
124
125    syscall_registry
126        .register_syscall_by_name(b"gema_log_compute_units_", SyscallLogBpfComputeUnits::call)?;
127
128    syscall_registry.register_syscall_by_name(b"gema_log_pubkey", SyscallLogPubkey::call)?;
129
130    syscall_registry.register_syscall_by_name(
131        b"gema_create_program_address",
132        SyscallCreateProgramAddress::call,
133    )?;
134    syscall_registry.register_syscall_by_name(
135        b"gema_try_find_program_address",
136        SyscallTryFindProgramAddress::call,
137    )?;
138
139    syscall_registry.register_syscall_by_name(b"gema_sha256", SyscallSha256::call)?;
140    syscall_registry.register_syscall_by_name(b"gema_keccak256", SyscallKeccak256::call)?;
141
142    if invoke_context.is_feature_active(&secp256k1_recover_syscall_enabled::id()) {
143        syscall_registry
144            .register_syscall_by_name(b"gema_secp256k1_recover", SyscallSecp256k1Recover::call)?;
145    }
146
147    if invoke_context.is_feature_active(&blake3_syscall_enabled::id()) {
148        syscall_registry.register_syscall_by_name(b"gema_blake3", SyscallBlake3::call)?;
149    }
150
151    syscall_registry
152        .register_syscall_by_name(b"gema_get_clock_sysvar", SyscallGetClockSysvar::call)?;
153    syscall_registry.register_syscall_by_name(
154        b"gema_get_epoch_schedule_sysvar",
155        SyscallGetEpochScheduleSysvar::call,
156    )?;
157    if invoke_context.is_feature_active(&disable_fees_sysvar::id()) {
158        syscall_registry
159            .register_syscall_by_name(b"gema_get_fees_sysvar", SyscallGetFeesSysvar::call)?;
160    }
161    syscall_registry
162        .register_syscall_by_name(b"gema_get_rent_sysvar", SyscallGetRentSysvar::call)?;
163
164    syscall_registry.register_syscall_by_name(b"gema_memcpy_", SyscallMemcpy::call)?;
165    syscall_registry.register_syscall_by_name(b"gema_memmove_", SyscallMemmove::call)?;
166    syscall_registry.register_syscall_by_name(b"gema_memcmp_", SyscallMemcmp::call)?;
167    syscall_registry.register_syscall_by_name(b"gema_memset_", SyscallMemset::call)?;
168
169    // Cross-program invocation syscalls
170    syscall_registry
171        .register_syscall_by_name(b"gema_invoke_signed_c", SyscallInvokeSignedC::call)?;
172    syscall_registry
173        .register_syscall_by_name(b"gema_invoke_signed_rust", SyscallInvokeSignedRust::call)?;
174
175    // Memory allocator
176    syscall_registry.register_syscall_by_name(b"gema_alloc_free_", SyscallAllocFree::call)?;
177
178    // Return data
179    if invoke_context.is_feature_active(&return_data_syscall_enabled::id()) {
180        syscall_registry
181            .register_syscall_by_name(b"gema_set_return_data", SyscallSetReturnData::call)?;
182        syscall_registry
183            .register_syscall_by_name(b"gema_get_return_data", SyscallGetReturnData::call)?;
184    }
185
186    // Log data
187    if invoke_context.is_feature_active(&sol_log_data_syscall_enabled::id()) {
188        syscall_registry.register_syscall_by_name(b"sol_log_data", SyscallLogData::call)?;
189    }
190
191    Ok(syscall_registry)
192}
193
194macro_rules! bind_feature_gated_syscall_context_object {
195    ($vm:expr, $is_feature_active:expr, $syscall_context_object:expr $(,)?) => {
196        if $is_feature_active {
197            match $vm.bind_syscall_context_object($syscall_context_object, None) {
198                Err(EbpfError::SyscallNotRegistered(_)) | Ok(()) => {}
199                Err(err) => {
200                    return Err(err);
201                }
202            }
203        }
204    };
205}
206
207pub fn bind_syscall_context_objects<'a>(
208    loader_id: &'a Pubkey,
209    vm: &mut EbpfVm<'a, BpfError, crate::ThisInstructionMeter>,
210    invoke_context: &'a mut dyn InvokeContext,
211    heap: AlignedMemory,
212) -> Result<(), EbpfError<BpfError>> {
213    let compute_budget = invoke_context.get_compute_budget();
214
215    // Syscall functions common across languages
216
217    vm.bind_syscall_context_object(Box::new(SyscallAbort {}), None)?;
218    vm.bind_syscall_context_object(
219        Box::new(SyscallPanic {
220            compute_meter: invoke_context.get_compute_meter(),
221            loader_id,
222        }),
223        None,
224    )?;
225    vm.bind_syscall_context_object(
226        Box::new(SyscallLog {
227            compute_meter: invoke_context.get_compute_meter(),
228            logger: invoke_context.get_logger(),
229            loader_id,
230        }),
231        None,
232    )?;
233    vm.bind_syscall_context_object(
234        Box::new(SyscallLogU64 {
235            cost: compute_budget.log_64_units,
236            compute_meter: invoke_context.get_compute_meter(),
237            logger: invoke_context.get_logger(),
238        }),
239        None,
240    )?;
241
242    vm.bind_syscall_context_object(
243        Box::new(SyscallLogBpfComputeUnits {
244            cost: 0,
245            compute_meter: invoke_context.get_compute_meter(),
246            logger: invoke_context.get_logger(),
247        }),
248        None,
249    )?;
250
251    vm.bind_syscall_context_object(
252        Box::new(SyscallLogPubkey {
253            cost: compute_budget.log_pubkey_units,
254            compute_meter: invoke_context.get_compute_meter(),
255            logger: invoke_context.get_logger(),
256            loader_id,
257        }),
258        None,
259    )?;
260
261    let allow_native_ids = invoke_context.is_feature_active(&allow_native_ids::id());
262    let check_seed_length = invoke_context.is_feature_active(&check_seed_length::id());
263    vm.bind_syscall_context_object(
264        Box::new(SyscallCreateProgramAddress {
265            cost: compute_budget.create_program_address_units,
266            compute_meter: invoke_context.get_compute_meter(),
267            loader_id,
268            allow_native_ids,
269            check_seed_length,
270        }),
271        None,
272    )?;
273    vm.bind_syscall_context_object(
274        Box::new(SyscallTryFindProgramAddress {
275            cost: compute_budget.create_program_address_units,
276            compute_meter: invoke_context.get_compute_meter(),
277            loader_id,
278            allow_native_ids,
279            check_seed_length,
280        }),
281        None,
282    )?;
283
284    vm.bind_syscall_context_object(
285        Box::new(SyscallSha256 {
286            sha256_base_cost: compute_budget.sha256_base_cost,
287            sha256_byte_cost: compute_budget.sha256_byte_cost,
288            compute_meter: invoke_context.get_compute_meter(),
289            loader_id,
290        }),
291        None,
292    )?;
293
294    vm.bind_syscall_context_object(
295        Box::new(SyscallKeccak256 {
296            base_cost: compute_budget.sha256_base_cost,
297            byte_cost: compute_budget.sha256_byte_cost,
298            compute_meter: invoke_context.get_compute_meter(),
299            loader_id,
300        }),
301        None,
302    )?;
303
304    vm.bind_syscall_context_object(
305        Box::new(SyscallMemcpy {
306            cost: invoke_context.get_compute_budget().cpi_bytes_per_unit,
307            compute_meter: invoke_context.get_compute_meter(),
308            loader_id,
309            mem_overlap_fix: invoke_context.is_feature_active(&mem_overlap_fix::id()),
310        }),
311        None,
312    )?;
313    vm.bind_syscall_context_object(
314        Box::new(SyscallMemmove {
315            cost: invoke_context.get_compute_budget().cpi_bytes_per_unit,
316            compute_meter: invoke_context.get_compute_meter(),
317            loader_id,
318        }),
319        None,
320    )?;
321    vm.bind_syscall_context_object(
322        Box::new(SyscallMemcmp {
323            cost: invoke_context.get_compute_budget().cpi_bytes_per_unit,
324            compute_meter: invoke_context.get_compute_meter(),
325            loader_id,
326        }),
327        None,
328    )?;
329    vm.bind_syscall_context_object(
330        Box::new(SyscallMemset {
331            cost: invoke_context.get_compute_budget().cpi_bytes_per_unit,
332            compute_meter: invoke_context.get_compute_meter(),
333            loader_id,
334        }),
335        None,
336    )?;
337
338    bind_feature_gated_syscall_context_object!(
339        vm,
340        invoke_context.is_feature_active(&blake3_syscall_enabled::id()),
341        Box::new(SyscallBlake3 {
342            base_cost: compute_budget.sha256_base_cost,
343            byte_cost: compute_budget.sha256_byte_cost,
344            compute_meter: invoke_context.get_compute_meter(),
345            loader_id,
346        }),
347    );
348
349    bind_feature_gated_syscall_context_object!(
350        vm,
351        invoke_context.is_feature_active(&secp256k1_recover_syscall_enabled::id()),
352        Box::new(SyscallSecp256k1Recover {
353            cost: compute_budget.secp256k1_recover_cost,
354            compute_meter: invoke_context.get_compute_meter(),
355            loader_id,
356            libsecp256k1_0_5_upgrade_enabled: invoke_context
357                .is_feature_active(&libsecp256k1_0_5_upgrade_enabled::id()),
358        }),
359    );
360
361    let is_fee_sysvar_via_syscall_active =
362        !invoke_context.is_feature_active(&disable_fees_sysvar::id());
363    let is_return_data_syscall_active =
364        invoke_context.is_feature_active(&return_data_syscall_enabled::id());
365    let is_gema_log_data_syscall_active =
366        invoke_context.is_feature_active(&sol_log_data_syscall_enabled::id());
367
368    let invoke_context = Rc::new(RefCell::new(invoke_context));
369
370    vm.bind_syscall_context_object(
371        Box::new(SyscallGetClockSysvar {
372            invoke_context: invoke_context.clone(),
373            loader_id,
374        }),
375        None,
376    )?;
377    vm.bind_syscall_context_object(
378        Box::new(SyscallGetEpochScheduleSysvar {
379            invoke_context: invoke_context.clone(),
380            loader_id,
381        }),
382        None,
383    )?;
384    bind_feature_gated_syscall_context_object!(
385        vm,
386        is_fee_sysvar_via_syscall_active,
387        Box::new(SyscallGetFeesSysvar {
388            invoke_context: invoke_context.clone(),
389            loader_id,
390        }),
391    );
392    vm.bind_syscall_context_object(
393        Box::new(SyscallGetRentSysvar {
394            invoke_context: invoke_context.clone(),
395            loader_id,
396        }),
397        None,
398    )?;
399
400    // Return data
401    bind_feature_gated_syscall_context_object!(
402        vm,
403        is_return_data_syscall_active,
404        Box::new(SyscallSetReturnData {
405            invoke_context: invoke_context.clone(),
406            loader_id,
407        }),
408    );
409
410    bind_feature_gated_syscall_context_object!(
411        vm,
412        is_return_data_syscall_active,
413        Box::new(SyscallGetReturnData {
414            invoke_context: invoke_context.clone(),
415            loader_id,
416        }),
417    );
418
419    // gema_log_data
420    bind_feature_gated_syscall_context_object!(
421        vm,
422        is_gema_log_data_syscall_active,
423        Box::new(SyscallLogData {
424            invoke_context: invoke_context.clone(),
425            loader_id,
426        }),
427    );
428
429    // Cross-program invocation syscalls
430    vm.bind_syscall_context_object(
431        Box::new(SyscallInvokeSignedC {
432            invoke_context: invoke_context.clone(),
433            loader_id,
434        }),
435        None,
436    )?;
437    vm.bind_syscall_context_object(
438        Box::new(SyscallInvokeSignedRust {
439            invoke_context: invoke_context.clone(),
440            loader_id,
441        }),
442        None,
443    )?;
444
445    // Memory allocator
446    vm.bind_syscall_context_object(
447        Box::new(SyscallAllocFree {
448            aligned: *loader_id != bpf_loader_deprecated::id(),
449            allocator: BpfAllocator::new(heap, ebpf::MM_HEAP_START),
450        }),
451        None,
452    )?;
453
454    Ok(())
455}
456
457fn translate(
458    memory_mapping: &MemoryMapping,
459    access_type: AccessType,
460    vm_addr: u64,
461    len: u64,
462) -> Result<u64, EbpfError<BpfError>> {
463    memory_mapping.map::<BpfError>(access_type, vm_addr, len)
464}
465
466fn translate_type_inner<'a, T>(
467    memory_mapping: &MemoryMapping,
468    access_type: AccessType,
469    vm_addr: u64,
470    loader_id: &Pubkey,
471) -> Result<&'a mut T, EbpfError<BpfError>> {
472    let host_addr = translate(memory_mapping, access_type, vm_addr, size_of::<T>() as u64)?;
473
474    if loader_id != &bpf_loader_deprecated::id()
475        && (host_addr as *mut T).align_offset(align_of::<T>()) != 0
476    {
477        return Err(SyscallError::UnalignedPointer.into());
478    }
479    Ok(unsafe { &mut *(host_addr as *mut T) })
480}
481fn translate_type_mut<'a, T>(
482    memory_mapping: &MemoryMapping,
483    vm_addr: u64,
484    loader_id: &Pubkey,
485) -> Result<&'a mut T, EbpfError<BpfError>> {
486    translate_type_inner::<T>(memory_mapping, AccessType::Store, vm_addr, loader_id)
487}
488fn translate_type<'a, T>(
489    memory_mapping: &MemoryMapping,
490    vm_addr: u64,
491    loader_id: &Pubkey,
492) -> Result<&'a T, EbpfError<BpfError>> {
493    translate_type_inner::<T>(memory_mapping, AccessType::Load, vm_addr, loader_id)
494        .map(|value| &*value)
495}
496
497fn translate_slice_inner<'a, T>(
498    memory_mapping: &MemoryMapping,
499    access_type: AccessType,
500    vm_addr: u64,
501    len: u64,
502    loader_id: &Pubkey,
503) -> Result<&'a mut [T], EbpfError<BpfError>> {
504    if len == 0 {
505        return Ok(&mut []);
506    }
507
508    let host_addr = translate(
509        memory_mapping,
510        access_type,
511        vm_addr,
512        len.saturating_mul(size_of::<T>() as u64),
513    )?;
514
515    if loader_id != &bpf_loader_deprecated::id()
516        && (host_addr as *mut T).align_offset(align_of::<T>()) != 0
517    {
518        return Err(SyscallError::UnalignedPointer.into());
519    }
520    Ok(unsafe { from_raw_parts_mut(host_addr as *mut T, len as usize) })
521}
522fn translate_slice_mut<'a, T>(
523    memory_mapping: &MemoryMapping,
524    vm_addr: u64,
525    len: u64,
526    loader_id: &Pubkey,
527) -> Result<&'a mut [T], EbpfError<BpfError>> {
528    translate_slice_inner::<T>(memory_mapping, AccessType::Store, vm_addr, len, loader_id)
529}
530fn translate_slice<'a, T>(
531    memory_mapping: &MemoryMapping,
532    vm_addr: u64,
533    len: u64,
534    loader_id: &Pubkey,
535) -> Result<&'a [T], EbpfError<BpfError>> {
536    translate_slice_inner::<T>(memory_mapping, AccessType::Load, vm_addr, len, loader_id)
537        .map(|value| &*value)
538}
539
540/// Take a virtual pointer to a string (points to BPF VM memory space), translate it
541/// pass it to a user-defined work function
542fn translate_string_and_do(
543    memory_mapping: &MemoryMapping,
544    addr: u64,
545    len: u64,
546    loader_id: &Pubkey,
547    work: &mut dyn FnMut(&str) -> Result<u64, EbpfError<BpfError>>,
548) -> Result<u64, EbpfError<BpfError>> {
549    let buf = translate_slice::<u8>(memory_mapping, addr, len, loader_id)?;
550    let i = match buf.iter().position(|byte| *byte == 0) {
551        Some(i) => i,
552        None => len as usize,
553    };
554    match from_utf8(&buf[..i]) {
555        Ok(message) => work(message),
556        Err(err) => Err(SyscallError::InvalidString(err, buf[..i].to_vec()).into()),
557    }
558}
559
560/// Abort syscall functions, called when the BPF program calls `abort()`
561/// LLVM will insert calls to `abort()` if it detects an untenable situation,
562/// `abort()` is not intended to be called explicitly by the program.
563/// Causes the BPF program to be halted immediately
564pub struct SyscallAbort {}
565impl SyscallObject<BpfError> for SyscallAbort {
566    fn call(
567        &mut self,
568        _arg1: u64,
569        _arg2: u64,
570        _arg3: u64,
571        _arg4: u64,
572        _arg5: u64,
573        _memory_mapping: &MemoryMapping,
574        result: &mut Result<u64, EbpfError<BpfError>>,
575    ) {
576        *result = Err(SyscallError::Abort.into());
577    }
578}
579
580/// Panic syscall function, called when the BPF program calls 'gema_panic_()`
581/// Causes the BPF program to be halted immediately
582/// Log a user's info message
583pub struct SyscallPanic<'a> {
584    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
585    loader_id: &'a Pubkey,
586}
587impl<'a> SyscallObject<BpfError> for SyscallPanic<'a> {
588    fn call(
589        &mut self,
590        file: u64,
591        len: u64,
592        line: u64,
593        column: u64,
594        _arg5: u64,
595        memory_mapping: &MemoryMapping,
596        result: &mut Result<u64, EbpfError<BpfError>>,
597    ) {
598        question_mark!(self.compute_meter.consume(len), result);
599        *result = translate_string_and_do(
600            memory_mapping,
601            file,
602            len,
603            self.loader_id,
604            &mut |string: &str| Err(SyscallError::Panic(string.to_string(), line, column).into()),
605        );
606    }
607}
608
609/// Log a user's info message
610pub struct SyscallLog<'a> {
611    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
612    logger: Rc<RefCell<dyn Logger>>,
613    loader_id: &'a Pubkey,
614}
615impl<'a> SyscallObject<BpfError> for SyscallLog<'a> {
616    fn call(
617        &mut self,
618        addr: u64,
619        len: u64,
620        _arg3: u64,
621        _arg4: u64,
622        _arg5: u64,
623        memory_mapping: &MemoryMapping,
624        result: &mut Result<u64, EbpfError<BpfError>>,
625    ) {
626        question_mark!(self.compute_meter.consume(len), result);
627        question_mark!(
628            translate_string_and_do(
629                memory_mapping,
630                addr,
631                len,
632                self.loader_id,
633                &mut |string: &str| {
634                    stable_log::program_log(&self.logger, string);
635                    Ok(0)
636                },
637            ),
638            result
639        );
640        *result = Ok(0);
641    }
642}
643
644/// Log 5 64-bit values
645pub struct SyscallLogU64 {
646    cost: u64,
647    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
648    logger: Rc<RefCell<dyn Logger>>,
649}
650impl SyscallObject<BpfError> for SyscallLogU64 {
651    fn call(
652        &mut self,
653        arg1: u64,
654        arg2: u64,
655        arg3: u64,
656        arg4: u64,
657        arg5: u64,
658        _memory_mapping: &MemoryMapping,
659        result: &mut Result<u64, EbpfError<BpfError>>,
660    ) {
661        question_mark!(self.compute_meter.consume(self.cost), result);
662        stable_log::program_log(
663            &self.logger,
664            &format!(
665                "{:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
666                arg1, arg2, arg3, arg4, arg5
667            ),
668        );
669        *result = Ok(0);
670    }
671}
672
673/// Log current compute consumption
674pub struct SyscallLogBpfComputeUnits {
675    cost: u64,
676    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
677    logger: Rc<RefCell<dyn Logger>>,
678}
679impl SyscallObject<BpfError> for SyscallLogBpfComputeUnits {
680    fn call(
681        &mut self,
682        _arg1: u64,
683        _arg2: u64,
684        _arg3: u64,
685        _arg4: u64,
686        _arg5: u64,
687        _memory_mapping: &MemoryMapping,
688        result: &mut Result<u64, EbpfError<BpfError>>,
689    ) {
690        question_mark!(self.compute_meter.consume(self.cost), result);
691        let logger = question_mark!(
692            self.logger
693                .try_borrow_mut()
694                .map_err(|_| SyscallError::InvokeContextBorrowFailed),
695            result
696        );
697        if logger.log_enabled() {
698            logger.log(&format!(
699                "Program consumption: {} units remaining",
700                self.compute_meter.borrow().get_remaining()
701            ));
702        }
703        *result = Ok(0);
704    }
705}
706
707/// Log 5 64-bit values
708pub struct SyscallLogPubkey<'a> {
709    cost: u64,
710    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
711    logger: Rc<RefCell<dyn Logger>>,
712    loader_id: &'a Pubkey,
713}
714impl<'a> SyscallObject<BpfError> for SyscallLogPubkey<'a> {
715    fn call(
716        &mut self,
717        pubkey_addr: u64,
718        _arg2: u64,
719        _arg3: u64,
720        _arg4: u64,
721        _arg5: u64,
722        memory_mapping: &MemoryMapping,
723        result: &mut Result<u64, EbpfError<BpfError>>,
724    ) {
725        question_mark!(self.compute_meter.consume(self.cost), result);
726        let pubkey = question_mark!(
727            translate_type::<Pubkey>(memory_mapping, pubkey_addr, self.loader_id,),
728            result
729        );
730        stable_log::program_log(&self.logger, &pubkey.to_string());
731        *result = Ok(0);
732    }
733}
734
735/// Dynamic memory allocation syscall called when the BPF program calls
736/// `gema_alloc_free_()`.  The allocator is expected to allocate/free
737/// from/to a given chunk of memory and enforce size restrictions.  The
738/// memory chunk is given to the allocator during allocator creation and
739/// information about that memory (start address and size) is passed
740/// to the VM to use for enforcement.
741pub struct SyscallAllocFree {
742    aligned: bool,
743    allocator: BpfAllocator,
744}
745impl SyscallObject<BpfError> for SyscallAllocFree {
746    fn call(
747        &mut self,
748        size: u64,
749        free_addr: u64,
750        _arg3: u64,
751        _arg4: u64,
752        _arg5: u64,
753        _memory_mapping: &MemoryMapping,
754        result: &mut Result<u64, EbpfError<BpfError>>,
755    ) {
756        let align = if self.aligned {
757            align_of::<u128>()
758        } else {
759            align_of::<u8>()
760        };
761        let layout = match Layout::from_size_align(size as usize, align) {
762            Ok(layout) => layout,
763            Err(_) => {
764                *result = Ok(0);
765                return;
766            }
767        };
768        *result = if free_addr == 0 {
769            match self.allocator.alloc(layout) {
770                Ok(addr) => Ok(addr as u64),
771                Err(_) => Ok(0),
772            }
773        } else {
774            self.allocator.dealloc(free_addr, layout);
775            Ok(0)
776        };
777    }
778}
779
780fn translate_and_check_program_address_inputs<'a>(
781    seeds_addr: u64,
782    seeds_len: u64,
783    program_id_addr: u64,
784    memory_mapping: &MemoryMapping,
785    loader_id: &Pubkey,
786    check_seed_length: bool,
787) -> Result<(Vec<&'a [u8]>, &'a Pubkey), EbpfError<BpfError>> {
788    let untranslated_seeds =
789        translate_slice::<&[&u8]>(memory_mapping, seeds_addr, seeds_len, loader_id)?;
790    if untranslated_seeds.len() > MAX_SEEDS {
791        return Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into());
792    }
793    let seeds = untranslated_seeds
794        .iter()
795        .map(|untranslated_seed| {
796            if check_seed_length && untranslated_seed.len() > MAX_SEED_LEN {
797                return Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into());
798            }
799            translate_slice::<u8>(
800                memory_mapping,
801                untranslated_seed.as_ptr() as *const _ as u64,
802                untranslated_seed.len() as u64,
803                loader_id,
804            )
805        })
806        .collect::<Result<Vec<_>, EbpfError<BpfError>>>()?;
807    let program_id = translate_type::<Pubkey>(memory_mapping, program_id_addr, loader_id)?;
808    Ok((seeds, program_id))
809}
810
811fn is_native_id(seeds: &[&[u8]], program_id: &Pubkey) -> bool {
812    use gemachain_sdk::{config, feature, secp256k1_program, stake, system_program, vote};
813    // Does more than just check native ids in order to emulate the same failure
814    // signature that `compute_program_address` had before the removal of the
815    // check.
816    if seeds.len() > MAX_SEEDS {
817        return true;
818    }
819    for seed in seeds.iter() {
820        if seed.len() > MAX_SEED_LEN {
821            return true;
822        }
823    }
824
825    let native_ids = [
826        bpf_loader::id(),
827        bpf_loader_deprecated::id(),
828        feature::id(),
829        config::program::id(),
830        stake::program::id(),
831        stake::config::id(),
832        vote::program::id(),
833        secp256k1_program::id(),
834        system_program::id(),
835        sysvar::id(),
836    ];
837    native_ids.contains(program_id)
838}
839
840/// Create a program address
841struct SyscallCreateProgramAddress<'a> {
842    cost: u64,
843    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
844    loader_id: &'a Pubkey,
845    allow_native_ids: bool,
846    check_seed_length: bool,
847}
848impl<'a> SyscallObject<BpfError> for SyscallCreateProgramAddress<'a> {
849    fn call(
850        &mut self,
851        seeds_addr: u64,
852        seeds_len: u64,
853        program_id_addr: u64,
854        address_addr: u64,
855        _arg5: u64,
856        memory_mapping: &MemoryMapping,
857        result: &mut Result<u64, EbpfError<BpfError>>,
858    ) {
859        if self.check_seed_length {
860            question_mark!(self.compute_meter.consume(self.cost), result);
861        }
862
863        let (seeds, program_id) = question_mark!(
864            translate_and_check_program_address_inputs(
865                seeds_addr,
866                seeds_len,
867                program_id_addr,
868                memory_mapping,
869                self.loader_id,
870                self.check_seed_length,
871            ),
872            result
873        );
874
875        if !self.check_seed_length {
876            question_mark!(self.compute_meter.consume(self.cost), result);
877        }
878
879        if !self.allow_native_ids && is_native_id(&seeds, program_id) {
880            *result = Ok(1);
881            return;
882        }
883
884        let new_address = match Pubkey::create_program_address(&seeds, program_id) {
885            Ok(address) => address,
886            Err(_) => {
887                *result = Ok(1);
888                return;
889            }
890        };
891        let address = question_mark!(
892            translate_slice_mut::<u8>(memory_mapping, address_addr, 32, self.loader_id,),
893            result
894        );
895        address.copy_from_slice(new_address.as_ref());
896        *result = Ok(0);
897    }
898}
899
900/// Create a program address
901struct SyscallTryFindProgramAddress<'a> {
902    cost: u64,
903    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
904    loader_id: &'a Pubkey,
905    allow_native_ids: bool,
906    check_seed_length: bool,
907}
908impl<'a> SyscallObject<BpfError> for SyscallTryFindProgramAddress<'a> {
909    fn call(
910        &mut self,
911        seeds_addr: u64,
912        seeds_len: u64,
913        program_id_addr: u64,
914        address_addr: u64,
915        bump_seed_addr: u64,
916        memory_mapping: &MemoryMapping,
917        result: &mut Result<u64, EbpfError<BpfError>>,
918    ) {
919        if self.check_seed_length {
920            question_mark!(self.compute_meter.consume(self.cost), result);
921        }
922
923        let (seeds, program_id) = question_mark!(
924            translate_and_check_program_address_inputs(
925                seeds_addr,
926                seeds_len,
927                program_id_addr,
928                memory_mapping,
929                self.loader_id,
930                self.check_seed_length,
931            ),
932            result
933        );
934
935        let mut bump_seed = [std::u8::MAX];
936        for _ in 0..std::u8::MAX {
937            {
938                let mut seeds_with_bump = seeds.to_vec();
939                seeds_with_bump.push(&bump_seed);
940
941                if !self.check_seed_length {
942                    question_mark!(self.compute_meter.consume(self.cost), result);
943                }
944
945                if self.allow_native_ids || !is_native_id(&seeds, program_id) {
946                    if let Ok(new_address) =
947                        Pubkey::create_program_address(&seeds_with_bump, program_id)
948                    {
949                        let bump_seed_ref = question_mark!(
950                            translate_type_mut::<u8>(
951                                memory_mapping,
952                                bump_seed_addr,
953                                self.loader_id,
954                            ),
955                            result
956                        );
957                        let address = question_mark!(
958                            translate_slice_mut::<u8>(
959                                memory_mapping,
960                                address_addr,
961                                32,
962                                self.loader_id,
963                            ),
964                            result
965                        );
966                        *bump_seed_ref = bump_seed[0];
967                        address.copy_from_slice(new_address.as_ref());
968                        *result = Ok(0);
969                        return;
970                    }
971                }
972            }
973            bump_seed[0] -= 1;
974            if self.check_seed_length {
975                question_mark!(self.compute_meter.consume(self.cost), result);
976            }
977        }
978        *result = Ok(1);
979    }
980}
981
982/// SHA256
983pub struct SyscallSha256<'a> {
984    sha256_base_cost: u64,
985    sha256_byte_cost: u64,
986    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
987    loader_id: &'a Pubkey,
988}
989impl<'a> SyscallObject<BpfError> for SyscallSha256<'a> {
990    fn call(
991        &mut self,
992        vals_addr: u64,
993        vals_len: u64,
994        result_addr: u64,
995        _arg4: u64,
996        _arg5: u64,
997        memory_mapping: &MemoryMapping,
998        result: &mut Result<u64, EbpfError<BpfError>>,
999    ) {
1000        question_mark!(self.compute_meter.consume(self.sha256_base_cost), result);
1001        let hash_result = question_mark!(
1002            translate_slice_mut::<u8>(
1003                memory_mapping,
1004                result_addr,
1005                HASH_BYTES as u64,
1006                self.loader_id,
1007            ),
1008            result
1009        );
1010        let mut hasher = Hasher::default();
1011        if vals_len > 0 {
1012            let vals = question_mark!(
1013                translate_slice::<&[u8]>(memory_mapping, vals_addr, vals_len, self.loader_id,),
1014                result
1015            );
1016            for val in vals.iter() {
1017                let bytes = question_mark!(
1018                    translate_slice::<u8>(
1019                        memory_mapping,
1020                        val.as_ptr() as u64,
1021                        val.len() as u64,
1022                        self.loader_id,
1023                    ),
1024                    result
1025                );
1026                question_mark!(
1027                    self.compute_meter
1028                        .consume(self.sha256_byte_cost * (val.len() as u64 / 2)),
1029                    result
1030                );
1031                hasher.hash(bytes);
1032            }
1033        }
1034        hash_result.copy_from_slice(&hasher.result().to_bytes());
1035        *result = Ok(0);
1036    }
1037}
1038
1039fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId>(
1040    id: &Pubkey,
1041    var_addr: u64,
1042    loader_id: &Pubkey,
1043    memory_mapping: &MemoryMapping,
1044    invoke_context: Rc<RefCell<&mut dyn InvokeContext>>,
1045) -> Result<u64, EbpfError<BpfError>> {
1046    let invoke_context = invoke_context
1047        .try_borrow()
1048        .map_err(|_| SyscallError::InvokeContextBorrowFailed)?;
1049
1050    invoke_context
1051        .get_compute_meter()
1052        .consume(invoke_context.get_compute_budget().sysvar_base_cost + size_of::<T>() as u64)?;
1053    let var = translate_type_mut::<T>(memory_mapping, var_addr, loader_id)?;
1054
1055    *var = process_instruction::get_sysvar::<T>(*invoke_context, id)
1056        .map_err(SyscallError::InstructionError)?;
1057
1058    Ok(SUCCESS)
1059}
1060
1061/// Get a Clock sysvar
1062struct SyscallGetClockSysvar<'a> {
1063    invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
1064    loader_id: &'a Pubkey,
1065}
1066impl<'a> SyscallObject<BpfError> for SyscallGetClockSysvar<'a> {
1067    fn call(
1068        &mut self,
1069        var_addr: u64,
1070        _arg2: u64,
1071        _arg3: u64,
1072        _arg4: u64,
1073        _arg5: u64,
1074        memory_mapping: &MemoryMapping,
1075        result: &mut Result<u64, EbpfError<BpfError>>,
1076    ) {
1077        *result = get_sysvar::<Clock>(
1078            &sysvar::clock::id(),
1079            var_addr,
1080            self.loader_id,
1081            memory_mapping,
1082            self.invoke_context.clone(),
1083        );
1084    }
1085}
1086/// Get a EpochSchedule sysvar
1087struct SyscallGetEpochScheduleSysvar<'a> {
1088    invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
1089    loader_id: &'a Pubkey,
1090}
1091impl<'a> SyscallObject<BpfError> for SyscallGetEpochScheduleSysvar<'a> {
1092    fn call(
1093        &mut self,
1094        var_addr: u64,
1095        _arg2: u64,
1096        _arg3: u64,
1097        _arg4: u64,
1098        _arg5: u64,
1099        memory_mapping: &MemoryMapping,
1100        result: &mut Result<u64, EbpfError<BpfError>>,
1101    ) {
1102        *result = get_sysvar::<EpochSchedule>(
1103            &sysvar::epoch_schedule::id(),
1104            var_addr,
1105            self.loader_id,
1106            memory_mapping,
1107            self.invoke_context.clone(),
1108        );
1109    }
1110}
1111/// Get a Fees sysvar
1112struct SyscallGetFeesSysvar<'a> {
1113    invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
1114    loader_id: &'a Pubkey,
1115}
1116#[allow(deprecated)]
1117impl<'a> SyscallObject<BpfError> for SyscallGetFeesSysvar<'a> {
1118    fn call(
1119        &mut self,
1120        var_addr: u64,
1121        _arg2: u64,
1122        _arg3: u64,
1123        _arg4: u64,
1124        _arg5: u64,
1125        memory_mapping: &MemoryMapping,
1126        result: &mut Result<u64, EbpfError<BpfError>>,
1127    ) {
1128        *result = get_sysvar::<Fees>(
1129            &sysvar::fees::id(),
1130            var_addr,
1131            self.loader_id,
1132            memory_mapping,
1133            self.invoke_context.clone(),
1134        );
1135    }
1136}
1137/// Get a Rent sysvar
1138struct SyscallGetRentSysvar<'a> {
1139    invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
1140    loader_id: &'a Pubkey,
1141}
1142impl<'a> SyscallObject<BpfError> for SyscallGetRentSysvar<'a> {
1143    fn call(
1144        &mut self,
1145        var_addr: u64,
1146        _arg2: u64,
1147        _arg3: u64,
1148        _arg4: u64,
1149        _arg5: u64,
1150        memory_mapping: &MemoryMapping,
1151        result: &mut Result<u64, EbpfError<BpfError>>,
1152    ) {
1153        *result = get_sysvar::<Rent>(
1154            &sysvar::rent::id(),
1155            var_addr,
1156            self.loader_id,
1157            memory_mapping,
1158            self.invoke_context.clone(),
1159        );
1160    }
1161}
1162
1163// Keccak256
1164pub struct SyscallKeccak256<'a> {
1165    base_cost: u64,
1166    byte_cost: u64,
1167    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
1168    loader_id: &'a Pubkey,
1169}
1170impl<'a> SyscallObject<BpfError> for SyscallKeccak256<'a> {
1171    fn call(
1172        &mut self,
1173        vals_addr: u64,
1174        vals_len: u64,
1175        result_addr: u64,
1176        _arg4: u64,
1177        _arg5: u64,
1178        memory_mapping: &MemoryMapping,
1179        result: &mut Result<u64, EbpfError<BpfError>>,
1180    ) {
1181        question_mark!(self.compute_meter.consume(self.base_cost), result);
1182        let hash_result = question_mark!(
1183            translate_slice_mut::<u8>(
1184                memory_mapping,
1185                result_addr,
1186                keccak::HASH_BYTES as u64,
1187                self.loader_id,
1188            ),
1189            result
1190        );
1191        let mut hasher = keccak::Hasher::default();
1192        if vals_len > 0 {
1193            let vals = question_mark!(
1194                translate_slice::<&[u8]>(memory_mapping, vals_addr, vals_len, self.loader_id),
1195                result
1196            );
1197            for val in vals.iter() {
1198                let bytes = question_mark!(
1199                    translate_slice::<u8>(
1200                        memory_mapping,
1201                        val.as_ptr() as u64,
1202                        val.len() as u64,
1203                        self.loader_id,
1204                    ),
1205                    result
1206                );
1207                question_mark!(
1208                    self.compute_meter
1209                        .consume(self.byte_cost * (val.len() as u64 / 2)),
1210                    result
1211                );
1212                hasher.hash(bytes);
1213            }
1214        }
1215        hash_result.copy_from_slice(&hasher.result().to_bytes());
1216        *result = Ok(0);
1217    }
1218}
1219
1220fn check_overlapping(src_addr: u64, dst_addr: u64, n: u64) -> bool {
1221    (src_addr <= dst_addr && src_addr + n > dst_addr)
1222        || (dst_addr <= src_addr && dst_addr + n > src_addr)
1223}
1224
1225/// memcpy
1226pub struct SyscallMemcpy<'a> {
1227    cost: u64,
1228    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
1229    loader_id: &'a Pubkey,
1230    mem_overlap_fix: bool,
1231}
1232impl<'a> SyscallObject<BpfError> for SyscallMemcpy<'a> {
1233    fn call(
1234        &mut self,
1235        dst_addr: u64,
1236        src_addr: u64,
1237        n: u64,
1238        _arg4: u64,
1239        _arg5: u64,
1240        memory_mapping: &MemoryMapping,
1241        result: &mut Result<u64, EbpfError<BpfError>>,
1242    ) {
1243        if if self.mem_overlap_fix {
1244            check_overlapping(src_addr, dst_addr, n)
1245        } else {
1246            dst_addr + n > src_addr && src_addr > dst_addr
1247        } {
1248            *result = Err(SyscallError::CopyOverlapping.into());
1249            return;
1250        }
1251
1252        question_mark!(self.compute_meter.consume(n / self.cost), result);
1253        let dst = question_mark!(
1254            translate_slice_mut::<u8>(memory_mapping, dst_addr, n, self.loader_id),
1255            result
1256        );
1257        let src = question_mark!(
1258            translate_slice::<u8>(memory_mapping, src_addr, n, self.loader_id),
1259            result
1260        );
1261        unsafe {
1262            std::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), n as usize);
1263        }
1264        *result = Ok(0);
1265    }
1266}
1267/// memmove
1268pub struct SyscallMemmove<'a> {
1269    cost: u64,
1270    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
1271    loader_id: &'a Pubkey,
1272}
1273impl<'a> SyscallObject<BpfError> for SyscallMemmove<'a> {
1274    fn call(
1275        &mut self,
1276        dst_addr: u64,
1277        src_addr: u64,
1278        n: u64,
1279        _arg4: u64,
1280        _arg5: u64,
1281        memory_mapping: &MemoryMapping,
1282        result: &mut Result<u64, EbpfError<BpfError>>,
1283    ) {
1284        question_mark!(self.compute_meter.consume(n / self.cost), result);
1285        let dst = question_mark!(
1286            translate_slice_mut::<u8>(memory_mapping, dst_addr, n, self.loader_id),
1287            result
1288        );
1289        let src = question_mark!(
1290            translate_slice::<u8>(memory_mapping, src_addr, n, self.loader_id),
1291            result
1292        );
1293        unsafe {
1294            std::ptr::copy(src.as_ptr(), dst.as_mut_ptr(), n as usize);
1295        }
1296        *result = Ok(0);
1297    }
1298}
1299/// memcmp
1300pub struct SyscallMemcmp<'a> {
1301    cost: u64,
1302    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
1303    loader_id: &'a Pubkey,
1304}
1305impl<'a> SyscallObject<BpfError> for SyscallMemcmp<'a> {
1306    fn call(
1307        &mut self,
1308        s1_addr: u64,
1309        s2_addr: u64,
1310        n: u64,
1311        cmp_result_addr: u64,
1312        _arg5: u64,
1313        memory_mapping: &MemoryMapping,
1314        result: &mut Result<u64, EbpfError<BpfError>>,
1315    ) {
1316        question_mark!(self.compute_meter.consume(n / self.cost), result);
1317        let s1 = question_mark!(
1318            translate_slice::<u8>(memory_mapping, s1_addr, n, self.loader_id),
1319            result
1320        );
1321        let s2 = question_mark!(
1322            translate_slice::<u8>(memory_mapping, s2_addr, n, self.loader_id),
1323            result
1324        );
1325        let cmp_result = question_mark!(
1326            translate_type_mut::<i32>(memory_mapping, cmp_result_addr, self.loader_id),
1327            result
1328        );
1329        let mut i = 0;
1330        while i < n as usize {
1331            let a = s1[i];
1332            let b = s2[i];
1333            if a != b {
1334                *cmp_result = a as i32 - b as i32;
1335                *result = Ok(0);
1336                return;
1337            }
1338            i += 1;
1339        }
1340        *cmp_result = 0;
1341        *result = Ok(0);
1342    }
1343}
1344/// memset
1345pub struct SyscallMemset<'a> {
1346    cost: u64,
1347    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
1348    loader_id: &'a Pubkey,
1349}
1350impl<'a> SyscallObject<BpfError> for SyscallMemset<'a> {
1351    fn call(
1352        &mut self,
1353        s_addr: u64,
1354        c: u64,
1355        n: u64,
1356        _arg4: u64,
1357        _arg5: u64,
1358        memory_mapping: &MemoryMapping,
1359        result: &mut Result<u64, EbpfError<BpfError>>,
1360    ) {
1361        question_mark!(self.compute_meter.consume(n / self.cost), result);
1362        let s = question_mark!(
1363            translate_slice_mut::<u8>(memory_mapping, s_addr, n, self.loader_id),
1364            result
1365        );
1366        for val in s.iter_mut().take(n as usize) {
1367            *val = c as u8;
1368        }
1369        *result = Ok(0);
1370    }
1371}
1372
1373/// secp256k1_recover
1374pub struct SyscallSecp256k1Recover<'a> {
1375    cost: u64,
1376    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
1377    loader_id: &'a Pubkey,
1378    libsecp256k1_0_5_upgrade_enabled: bool,
1379}
1380
1381impl<'a> SyscallObject<BpfError> for SyscallSecp256k1Recover<'a> {
1382    fn call(
1383        &mut self,
1384        hash_addr: u64,
1385        recovery_id_val: u64,
1386        signature_addr: u64,
1387        result_addr: u64,
1388        _arg5: u64,
1389        memory_mapping: &MemoryMapping,
1390        result: &mut Result<u64, EbpfError<BpfError>>,
1391    ) {
1392        question_mark!(self.compute_meter.consume(self.cost), result);
1393
1394        let hash = question_mark!(
1395            translate_slice::<u8>(
1396                memory_mapping,
1397                hash_addr,
1398                keccak::HASH_BYTES as u64,
1399                self.loader_id,
1400            ),
1401            result
1402        );
1403        let signature = question_mark!(
1404            translate_slice::<u8>(
1405                memory_mapping,
1406                signature_addr,
1407                SECP256K1_SIGNATURE_LENGTH as u64,
1408                self.loader_id,
1409            ),
1410            result
1411        );
1412        let secp256k1_recover_result = question_mark!(
1413            translate_slice_mut::<u8>(
1414                memory_mapping,
1415                result_addr,
1416                SECP256K1_PUBLIC_KEY_LENGTH as u64,
1417                self.loader_id,
1418            ),
1419            result
1420        );
1421
1422        let message = match libsecp256k1::Message::parse_slice(hash) {
1423            Ok(msg) => msg,
1424            Err(_) => {
1425                *result = Ok(Secp256k1RecoverError::InvalidHash.into());
1426                return;
1427            }
1428        };
1429        let recovery_id = match libsecp256k1::RecoveryId::parse(recovery_id_val as u8) {
1430            Ok(id) => id,
1431            Err(_) => {
1432                *result = Ok(Secp256k1RecoverError::InvalidRecoveryId.into());
1433                return;
1434            }
1435        };
1436        let sig_parse_result = if self.libsecp256k1_0_5_upgrade_enabled {
1437            libsecp256k1::Signature::parse_standard_slice(signature)
1438        } else {
1439            libsecp256k1::Signature::parse_overflowing_slice(signature)
1440        };
1441
1442        let signature = match sig_parse_result {
1443            Ok(sig) => sig,
1444            Err(_) => {
1445                *result = Ok(Secp256k1RecoverError::InvalidSignature.into());
1446                return;
1447            }
1448        };
1449
1450        let public_key = match libsecp256k1::recover(&message, &signature, &recovery_id) {
1451            Ok(key) => key.serialize(),
1452            Err(_) => {
1453                *result = Ok(Secp256k1RecoverError::InvalidSignature.into());
1454                return;
1455            }
1456        };
1457
1458        secp256k1_recover_result.copy_from_slice(&public_key[1..65]);
1459        *result = Ok(SUCCESS);
1460    }
1461}
1462
1463// Blake3
1464pub struct SyscallBlake3<'a> {
1465    base_cost: u64,
1466    byte_cost: u64,
1467    compute_meter: Rc<RefCell<dyn ComputeMeter>>,
1468    loader_id: &'a Pubkey,
1469}
1470impl<'a> SyscallObject<BpfError> for SyscallBlake3<'a> {
1471    fn call(
1472        &mut self,
1473        vals_addr: u64,
1474        vals_len: u64,
1475        result_addr: u64,
1476        _arg4: u64,
1477        _arg5: u64,
1478        memory_mapping: &MemoryMapping,
1479        result: &mut Result<u64, EbpfError<BpfError>>,
1480    ) {
1481        question_mark!(self.compute_meter.consume(self.base_cost), result);
1482        let hash_result = question_mark!(
1483            translate_slice_mut::<u8>(
1484                memory_mapping,
1485                result_addr,
1486                blake3::HASH_BYTES as u64,
1487                self.loader_id,
1488            ),
1489            result
1490        );
1491        let mut hasher = blake3::Hasher::default();
1492        if vals_len > 0 {
1493            let vals = question_mark!(
1494                translate_slice::<&[u8]>(memory_mapping, vals_addr, vals_len, self.loader_id),
1495                result
1496            );
1497            for val in vals.iter() {
1498                let bytes = question_mark!(
1499                    translate_slice::<u8>(
1500                        memory_mapping,
1501                        val.as_ptr() as u64,
1502                        val.len() as u64,
1503                        self.loader_id,
1504                    ),
1505                    result
1506                );
1507                question_mark!(
1508                    self.compute_meter
1509                        .consume(self.byte_cost * (val.len() as u64 / 2)),
1510                    result
1511                );
1512                hasher.hash(bytes);
1513            }
1514        }
1515        hash_result.copy_from_slice(&hasher.result().to_bytes());
1516        *result = Ok(0);
1517    }
1518}
1519
1520// Cross-program invocation syscalls
1521
1522struct AccountReferences<'a> {
1523    carats: &'a mut u64,
1524    owner: &'a mut Pubkey,
1525    data: &'a mut [u8],
1526    vm_data_addr: u64,
1527    ref_to_len_in_vm: &'a mut u64,
1528    serialized_len_ptr: &'a mut u64,
1529    executable: bool,
1530    rent_epoch: u64,
1531}
1532type TranslatedAccounts<'a> = (
1533    Vec<usize>,
1534    Vec<(
1535        Rc<RefCell<AccountSharedData>>,
1536        Option<AccountReferences<'a>>,
1537    )>,
1538);
1539
1540/// Implemented by language specific data structure translators
1541trait SyscallInvokeSigned<'a> {
1542    fn get_context_mut(&self) -> Result<RefMut<&'a mut dyn InvokeContext>, EbpfError<BpfError>>;
1543    fn get_context(&self) -> Result<Ref<&'a mut dyn InvokeContext>, EbpfError<BpfError>>;
1544    fn translate_instruction(
1545        &self,
1546        addr: u64,
1547        memory_mapping: &MemoryMapping,
1548        invoke_context: &mut dyn InvokeContext,
1549    ) -> Result<Instruction, EbpfError<BpfError>>;
1550    fn translate_accounts(
1551        &self,
1552        message: &Message,
1553        account_infos_addr: u64,
1554        account_infos_len: u64,
1555        memory_mapping: &MemoryMapping,
1556        invoke_context: &mut dyn InvokeContext,
1557    ) -> Result<TranslatedAccounts<'a>, EbpfError<BpfError>>;
1558    fn translate_signers(
1559        &self,
1560        program_id: &Pubkey,
1561        signers_seeds_addr: u64,
1562        signers_seeds_len: u64,
1563        memory_mapping: &MemoryMapping,
1564    ) -> Result<Vec<Pubkey>, EbpfError<BpfError>>;
1565}
1566
1567/// Cross-program invocation called from Rust
1568pub struct SyscallInvokeSignedRust<'a> {
1569    invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
1570    loader_id: &'a Pubkey,
1571}
1572impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> {
1573    fn get_context_mut(&self) -> Result<RefMut<&'a mut dyn InvokeContext>, EbpfError<BpfError>> {
1574        self.invoke_context
1575            .try_borrow_mut()
1576            .map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
1577    }
1578    fn get_context(&self) -> Result<Ref<&'a mut dyn InvokeContext>, EbpfError<BpfError>> {
1579        self.invoke_context
1580            .try_borrow()
1581            .map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
1582    }
1583    fn translate_instruction(
1584        &self,
1585        addr: u64,
1586        memory_mapping: &MemoryMapping,
1587        invoke_context: &mut dyn InvokeContext,
1588    ) -> Result<Instruction, EbpfError<BpfError>> {
1589        let ix = translate_type::<Instruction>(memory_mapping, addr, self.loader_id)?;
1590
1591        check_instruction_size(ix.accounts.len(), ix.data.len(), invoke_context)?;
1592
1593        let accounts = translate_slice::<AccountMeta>(
1594            memory_mapping,
1595            ix.accounts.as_ptr() as u64,
1596            ix.accounts.len() as u64,
1597            self.loader_id,
1598        )?
1599        .to_vec();
1600        let data = translate_slice::<u8>(
1601            memory_mapping,
1602            ix.data.as_ptr() as u64,
1603            ix.data.len() as u64,
1604            self.loader_id,
1605        )?
1606        .to_vec();
1607        Ok(Instruction {
1608            program_id: ix.program_id,
1609            accounts,
1610            data,
1611        })
1612    }
1613
1614    fn translate_accounts(
1615        &self,
1616        message: &Message,
1617        account_infos_addr: u64,
1618        account_infos_len: u64,
1619        memory_mapping: &MemoryMapping,
1620        invoke_context: &mut dyn InvokeContext,
1621    ) -> Result<TranslatedAccounts<'a>, EbpfError<BpfError>> {
1622        let account_infos = translate_slice::<AccountInfo>(
1623            memory_mapping,
1624            account_infos_addr,
1625            account_infos_len,
1626            self.loader_id,
1627        )?;
1628        check_account_infos(account_infos.len(), invoke_context)?;
1629        let account_info_keys = account_infos
1630            .iter()
1631            .map(|account_info| {
1632                translate_type::<Pubkey>(
1633                    memory_mapping,
1634                    account_info.key as *const _ as u64,
1635                    self.loader_id,
1636                )
1637            })
1638            .collect::<Result<Vec<_>, EbpfError<BpfError>>>()?;
1639
1640        let translate = |account_info: &AccountInfo, invoke_context: &mut dyn InvokeContext| {
1641            // Translate the account from user space
1642
1643            let carats = {
1644                // Double translate carats out of RefCell
1645                let ptr = translate_type::<u64>(
1646                    memory_mapping,
1647                    account_info.carats.as_ptr() as u64,
1648                    self.loader_id,
1649                )?;
1650                translate_type_mut::<u64>(memory_mapping, *ptr, self.loader_id)?
1651            };
1652            let owner = translate_type_mut::<Pubkey>(
1653                memory_mapping,
1654                account_info.owner as *const _ as u64,
1655                self.loader_id,
1656            )?;
1657
1658            let (data, vm_data_addr, ref_to_len_in_vm, serialized_len_ptr) = {
1659                // Double translate data out of RefCell
1660                let data = *translate_type::<&[u8]>(
1661                    memory_mapping,
1662                    account_info.data.as_ptr() as *const _ as u64,
1663                    self.loader_id,
1664                )?;
1665
1666                invoke_context.get_compute_meter().consume(
1667                    data.len() as u64 / invoke_context.get_compute_budget().cpi_bytes_per_unit,
1668                )?;
1669
1670                let translated = translate(
1671                    memory_mapping,
1672                    AccessType::Store,
1673                    unsafe { (account_info.data.as_ptr() as *const u64).offset(1) as u64 },
1674                    8,
1675                )? as *mut u64;
1676                let ref_to_len_in_vm = unsafe { &mut *translated };
1677                let ref_of_len_in_input_buffer = unsafe { data.as_ptr().offset(-8) };
1678                let serialized_len_ptr = translate_type_mut::<u64>(
1679                    memory_mapping,
1680                    ref_of_len_in_input_buffer as *const _ as u64,
1681                    self.loader_id,
1682                )?;
1683                let vm_data_addr = data.as_ptr() as u64;
1684                (
1685                    translate_slice_mut::<u8>(
1686                        memory_mapping,
1687                        vm_data_addr,
1688                        data.len() as u64,
1689                        self.loader_id,
1690                    )?,
1691                    vm_data_addr,
1692                    ref_to_len_in_vm,
1693                    serialized_len_ptr,
1694                )
1695            };
1696
1697            Ok(AccountReferences {
1698                carats,
1699                owner,
1700                data,
1701                vm_data_addr,
1702                ref_to_len_in_vm,
1703                serialized_len_ptr,
1704                executable: account_info.executable,
1705                rent_epoch: account_info.rent_epoch,
1706            })
1707        };
1708
1709        get_translated_accounts(
1710            message,
1711            &account_info_keys,
1712            account_infos,
1713            invoke_context,
1714            translate,
1715        )
1716    }
1717
1718    fn translate_signers(
1719        &self,
1720        program_id: &Pubkey,
1721        signers_seeds_addr: u64,
1722        signers_seeds_len: u64,
1723        memory_mapping: &MemoryMapping,
1724    ) -> Result<Vec<Pubkey>, EbpfError<BpfError>> {
1725        let mut signers = Vec::new();
1726        if signers_seeds_len > 0 {
1727            let signers_seeds = translate_slice::<&[&[u8]]>(
1728                memory_mapping,
1729                signers_seeds_addr,
1730                signers_seeds_len,
1731                self.loader_id,
1732            )?;
1733            if signers_seeds.len() > MAX_SIGNERS {
1734                return Err(SyscallError::TooManySigners.into());
1735            }
1736            for signer_seeds in signers_seeds.iter() {
1737                let untranslated_seeds = translate_slice::<&[u8]>(
1738                    memory_mapping,
1739                    signer_seeds.as_ptr() as *const _ as u64,
1740                    signer_seeds.len() as u64,
1741                    self.loader_id,
1742                )?;
1743                if untranslated_seeds.len() > MAX_SEEDS {
1744                    return Err(SyscallError::InstructionError(
1745                        InstructionError::MaxSeedLengthExceeded,
1746                    )
1747                    .into());
1748                }
1749                let seeds = untranslated_seeds
1750                    .iter()
1751                    .map(|untranslated_seed| {
1752                        translate_slice::<u8>(
1753                            memory_mapping,
1754                            untranslated_seed.as_ptr() as *const _ as u64,
1755                            untranslated_seed.len() as u64,
1756                            self.loader_id,
1757                        )
1758                    })
1759                    .collect::<Result<Vec<_>, EbpfError<BpfError>>>()?;
1760                let signer = Pubkey::create_program_address(&seeds, program_id)
1761                    .map_err(SyscallError::BadSeeds)?;
1762                signers.push(signer);
1763            }
1764            Ok(signers)
1765        } else {
1766            Ok(vec![])
1767        }
1768    }
1769}
1770impl<'a> SyscallObject<BpfError> for SyscallInvokeSignedRust<'a> {
1771    fn call(
1772        &mut self,
1773        instruction_addr: u64,
1774        account_infos_addr: u64,
1775        account_infos_len: u64,
1776        signers_seeds_addr: u64,
1777        signers_seeds_len: u64,
1778        memory_mapping: &MemoryMapping,
1779        result: &mut Result<u64, EbpfError<BpfError>>,
1780    ) {
1781        *result = call(
1782            self,
1783            instruction_addr,
1784            account_infos_addr,
1785            account_infos_len,
1786            signers_seeds_addr,
1787            signers_seeds_len,
1788            memory_mapping,
1789        );
1790    }
1791}
1792
1793/// Rust representation of C's GemaInstruction
1794#[derive(Debug)]
1795struct GemaInstruction {
1796    program_id_addr: u64,
1797    accounts_addr: u64,
1798    accounts_len: usize,
1799    data_addr: u64,
1800    data_len: usize,
1801}
1802
1803/// Rust representation of C's GemaAccountMeta
1804#[derive(Debug)]
1805struct GemaAccountMeta {
1806    pubkey_addr: u64,
1807    is_writable: bool,
1808    is_signer: bool,
1809}
1810
1811/// Rust representation of C's GemaAccountInfo
1812#[derive(Debug)]
1813struct GemaAccountInfo {
1814    key_addr: u64,
1815    carats_addr: u64,
1816    data_len: u64,
1817    data_addr: u64,
1818    owner_addr: u64,
1819    rent_epoch: u64,
1820    is_signer: bool,
1821    is_writable: bool,
1822    executable: bool,
1823}
1824
1825/// Rust representation of C's GemaSignerSeed
1826#[derive(Debug)]
1827struct GemaSignerSeedC {
1828    addr: u64,
1829    len: u64,
1830}
1831
1832/// Rust representation of C's GemaSignerSeeds
1833#[derive(Debug)]
1834struct GemaSignerSeedsC {
1835    addr: u64,
1836    len: u64,
1837}
1838
1839/// Cross-program invocation called from C
1840pub struct SyscallInvokeSignedC<'a> {
1841    invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
1842    loader_id: &'a Pubkey,
1843}
1844impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> {
1845    fn get_context_mut(&self) -> Result<RefMut<&'a mut dyn InvokeContext>, EbpfError<BpfError>> {
1846        self.invoke_context
1847            .try_borrow_mut()
1848            .map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
1849    }
1850    fn get_context(&self) -> Result<Ref<&'a mut dyn InvokeContext>, EbpfError<BpfError>> {
1851        self.invoke_context
1852            .try_borrow()
1853            .map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
1854    }
1855
1856    fn translate_instruction(
1857        &self,
1858        addr: u64,
1859        memory_mapping: &MemoryMapping,
1860        invoke_context: &mut dyn InvokeContext,
1861    ) -> Result<Instruction, EbpfError<BpfError>> {
1862        let ix_c = translate_type::<GemaInstruction>(memory_mapping, addr, self.loader_id)?;
1863
1864        check_instruction_size(ix_c.accounts_len, ix_c.data_len, invoke_context)?;
1865        let program_id =
1866            translate_type::<Pubkey>(memory_mapping, ix_c.program_id_addr, self.loader_id)?;
1867        let meta_cs = translate_slice::<GemaAccountMeta>(
1868            memory_mapping,
1869            ix_c.accounts_addr,
1870            ix_c.accounts_len as u64,
1871            self.loader_id,
1872        )?;
1873        let data = translate_slice::<u8>(
1874            memory_mapping,
1875            ix_c.data_addr,
1876            ix_c.data_len as u64,
1877            self.loader_id,
1878        )?
1879        .to_vec();
1880        let accounts = meta_cs
1881            .iter()
1882            .map(|meta_c| {
1883                let pubkey =
1884                    translate_type::<Pubkey>(memory_mapping, meta_c.pubkey_addr, self.loader_id)?;
1885                Ok(AccountMeta {
1886                    pubkey: *pubkey,
1887                    is_signer: meta_c.is_signer,
1888                    is_writable: meta_c.is_writable,
1889                })
1890            })
1891            .collect::<Result<Vec<AccountMeta>, EbpfError<BpfError>>>()?;
1892
1893        Ok(Instruction {
1894            program_id: *program_id,
1895            accounts,
1896            data,
1897        })
1898    }
1899
1900    fn translate_accounts(
1901        &self,
1902        message: &Message,
1903        account_infos_addr: u64,
1904        account_infos_len: u64,
1905        memory_mapping: &MemoryMapping,
1906        invoke_context: &mut dyn InvokeContext,
1907    ) -> Result<TranslatedAccounts<'a>, EbpfError<BpfError>> {
1908        let account_infos = translate_slice::<GemaAccountInfo>(
1909            memory_mapping,
1910            account_infos_addr,
1911            account_infos_len,
1912            self.loader_id,
1913        )?;
1914        check_account_infos(account_infos.len(), invoke_context)?;
1915        let account_info_keys = account_infos
1916            .iter()
1917            .map(|account_info| {
1918                translate_type::<Pubkey>(memory_mapping, account_info.key_addr, self.loader_id)
1919            })
1920            .collect::<Result<Vec<_>, EbpfError<BpfError>>>()?;
1921
1922        let translate = |account_info: &GemaAccountInfo, invoke_context: &mut dyn InvokeContext| {
1923            // Translate the account from user space
1924
1925            let carats = translate_type_mut::<u64>(
1926                memory_mapping,
1927                account_info.carats_addr,
1928                self.loader_id,
1929            )?;
1930            let owner = translate_type_mut::<Pubkey>(
1931                memory_mapping,
1932                account_info.owner_addr,
1933                self.loader_id,
1934            )?;
1935            let vm_data_addr = account_info.data_addr;
1936
1937            invoke_context.get_compute_meter().consume(
1938                account_info.data_len / invoke_context.get_compute_budget().cpi_bytes_per_unit,
1939            )?;
1940
1941            let data = translate_slice_mut::<u8>(
1942                memory_mapping,
1943                vm_data_addr,
1944                account_info.data_len,
1945                self.loader_id,
1946            )?;
1947
1948            let first_info_addr = &account_infos[0] as *const _ as u64;
1949            let addr = &account_info.data_len as *const u64 as u64;
1950            let vm_addr = account_infos_addr + (addr - first_info_addr);
1951            let _ = translate(
1952                memory_mapping,
1953                AccessType::Store,
1954                vm_addr,
1955                size_of::<u64>() as u64,
1956            )?;
1957            let ref_to_len_in_vm = unsafe { &mut *(addr as *mut u64) };
1958
1959            let ref_of_len_in_input_buffer =
1960                unsafe { (account_info.data_addr as *mut u8).offset(-8) };
1961            let serialized_len_ptr = translate_type_mut::<u64>(
1962                memory_mapping,
1963                ref_of_len_in_input_buffer as *const _ as u64,
1964                self.loader_id,
1965            )?;
1966
1967            Ok(AccountReferences {
1968                carats,
1969                owner,
1970                data,
1971                vm_data_addr,
1972                ref_to_len_in_vm,
1973                serialized_len_ptr,
1974                executable: account_info.executable,
1975                rent_epoch: account_info.rent_epoch,
1976            })
1977        };
1978
1979        get_translated_accounts(
1980            message,
1981            &account_info_keys,
1982            account_infos,
1983            invoke_context,
1984            translate,
1985        )
1986    }
1987
1988    fn translate_signers(
1989        &self,
1990        program_id: &Pubkey,
1991        signers_seeds_addr: u64,
1992        signers_seeds_len: u64,
1993        memory_mapping: &MemoryMapping,
1994    ) -> Result<Vec<Pubkey>, EbpfError<BpfError>> {
1995        if signers_seeds_len > 0 {
1996            let signers_seeds = translate_slice::<GemaSignerSeedC>(
1997                memory_mapping,
1998                signers_seeds_addr,
1999                signers_seeds_len,
2000                self.loader_id,
2001            )?;
2002            if signers_seeds.len() > MAX_SIGNERS {
2003                return Err(SyscallError::TooManySigners.into());
2004            }
2005            Ok(signers_seeds
2006                .iter()
2007                .map(|signer_seeds| {
2008                    let seeds = translate_slice::<GemaSignerSeedC>(
2009                        memory_mapping,
2010                        signer_seeds.addr,
2011                        signer_seeds.len,
2012                        self.loader_id,
2013                    )?;
2014                    if seeds.len() > MAX_SEEDS {
2015                        return Err(SyscallError::InstructionError(
2016                            InstructionError::MaxSeedLengthExceeded,
2017                        )
2018                        .into());
2019                    }
2020                    let seeds_bytes = seeds
2021                        .iter()
2022                        .map(|seed| {
2023                            translate_slice::<u8>(
2024                                memory_mapping,
2025                                seed.addr,
2026                                seed.len,
2027                                self.loader_id,
2028                            )
2029                        })
2030                        .collect::<Result<Vec<_>, EbpfError<BpfError>>>()?;
2031                    Pubkey::create_program_address(&seeds_bytes, program_id)
2032                        .map_err(|err| SyscallError::BadSeeds(err).into())
2033                })
2034                .collect::<Result<Vec<_>, EbpfError<BpfError>>>()?)
2035        } else {
2036            Ok(vec![])
2037        }
2038    }
2039}
2040impl<'a> SyscallObject<BpfError> for SyscallInvokeSignedC<'a> {
2041    fn call(
2042        &mut self,
2043        instruction_addr: u64,
2044        account_infos_addr: u64,
2045        account_infos_len: u64,
2046        signers_seeds_addr: u64,
2047        signers_seeds_len: u64,
2048        memory_mapping: &MemoryMapping,
2049        result: &mut Result<u64, EbpfError<BpfError>>,
2050    ) {
2051        *result = call(
2052            self,
2053            instruction_addr,
2054            account_infos_addr,
2055            account_infos_len,
2056            signers_seeds_addr,
2057            signers_seeds_len,
2058            memory_mapping,
2059        );
2060    }
2061}
2062
2063fn get_translated_accounts<'a, T, F>(
2064    message: &Message,
2065    account_info_keys: &[&Pubkey],
2066    account_infos: &[T],
2067    invoke_context: &mut dyn InvokeContext,
2068    do_translate: F,
2069) -> Result<TranslatedAccounts<'a>, EbpfError<BpfError>>
2070where
2071    F: Fn(&T, &mut dyn InvokeContext) -> Result<AccountReferences<'a>, EbpfError<BpfError>>,
2072{
2073    let demote_program_write_locks =
2074        invoke_context.is_feature_active(&demote_program_write_locks::id());
2075    let mut account_indices = Vec::with_capacity(message.account_keys.len());
2076    let mut accounts = Vec::with_capacity(message.account_keys.len());
2077    for (i, account_key) in message.account_keys.iter().enumerate() {
2078        if let Some((account_index, account)) = invoke_context.get_account(account_key) {
2079            if i == message.instructions[0].program_id_index as usize
2080                || account.borrow().executable()
2081            {
2082                // Use the known account
2083                account_indices.push(account_index);
2084                accounts.push((account, None));
2085                continue;
2086            } else if let Some(account_ref_index) =
2087                account_info_keys.iter().position(|key| *key == account_key)
2088            {
2089                let account_ref = do_translate(&account_infos[account_ref_index], invoke_context)?;
2090                {
2091                    let mut account = account.borrow_mut();
2092                    account.copy_into_owner_from_slice(account_ref.owner.as_ref());
2093                    account.set_data_from_slice(account_ref.data);
2094                    account.set_carats(*account_ref.carats);
2095                    account.set_executable(account_ref.executable);
2096                    account.set_rent_epoch(account_ref.rent_epoch);
2097                }
2098                let account_ref = if message.is_writable(i, demote_program_write_locks) {
2099                    Some(account_ref)
2100                } else {
2101                    None
2102                };
2103                account_indices.push(account_index);
2104                accounts.push((account, account_ref));
2105                continue;
2106            }
2107        }
2108        ic_msg!(
2109            invoke_context,
2110            "Instruction references an unknown account {}",
2111            account_key
2112        );
2113        return Err(SyscallError::InstructionError(InstructionError::MissingAccount).into());
2114    }
2115
2116    Ok((account_indices, accounts))
2117}
2118
2119fn check_instruction_size(
2120    num_accounts: usize,
2121    data_len: usize,
2122    invoke_context: &mut dyn InvokeContext,
2123) -> Result<(), EbpfError<BpfError>> {
2124    let size = num_accounts
2125        .saturating_mul(size_of::<AccountMeta>())
2126        .saturating_add(data_len);
2127    let max_size = invoke_context.get_compute_budget().max_cpi_instruction_size;
2128    if size > max_size {
2129        return Err(SyscallError::InstructionTooLarge(size, max_size).into());
2130    }
2131    Ok(())
2132}
2133
2134fn check_account_infos(
2135    len: usize,
2136    invoke_context: &mut dyn InvokeContext,
2137) -> Result<(), EbpfError<BpfError>> {
2138    if len * size_of::<Pubkey>() > invoke_context.get_compute_budget().max_cpi_instruction_size {
2139        // Cap the number of account_infos a caller can pass to approximate
2140        // maximum that accounts that could be passed in an instruction
2141        return Err(SyscallError::TooManyAccounts.into());
2142    };
2143    Ok(())
2144}
2145
2146fn check_authorized_program(
2147    program_id: &Pubkey,
2148    instruction_data: &[u8],
2149    close_upgradeable_program_accounts: bool,
2150) -> Result<(), EbpfError<BpfError>> {
2151    if native_loader::check_id(program_id)
2152        || bpf_loader::check_id(program_id)
2153        || bpf_loader_deprecated::check_id(program_id)
2154        || (bpf_loader_upgradeable::check_id(program_id)
2155            && !(bpf_loader_upgradeable::is_upgrade_instruction(instruction_data)
2156                || bpf_loader_upgradeable::is_set_authority_instruction(instruction_data)
2157                || (close_upgradeable_program_accounts
2158                    && bpf_loader_upgradeable::is_close_instruction(instruction_data))))
2159    {
2160        return Err(SyscallError::ProgramNotSupported(*program_id).into());
2161    }
2162    Ok(())
2163}
2164
2165/// Call process instruction, common to both Rust and C
2166fn call<'a>(
2167    syscall: &mut dyn SyscallInvokeSigned<'a>,
2168    instruction_addr: u64,
2169    account_infos_addr: u64,
2170    account_infos_len: u64,
2171    signers_seeds_addr: u64,
2172    signers_seeds_len: u64,
2173    memory_mapping: &MemoryMapping,
2174) -> Result<u64, EbpfError<BpfError>> {
2175    let mut invoke_context = syscall.get_context_mut()?;
2176    invoke_context
2177        .get_compute_meter()
2178        .consume(invoke_context.get_compute_budget().invoke_units)?;
2179
2180    // Translate and verify caller's data
2181    let instruction =
2182        syscall.translate_instruction(instruction_addr, memory_mapping, *invoke_context)?;
2183    let caller_program_id = invoke_context
2184        .get_caller()
2185        .map_err(SyscallError::InstructionError)?;
2186    let signers = syscall.translate_signers(
2187        caller_program_id,
2188        signers_seeds_addr,
2189        signers_seeds_len,
2190        memory_mapping,
2191    )?;
2192    let (message, caller_write_privileges, program_indices) =
2193        InstructionProcessor::create_message(&instruction, &signers, &invoke_context)
2194            .map_err(SyscallError::InstructionError)?;
2195    check_authorized_program(
2196        &instruction.program_id,
2197        &instruction.data,
2198        invoke_context.is_feature_active(&close_upgradeable_program_accounts::id()),
2199    )?;
2200    let (account_indices, mut accounts) = syscall.translate_accounts(
2201        &message,
2202        account_infos_addr,
2203        account_infos_len,
2204        memory_mapping,
2205        *invoke_context,
2206    )?;
2207
2208    // Record the instruction
2209    invoke_context.record_instruction(&instruction);
2210
2211    // Process instruction
2212    InstructionProcessor::process_cross_program_instruction(
2213        &message,
2214        &program_indices,
2215        &account_indices,
2216        &caller_write_privileges,
2217        *invoke_context,
2218    )
2219    .map_err(SyscallError::InstructionError)?;
2220
2221    // Copy results back to caller
2222    for (account, account_ref) in accounts.iter_mut() {
2223        let account = account.borrow();
2224        if let Some(account_ref) = account_ref {
2225            *account_ref.carats = account.carats();
2226            *account_ref.owner = *account.owner();
2227            if account_ref.data.len() != account.data().len() {
2228                if !account_ref.data.is_empty() {
2229                    // Only support for `CreateAccount` at this time.
2230                    // Need a way to limit total realloc size across multiple CPI calls
2231                    ic_msg!(
2232                        invoke_context,
2233                        "Inner instructions do not support realloc, only SystemProgram::CreateAccount",
2234                    );
2235                    return Err(
2236                        SyscallError::InstructionError(InstructionError::InvalidRealloc).into(),
2237                    );
2238                }
2239                if account.data().len() > account_ref.data.len() + MAX_PERMITTED_DATA_INCREASE {
2240                    ic_msg!(
2241                        invoke_context,
2242                        "SystemProgram::CreateAccount data size limited to {} in inner instructions",
2243                        MAX_PERMITTED_DATA_INCREASE
2244                    );
2245                    return Err(
2246                        SyscallError::InstructionError(InstructionError::InvalidRealloc).into(),
2247                    );
2248                }
2249                account_ref.data = translate_slice_mut::<u8>(
2250                    memory_mapping,
2251                    account_ref.vm_data_addr,
2252                    account.data().len() as u64,
2253                    &bpf_loader_deprecated::id(), // Don't care since it is byte aligned
2254                )?;
2255                *account_ref.ref_to_len_in_vm = account.data().len() as u64;
2256                *account_ref.serialized_len_ptr = account.data().len() as u64;
2257            }
2258            account_ref
2259                .data
2260                .copy_from_slice(&account.data()[0..account_ref.data.len()]);
2261        }
2262    }
2263
2264    Ok(SUCCESS)
2265}
2266
2267// Return data handling
2268pub struct SyscallSetReturnData<'a> {
2269    invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
2270    loader_id: &'a Pubkey,
2271}
2272impl<'a> SyscallObject<BpfError> for SyscallSetReturnData<'a> {
2273    fn call(
2274        &mut self,
2275        addr: u64,
2276        len: u64,
2277        _arg3: u64,
2278        _arg4: u64,
2279        _arg5: u64,
2280        memory_mapping: &MemoryMapping,
2281        result: &mut Result<u64, EbpfError<BpfError>>,
2282    ) {
2283        let mut invoke_context = question_mark!(
2284            self.invoke_context
2285                .try_borrow_mut()
2286                .map_err(|_| SyscallError::InvokeContextBorrowFailed),
2287            result
2288        );
2289
2290        let budget = invoke_context.get_compute_budget();
2291
2292        question_mark!(
2293            invoke_context
2294                .get_compute_meter()
2295                .consume(len / budget.cpi_bytes_per_unit + budget.syscall_base_cost),
2296            result
2297        );
2298
2299        if len > MAX_RETURN_DATA as u64 {
2300            *result = Err(SyscallError::ReturnDataTooLarge(len, MAX_RETURN_DATA as u64).into());
2301            return;
2302        }
2303
2304        if len == 0 {
2305            invoke_context.set_return_data(None);
2306        } else {
2307            let return_data = question_mark!(
2308                translate_slice::<u8>(memory_mapping, addr, len, self.loader_id),
2309                result
2310            );
2311
2312            let program_id = *question_mark!(
2313                invoke_context
2314                    .get_caller()
2315                    .map_err(SyscallError::InstructionError),
2316                result
2317            );
2318
2319            invoke_context.set_return_data(Some((program_id, return_data.to_vec())));
2320        }
2321
2322        *result = Ok(0);
2323    }
2324}
2325
2326pub struct SyscallGetReturnData<'a> {
2327    invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
2328    loader_id: &'a Pubkey,
2329}
2330impl<'a> SyscallObject<BpfError> for SyscallGetReturnData<'a> {
2331    fn call(
2332        &mut self,
2333        return_data_addr: u64,
2334        len: u64,
2335        program_id_addr: u64,
2336        _arg4: u64,
2337        _arg5: u64,
2338        memory_mapping: &MemoryMapping,
2339        result: &mut Result<u64, EbpfError<BpfError>>,
2340    ) {
2341        let invoke_context = question_mark!(
2342            self.invoke_context
2343                .try_borrow()
2344                .map_err(|_| SyscallError::InvokeContextBorrowFailed),
2345            result
2346        );
2347
2348        let budget = invoke_context.get_compute_budget();
2349
2350        question_mark!(
2351            invoke_context
2352                .get_compute_meter()
2353                .consume(budget.syscall_base_cost),
2354            result
2355        );
2356
2357        if let Some((program_id, return_data)) = invoke_context.get_return_data() {
2358            if len != 0 {
2359                let length = min(return_data.len() as u64, len);
2360
2361                question_mark!(
2362                    invoke_context
2363                        .get_compute_meter()
2364                        .consume((length + size_of::<Pubkey>() as u64) / budget.cpi_bytes_per_unit),
2365                    result
2366                );
2367
2368                let return_data_result = question_mark!(
2369                    translate_slice_mut::<u8>(
2370                        memory_mapping,
2371                        return_data_addr,
2372                        length,
2373                        self.loader_id,
2374                    ),
2375                    result
2376                );
2377
2378                return_data_result.copy_from_slice(&return_data[..length as usize]);
2379
2380                let program_id_result = question_mark!(
2381                    translate_slice_mut::<Pubkey>(
2382                        memory_mapping,
2383                        program_id_addr,
2384                        1,
2385                        self.loader_id,
2386                    ),
2387                    result
2388                );
2389
2390                program_id_result[0] = *program_id;
2391            }
2392
2393            // Return the actual length, rather the length returned
2394            *result = Ok(return_data.len() as u64);
2395        } else {
2396            *result = Ok(0);
2397        }
2398    }
2399}
2400
2401// Log data handling
2402pub struct SyscallLogData<'a> {
2403    invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
2404    loader_id: &'a Pubkey,
2405}
2406impl<'a> SyscallObject<BpfError> for SyscallLogData<'a> {
2407    fn call(
2408        &mut self,
2409        addr: u64,
2410        len: u64,
2411        _arg3: u64,
2412        _arg4: u64,
2413        _arg5: u64,
2414        memory_mapping: &MemoryMapping,
2415        result: &mut Result<u64, EbpfError<BpfError>>,
2416    ) {
2417        let invoke_context = question_mark!(
2418            self.invoke_context
2419                .try_borrow()
2420                .map_err(|_| SyscallError::InvokeContextBorrowFailed),
2421            result
2422        );
2423
2424        let budget = invoke_context.get_compute_budget();
2425
2426        question_mark!(
2427            invoke_context
2428                .get_compute_meter()
2429                .consume(budget.syscall_base_cost),
2430            result
2431        );
2432
2433        let untranslated_fields = question_mark!(
2434            translate_slice::<&[u8]>(memory_mapping, addr, len, self.loader_id),
2435            result
2436        );
2437
2438        question_mark!(
2439            invoke_context
2440                .get_compute_meter()
2441                .consume(untranslated_fields.iter().map(|e| e.len() as u64).sum()),
2442            result
2443        );
2444
2445        let mut fields = Vec::with_capacity(untranslated_fields.len());
2446
2447        for untranslated_field in untranslated_fields {
2448            fields.push(question_mark!(
2449                translate_slice::<u8>(
2450                    memory_mapping,
2451                    untranslated_field.as_ptr() as *const _ as u64,
2452                    untranslated_field.len() as u64,
2453                    self.loader_id,
2454                ),
2455                result
2456            ));
2457        }
2458
2459        let logger = invoke_context.get_logger();
2460
2461        stable_log::program_data(&logger, &fields);
2462
2463        *result = Ok(0);
2464    }
2465}
2466
2467#[cfg(test)]
2468mod tests {
2469    use super::*;
2470    use gemachain_rbpf::{
2471        ebpf::HOST_ALIGN, memory_region::MemoryRegion, user_error::UserError, vm::Config,
2472    };
2473    use gemachain_sdk::{
2474        bpf_loader,
2475        fee_calculator::FeeCalculator,
2476        hash::hashv,
2477        process_instruction::{MockComputeMeter, MockInvokeContext, MockLogger},
2478    };
2479    use std::str::FromStr;
2480
2481    macro_rules! assert_access_violation {
2482        ($result:expr, $va:expr, $len:expr) => {
2483            match $result {
2484                Err(EbpfError::AccessViolation(_, _, va, len, _)) if $va == va && $len == len => (),
2485                Err(EbpfError::StackAccessViolation(_, _, va, len, _))
2486                    if $va == va && $len == len => {}
2487                _ => panic!(),
2488            }
2489        };
2490    }
2491
2492    #[allow(dead_code)]
2493    struct MockSlice {
2494        pub vm_addr: u64,
2495        pub len: usize,
2496    }
2497
2498    #[test]
2499    fn test_translate() {
2500        const START: u64 = 0x100000000;
2501        const LENGTH: u64 = 1000;
2502        let data = vec![0u8; LENGTH as usize];
2503        let addr = data.as_ptr() as u64;
2504        let config = Config::default();
2505        let memory_mapping = MemoryMapping::new::<UserError>(
2506            vec![
2507                MemoryRegion::default(),
2508                MemoryRegion::new_from_slice(&data, START, 0, false),
2509            ],
2510            &config,
2511        )
2512        .unwrap();
2513
2514        let cases = vec![
2515            (true, START, 0, addr),
2516            (true, START, 1, addr),
2517            (true, START, LENGTH, addr),
2518            (true, START + 1, LENGTH - 1, addr + 1),
2519            (false, START + 1, LENGTH, 0),
2520            (true, START + LENGTH - 1, 1, addr + LENGTH - 1),
2521            (true, START + LENGTH, 0, addr + LENGTH),
2522            (false, START + LENGTH, 1, 0),
2523            (false, START, LENGTH + 1, 0),
2524            (false, 0, 0, 0),
2525            (false, 0, 1, 0),
2526            (false, START - 1, 0, 0),
2527            (false, START - 1, 1, 0),
2528            (true, START + LENGTH / 2, LENGTH / 2, addr + LENGTH / 2),
2529        ];
2530        for (ok, start, length, value) in cases {
2531            if ok {
2532                assert_eq!(
2533                    translate(&memory_mapping, AccessType::Load, start, length).unwrap(),
2534                    value
2535                )
2536            } else {
2537                assert!(translate(&memory_mapping, AccessType::Load, start, length).is_err())
2538            }
2539        }
2540    }
2541
2542    #[test]
2543    fn test_translate_type() {
2544        // Pubkey
2545        let pubkey = gemachain_sdk::pubkey::new_rand();
2546        let addr = &pubkey as *const _ as u64;
2547        let config = Config::default();
2548        let memory_mapping = MemoryMapping::new::<UserError>(
2549            vec![
2550                MemoryRegion::default(),
2551                MemoryRegion {
2552                    host_addr: addr,
2553                    vm_addr: 0x100000000,
2554                    len: std::mem::size_of::<Pubkey>() as u64,
2555                    vm_gap_shift: 63,
2556                    is_writable: false,
2557                },
2558            ],
2559            &config,
2560        )
2561        .unwrap();
2562        let translated_pubkey =
2563            translate_type::<Pubkey>(&memory_mapping, 0x100000000, &bpf_loader::id()).unwrap();
2564        assert_eq!(pubkey, *translated_pubkey);
2565
2566        // Instruction
2567        let instruction = Instruction::new_with_bincode(
2568            gemachain_sdk::pubkey::new_rand(),
2569            &"foobar",
2570            vec![AccountMeta::new(gemachain_sdk::pubkey::new_rand(), false)],
2571        );
2572        let addr = &instruction as *const _ as u64;
2573        let mut memory_mapping = MemoryMapping::new::<UserError>(
2574            vec![
2575                MemoryRegion::default(),
2576                MemoryRegion {
2577                    host_addr: addr,
2578                    vm_addr: 0x100000000,
2579                    len: std::mem::size_of::<Instruction>() as u64,
2580                    vm_gap_shift: 63,
2581                    is_writable: false,
2582                },
2583            ],
2584            &config,
2585        )
2586        .unwrap();
2587        let translated_instruction =
2588            translate_type::<Instruction>(&memory_mapping, 0x100000000, &bpf_loader::id()).unwrap();
2589        assert_eq!(instruction, *translated_instruction);
2590        memory_mapping.resize_region::<BpfError>(1, 1).unwrap();
2591        assert!(
2592            translate_type::<Instruction>(&memory_mapping, 0x100000000, &bpf_loader::id(),)
2593                .is_err()
2594        );
2595    }
2596
2597    #[test]
2598    fn test_translate_slice() {
2599        // zero len
2600        let good_data = vec![1u8, 2, 3, 4, 5];
2601        let data: Vec<u8> = vec![];
2602        assert_eq!(0x1 as *const u8, data.as_ptr());
2603        let addr = good_data.as_ptr() as *const _ as u64;
2604        let config = Config::default();
2605        let memory_mapping = MemoryMapping::new::<UserError>(
2606            vec![
2607                MemoryRegion::default(),
2608                MemoryRegion {
2609                    host_addr: addr,
2610                    vm_addr: 0x100000000,
2611                    len: good_data.len() as u64,
2612                    vm_gap_shift: 63,
2613                    is_writable: false,
2614                },
2615            ],
2616            &config,
2617        )
2618        .unwrap();
2619        let translated_data =
2620            translate_slice::<u8>(&memory_mapping, data.as_ptr() as u64, 0, &bpf_loader::id())
2621                .unwrap();
2622        assert_eq!(data, translated_data);
2623        assert_eq!(0, translated_data.len());
2624
2625        // u8
2626        let mut data = vec![1u8, 2, 3, 4, 5];
2627        let addr = data.as_ptr() as *const _ as u64;
2628        let memory_mapping = MemoryMapping::new::<UserError>(
2629            vec![
2630                MemoryRegion::default(),
2631                MemoryRegion {
2632                    host_addr: addr,
2633                    vm_addr: 0x100000000,
2634                    len: data.len() as u64,
2635                    vm_gap_shift: 63,
2636                    is_writable: false,
2637                },
2638            ],
2639            &config,
2640        )
2641        .unwrap();
2642        let translated_data = translate_slice::<u8>(
2643            &memory_mapping,
2644            0x100000000,
2645            data.len() as u64,
2646            &bpf_loader::id(),
2647        )
2648        .unwrap();
2649        assert_eq!(data, translated_data);
2650        data[0] = 10;
2651        assert_eq!(data, translated_data);
2652        assert!(translate_slice::<u8>(
2653            &memory_mapping,
2654            data.as_ptr() as u64,
2655            u64::MAX,
2656            &bpf_loader::id(),
2657        )
2658        .is_err());
2659
2660        assert!(translate_slice::<u8>(
2661            &memory_mapping,
2662            0x100000000 - 1,
2663            data.len() as u64,
2664            &bpf_loader::id(),
2665        )
2666        .is_err());
2667
2668        // u64
2669        let mut data = vec![1u64, 2, 3, 4, 5];
2670        let addr = data.as_ptr() as *const _ as u64;
2671        let memory_mapping = MemoryMapping::new::<UserError>(
2672            vec![
2673                MemoryRegion::default(),
2674                MemoryRegion {
2675                    host_addr: addr,
2676                    vm_addr: 0x100000000,
2677                    len: (data.len() * size_of::<u64>()) as u64,
2678                    vm_gap_shift: 63,
2679                    is_writable: false,
2680                },
2681            ],
2682            &config,
2683        )
2684        .unwrap();
2685        let translated_data = translate_slice::<u64>(
2686            &memory_mapping,
2687            0x100000000,
2688            data.len() as u64,
2689            &bpf_loader::id(),
2690        )
2691        .unwrap();
2692        assert_eq!(data, translated_data);
2693        data[0] = 10;
2694        assert_eq!(data, translated_data);
2695        assert!(
2696            translate_slice::<u64>(&memory_mapping, 0x100000000, u64::MAX, &bpf_loader::id(),)
2697                .is_err()
2698        );
2699
2700        // Pubkeys
2701        let mut data = vec![gemachain_sdk::pubkey::new_rand(); 5];
2702        let addr = data.as_ptr() as *const _ as u64;
2703        let memory_mapping = MemoryMapping::new::<UserError>(
2704            vec![
2705                MemoryRegion::default(),
2706                MemoryRegion {
2707                    host_addr: addr,
2708                    vm_addr: 0x100000000,
2709                    len: (data.len() * std::mem::size_of::<Pubkey>()) as u64,
2710                    vm_gap_shift: 63,
2711                    is_writable: false,
2712                },
2713            ],
2714            &config,
2715        )
2716        .unwrap();
2717        let translated_data = translate_slice::<Pubkey>(
2718            &memory_mapping,
2719            0x100000000,
2720            data.len() as u64,
2721            &bpf_loader::id(),
2722        )
2723        .unwrap();
2724        assert_eq!(data, translated_data);
2725        data[0] = gemachain_sdk::pubkey::new_rand(); // Both should point to same place
2726        assert_eq!(data, translated_data);
2727    }
2728
2729    #[test]
2730    fn test_translate_string_and_do() {
2731        let string = "Gaggablaghblagh!";
2732        let addr = string.as_ptr() as *const _ as u64;
2733        let config = Config::default();
2734        let memory_mapping = MemoryMapping::new::<UserError>(
2735            vec![
2736                MemoryRegion::default(),
2737                MemoryRegion {
2738                    host_addr: addr,
2739                    vm_addr: 0x100000000,
2740                    len: string.len() as u64,
2741                    vm_gap_shift: 63,
2742                    is_writable: false,
2743                },
2744            ],
2745            &config,
2746        )
2747        .unwrap();
2748        assert_eq!(
2749            42,
2750            translate_string_and_do(
2751                &memory_mapping,
2752                0x100000000,
2753                string.len() as u64,
2754                &bpf_loader::id(),
2755                &mut |string: &str| {
2756                    assert_eq!(string, "Gaggablaghblagh!");
2757                    Ok(42)
2758                }
2759            )
2760            .unwrap()
2761        );
2762    }
2763
2764    #[test]
2765    #[should_panic(expected = "UserError(SyscallError(Abort))")]
2766    fn test_syscall_abort() {
2767        let config = Config::default();
2768        let memory_mapping =
2769            MemoryMapping::new::<UserError>(vec![MemoryRegion::default()], &config).unwrap();
2770        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
2771        SyscallAbort::call(
2772            &mut SyscallAbort {},
2773            0,
2774            0,
2775            0,
2776            0,
2777            0,
2778            &memory_mapping,
2779            &mut result,
2780        );
2781        result.unwrap();
2782    }
2783
2784    #[test]
2785    #[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")]
2786    fn test_syscall_gema_panic() {
2787        let string = "Gaggablaghblagh!";
2788        let addr = string.as_ptr() as *const _ as u64;
2789        let config = Config::default();
2790        let memory_mapping = MemoryMapping::new::<UserError>(
2791            vec![
2792                MemoryRegion::default(),
2793                MemoryRegion {
2794                    host_addr: addr,
2795                    vm_addr: 0x100000000,
2796                    len: string.len() as u64,
2797                    vm_gap_shift: 63,
2798                    is_writable: false,
2799                },
2800            ],
2801            &config,
2802        )
2803        .unwrap();
2804
2805        let compute_meter: Rc<RefCell<dyn ComputeMeter>> =
2806            Rc::new(RefCell::new(MockComputeMeter {
2807                remaining: string.len() as u64 - 1,
2808            }));
2809        let mut syscall_panic = SyscallPanic {
2810            compute_meter,
2811            loader_id: &bpf_loader::id(),
2812        };
2813        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
2814        syscall_panic.call(
2815            0x100000000,
2816            string.len() as u64,
2817            42,
2818            84,
2819            0,
2820            &memory_mapping,
2821            &mut result,
2822        );
2823        assert_eq!(
2824            Err(EbpfError::UserError(BpfError::SyscallError(
2825                SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
2826            ))),
2827            result
2828        );
2829
2830        let compute_meter: Rc<RefCell<dyn ComputeMeter>> =
2831            Rc::new(RefCell::new(MockComputeMeter {
2832                remaining: string.len() as u64,
2833            }));
2834        let mut syscall_panic = SyscallPanic {
2835            compute_meter,
2836            loader_id: &bpf_loader::id(),
2837        };
2838        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
2839        syscall_panic.call(
2840            0x100000000,
2841            string.len() as u64,
2842            42,
2843            84,
2844            0,
2845            &memory_mapping,
2846            &mut result,
2847        );
2848        result.unwrap();
2849    }
2850
2851    #[test]
2852    fn test_syscall_gema_log() {
2853        let string = "Gaggablaghblagh!";
2854        let addr = string.as_ptr() as *const _ as u64;
2855
2856        let compute_meter: Rc<RefCell<dyn ComputeMeter>> =
2857            Rc::new(RefCell::new(MockComputeMeter { remaining: 1000000 }));
2858        let log = Rc::new(RefCell::new(vec![]));
2859        let logger: Rc<RefCell<dyn Logger>> =
2860            Rc::new(RefCell::new(MockLogger { log: log.clone() }));
2861        let mut syscall_gema_log = SyscallLog {
2862            compute_meter,
2863            logger,
2864            loader_id: &bpf_loader::id(),
2865        };
2866        let config = Config::default();
2867        let memory_mapping = MemoryMapping::new::<UserError>(
2868            vec![
2869                MemoryRegion::default(),
2870                MemoryRegion {
2871                    host_addr: addr,
2872                    vm_addr: 0x100000000,
2873                    len: string.len() as u64,
2874                    vm_gap_shift: 63,
2875                    is_writable: false,
2876                },
2877            ],
2878            &config,
2879        )
2880        .unwrap();
2881
2882        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
2883        syscall_gema_log.call(
2884            0x100000000,
2885            string.len() as u64,
2886            0,
2887            0,
2888            0,
2889            &memory_mapping,
2890            &mut result,
2891        );
2892        result.unwrap();
2893        assert_eq!(log.borrow().len(), 1);
2894        assert_eq!(log.borrow()[0], "Program log: Gaggablaghblagh!");
2895
2896        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
2897        syscall_gema_log.call(
2898            0x100000001, // AccessViolation
2899            string.len() as u64,
2900            0,
2901            0,
2902            0,
2903            &memory_mapping,
2904            &mut result,
2905        );
2906        assert_access_violation!(result, 0x100000001, string.len() as u64);
2907        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
2908        syscall_gema_log.call(
2909            0x100000000,
2910            string.len() as u64 * 2, // AccessViolation
2911            0,
2912            0,
2913            0,
2914            &memory_mapping,
2915            &mut result,
2916        );
2917        assert_access_violation!(result, 0x100000000, string.len() as u64 * 2);
2918        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
2919        syscall_gema_log.call(
2920            0x100000000,
2921            string.len() as u64,
2922            0,
2923            0,
2924            0,
2925            &memory_mapping,
2926            &mut result,
2927        );
2928
2929        let compute_meter: Rc<RefCell<dyn ComputeMeter>> =
2930            Rc::new(RefCell::new(MockComputeMeter {
2931                remaining: (string.len() as u64 * 2) - 1,
2932            }));
2933        let logger: Rc<RefCell<dyn Logger>> = Rc::new(RefCell::new(MockLogger { log }));
2934        let mut syscall_gema_log = SyscallLog {
2935            compute_meter,
2936            logger,
2937            loader_id: &bpf_loader::id(),
2938        };
2939        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
2940        syscall_gema_log.call(
2941            0x100000000,
2942            string.len() as u64,
2943            0,
2944            0,
2945            0,
2946            &memory_mapping,
2947            &mut result,
2948        );
2949        result.unwrap();
2950        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
2951        syscall_gema_log.call(
2952            0x100000000,
2953            string.len() as u64,
2954            0,
2955            0,
2956            0,
2957            &memory_mapping,
2958            &mut result,
2959        );
2960        assert_eq!(
2961            Err(EbpfError::UserError(BpfError::SyscallError(
2962                SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
2963            ))),
2964            result
2965        );
2966    }
2967
2968    #[test]
2969    fn test_syscall_gema_log_u64() {
2970        let compute_meter: Rc<RefCell<dyn ComputeMeter>> =
2971            Rc::new(RefCell::new(MockComputeMeter {
2972                remaining: std::u64::MAX,
2973            }));
2974        let log = Rc::new(RefCell::new(vec![]));
2975        let logger: Rc<RefCell<dyn Logger>> =
2976            Rc::new(RefCell::new(MockLogger { log: log.clone() }));
2977        let mut syscall_gema_log_u64 = SyscallLogU64 {
2978            cost: 0,
2979            compute_meter,
2980            logger,
2981        };
2982        let config = Config::default();
2983        let memory_mapping = MemoryMapping::new::<UserError>(vec![], &config).unwrap();
2984
2985        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
2986        syscall_gema_log_u64.call(1, 2, 3, 4, 5, &memory_mapping, &mut result);
2987        result.unwrap();
2988
2989        assert_eq!(log.borrow().len(), 1);
2990        assert_eq!(log.borrow()[0], "Program log: 0x1, 0x2, 0x3, 0x4, 0x5");
2991    }
2992
2993    #[test]
2994    fn test_syscall_gema_pubkey() {
2995        let pubkey = Pubkey::from_str("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN").unwrap();
2996        let addr = &pubkey.as_ref()[0] as *const _ as u64;
2997
2998        let compute_meter: Rc<RefCell<dyn ComputeMeter>> =
2999            Rc::new(RefCell::new(MockComputeMeter { remaining: 2 }));
3000        let log = Rc::new(RefCell::new(vec![]));
3001        let logger: Rc<RefCell<dyn Logger>> =
3002            Rc::new(RefCell::new(MockLogger { log: log.clone() }));
3003        let mut syscall_gema_pubkey = SyscallLogPubkey {
3004            cost: 1,
3005            compute_meter,
3006            logger,
3007            loader_id: &bpf_loader::id(),
3008        };
3009        let config = Config::default();
3010        let memory_mapping = MemoryMapping::new::<UserError>(
3011            vec![
3012                MemoryRegion::default(),
3013                MemoryRegion {
3014                    host_addr: addr,
3015                    vm_addr: 0x100000000,
3016                    len: 32,
3017                    vm_gap_shift: 63,
3018                    is_writable: false,
3019                },
3020            ],
3021            &config,
3022        )
3023        .unwrap();
3024
3025        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3026        syscall_gema_pubkey.call(0x100000000, 0, 0, 0, 0, &memory_mapping, &mut result);
3027        result.unwrap();
3028        assert_eq!(log.borrow().len(), 1);
3029        assert_eq!(
3030            log.borrow()[0],
3031            "Program log: MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN"
3032        );
3033        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3034        syscall_gema_pubkey.call(
3035            0x100000001, // AccessViolation
3036            32,
3037            0,
3038            0,
3039            0,
3040            &memory_mapping,
3041            &mut result,
3042        );
3043        assert_access_violation!(result, 0x100000001, 32);
3044        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3045        syscall_gema_pubkey.call(100, 32, 0, 0, 0, &memory_mapping, &mut result);
3046        assert_eq!(
3047            Err(EbpfError::UserError(BpfError::SyscallError(
3048                SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
3049            ))),
3050            result
3051        );
3052    }
3053
3054    #[test]
3055    fn test_syscall_gema_alloc_free() {
3056        let config = Config::default();
3057        // large alloc
3058        {
3059            let heap = AlignedMemory::new_with_size(100, HOST_ALIGN);
3060            let memory_mapping = MemoryMapping::new::<UserError>(
3061                vec![
3062                    MemoryRegion::default(),
3063                    MemoryRegion::new_from_slice(&[], ebpf::MM_PROGRAM_START, 0, false),
3064                    MemoryRegion::new_from_slice(&[], ebpf::MM_STACK_START, 4096, true),
3065                    MemoryRegion::new_from_slice(heap.as_slice(), ebpf::MM_HEAP_START, 0, true),
3066                    MemoryRegion::new_from_slice(&[], ebpf::MM_INPUT_START, 0, true),
3067                ],
3068                &config,
3069            )
3070            .unwrap();
3071            let mut syscall = SyscallAllocFree {
3072                aligned: true,
3073                allocator: BpfAllocator::new(heap, ebpf::MM_HEAP_START),
3074            };
3075            let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3076            syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result);
3077            assert_ne!(result.unwrap(), 0);
3078            let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3079            syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result);
3080            assert_eq!(result.unwrap(), 0);
3081            let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3082            syscall.call(u64::MAX, 0, 0, 0, 0, &memory_mapping, &mut result);
3083            assert_eq!(result.unwrap(), 0);
3084        }
3085        // many small unaligned allocs
3086        {
3087            let heap = AlignedMemory::new_with_size(100, HOST_ALIGN);
3088            let memory_mapping = MemoryMapping::new::<UserError>(
3089                vec![
3090                    MemoryRegion::default(),
3091                    MemoryRegion::new_from_slice(&[], ebpf::MM_PROGRAM_START, 0, false),
3092                    MemoryRegion::new_from_slice(&[], ebpf::MM_STACK_START, 4096, true),
3093                    MemoryRegion::new_from_slice(heap.as_slice(), ebpf::MM_HEAP_START, 0, true),
3094                    MemoryRegion::new_from_slice(&[], ebpf::MM_INPUT_START, 0, true),
3095                ],
3096                &config,
3097            )
3098            .unwrap();
3099            let mut syscall = SyscallAllocFree {
3100                aligned: false,
3101                allocator: BpfAllocator::new(heap, ebpf::MM_HEAP_START),
3102            };
3103            for _ in 0..100 {
3104                let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3105                syscall.call(1, 0, 0, 0, 0, &memory_mapping, &mut result);
3106                assert_ne!(result.unwrap(), 0);
3107            }
3108            let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3109            syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result);
3110            assert_eq!(result.unwrap(), 0);
3111        }
3112        // many small aligned allocs
3113        {
3114            let heap = AlignedMemory::new_with_size(100, HOST_ALIGN);
3115            let memory_mapping = MemoryMapping::new::<UserError>(
3116                vec![
3117                    MemoryRegion::default(),
3118                    MemoryRegion::new_from_slice(&[], ebpf::MM_PROGRAM_START, 0, false),
3119                    MemoryRegion::new_from_slice(&[], ebpf::MM_STACK_START, 4096, true),
3120                    MemoryRegion::new_from_slice(heap.as_slice(), ebpf::MM_HEAP_START, 0, true),
3121                    MemoryRegion::new_from_slice(&[], ebpf::MM_INPUT_START, 0, true),
3122                ],
3123                &config,
3124            )
3125            .unwrap();
3126            let mut syscall = SyscallAllocFree {
3127                aligned: true,
3128                allocator: BpfAllocator::new(heap, ebpf::MM_HEAP_START),
3129            };
3130            for _ in 0..12 {
3131                let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3132                syscall.call(1, 0, 0, 0, 0, &memory_mapping, &mut result);
3133                assert_ne!(result.unwrap(), 0);
3134            }
3135            let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3136            syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result);
3137            assert_eq!(result.unwrap(), 0);
3138        }
3139        // aligned allocs
3140
3141        fn check_alignment<T>() {
3142            let heap = AlignedMemory::new_with_size(100, HOST_ALIGN);
3143            let config = Config::default();
3144            let memory_mapping = MemoryMapping::new::<UserError>(
3145                vec![
3146                    MemoryRegion::default(),
3147                    MemoryRegion::new_from_slice(&[], ebpf::MM_PROGRAM_START, 0, false),
3148                    MemoryRegion::new_from_slice(&[], ebpf::MM_STACK_START, 4096, true),
3149                    MemoryRegion::new_from_slice(heap.as_slice(), ebpf::MM_HEAP_START, 0, true),
3150                    MemoryRegion::new_from_slice(&[], ebpf::MM_INPUT_START, 0, true),
3151                ],
3152                &config,
3153            )
3154            .unwrap();
3155            let mut syscall = SyscallAllocFree {
3156                aligned: true,
3157                allocator: BpfAllocator::new(heap, ebpf::MM_HEAP_START),
3158            };
3159            let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3160            syscall.call(
3161                size_of::<u8>() as u64,
3162                0,
3163                0,
3164                0,
3165                0,
3166                &memory_mapping,
3167                &mut result,
3168            );
3169            let address = result.unwrap();
3170            assert_ne!(address, 0);
3171            assert_eq!((address as *const u8).align_offset(align_of::<u8>()), 0);
3172        }
3173        check_alignment::<u8>();
3174        check_alignment::<u16>();
3175        check_alignment::<u32>();
3176        check_alignment::<u64>();
3177        check_alignment::<u128>();
3178    }
3179
3180    #[test]
3181    fn test_syscall_sha256() {
3182        let bytes1 = "Gaggablaghblagh!";
3183        let bytes2 = "flurbos";
3184
3185        let mock_slice1 = MockSlice {
3186            vm_addr: 0x300000000,
3187            len: bytes1.len(),
3188        };
3189        let mock_slice2 = MockSlice {
3190            vm_addr: 0x400000000,
3191            len: bytes2.len(),
3192        };
3193        let bytes_to_hash = [mock_slice1, mock_slice2];
3194        let hash_result = [0; HASH_BYTES];
3195        let ro_len = bytes_to_hash.len() as u64;
3196        let ro_va = 0x100000000;
3197        let rw_va = 0x200000000;
3198        let config = Config::default();
3199        let memory_mapping = MemoryMapping::new::<UserError>(
3200            vec![
3201                MemoryRegion::default(),
3202                MemoryRegion {
3203                    host_addr: bytes_to_hash.as_ptr() as *const _ as u64,
3204                    vm_addr: ro_va,
3205                    len: 32,
3206                    vm_gap_shift: 63,
3207                    is_writable: false,
3208                },
3209                MemoryRegion {
3210                    host_addr: hash_result.as_ptr() as *const _ as u64,
3211                    vm_addr: rw_va,
3212                    len: HASH_BYTES as u64,
3213                    vm_gap_shift: 63,
3214                    is_writable: true,
3215                },
3216                MemoryRegion {
3217                    host_addr: bytes1.as_ptr() as *const _ as u64,
3218                    vm_addr: bytes_to_hash[0].vm_addr,
3219                    len: bytes1.len() as u64,
3220                    vm_gap_shift: 63,
3221                    is_writable: false,
3222                },
3223                MemoryRegion {
3224                    host_addr: bytes2.as_ptr() as *const _ as u64,
3225                    vm_addr: bytes_to_hash[1].vm_addr,
3226                    len: bytes2.len() as u64,
3227                    vm_gap_shift: 63,
3228                    is_writable: false,
3229                },
3230            ],
3231            &config,
3232        )
3233        .unwrap();
3234        let compute_meter: Rc<RefCell<dyn ComputeMeter>> =
3235            Rc::new(RefCell::new(MockComputeMeter {
3236                remaining: (bytes1.len() + bytes2.len()) as u64,
3237            }));
3238        let mut syscall = SyscallSha256 {
3239            sha256_base_cost: 0,
3240            sha256_byte_cost: 2,
3241            compute_meter,
3242            loader_id: &bpf_loader_deprecated::id(),
3243        };
3244
3245        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3246        syscall.call(ro_va, ro_len, rw_va, 0, 0, &memory_mapping, &mut result);
3247        result.unwrap();
3248
3249        let hash_local = hashv(&[bytes1.as_ref(), bytes2.as_ref()]).to_bytes();
3250        assert_eq!(hash_result, hash_local);
3251        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3252        syscall.call(
3253            ro_va - 1, // AccessViolation
3254            ro_len,
3255            rw_va,
3256            0,
3257            0,
3258            &memory_mapping,
3259            &mut result,
3260        );
3261        assert_access_violation!(result, ro_va - 1, 32);
3262        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3263        syscall.call(
3264            ro_va,
3265            ro_len + 1, // AccessViolation
3266            rw_va,
3267            0,
3268            0,
3269            &memory_mapping,
3270            &mut result,
3271        );
3272        assert_access_violation!(result, ro_va, 48);
3273        let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3274        syscall.call(
3275            ro_va,
3276            ro_len,
3277            rw_va - 1, // AccessViolation
3278            0,
3279            0,
3280            &memory_mapping,
3281            &mut result,
3282        );
3283        assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64);
3284
3285        syscall.call(ro_va, ro_len, rw_va, 0, 0, &memory_mapping, &mut result);
3286        assert_eq!(
3287            Err(EbpfError::UserError(BpfError::SyscallError(
3288                SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
3289            ))),
3290            result
3291        );
3292    }
3293
3294    #[test]
3295    fn test_syscall_get_sysvar() {
3296        let config = Config::default();
3297        // Test clock sysvar
3298        {
3299            let got_clock = Clock::default();
3300            let got_clock_va = 0x100000000;
3301
3302            let memory_mapping = MemoryMapping::new::<UserError>(
3303                vec![
3304                    MemoryRegion::default(),
3305                    MemoryRegion {
3306                        host_addr: &got_clock as *const _ as u64,
3307                        vm_addr: got_clock_va,
3308                        len: size_of::<Clock>() as u64,
3309                        vm_gap_shift: 63,
3310                        is_writable: true,
3311                    },
3312                ],
3313                &config,
3314            )
3315            .unwrap();
3316
3317            let src_clock = Clock {
3318                slot: 1,
3319                epoch_start_timestamp: 2,
3320                epoch: 3,
3321                leader_schedule_epoch: 4,
3322                unix_timestamp: 5,
3323            };
3324            let mut invoke_context = MockInvokeContext::new(vec![]);
3325            let mut data = vec![];
3326            bincode::serialize_into(&mut data, &src_clock).unwrap();
3327            invoke_context
3328                .sysvars
3329                .push((sysvar::clock::id(), Some(Rc::new(data))));
3330
3331            let mut syscall = SyscallGetClockSysvar {
3332                invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
3333                loader_id: &bpf_loader::id(),
3334            };
3335            let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3336
3337            syscall.call(got_clock_va, 0, 0, 0, 0, &memory_mapping, &mut result);
3338            result.unwrap();
3339            assert_eq!(got_clock, src_clock);
3340        }
3341
3342        // Test epoch_schedule sysvar
3343        {
3344            let got_epochschedule = EpochSchedule::default();
3345            let got_epochschedule_va = 0x100000000;
3346
3347            let memory_mapping = MemoryMapping::new::<UserError>(
3348                vec![
3349                    MemoryRegion::default(),
3350                    MemoryRegion {
3351                        host_addr: &got_epochschedule as *const _ as u64,
3352                        vm_addr: got_epochschedule_va,
3353                        len: size_of::<EpochSchedule>() as u64,
3354                        vm_gap_shift: 63,
3355                        is_writable: true,
3356                    },
3357                ],
3358                &config,
3359            )
3360            .unwrap();
3361
3362            let src_epochschedule = EpochSchedule {
3363                slots_per_epoch: 1,
3364                leader_schedule_slot_offset: 2,
3365                warmup: false,
3366                first_normal_epoch: 3,
3367                first_normal_slot: 4,
3368            };
3369            let mut invoke_context = MockInvokeContext::new(vec![]);
3370            let mut data = vec![];
3371            bincode::serialize_into(&mut data, &src_epochschedule).unwrap();
3372            invoke_context
3373                .sysvars
3374                .push((sysvar::epoch_schedule::id(), Some(Rc::new(data))));
3375
3376            let mut syscall = SyscallGetEpochScheduleSysvar {
3377                invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
3378                loader_id: &bpf_loader::id(),
3379            };
3380            let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3381
3382            syscall.call(
3383                got_epochschedule_va,
3384                0,
3385                0,
3386                0,
3387                0,
3388                &memory_mapping,
3389                &mut result,
3390            );
3391            result.unwrap();
3392            assert_eq!(got_epochschedule, src_epochschedule);
3393        }
3394
3395        // Test fees sysvar
3396        #[allow(deprecated)]
3397        {
3398            let got_fees = Fees::default();
3399            let got_fees_va = 0x100000000;
3400
3401            let memory_mapping = MemoryMapping::new::<UserError>(
3402                vec![
3403                    MemoryRegion::default(),
3404                    MemoryRegion {
3405                        host_addr: &got_fees as *const _ as u64,
3406                        vm_addr: got_fees_va,
3407                        len: size_of::<Fees>() as u64,
3408                        vm_gap_shift: 63,
3409                        is_writable: true,
3410                    },
3411                ],
3412                &config,
3413            )
3414            .unwrap();
3415
3416            let src_fees = Fees {
3417                fee_calculator: FeeCalculator {
3418                    carats_per_signature: 1,
3419                },
3420            };
3421            let mut invoke_context = MockInvokeContext::new(vec![]);
3422            let mut data = vec![];
3423            bincode::serialize_into(&mut data, &src_fees).unwrap();
3424            invoke_context
3425                .sysvars
3426                .push((sysvar::fees::id(), Some(Rc::new(data))));
3427
3428            let mut syscall = SyscallGetFeesSysvar {
3429                invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
3430                loader_id: &bpf_loader::id(),
3431            };
3432            let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3433
3434            syscall.call(got_fees_va, 0, 0, 0, 0, &memory_mapping, &mut result);
3435            result.unwrap();
3436            assert_eq!(got_fees, src_fees);
3437        }
3438
3439        // Test rent sysvar
3440        {
3441            let got_rent = Rent::default();
3442            let got_rent_va = 0x100000000;
3443
3444            let memory_mapping = MemoryMapping::new::<UserError>(
3445                vec![
3446                    MemoryRegion::default(),
3447                    MemoryRegion {
3448                        host_addr: &got_rent as *const _ as u64,
3449                        vm_addr: got_rent_va,
3450                        len: size_of::<Rent>() as u64,
3451                        vm_gap_shift: 63,
3452                        is_writable: true,
3453                    },
3454                ],
3455                &config,
3456            )
3457            .unwrap();
3458
3459            let src_rent = Rent {
3460                carats_per_byte_year: 1,
3461                exemption_threshold: 2.0,
3462                burn_percent: 3,
3463            };
3464            let mut invoke_context = MockInvokeContext::new(vec![]);
3465            let mut data = vec![];
3466            bincode::serialize_into(&mut data, &src_rent).unwrap();
3467            invoke_context
3468                .sysvars
3469                .push((sysvar::rent::id(), Some(Rc::new(data))));
3470
3471            let mut syscall = SyscallGetRentSysvar {
3472                invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
3473                loader_id: &bpf_loader::id(),
3474            };
3475            let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
3476
3477            syscall.call(got_rent_va, 0, 0, 0, 0, &memory_mapping, &mut result);
3478            result.unwrap();
3479            assert_eq!(got_rent, src_rent);
3480        }
3481    }
3482
3483    #[test]
3484    fn test_overlapping() {
3485        assert!(!check_overlapping(10, 7, 3));
3486        assert!(check_overlapping(10, 8, 3));
3487        assert!(check_overlapping(10, 9, 3));
3488        assert!(check_overlapping(10, 10, 3));
3489        assert!(check_overlapping(10, 11, 3));
3490        assert!(check_overlapping(10, 12, 3));
3491        assert!(!check_overlapping(10, 13, 3));
3492    }
3493
3494    fn call_program_address_common(
3495        seeds: &[&[u8]],
3496        program_id: &Pubkey,
3497        syscall: &mut dyn SyscallObject<BpfError>,
3498    ) -> Result<(Pubkey, u8), EbpfError<BpfError>> {
3499        const SEEDS_VA: u64 = 0x100000000;
3500        const PROGRAM_ID_VA: u64 = 0x200000000;
3501        const ADDRESS_VA: u64 = 0x300000000;
3502        const BUMP_SEED_VA: u64 = 0x400000000;
3503        const SEED_VA: u64 = 0x500000000;
3504
3505        let config = Config::default();
3506        let address = Pubkey::default();
3507        let bump_seed = 0;
3508        let mut mock_slices = Vec::with_capacity(seeds.len());
3509        let mut regions = vec![
3510            MemoryRegion::default(),
3511            MemoryRegion {
3512                host_addr: mock_slices.as_ptr() as u64,
3513                vm_addr: SEEDS_VA,
3514                len: (seeds.len() * size_of::<MockSlice>()) as u64,
3515                vm_gap_shift: 63,
3516                is_writable: false,
3517            },
3518            MemoryRegion {
3519                host_addr: program_id.as_ref().as_ptr() as u64,
3520                vm_addr: PROGRAM_ID_VA,
3521                len: 32,
3522                vm_gap_shift: 63,
3523                is_writable: false,
3524            },
3525            MemoryRegion {
3526                host_addr: address.as_ref().as_ptr() as u64,
3527                vm_addr: ADDRESS_VA,
3528                len: 32,
3529                vm_gap_shift: 63,
3530                is_writable: true,
3531            },
3532            MemoryRegion {
3533                host_addr: &bump_seed as *const u8 as u64,
3534                vm_addr: BUMP_SEED_VA,
3535                len: 32,
3536                vm_gap_shift: 63,
3537                is_writable: true,
3538            },
3539        ];
3540
3541        for (i, seed) in seeds.iter().enumerate() {
3542            let vm_addr = SEED_VA + (i as u64 * 0x100000000);
3543            let mock_slice = MockSlice {
3544                vm_addr,
3545                len: seed.len(),
3546            };
3547            mock_slices.push(mock_slice);
3548            regions.push(MemoryRegion {
3549                host_addr: seed.as_ptr() as u64,
3550                vm_addr,
3551                len: seed.len() as u64,
3552                vm_gap_shift: 63,
3553                is_writable: false,
3554            });
3555        }
3556        let memory_mapping = MemoryMapping::new::<UserError>(regions, &config).unwrap();
3557
3558        let mut result = Ok(0);
3559        syscall.call(
3560            SEEDS_VA,
3561            seeds.len() as u64,
3562            PROGRAM_ID_VA,
3563            ADDRESS_VA,
3564            BUMP_SEED_VA,
3565            &memory_mapping,
3566            &mut result,
3567        );
3568        let _ = result?;
3569        Ok((address, bump_seed))
3570    }
3571
3572    fn create_program_address(
3573        seeds: &[&[u8]],
3574        program_id: &Pubkey,
3575        remaining: u64,
3576    ) -> Result<Pubkey, EbpfError<BpfError>> {
3577        let compute_meter: Rc<RefCell<dyn ComputeMeter>> =
3578            Rc::new(RefCell::new(MockComputeMeter { remaining }));
3579        let mut syscall = SyscallCreateProgramAddress {
3580            cost: 1,
3581            compute_meter: compute_meter.clone(),
3582            loader_id: &bpf_loader::id(),
3583            allow_native_ids: true,
3584            check_seed_length: true,
3585        };
3586        let (address, _) = call_program_address_common(seeds, program_id, &mut syscall)?;
3587        Ok(address)
3588    }
3589
3590    fn try_find_program_address(
3591        seeds: &[&[u8]],
3592        program_id: &Pubkey,
3593        remaining: u64,
3594    ) -> Result<(Pubkey, u8), EbpfError<BpfError>> {
3595        let compute_meter: Rc<RefCell<dyn ComputeMeter>> =
3596            Rc::new(RefCell::new(MockComputeMeter { remaining }));
3597        let mut syscall = SyscallTryFindProgramAddress {
3598            cost: 1,
3599            compute_meter: compute_meter.clone(),
3600            loader_id: &bpf_loader::id(),
3601            allow_native_ids: true,
3602            check_seed_length: true,
3603        };
3604        call_program_address_common(seeds, program_id, &mut syscall)
3605    }
3606
3607    #[test]
3608    fn test_create_program_address() {
3609        // These tests duplicate the direct tests in gemachain_program::pubkey
3610
3611        let program_id = Pubkey::from_str("BPFLoaderUpgradeab1e11111111111111111111111").unwrap();
3612
3613        let exceeded_seed = &[127; MAX_SEED_LEN + 1];
3614        let result = create_program_address(&[exceeded_seed], &program_id, 1);
3615        assert_eq!(
3616            result,
3617            Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into())
3618        );
3619        assert_eq!(
3620            create_program_address(&[b"short_seed", exceeded_seed], &program_id, 1),
3621            Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into())
3622        );
3623        let max_seed = &[0; MAX_SEED_LEN];
3624        assert!(create_program_address(&[max_seed], &program_id, 1).is_ok());
3625        let exceeded_seeds: &[&[u8]] = &[
3626            &[1],
3627            &[2],
3628            &[3],
3629            &[4],
3630            &[5],
3631            &[6],
3632            &[7],
3633            &[8],
3634            &[9],
3635            &[10],
3636            &[11],
3637            &[12],
3638            &[13],
3639            &[14],
3640            &[15],
3641            &[16],
3642        ];
3643        assert!(create_program_address(exceeded_seeds, &program_id, 1).is_ok());
3644        let max_seeds: &[&[u8]] = &[
3645            &[1],
3646            &[2],
3647            &[3],
3648            &[4],
3649            &[5],
3650            &[6],
3651            &[7],
3652            &[8],
3653            &[9],
3654            &[10],
3655            &[11],
3656            &[12],
3657            &[13],
3658            &[14],
3659            &[15],
3660            &[16],
3661            &[17],
3662        ];
3663        assert_eq!(
3664            create_program_address(max_seeds, &program_id, 1),
3665            Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into())
3666        );
3667        assert_eq!(
3668            create_program_address(&[b"", &[1]], &program_id, 0),
3669            Err(
3670                SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
3671                    .into()
3672            )
3673        );
3674        assert_eq!(
3675            create_program_address(&[b"", &[1]], &program_id, 1),
3676            Ok("BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe"
3677                .parse()
3678                .unwrap())
3679        );
3680        assert_eq!(
3681            create_program_address(&["☉".as_ref(), &[0]], &program_id, 1),
3682            Ok("13yWmRpaTR4r5nAktwLqMpRNr28tnVUZw26rTvPSSB19"
3683                .parse()
3684                .unwrap())
3685        );
3686        assert_eq!(
3687            create_program_address(&[b"Talking", b"Squirrels"], &program_id, 1),
3688            Ok("2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk"
3689                .parse()
3690                .unwrap())
3691        );
3692        let public_key = Pubkey::from_str("SeedPubey1111111111111111111111111111111111").unwrap();
3693        assert_eq!(
3694            create_program_address(&[public_key.as_ref(), &[1]], &program_id, 1),
3695            Ok("976ymqVnfE32QFe6NfGDctSvVa36LWnvYxhU6G2232YL"
3696                .parse()
3697                .unwrap())
3698        );
3699        assert_ne!(
3700            create_program_address(&[b"Talking", b"Squirrels"], &program_id, 1).unwrap(),
3701            create_program_address(&[b"Talking"], &program_id, 1).unwrap(),
3702        );
3703    }
3704
3705    #[test]
3706    fn test_find_program_address() {
3707        for _ in 0..1_000 {
3708            let program_id = Pubkey::new_unique();
3709            let (address, bump_seed) =
3710                try_find_program_address(&[b"Lil'", b"Bits"], &program_id, 100).unwrap();
3711            assert_eq!(
3712                address,
3713                create_program_address(&[b"Lil'", b"Bits", &[bump_seed]], &program_id, 1).unwrap()
3714            );
3715        }
3716
3717        let program_id = Pubkey::from_str("BPFLoaderUpgradeab1e11111111111111111111111").unwrap();
3718        let max_tries = 256; // one per seed
3719        let seeds: &[&[u8]] = &[b""];
3720        let (_, bump_seed) = try_find_program_address(seeds, &program_id, max_tries).unwrap();
3721        let remaining = 256 - bump_seed as u64;
3722        let _ = try_find_program_address(seeds, &program_id, remaining).unwrap();
3723        assert_eq!(
3724            try_find_program_address(seeds, &program_id, remaining - 1),
3725            Err(
3726                SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded)
3727                    .into()
3728            )
3729        );
3730        let exceeded_seed = &[127; MAX_SEED_LEN + 1];
3731        assert_eq!(
3732            try_find_program_address(&[exceeded_seed], &program_id, max_tries - 1),
3733            Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into())
3734        );
3735        let exceeded_seeds: &[&[u8]] = &[
3736            &[1],
3737            &[2],
3738            &[3],
3739            &[4],
3740            &[5],
3741            &[6],
3742            &[7],
3743            &[8],
3744            &[9],
3745            &[10],
3746            &[11],
3747            &[12],
3748            &[13],
3749            &[14],
3750            &[15],
3751            &[16],
3752            &[17],
3753        ];
3754        assert_eq!(
3755            try_find_program_address(exceeded_seeds, &program_id, max_tries - 1),
3756            Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into())
3757        );
3758    }
3759}