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