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
53pub const MAX_SIGNERS: usize = 16;
55
56#[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
107use 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 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 syscall_registry.register_syscall_by_name(b"gema_alloc_free_", SyscallAllocFree::call)?;
177
178 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 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 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 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 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 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 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
540fn 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
560pub 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
580pub 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
609pub 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
644pub 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
673pub 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
707pub 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
735pub 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 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
840struct 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
900struct 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
982pub 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
1061struct 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}
1086struct 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}
1111struct 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}
1137struct 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
1163pub 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
1225pub 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}
1267pub 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}
1299pub 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}
1344pub 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
1373pub 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
1463pub 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
1520struct 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
1540trait 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
1567pub 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 let carats = {
1644 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 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#[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#[derive(Debug)]
1805struct GemaAccountMeta {
1806 pubkey_addr: u64,
1807 is_writable: bool,
1808 is_signer: bool,
1809}
1810
1811#[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#[derive(Debug)]
1827struct GemaSignerSeedC {
1828 addr: u64,
1829 len: u64,
1830}
1831
1832#[derive(Debug)]
1834struct GemaSignerSeedsC {
1835 addr: u64,
1836 len: u64,
1837}
1838
1839pub 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 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 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 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
2165fn 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 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 invoke_context.record_instruction(&instruction);
2210
2211 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 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 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(), )?;
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
2267pub 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 *result = Ok(return_data.len() as u64);
2395 } else {
2396 *result = Ok(0);
2397 }
2398 }
2399}
2400
2401pub 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 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 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 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 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 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 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(); 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, 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, 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, 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 {
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 {
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 {
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 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, 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, 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, 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 {
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 {
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 #[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 {
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 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; 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}