1pub use self::{
2 cpi::{SyscallInvokeSignedC, SyscallInvokeSignedRust},
3 logging::{
4 SyscallLog, SyscallLogBpfComputeUnits, SyscallLogData, SyscallLogPubkey, SyscallLogU64,
5 },
6 mem_ops::{SyscallMemcmp, SyscallMemcpy, SyscallMemmove, SyscallMemset},
7 sysvar::{
8 SyscallGetClockSysvar, SyscallGetEpochRewardsSysvar, SyscallGetEpochScheduleSysvar,
9 SyscallGetFeesSysvar, SyscallGetLastRestartSlotSysvar, SyscallGetRentSysvar,
10 SyscallGetSysvar,
11 },
12};
13#[allow(deprecated)]
14use {
15 solana_account_info::AccountInfo,
16 solana_big_mod_exp::{big_mod_exp, BigModExpParams},
17 solana_blake3_hasher as blake3,
18 solana_bn254::prelude::{
19 alt_bn128_addition, alt_bn128_multiplication, alt_bn128_multiplication_128,
20 alt_bn128_pairing, AltBn128Error, ALT_BN128_ADDITION_OUTPUT_LEN,
21 ALT_BN128_MULTIPLICATION_OUTPUT_LEN, ALT_BN128_PAIRING_ELEMENT_LEN,
22 ALT_BN128_PAIRING_OUTPUT_LEN,
23 },
24 solana_compute_budget::compute_budget::ComputeBudget,
25 solana_cpi::MAX_RETURN_DATA,
26 solana_feature_set::{
27 self as feature_set, abort_on_invalid_curve, blake3_syscall_enabled,
28 bpf_account_data_direct_mapping, curve25519_syscall_enabled,
29 disable_deploy_of_alloc_free_syscall, disable_fees_sysvar, disable_sbpf_v0_execution,
30 enable_alt_bn128_compression_syscall, enable_alt_bn128_syscall, enable_big_mod_exp_syscall,
31 enable_get_epoch_stake_syscall, enable_poseidon_syscall,
32 enable_sbpf_v1_deployment_and_execution, enable_sbpf_v2_deployment_and_execution,
33 enable_sbpf_v3_deployment_and_execution, get_sysvar_syscall_enabled,
34 last_restart_slot_sysvar, reenable_sbpf_v0_execution,
35 remaining_compute_units_syscall_enabled, FeatureSet,
36 },
37 solana_hash::Hash,
38 solana_instruction::{error::InstructionError, AccountMeta, ProcessedSiblingInstruction},
39 solana_keccak_hasher as keccak,
40 solana_log_collector::{ic_logger_msg, ic_msg},
41 solana_poseidon as poseidon,
42 solana_precompiles::is_precompile,
43 solana_program_entrypoint::{BPF_ALIGN_OF_U128, MAX_PERMITTED_DATA_INCREASE, SUCCESS},
44 solana_program_memory::is_nonoverlapping,
45 solana_program_runtime::{invoke_context::InvokeContext, stable_log},
46 solana_pubkey::{Pubkey, PubkeyError, MAX_SEEDS, MAX_SEED_LEN, PUBKEY_BYTES},
47 solana_sbpf::{
48 declare_builtin_function,
49 memory_region::{AccessType, MemoryMapping},
50 program::{BuiltinProgram, SBPFVersion},
51 vm::Config,
52 },
53 solana_sdk_ids::{bpf_loader, bpf_loader_deprecated, native_loader},
54 solana_secp256k1_recover::{
55 Secp256k1RecoverError, SECP256K1_PUBLIC_KEY_LENGTH, SECP256K1_SIGNATURE_LENGTH,
56 },
57 solana_sha256_hasher::Hasher,
58 solana_sysvar::Sysvar,
59 solana_sysvar_id::SysvarId,
60 solana_timings::ExecuteTimings,
61 solana_transaction_context::{IndexOfAccount, InstructionAccount},
62 solana_type_overrides::sync::Arc,
63 std::{
64 alloc::Layout,
65 marker::PhantomData,
66 mem::{align_of, size_of},
67 slice::from_raw_parts_mut,
68 str::{from_utf8, Utf8Error},
69 },
70 thiserror::Error as ThisError,
71};
72
73mod cpi;
74mod logging;
75mod mem_ops;
76mod sysvar;
77
78const MAX_SIGNERS: usize = 16;
80
81#[derive(Debug, ThisError, PartialEq, Eq)]
83pub enum SyscallError {
84 #[error("{0}: {1:?}")]
85 InvalidString(Utf8Error, Vec<u8>),
86 #[error("SBF program panicked")]
87 Abort,
88 #[error("SBF program Panicked in {0} at {1}:{2}")]
89 Panic(String, u64, u64),
90 #[error("Cannot borrow invoke context")]
91 InvokeContextBorrowFailed,
92 #[error("Malformed signer seed: {0}: {1:?}")]
93 MalformedSignerSeed(Utf8Error, Vec<u8>),
94 #[error("Could not create program address with signer seeds: {0}")]
95 BadSeeds(PubkeyError),
96 #[error("Program {0} not supported by inner instructions")]
97 ProgramNotSupported(Pubkey),
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 #[error("Invalid pointer")]
129 InvalidPointer,
130 #[error("Arithmetic overflow")]
131 ArithmeticOverflow,
132}
133
134type Error = Box<dyn std::error::Error>;
135
136trait HasherImpl {
137 const NAME: &'static str;
138 type Output: AsRef<[u8]>;
139
140 fn create_hasher() -> Self;
141 fn hash(&mut self, val: &[u8]);
142 fn result(self) -> Self::Output;
143 fn get_base_cost(compute_budget: &ComputeBudget) -> u64;
144 fn get_byte_cost(compute_budget: &ComputeBudget) -> u64;
145 fn get_max_slices(compute_budget: &ComputeBudget) -> u64;
146}
147
148struct Sha256Hasher(Hasher);
149struct Blake3Hasher(blake3::Hasher);
150struct Keccak256Hasher(keccak::Hasher);
151
152impl HasherImpl for Sha256Hasher {
153 const NAME: &'static str = "Sha256";
154 type Output = Hash;
155
156 fn create_hasher() -> Self {
157 Sha256Hasher(Hasher::default())
158 }
159
160 fn hash(&mut self, val: &[u8]) {
161 self.0.hash(val);
162 }
163
164 fn result(self) -> Self::Output {
165 self.0.result()
166 }
167
168 fn get_base_cost(compute_budget: &ComputeBudget) -> u64 {
169 compute_budget.sha256_base_cost
170 }
171 fn get_byte_cost(compute_budget: &ComputeBudget) -> u64 {
172 compute_budget.sha256_byte_cost
173 }
174 fn get_max_slices(compute_budget: &ComputeBudget) -> u64 {
175 compute_budget.sha256_max_slices
176 }
177}
178
179impl HasherImpl for Blake3Hasher {
180 const NAME: &'static str = "Blake3";
181 type Output = blake3::Hash;
182
183 fn create_hasher() -> Self {
184 Blake3Hasher(blake3::Hasher::default())
185 }
186
187 fn hash(&mut self, val: &[u8]) {
188 self.0.hash(val);
189 }
190
191 fn result(self) -> Self::Output {
192 self.0.result()
193 }
194
195 fn get_base_cost(compute_budget: &ComputeBudget) -> u64 {
196 compute_budget.sha256_base_cost
197 }
198 fn get_byte_cost(compute_budget: &ComputeBudget) -> u64 {
199 compute_budget.sha256_byte_cost
200 }
201 fn get_max_slices(compute_budget: &ComputeBudget) -> u64 {
202 compute_budget.sha256_max_slices
203 }
204}
205
206impl HasherImpl for Keccak256Hasher {
207 const NAME: &'static str = "Keccak256";
208 type Output = keccak::Hash;
209
210 fn create_hasher() -> Self {
211 Keccak256Hasher(keccak::Hasher::default())
212 }
213
214 fn hash(&mut self, val: &[u8]) {
215 self.0.hash(val);
216 }
217
218 fn result(self) -> Self::Output {
219 self.0.result()
220 }
221
222 fn get_base_cost(compute_budget: &ComputeBudget) -> u64 {
223 compute_budget.sha256_base_cost
224 }
225 fn get_byte_cost(compute_budget: &ComputeBudget) -> u64 {
226 compute_budget.sha256_byte_cost
227 }
228 fn get_max_slices(compute_budget: &ComputeBudget) -> u64 {
229 compute_budget.sha256_max_slices
230 }
231}
232
233#[repr(C)]
245pub struct VmSlice<T> {
246 ptr: u64,
247 len: u64,
248 resource_type: PhantomData<T>,
249}
250
251impl<T> VmSlice<T> {
252 pub fn new(ptr: u64, len: u64) -> Self {
253 VmSlice {
254 ptr,
255 len,
256 resource_type: PhantomData,
257 }
258 }
259
260 pub fn ptr(&self) -> u64 {
261 self.ptr
262 }
263 pub fn len(&self) -> u64 {
264 self.len
265 }
266
267 pub fn is_empty(&self) -> bool {
268 self.len == 0
269 }
270
271 pub fn resize(&mut self, len: u64) {
274 self.len = len;
275 }
276
277 pub fn translate(
279 &self,
280 memory_mapping: &MemoryMapping,
281 check_aligned: bool,
282 ) -> Result<&[T], Error> {
283 translate_slice::<T>(memory_mapping, self.ptr, self.len, check_aligned)
284 }
285
286 pub fn translate_mut(
287 &mut self,
288 memory_mapping: &MemoryMapping,
289 check_aligned: bool,
290 ) -> Result<&mut [T], Error> {
291 translate_slice_mut::<T>(memory_mapping, self.ptr, self.len, check_aligned)
292 }
293}
294
295fn consume_compute_meter(invoke_context: &InvokeContext, amount: u64) -> Result<(), Error> {
296 invoke_context.consume_checked(amount)?;
297 Ok(())
298}
299
300macro_rules! register_feature_gated_function {
301 ($result:expr, $is_feature_active:expr, $name:expr, $call:expr $(,)?) => {
302 if $is_feature_active {
303 $result.register_function($name, $call)
304 } else {
305 Ok(())
306 }
307 };
308}
309
310pub(crate) fn morph_into_deployment_environment_v1(
311 from: Arc<BuiltinProgram<InvokeContext>>,
312) -> Result<BuiltinProgram<InvokeContext>, Error> {
313 let mut config = from.get_config().clone();
314 config.reject_broken_elfs = true;
315 let mut result = BuiltinProgram::new_loader(config);
321
322 for (_key, (name, value)) in from.get_function_registry().iter() {
323 if name != *b"sol_alloc_free_" {
325 result.register_function(unsafe { std::str::from_utf8_unchecked(name) }, value)?;
326 }
327 }
328
329 Ok(result)
330}
331
332pub fn create_program_runtime_environment_v1<'a>(
333 feature_set: &FeatureSet,
334 compute_budget: &ComputeBudget,
335 reject_deployment_of_broken_elfs: bool,
336 debugging_features: bool,
337) -> Result<BuiltinProgram<InvokeContext<'a>>, Error> {
338 let enable_alt_bn128_syscall = feature_set.is_active(&enable_alt_bn128_syscall::id());
339 let enable_alt_bn128_compression_syscall =
340 feature_set.is_active(&enable_alt_bn128_compression_syscall::id());
341 let enable_big_mod_exp_syscall = feature_set.is_active(&enable_big_mod_exp_syscall::id());
342 let blake3_syscall_enabled = feature_set.is_active(&blake3_syscall_enabled::id());
343 let curve25519_syscall_enabled = feature_set.is_active(&curve25519_syscall_enabled::id());
344 let disable_fees_sysvar = feature_set.is_active(&disable_fees_sysvar::id());
345 let disable_deploy_of_alloc_free_syscall = reject_deployment_of_broken_elfs
346 && feature_set.is_active(&disable_deploy_of_alloc_free_syscall::id());
347 let last_restart_slot_syscall_enabled = feature_set.is_active(&last_restart_slot_sysvar::id());
348 let enable_poseidon_syscall = feature_set.is_active(&enable_poseidon_syscall::id());
349 let remaining_compute_units_syscall_enabled =
350 feature_set.is_active(&remaining_compute_units_syscall_enabled::id());
351 let get_sysvar_syscall_enabled = feature_set.is_active(&get_sysvar_syscall_enabled::id());
352 let enable_get_epoch_stake_syscall =
353 feature_set.is_active(&enable_get_epoch_stake_syscall::id());
354 let min_sbpf_version = if !feature_set.is_active(&disable_sbpf_v0_execution::id())
355 || feature_set.is_active(&reenable_sbpf_v0_execution::id())
356 {
357 SBPFVersion::V0
358 } else {
359 SBPFVersion::V3
360 };
361 let max_sbpf_version = if feature_set.is_active(&enable_sbpf_v3_deployment_and_execution::id())
362 {
363 SBPFVersion::V3
364 } else if feature_set.is_active(&enable_sbpf_v2_deployment_and_execution::id()) {
365 SBPFVersion::V2
366 } else if feature_set.is_active(&enable_sbpf_v1_deployment_and_execution::id()) {
367 SBPFVersion::V1
368 } else {
369 SBPFVersion::V0
370 };
371 debug_assert!(min_sbpf_version <= max_sbpf_version);
372
373 let config = Config {
374 max_call_depth: compute_budget.max_call_depth,
375 stack_frame_size: compute_budget.stack_frame_size,
376 enable_address_translation: true,
377 enable_stack_frame_gaps: !feature_set.is_active(&bpf_account_data_direct_mapping::id()),
378 instruction_meter_checkpoint_distance: 10000,
379 enable_instruction_meter: true,
380 enable_instruction_tracing: debugging_features,
381 enable_symbol_and_section_labels: debugging_features,
382 reject_broken_elfs: reject_deployment_of_broken_elfs,
383 noop_instruction_rate: 256,
384 sanitize_user_provided_values: true,
385 enabled_sbpf_versions: min_sbpf_version..=max_sbpf_version,
386 optimize_rodata: false,
387 aligned_memory_mapping: !feature_set.is_active(&bpf_account_data_direct_mapping::id()),
388 };
390 let mut result = BuiltinProgram::new_loader(config);
391
392 result.register_function("abort", SyscallAbort::vm)?;
394
395 result.register_function("sol_panic_", SyscallPanic::vm)?;
397
398 result.register_function("sol_log_", SyscallLog::vm)?;
400 result.register_function("sol_log_64_", SyscallLogU64::vm)?;
401 result.register_function("sol_log_pubkey", SyscallLogPubkey::vm)?;
402 result.register_function("sol_log_compute_units_", SyscallLogBpfComputeUnits::vm)?;
403
404 result.register_function(
406 "sol_create_program_address",
407 SyscallCreateProgramAddress::vm,
408 )?;
409 result.register_function(
410 "sol_try_find_program_address",
411 SyscallTryFindProgramAddress::vm,
412 )?;
413
414 result.register_function("sol_sha256", SyscallHash::vm::<Sha256Hasher>)?;
416
417 result.register_function("sol_keccak256", SyscallHash::vm::<Keccak256Hasher>)?;
419
420 result.register_function("sol_secp256k1_recover", SyscallSecp256k1Recover::vm)?;
422
423 register_feature_gated_function!(
425 result,
426 blake3_syscall_enabled,
427 "sol_blake3",
428 SyscallHash::vm::<Blake3Hasher>,
429 )?;
430
431 register_feature_gated_function!(
433 result,
434 curve25519_syscall_enabled,
435 "sol_curve_validate_point",
436 SyscallCurvePointValidation::vm,
437 )?;
438 register_feature_gated_function!(
439 result,
440 curve25519_syscall_enabled,
441 "sol_curve_group_op",
442 SyscallCurveGroupOps::vm,
443 )?;
444 register_feature_gated_function!(
445 result,
446 curve25519_syscall_enabled,
447 "sol_curve_multiscalar_mul",
448 SyscallCurveMultiscalarMultiplication::vm,
449 )?;
450
451 result.register_function("sol_get_clock_sysvar", SyscallGetClockSysvar::vm)?;
453 result.register_function(
454 "sol_get_epoch_schedule_sysvar",
455 SyscallGetEpochScheduleSysvar::vm,
456 )?;
457 register_feature_gated_function!(
458 result,
459 !disable_fees_sysvar,
460 "sol_get_fees_sysvar",
461 SyscallGetFeesSysvar::vm,
462 )?;
463 result.register_function("sol_get_rent_sysvar", SyscallGetRentSysvar::vm)?;
464
465 register_feature_gated_function!(
466 result,
467 last_restart_slot_syscall_enabled,
468 "sol_get_last_restart_slot",
469 SyscallGetLastRestartSlotSysvar::vm,
470 )?;
471
472 result.register_function(
473 "sol_get_epoch_rewards_sysvar",
474 SyscallGetEpochRewardsSysvar::vm,
475 )?;
476
477 result.register_function("sol_memcpy_", SyscallMemcpy::vm)?;
479 result.register_function("sol_memmove_", SyscallMemmove::vm)?;
480 result.register_function("sol_memset_", SyscallMemset::vm)?;
481 result.register_function("sol_memcmp_", SyscallMemcmp::vm)?;
482
483 result.register_function(
485 "sol_get_processed_sibling_instruction",
486 SyscallGetProcessedSiblingInstruction::vm,
487 )?;
488
489 result.register_function("sol_get_stack_height", SyscallGetStackHeight::vm)?;
491
492 result.register_function("sol_set_return_data", SyscallSetReturnData::vm)?;
494 result.register_function("sol_get_return_data", SyscallGetReturnData::vm)?;
495
496 result.register_function("sol_invoke_signed_c", SyscallInvokeSignedC::vm)?;
498 result.register_function("sol_invoke_signed_rust", SyscallInvokeSignedRust::vm)?;
499
500 register_feature_gated_function!(
502 result,
503 !disable_deploy_of_alloc_free_syscall,
504 "sol_alloc_free_",
505 SyscallAllocFree::vm,
506 )?;
507
508 register_feature_gated_function!(
510 result,
511 enable_alt_bn128_syscall,
512 "sol_alt_bn128_group_op",
513 SyscallAltBn128::vm,
514 )?;
515
516 register_feature_gated_function!(
518 result,
519 enable_big_mod_exp_syscall,
520 "sol_big_mod_exp",
521 SyscallBigModExp::vm,
522 )?;
523
524 register_feature_gated_function!(
526 result,
527 enable_poseidon_syscall,
528 "sol_poseidon",
529 SyscallPoseidon::vm,
530 )?;
531
532 register_feature_gated_function!(
534 result,
535 remaining_compute_units_syscall_enabled,
536 "sol_remaining_compute_units",
537 SyscallRemainingComputeUnits::vm
538 )?;
539
540 register_feature_gated_function!(
542 result,
543 enable_alt_bn128_compression_syscall,
544 "sol_alt_bn128_compression",
545 SyscallAltBn128Compression::vm,
546 )?;
547
548 register_feature_gated_function!(
550 result,
551 get_sysvar_syscall_enabled,
552 "sol_get_sysvar",
553 SyscallGetSysvar::vm,
554 )?;
555
556 register_feature_gated_function!(
558 result,
559 enable_get_epoch_stake_syscall,
560 "sol_get_epoch_stake",
561 SyscallGetEpochStake::vm,
562 )?;
563
564 result.register_function("sol_log_data", SyscallLogData::vm)?;
566
567 Ok(result)
568}
569
570pub fn create_program_runtime_environment_v2<'a>(
571 compute_budget: &ComputeBudget,
572 debugging_features: bool,
573) -> BuiltinProgram<InvokeContext<'a>> {
574 let config = Config {
575 max_call_depth: compute_budget.max_call_depth,
576 stack_frame_size: compute_budget.stack_frame_size,
577 enable_address_translation: true, enable_stack_frame_gaps: false,
579 instruction_meter_checkpoint_distance: 10000,
580 enable_instruction_meter: true,
581 enable_instruction_tracing: debugging_features,
582 enable_symbol_and_section_labels: debugging_features,
583 reject_broken_elfs: true,
584 noop_instruction_rate: 256,
585 sanitize_user_provided_values: true,
586 enabled_sbpf_versions: SBPFVersion::Reserved..=SBPFVersion::Reserved,
587 optimize_rodata: true,
588 aligned_memory_mapping: true,
589 };
591 BuiltinProgram::new_loader(config)
592}
593
594fn address_is_aligned<T>(address: u64) -> bool {
595 (address as *mut T as usize)
596 .checked_rem(align_of::<T>())
597 .map(|rem| rem == 0)
598 .expect("T to be non-zero aligned")
599}
600
601fn translate(
602 memory_mapping: &MemoryMapping,
603 access_type: AccessType,
604 vm_addr: u64,
605 len: u64,
606) -> Result<u64, Error> {
607 memory_mapping
608 .map(access_type, vm_addr, len)
609 .map_err(|err| err.into())
610 .into()
611}
612
613fn translate_type_inner<'a, T>(
614 memory_mapping: &MemoryMapping,
615 access_type: AccessType,
616 vm_addr: u64,
617 check_aligned: bool,
618) -> Result<&'a mut T, Error> {
619 let host_addr = translate(memory_mapping, access_type, vm_addr, size_of::<T>() as u64)?;
620 if !check_aligned {
621 Ok(unsafe { std::mem::transmute::<u64, &mut T>(host_addr) })
622 } else if !address_is_aligned::<T>(host_addr) {
623 Err(SyscallError::UnalignedPointer.into())
624 } else {
625 Ok(unsafe { &mut *(host_addr as *mut T) })
626 }
627}
628fn translate_type_mut<'a, T>(
629 memory_mapping: &MemoryMapping,
630 vm_addr: u64,
631 check_aligned: bool,
632) -> Result<&'a mut T, Error> {
633 translate_type_inner::<T>(memory_mapping, AccessType::Store, vm_addr, check_aligned)
634}
635fn translate_type<'a, T>(
636 memory_mapping: &MemoryMapping,
637 vm_addr: u64,
638 check_aligned: bool,
639) -> Result<&'a T, Error> {
640 translate_type_inner::<T>(memory_mapping, AccessType::Load, vm_addr, check_aligned)
641 .map(|value| &*value)
642}
643
644fn translate_slice_inner<'a, T>(
645 memory_mapping: &MemoryMapping,
646 access_type: AccessType,
647 vm_addr: u64,
648 len: u64,
649 check_aligned: bool,
650) -> Result<&'a mut [T], Error> {
651 if len == 0 {
652 return Ok(&mut []);
653 }
654
655 let total_size = len.saturating_mul(size_of::<T>() as u64);
656 if isize::try_from(total_size).is_err() {
657 return Err(SyscallError::InvalidLength.into());
658 }
659
660 let host_addr = translate(memory_mapping, access_type, vm_addr, total_size)?;
661
662 if check_aligned && !address_is_aligned::<T>(host_addr) {
663 return Err(SyscallError::UnalignedPointer.into());
664 }
665 Ok(unsafe { from_raw_parts_mut(host_addr as *mut T, len as usize) })
666}
667fn translate_slice_mut<'a, T>(
668 memory_mapping: &MemoryMapping,
669 vm_addr: u64,
670 len: u64,
671 check_aligned: bool,
672) -> Result<&'a mut [T], Error> {
673 translate_slice_inner::<T>(
674 memory_mapping,
675 AccessType::Store,
676 vm_addr,
677 len,
678 check_aligned,
679 )
680}
681fn translate_slice<'a, T>(
682 memory_mapping: &MemoryMapping,
683 vm_addr: u64,
684 len: u64,
685 check_aligned: bool,
686) -> Result<&'a [T], Error> {
687 translate_slice_inner::<T>(
688 memory_mapping,
689 AccessType::Load,
690 vm_addr,
691 len,
692 check_aligned,
693 )
694 .map(|value| &*value)
695}
696
697fn translate_slice_of_slices_inner<'a, T>(
698 memory_mapping: &MemoryMapping,
699 access_type: AccessType,
700 vm_addr: u64,
701 len: u64,
702 check_aligned: bool,
703) -> Result<&'a mut [VmSlice<T>], Error> {
704 if len == 0 {
705 return Ok(&mut []);
706 }
707
708 let total_size = len.saturating_mul(size_of::<VmSlice<T>>() as u64);
709 if isize::try_from(total_size).is_err() {
710 return Err(SyscallError::InvalidLength.into());
711 }
712
713 let host_addr = translate(memory_mapping, access_type, vm_addr, total_size)?;
714
715 if check_aligned && !address_is_aligned::<VmSlice<T>>(host_addr) {
716 return Err(SyscallError::UnalignedPointer.into());
717 }
718 Ok(unsafe { from_raw_parts_mut(host_addr as *mut VmSlice<T>, len as usize) })
719}
720
721#[allow(dead_code)]
722fn translate_slice_of_slices_mut<'a, T>(
723 memory_mapping: &MemoryMapping,
724 vm_addr: u64,
725 len: u64,
726 check_aligned: bool,
727) -> Result<&'a mut [VmSlice<T>], Error> {
728 translate_slice_of_slices_inner::<T>(
729 memory_mapping,
730 AccessType::Store,
731 vm_addr,
732 len,
733 check_aligned,
734 )
735}
736
737fn translate_slice_of_slices<'a, T>(
738 memory_mapping: &MemoryMapping,
739 vm_addr: u64,
740 len: u64,
741 check_aligned: bool,
742) -> Result<&'a [VmSlice<T>], Error> {
743 translate_slice_of_slices_inner::<T>(
744 memory_mapping,
745 AccessType::Load,
746 vm_addr,
747 len,
748 check_aligned,
749 )
750 .map(|value| &*value)
751}
752
753fn translate_string_and_do(
756 memory_mapping: &MemoryMapping,
757 addr: u64,
758 len: u64,
759 check_aligned: bool,
760 work: &mut dyn FnMut(&str) -> Result<u64, Error>,
761) -> Result<u64, Error> {
762 let buf = translate_slice::<u8>(memory_mapping, addr, len, check_aligned)?;
763 match from_utf8(buf) {
764 Ok(message) => work(message),
765 Err(err) => Err(SyscallError::InvalidString(err, buf.to_vec()).into()),
766 }
767}
768
769declare_builtin_function!(
770 SyscallAbort,
775 fn rust(
776 _invoke_context: &mut InvokeContext,
777 _arg1: u64,
778 _arg2: u64,
779 _arg3: u64,
780 _arg4: u64,
781 _arg5: u64,
782 _memory_mapping: &mut MemoryMapping,
783 ) -> Result<u64, Error> {
784 Err(SyscallError::Abort.into())
785 }
786);
787
788declare_builtin_function!(
789 SyscallPanic,
792 fn rust(
793 invoke_context: &mut InvokeContext,
794 file: u64,
795 len: u64,
796 line: u64,
797 column: u64,
798 _arg5: u64,
799 memory_mapping: &mut MemoryMapping,
800 ) -> Result<u64, Error> {
801 consume_compute_meter(invoke_context, len)?;
802
803 translate_string_and_do(
804 memory_mapping,
805 file,
806 len,
807 invoke_context.get_check_aligned(),
808 &mut |string: &str| Err(SyscallError::Panic(string.to_string(), line, column).into()),
809 )
810 }
811);
812
813declare_builtin_function!(
814 SyscallAllocFree,
821 fn rust(
822 invoke_context: &mut InvokeContext,
823 size: u64,
824 free_addr: u64,
825 _arg3: u64,
826 _arg4: u64,
827 _arg5: u64,
828 _memory_mapping: &mut MemoryMapping,
829 ) -> Result<u64, Error> {
830 let align = if invoke_context.get_check_aligned() {
831 BPF_ALIGN_OF_U128
832 } else {
833 align_of::<u8>()
834 };
835 let Ok(layout) = Layout::from_size_align(size as usize, align) else {
836 return Ok(0);
837 };
838 let allocator = &mut invoke_context.get_syscall_context_mut()?.allocator;
839 if free_addr == 0 {
840 match allocator.alloc(layout) {
841 Ok(addr) => Ok(addr),
842 Err(_) => Ok(0),
843 }
844 } else {
845 Ok(0)
847 }
848 }
849);
850
851fn translate_and_check_program_address_inputs<'a>(
852 seeds_addr: u64,
853 seeds_len: u64,
854 program_id_addr: u64,
855 memory_mapping: &mut MemoryMapping,
856 check_aligned: bool,
857) -> Result<(Vec<&'a [u8]>, &'a Pubkey), Error> {
858 let untranslated_seeds =
859 translate_slice_of_slices::<u8>(memory_mapping, seeds_addr, seeds_len, check_aligned)?;
860 if untranslated_seeds.len() > MAX_SEEDS {
861 return Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into());
862 }
863 let seeds = untranslated_seeds
864 .iter()
865 .map(|untranslated_seed| {
866 if untranslated_seed.len() > MAX_SEED_LEN as u64 {
867 return Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into());
868 }
869 untranslated_seed.translate(memory_mapping, check_aligned)
870 })
871 .collect::<Result<Vec<_>, Error>>()?;
872 let program_id = translate_type::<Pubkey>(memory_mapping, program_id_addr, check_aligned)?;
873 Ok((seeds, program_id))
874}
875
876declare_builtin_function!(
877 SyscallCreateProgramAddress,
879 fn rust(
880 invoke_context: &mut InvokeContext,
881 seeds_addr: u64,
882 seeds_len: u64,
883 program_id_addr: u64,
884 address_addr: u64,
885 _arg5: u64,
886 memory_mapping: &mut MemoryMapping,
887 ) -> Result<u64, Error> {
888 let cost = invoke_context
889 .get_compute_budget()
890 .create_program_address_units;
891 consume_compute_meter(invoke_context, cost)?;
892
893 let (seeds, program_id) = translate_and_check_program_address_inputs(
894 seeds_addr,
895 seeds_len,
896 program_id_addr,
897 memory_mapping,
898 invoke_context.get_check_aligned(),
899 )?;
900
901 let Ok(new_address) = Pubkey::create_program_address(&seeds, program_id) else {
902 return Ok(1);
903 };
904 let address = translate_slice_mut::<u8>(
905 memory_mapping,
906 address_addr,
907 32,
908 invoke_context.get_check_aligned(),
909 )?;
910 address.copy_from_slice(new_address.as_ref());
911 Ok(0)
912 }
913);
914
915declare_builtin_function!(
916 SyscallTryFindProgramAddress,
918 fn rust(
919 invoke_context: &mut InvokeContext,
920 seeds_addr: u64,
921 seeds_len: u64,
922 program_id_addr: u64,
923 address_addr: u64,
924 bump_seed_addr: u64,
925 memory_mapping: &mut MemoryMapping,
926 ) -> Result<u64, Error> {
927 let cost = invoke_context
928 .get_compute_budget()
929 .create_program_address_units;
930 consume_compute_meter(invoke_context, cost)?;
931
932 let (seeds, program_id) = translate_and_check_program_address_inputs(
933 seeds_addr,
934 seeds_len,
935 program_id_addr,
936 memory_mapping,
937 invoke_context.get_check_aligned(),
938 )?;
939
940 let mut bump_seed = [u8::MAX];
941 for _ in 0..u8::MAX {
942 {
943 let mut seeds_with_bump = seeds.to_vec();
944 seeds_with_bump.push(&bump_seed);
945
946 if let Ok(new_address) =
947 Pubkey::create_program_address(&seeds_with_bump, program_id)
948 {
949 let bump_seed_ref = translate_type_mut::<u8>(
950 memory_mapping,
951 bump_seed_addr,
952 invoke_context.get_check_aligned(),
953 )?;
954 let address = translate_slice_mut::<u8>(
955 memory_mapping,
956 address_addr,
957 std::mem::size_of::<Pubkey>() as u64,
958 invoke_context.get_check_aligned(),
959 )?;
960 if !is_nonoverlapping(
961 bump_seed_ref as *const _ as usize,
962 std::mem::size_of_val(bump_seed_ref),
963 address.as_ptr() as usize,
964 std::mem::size_of::<Pubkey>(),
965 ) {
966 return Err(SyscallError::CopyOverlapping.into());
967 }
968 *bump_seed_ref = bump_seed[0];
969 address.copy_from_slice(new_address.as_ref());
970 return Ok(0);
971 }
972 }
973 bump_seed[0] = bump_seed[0].saturating_sub(1);
974 consume_compute_meter(invoke_context, cost)?;
975 }
976 Ok(1)
977 }
978);
979
980declare_builtin_function!(
981 SyscallSecp256k1Recover,
983 fn rust(
984 invoke_context: &mut InvokeContext,
985 hash_addr: u64,
986 recovery_id_val: u64,
987 signature_addr: u64,
988 result_addr: u64,
989 _arg5: u64,
990 memory_mapping: &mut MemoryMapping,
991 ) -> Result<u64, Error> {
992 let cost = invoke_context.get_compute_budget().secp256k1_recover_cost;
993 consume_compute_meter(invoke_context, cost)?;
994
995 let hash = translate_slice::<u8>(
996 memory_mapping,
997 hash_addr,
998 keccak::HASH_BYTES as u64,
999 invoke_context.get_check_aligned(),
1000 )?;
1001 let signature = translate_slice::<u8>(
1002 memory_mapping,
1003 signature_addr,
1004 SECP256K1_SIGNATURE_LENGTH as u64,
1005 invoke_context.get_check_aligned(),
1006 )?;
1007 let secp256k1_recover_result = translate_slice_mut::<u8>(
1008 memory_mapping,
1009 result_addr,
1010 SECP256K1_PUBLIC_KEY_LENGTH as u64,
1011 invoke_context.get_check_aligned(),
1012 )?;
1013
1014 let Ok(message) = libsecp256k1::Message::parse_slice(hash) else {
1015 return Ok(Secp256k1RecoverError::InvalidHash.into());
1016 };
1017 let Ok(adjusted_recover_id_val) = recovery_id_val.try_into() else {
1018 return Ok(Secp256k1RecoverError::InvalidRecoveryId.into());
1019 };
1020 let Ok(recovery_id) = libsecp256k1::RecoveryId::parse(adjusted_recover_id_val) else {
1021 return Ok(Secp256k1RecoverError::InvalidRecoveryId.into());
1022 };
1023 let Ok(signature) = libsecp256k1::Signature::parse_standard_slice(signature) else {
1024 return Ok(Secp256k1RecoverError::InvalidSignature.into());
1025 };
1026
1027 let public_key = match libsecp256k1::recover(&message, &signature, &recovery_id) {
1028 Ok(key) => key.serialize(),
1029 Err(_) => {
1030 return Ok(Secp256k1RecoverError::InvalidSignature.into());
1031 }
1032 };
1033
1034 secp256k1_recover_result.copy_from_slice(&public_key[1..65]);
1035 Ok(SUCCESS)
1036 }
1037);
1038
1039declare_builtin_function!(
1040 SyscallCurvePointValidation,
1044 fn rust(
1045 invoke_context: &mut InvokeContext,
1046 curve_id: u64,
1047 point_addr: u64,
1048 _arg3: u64,
1049 _arg4: u64,
1050 _arg5: u64,
1051 memory_mapping: &mut MemoryMapping,
1052 ) -> Result<u64, Error> {
1053 use solana_curve25519::{curve_syscall_traits::*, edwards, ristretto};
1054 match curve_id {
1055 CURVE25519_EDWARDS => {
1056 let cost = invoke_context
1057 .get_compute_budget()
1058 .curve25519_edwards_validate_point_cost;
1059 consume_compute_meter(invoke_context, cost)?;
1060
1061 let point = translate_type::<edwards::PodEdwardsPoint>(
1062 memory_mapping,
1063 point_addr,
1064 invoke_context.get_check_aligned(),
1065 )?;
1066
1067 if edwards::validate_edwards(point) {
1068 Ok(0)
1069 } else {
1070 Ok(1)
1071 }
1072 }
1073 CURVE25519_RISTRETTO => {
1074 let cost = invoke_context
1075 .get_compute_budget()
1076 .curve25519_ristretto_validate_point_cost;
1077 consume_compute_meter(invoke_context, cost)?;
1078
1079 let point = translate_type::<ristretto::PodRistrettoPoint>(
1080 memory_mapping,
1081 point_addr,
1082 invoke_context.get_check_aligned(),
1083 )?;
1084
1085 if ristretto::validate_ristretto(point) {
1086 Ok(0)
1087 } else {
1088 Ok(1)
1089 }
1090 }
1091 _ => {
1092 if invoke_context
1093 .get_feature_set()
1094 .is_active(&abort_on_invalid_curve::id())
1095 {
1096 Err(SyscallError::InvalidAttribute.into())
1097 } else {
1098 Ok(1)
1099 }
1100 }
1101 }
1102 }
1103);
1104
1105declare_builtin_function!(
1106 SyscallCurveGroupOps,
1110 fn rust(
1111 invoke_context: &mut InvokeContext,
1112 curve_id: u64,
1113 group_op: u64,
1114 left_input_addr: u64,
1115 right_input_addr: u64,
1116 result_point_addr: u64,
1117 memory_mapping: &mut MemoryMapping,
1118 ) -> Result<u64, Error> {
1119 use solana_curve25519::{curve_syscall_traits::*, edwards, ristretto, scalar};
1120 match curve_id {
1121 CURVE25519_EDWARDS => match group_op {
1122 ADD => {
1123 let cost = invoke_context
1124 .get_compute_budget()
1125 .curve25519_edwards_add_cost;
1126 consume_compute_meter(invoke_context, cost)?;
1127
1128 let left_point = translate_type::<edwards::PodEdwardsPoint>(
1129 memory_mapping,
1130 left_input_addr,
1131 invoke_context.get_check_aligned(),
1132 )?;
1133 let right_point = translate_type::<edwards::PodEdwardsPoint>(
1134 memory_mapping,
1135 right_input_addr,
1136 invoke_context.get_check_aligned(),
1137 )?;
1138
1139 if let Some(result_point) = edwards::add_edwards(left_point, right_point) {
1140 *translate_type_mut::<edwards::PodEdwardsPoint>(
1141 memory_mapping,
1142 result_point_addr,
1143 invoke_context.get_check_aligned(),
1144 )? = result_point;
1145 Ok(0)
1146 } else {
1147 Ok(1)
1148 }
1149 }
1150 SUB => {
1151 let cost = invoke_context
1152 .get_compute_budget()
1153 .curve25519_edwards_subtract_cost;
1154 consume_compute_meter(invoke_context, cost)?;
1155
1156 let left_point = translate_type::<edwards::PodEdwardsPoint>(
1157 memory_mapping,
1158 left_input_addr,
1159 invoke_context.get_check_aligned(),
1160 )?;
1161 let right_point = translate_type::<edwards::PodEdwardsPoint>(
1162 memory_mapping,
1163 right_input_addr,
1164 invoke_context.get_check_aligned(),
1165 )?;
1166
1167 if let Some(result_point) = edwards::subtract_edwards(left_point, right_point) {
1168 *translate_type_mut::<edwards::PodEdwardsPoint>(
1169 memory_mapping,
1170 result_point_addr,
1171 invoke_context.get_check_aligned(),
1172 )? = result_point;
1173 Ok(0)
1174 } else {
1175 Ok(1)
1176 }
1177 }
1178 MUL => {
1179 let cost = invoke_context
1180 .get_compute_budget()
1181 .curve25519_edwards_multiply_cost;
1182 consume_compute_meter(invoke_context, cost)?;
1183
1184 let scalar = translate_type::<scalar::PodScalar>(
1185 memory_mapping,
1186 left_input_addr,
1187 invoke_context.get_check_aligned(),
1188 )?;
1189 let input_point = translate_type::<edwards::PodEdwardsPoint>(
1190 memory_mapping,
1191 right_input_addr,
1192 invoke_context.get_check_aligned(),
1193 )?;
1194
1195 if let Some(result_point) = edwards::multiply_edwards(scalar, input_point) {
1196 *translate_type_mut::<edwards::PodEdwardsPoint>(
1197 memory_mapping,
1198 result_point_addr,
1199 invoke_context.get_check_aligned(),
1200 )? = result_point;
1201 Ok(0)
1202 } else {
1203 Ok(1)
1204 }
1205 }
1206 _ => {
1207 if invoke_context
1208 .get_feature_set()
1209 .is_active(&abort_on_invalid_curve::id())
1210 {
1211 Err(SyscallError::InvalidAttribute.into())
1212 } else {
1213 Ok(1)
1214 }
1215 }
1216 },
1217
1218 CURVE25519_RISTRETTO => match group_op {
1219 ADD => {
1220 let cost = invoke_context
1221 .get_compute_budget()
1222 .curve25519_ristretto_add_cost;
1223 consume_compute_meter(invoke_context, cost)?;
1224
1225 let left_point = translate_type::<ristretto::PodRistrettoPoint>(
1226 memory_mapping,
1227 left_input_addr,
1228 invoke_context.get_check_aligned(),
1229 )?;
1230 let right_point = translate_type::<ristretto::PodRistrettoPoint>(
1231 memory_mapping,
1232 right_input_addr,
1233 invoke_context.get_check_aligned(),
1234 )?;
1235
1236 if let Some(result_point) = ristretto::add_ristretto(left_point, right_point) {
1237 *translate_type_mut::<ristretto::PodRistrettoPoint>(
1238 memory_mapping,
1239 result_point_addr,
1240 invoke_context.get_check_aligned(),
1241 )? = result_point;
1242 Ok(0)
1243 } else {
1244 Ok(1)
1245 }
1246 }
1247 SUB => {
1248 let cost = invoke_context
1249 .get_compute_budget()
1250 .curve25519_ristretto_subtract_cost;
1251 consume_compute_meter(invoke_context, cost)?;
1252
1253 let left_point = translate_type::<ristretto::PodRistrettoPoint>(
1254 memory_mapping,
1255 left_input_addr,
1256 invoke_context.get_check_aligned(),
1257 )?;
1258 let right_point = translate_type::<ristretto::PodRistrettoPoint>(
1259 memory_mapping,
1260 right_input_addr,
1261 invoke_context.get_check_aligned(),
1262 )?;
1263
1264 if let Some(result_point) =
1265 ristretto::subtract_ristretto(left_point, right_point)
1266 {
1267 *translate_type_mut::<ristretto::PodRistrettoPoint>(
1268 memory_mapping,
1269 result_point_addr,
1270 invoke_context.get_check_aligned(),
1271 )? = result_point;
1272 Ok(0)
1273 } else {
1274 Ok(1)
1275 }
1276 }
1277 MUL => {
1278 let cost = invoke_context
1279 .get_compute_budget()
1280 .curve25519_ristretto_multiply_cost;
1281 consume_compute_meter(invoke_context, cost)?;
1282
1283 let scalar = translate_type::<scalar::PodScalar>(
1284 memory_mapping,
1285 left_input_addr,
1286 invoke_context.get_check_aligned(),
1287 )?;
1288 let input_point = translate_type::<ristretto::PodRistrettoPoint>(
1289 memory_mapping,
1290 right_input_addr,
1291 invoke_context.get_check_aligned(),
1292 )?;
1293
1294 if let Some(result_point) = ristretto::multiply_ristretto(scalar, input_point) {
1295 *translate_type_mut::<ristretto::PodRistrettoPoint>(
1296 memory_mapping,
1297 result_point_addr,
1298 invoke_context.get_check_aligned(),
1299 )? = result_point;
1300 Ok(0)
1301 } else {
1302 Ok(1)
1303 }
1304 }
1305 _ => {
1306 if invoke_context
1307 .get_feature_set()
1308 .is_active(&abort_on_invalid_curve::id())
1309 {
1310 Err(SyscallError::InvalidAttribute.into())
1311 } else {
1312 Ok(1)
1313 }
1314 }
1315 },
1316
1317 _ => {
1318 if invoke_context
1319 .get_feature_set()
1320 .is_active(&abort_on_invalid_curve::id())
1321 {
1322 Err(SyscallError::InvalidAttribute.into())
1323 } else {
1324 Ok(1)
1325 }
1326 }
1327 }
1328 }
1329);
1330
1331declare_builtin_function!(
1332 SyscallCurveMultiscalarMultiplication,
1336 fn rust(
1337 invoke_context: &mut InvokeContext,
1338 curve_id: u64,
1339 scalars_addr: u64,
1340 points_addr: u64,
1341 points_len: u64,
1342 result_point_addr: u64,
1343 memory_mapping: &mut MemoryMapping,
1344 ) -> Result<u64, Error> {
1345 use solana_curve25519::{curve_syscall_traits::*, edwards, ristretto, scalar};
1346
1347 if points_len > 512 {
1348 return Err(Box::new(SyscallError::InvalidLength));
1349 }
1350
1351 match curve_id {
1352 CURVE25519_EDWARDS => {
1353 let cost = invoke_context
1354 .get_compute_budget()
1355 .curve25519_edwards_msm_base_cost
1356 .saturating_add(
1357 invoke_context
1358 .get_compute_budget()
1359 .curve25519_edwards_msm_incremental_cost
1360 .saturating_mul(points_len.saturating_sub(1)),
1361 );
1362 consume_compute_meter(invoke_context, cost)?;
1363
1364 let scalars = translate_slice::<scalar::PodScalar>(
1365 memory_mapping,
1366 scalars_addr,
1367 points_len,
1368 invoke_context.get_check_aligned(),
1369 )?;
1370
1371 let points = translate_slice::<edwards::PodEdwardsPoint>(
1372 memory_mapping,
1373 points_addr,
1374 points_len,
1375 invoke_context.get_check_aligned(),
1376 )?;
1377
1378 if let Some(result_point) = edwards::multiscalar_multiply_edwards(scalars, points) {
1379 *translate_type_mut::<edwards::PodEdwardsPoint>(
1380 memory_mapping,
1381 result_point_addr,
1382 invoke_context.get_check_aligned(),
1383 )? = result_point;
1384 Ok(0)
1385 } else {
1386 Ok(1)
1387 }
1388 }
1389
1390 CURVE25519_RISTRETTO => {
1391 let cost = invoke_context
1392 .get_compute_budget()
1393 .curve25519_ristretto_msm_base_cost
1394 .saturating_add(
1395 invoke_context
1396 .get_compute_budget()
1397 .curve25519_ristretto_msm_incremental_cost
1398 .saturating_mul(points_len.saturating_sub(1)),
1399 );
1400 consume_compute_meter(invoke_context, cost)?;
1401
1402 let scalars = translate_slice::<scalar::PodScalar>(
1403 memory_mapping,
1404 scalars_addr,
1405 points_len,
1406 invoke_context.get_check_aligned(),
1407 )?;
1408
1409 let points = translate_slice::<ristretto::PodRistrettoPoint>(
1410 memory_mapping,
1411 points_addr,
1412 points_len,
1413 invoke_context.get_check_aligned(),
1414 )?;
1415
1416 if let Some(result_point) =
1417 ristretto::multiscalar_multiply_ristretto(scalars, points)
1418 {
1419 *translate_type_mut::<ristretto::PodRistrettoPoint>(
1420 memory_mapping,
1421 result_point_addr,
1422 invoke_context.get_check_aligned(),
1423 )? = result_point;
1424 Ok(0)
1425 } else {
1426 Ok(1)
1427 }
1428 }
1429
1430 _ => {
1431 if invoke_context
1432 .get_feature_set()
1433 .is_active(&abort_on_invalid_curve::id())
1434 {
1435 Err(SyscallError::InvalidAttribute.into())
1436 } else {
1437 Ok(1)
1438 }
1439 }
1440 }
1441 }
1442);
1443
1444declare_builtin_function!(
1445 SyscallSetReturnData,
1447 fn rust(
1448 invoke_context: &mut InvokeContext,
1449 addr: u64,
1450 len: u64,
1451 _arg3: u64,
1452 _arg4: u64,
1453 _arg5: u64,
1454 memory_mapping: &mut MemoryMapping,
1455 ) -> Result<u64, Error> {
1456 let budget = invoke_context.get_compute_budget();
1457
1458 let cost = len
1459 .checked_div(budget.cpi_bytes_per_unit)
1460 .unwrap_or(u64::MAX)
1461 .saturating_add(budget.syscall_base_cost);
1462 consume_compute_meter(invoke_context, cost)?;
1463
1464 if len > MAX_RETURN_DATA as u64 {
1465 return Err(SyscallError::ReturnDataTooLarge(len, MAX_RETURN_DATA as u64).into());
1466 }
1467
1468 let return_data = if len == 0 {
1469 Vec::new()
1470 } else {
1471 translate_slice::<u8>(
1472 memory_mapping,
1473 addr,
1474 len,
1475 invoke_context.get_check_aligned(),
1476 )?
1477 .to_vec()
1478 };
1479 let transaction_context = &mut invoke_context.transaction_context;
1480 let program_id = *transaction_context
1481 .get_current_instruction_context()
1482 .and_then(|instruction_context| {
1483 instruction_context.get_last_program_key(transaction_context)
1484 })?;
1485
1486 transaction_context.set_return_data(program_id, return_data)?;
1487
1488 Ok(0)
1489 }
1490);
1491
1492declare_builtin_function!(
1493 SyscallGetReturnData,
1495 fn rust(
1496 invoke_context: &mut InvokeContext,
1497 return_data_addr: u64,
1498 length: u64,
1499 program_id_addr: u64,
1500 _arg4: u64,
1501 _arg5: u64,
1502 memory_mapping: &mut MemoryMapping,
1503 ) -> Result<u64, Error> {
1504 let budget = invoke_context.get_compute_budget();
1505
1506 consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
1507
1508 let (program_id, return_data) = invoke_context.transaction_context.get_return_data();
1509 let length = length.min(return_data.len() as u64);
1510 if length != 0 {
1511 let cost = length
1512 .saturating_add(size_of::<Pubkey>() as u64)
1513 .checked_div(budget.cpi_bytes_per_unit)
1514 .unwrap_or(u64::MAX);
1515 consume_compute_meter(invoke_context, cost)?;
1516
1517 let return_data_result = translate_slice_mut::<u8>(
1518 memory_mapping,
1519 return_data_addr,
1520 length,
1521 invoke_context.get_check_aligned(),
1522 )?;
1523
1524 let to_slice = return_data_result;
1525 let from_slice = return_data
1526 .get(..length as usize)
1527 .ok_or(SyscallError::InvokeContextBorrowFailed)?;
1528 if to_slice.len() != from_slice.len() {
1529 return Err(SyscallError::InvalidLength.into());
1530 }
1531 to_slice.copy_from_slice(from_slice);
1532
1533 let program_id_result = translate_type_mut::<Pubkey>(
1534 memory_mapping,
1535 program_id_addr,
1536 invoke_context.get_check_aligned(),
1537 )?;
1538
1539 if !is_nonoverlapping(
1540 to_slice.as_ptr() as usize,
1541 length as usize,
1542 program_id_result as *const _ as usize,
1543 std::mem::size_of::<Pubkey>(),
1544 ) {
1545 return Err(SyscallError::CopyOverlapping.into());
1546 }
1547
1548 *program_id_result = *program_id;
1549 }
1550
1551 Ok(return_data.len() as u64)
1553 }
1554);
1555
1556declare_builtin_function!(
1557 SyscallGetProcessedSiblingInstruction,
1559 fn rust(
1560 invoke_context: &mut InvokeContext,
1561 index: u64,
1562 meta_addr: u64,
1563 program_id_addr: u64,
1564 data_addr: u64,
1565 accounts_addr: u64,
1566 memory_mapping: &mut MemoryMapping,
1567 ) -> Result<u64, Error> {
1568 let budget = invoke_context.get_compute_budget();
1569
1570 consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
1571
1572 let stack_height = invoke_context.get_stack_height();
1575 let instruction_trace_length = invoke_context
1576 .transaction_context
1577 .get_instruction_trace_length();
1578 let mut reverse_index_at_stack_height = 0;
1579 let mut found_instruction_context = None;
1580 for index_in_trace in (0..instruction_trace_length).rev() {
1581 let instruction_context = invoke_context
1582 .transaction_context
1583 .get_instruction_context_at_index_in_trace(index_in_trace)?;
1584 if instruction_context.get_stack_height() < stack_height {
1585 break;
1586 }
1587 if instruction_context.get_stack_height() == stack_height {
1588 if index.saturating_add(1) == reverse_index_at_stack_height {
1589 found_instruction_context = Some(instruction_context);
1590 break;
1591 }
1592 reverse_index_at_stack_height = reverse_index_at_stack_height.saturating_add(1);
1593 }
1594 }
1595
1596 if let Some(instruction_context) = found_instruction_context {
1597 let result_header = translate_type_mut::<ProcessedSiblingInstruction>(
1598 memory_mapping,
1599 meta_addr,
1600 invoke_context.get_check_aligned(),
1601 )?;
1602
1603 if result_header.data_len == (instruction_context.get_instruction_data().len() as u64)
1604 && result_header.accounts_len
1605 == (instruction_context.get_number_of_instruction_accounts() as u64)
1606 {
1607 let program_id = translate_type_mut::<Pubkey>(
1608 memory_mapping,
1609 program_id_addr,
1610 invoke_context.get_check_aligned(),
1611 )?;
1612 let data = translate_slice_mut::<u8>(
1613 memory_mapping,
1614 data_addr,
1615 result_header.data_len,
1616 invoke_context.get_check_aligned(),
1617 )?;
1618 let accounts = translate_slice_mut::<AccountMeta>(
1619 memory_mapping,
1620 accounts_addr,
1621 result_header.accounts_len,
1622 invoke_context.get_check_aligned(),
1623 )?;
1624
1625 if !is_nonoverlapping(
1626 result_header as *const _ as usize,
1627 std::mem::size_of::<ProcessedSiblingInstruction>(),
1628 program_id as *const _ as usize,
1629 std::mem::size_of::<Pubkey>(),
1630 ) || !is_nonoverlapping(
1631 result_header as *const _ as usize,
1632 std::mem::size_of::<ProcessedSiblingInstruction>(),
1633 accounts.as_ptr() as usize,
1634 std::mem::size_of::<AccountMeta>()
1635 .saturating_mul(result_header.accounts_len as usize),
1636 ) || !is_nonoverlapping(
1637 result_header as *const _ as usize,
1638 std::mem::size_of::<ProcessedSiblingInstruction>(),
1639 data.as_ptr() as usize,
1640 result_header.data_len as usize,
1641 ) || !is_nonoverlapping(
1642 program_id as *const _ as usize,
1643 std::mem::size_of::<Pubkey>(),
1644 data.as_ptr() as usize,
1645 result_header.data_len as usize,
1646 ) || !is_nonoverlapping(
1647 program_id as *const _ as usize,
1648 std::mem::size_of::<Pubkey>(),
1649 accounts.as_ptr() as usize,
1650 std::mem::size_of::<AccountMeta>()
1651 .saturating_mul(result_header.accounts_len as usize),
1652 ) || !is_nonoverlapping(
1653 data.as_ptr() as usize,
1654 result_header.data_len as usize,
1655 accounts.as_ptr() as usize,
1656 std::mem::size_of::<AccountMeta>()
1657 .saturating_mul(result_header.accounts_len as usize),
1658 ) {
1659 return Err(SyscallError::CopyOverlapping.into());
1660 }
1661
1662 *program_id = *instruction_context
1663 .get_last_program_key(invoke_context.transaction_context)?;
1664 data.clone_from_slice(instruction_context.get_instruction_data());
1665 let account_metas = (0..instruction_context.get_number_of_instruction_accounts())
1666 .map(|instruction_account_index| {
1667 Ok(AccountMeta {
1668 pubkey: *invoke_context
1669 .transaction_context
1670 .get_key_of_account_at_index(
1671 instruction_context
1672 .get_index_of_instruction_account_in_transaction(
1673 instruction_account_index,
1674 )?,
1675 )?,
1676 is_signer: instruction_context
1677 .is_instruction_account_signer(instruction_account_index)?,
1678 is_writable: instruction_context
1679 .is_instruction_account_writable(instruction_account_index)?,
1680 })
1681 })
1682 .collect::<Result<Vec<_>, InstructionError>>()?;
1683 accounts.clone_from_slice(account_metas.as_slice());
1684 }
1685 result_header.data_len = instruction_context.get_instruction_data().len() as u64;
1686 result_header.accounts_len =
1687 instruction_context.get_number_of_instruction_accounts() as u64;
1688 return Ok(true as u64);
1689 }
1690 Ok(false as u64)
1691 }
1692);
1693
1694declare_builtin_function!(
1695 SyscallGetStackHeight,
1697 fn rust(
1698 invoke_context: &mut InvokeContext,
1699 _arg1: u64,
1700 _arg2: u64,
1701 _arg3: u64,
1702 _arg4: u64,
1703 _arg5: u64,
1704 _memory_mapping: &mut MemoryMapping,
1705 ) -> Result<u64, Error> {
1706 let budget = invoke_context.get_compute_budget();
1707
1708 consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
1709
1710 Ok(invoke_context.get_stack_height() as u64)
1711 }
1712);
1713
1714declare_builtin_function!(
1715 SyscallAltBn128,
1717 fn rust(
1718 invoke_context: &mut InvokeContext,
1719 group_op: u64,
1720 input_addr: u64,
1721 input_size: u64,
1722 result_addr: u64,
1723 _arg5: u64,
1724 memory_mapping: &mut MemoryMapping,
1725 ) -> Result<u64, Error> {
1726 use solana_bn254::prelude::{ALT_BN128_ADD, ALT_BN128_MUL, ALT_BN128_PAIRING};
1727 let budget = invoke_context.get_compute_budget();
1728 let (cost, output): (u64, usize) = match group_op {
1729 ALT_BN128_ADD => (
1730 budget.alt_bn128_addition_cost,
1731 ALT_BN128_ADDITION_OUTPUT_LEN,
1732 ),
1733 ALT_BN128_MUL => (
1734 budget.alt_bn128_multiplication_cost,
1735 ALT_BN128_MULTIPLICATION_OUTPUT_LEN,
1736 ),
1737 ALT_BN128_PAIRING => {
1738 let ele_len = input_size
1739 .checked_div(ALT_BN128_PAIRING_ELEMENT_LEN as u64)
1740 .expect("div by non-zero constant");
1741 let cost = budget
1742 .alt_bn128_pairing_one_pair_cost_first
1743 .saturating_add(
1744 budget
1745 .alt_bn128_pairing_one_pair_cost_other
1746 .saturating_mul(ele_len.saturating_sub(1)),
1747 )
1748 .saturating_add(budget.sha256_base_cost)
1749 .saturating_add(input_size)
1750 .saturating_add(ALT_BN128_PAIRING_OUTPUT_LEN as u64);
1751 (cost, ALT_BN128_PAIRING_OUTPUT_LEN)
1752 }
1753 _ => {
1754 return Err(SyscallError::InvalidAttribute.into());
1755 }
1756 };
1757
1758 consume_compute_meter(invoke_context, cost)?;
1759
1760 let input = translate_slice::<u8>(
1761 memory_mapping,
1762 input_addr,
1763 input_size,
1764 invoke_context.get_check_aligned(),
1765 )?;
1766
1767 let call_result = translate_slice_mut::<u8>(
1768 memory_mapping,
1769 result_addr,
1770 output as u64,
1771 invoke_context.get_check_aligned(),
1772 )?;
1773
1774 let calculation = match group_op {
1775 ALT_BN128_ADD => alt_bn128_addition,
1776 ALT_BN128_MUL => {
1777 let fix_alt_bn128_multiplication_input_length = invoke_context
1778 .get_feature_set()
1779 .is_active(&feature_set::fix_alt_bn128_multiplication_input_length::id());
1780 if fix_alt_bn128_multiplication_input_length {
1781 alt_bn128_multiplication
1782 } else {
1783 alt_bn128_multiplication_128
1784 }
1785 }
1786 ALT_BN128_PAIRING => alt_bn128_pairing,
1787 _ => {
1788 return Err(SyscallError::InvalidAttribute.into());
1789 }
1790 };
1791
1792 let simplify_alt_bn128_syscall_error_codes = invoke_context
1793 .get_feature_set()
1794 .is_active(&feature_set::simplify_alt_bn128_syscall_error_codes::id());
1795
1796 let result_point = match calculation(input) {
1797 Ok(result_point) => result_point,
1798 Err(e) => {
1799 return if simplify_alt_bn128_syscall_error_codes {
1800 Ok(1)
1801 } else {
1802 Ok(e.into())
1803 };
1804 }
1805 };
1806
1807 if result_point.len() != output && !simplify_alt_bn128_syscall_error_codes {
1810 return Ok(AltBn128Error::SliceOutOfBounds.into());
1811 }
1812
1813 call_result.copy_from_slice(&result_point);
1814 Ok(SUCCESS)
1815 }
1816);
1817
1818declare_builtin_function!(
1819 SyscallBigModExp,
1821 fn rust(
1822 invoke_context: &mut InvokeContext,
1823 params: u64,
1824 return_value: u64,
1825 _arg3: u64,
1826 _arg4: u64,
1827 _arg5: u64,
1828 memory_mapping: &mut MemoryMapping,
1829 ) -> Result<u64, Error> {
1830 let params = &translate_slice::<BigModExpParams>(
1831 memory_mapping,
1832 params,
1833 1,
1834 invoke_context.get_check_aligned(),
1835 )?
1836 .first()
1837 .ok_or(SyscallError::InvalidLength)?;
1838
1839 if params.base_len > 512 || params.exponent_len > 512 || params.modulus_len > 512 {
1840 return Err(Box::new(SyscallError::InvalidLength));
1841 }
1842
1843 let input_len: u64 = std::cmp::max(params.base_len, params.exponent_len);
1844 let input_len: u64 = std::cmp::max(input_len, params.modulus_len);
1845
1846 let budget = invoke_context.get_compute_budget();
1847 consume_compute_meter(
1849 invoke_context,
1850 budget.syscall_base_cost.saturating_add(
1851 input_len
1852 .saturating_mul(input_len)
1853 .checked_div(budget.big_modular_exponentiation_cost_divisor)
1854 .unwrap_or(u64::MAX)
1855 .saturating_add(budget.big_modular_exponentiation_base_cost),
1856 ),
1857 )?;
1858
1859 let base = translate_slice::<u8>(
1860 memory_mapping,
1861 params.base as *const _ as u64,
1862 params.base_len,
1863 invoke_context.get_check_aligned(),
1864 )?;
1865
1866 let exponent = translate_slice::<u8>(
1867 memory_mapping,
1868 params.exponent as *const _ as u64,
1869 params.exponent_len,
1870 invoke_context.get_check_aligned(),
1871 )?;
1872
1873 let modulus = translate_slice::<u8>(
1874 memory_mapping,
1875 params.modulus as *const _ as u64,
1876 params.modulus_len,
1877 invoke_context.get_check_aligned(),
1878 )?;
1879
1880 let value = big_mod_exp(base, exponent, modulus);
1881
1882 let return_value = translate_slice_mut::<u8>(
1883 memory_mapping,
1884 return_value,
1885 params.modulus_len,
1886 invoke_context.get_check_aligned(),
1887 )?;
1888 return_value.copy_from_slice(value.as_slice());
1889
1890 Ok(0)
1891 }
1892);
1893
1894declare_builtin_function!(
1895 SyscallPoseidon,
1897 fn rust(
1898 invoke_context: &mut InvokeContext,
1899 parameters: u64,
1900 endianness: u64,
1901 vals_addr: u64,
1902 vals_len: u64,
1903 result_addr: u64,
1904 memory_mapping: &mut MemoryMapping,
1905 ) -> Result<u64, Error> {
1906 let parameters: poseidon::Parameters = parameters.try_into()?;
1907 let endianness: poseidon::Endianness = endianness.try_into()?;
1908
1909 if vals_len > 12 {
1910 ic_msg!(
1911 invoke_context,
1912 "Poseidon hashing {} sequences is not supported",
1913 vals_len,
1914 );
1915 return Err(SyscallError::InvalidLength.into());
1916 }
1917
1918 let budget = invoke_context.get_compute_budget();
1919 let Some(cost) = budget.poseidon_cost(vals_len) else {
1920 ic_msg!(
1921 invoke_context,
1922 "Overflow while calculating the compute cost"
1923 );
1924 return Err(SyscallError::ArithmeticOverflow.into());
1925 };
1926 consume_compute_meter(invoke_context, cost.to_owned())?;
1927
1928 let hash_result = translate_slice_mut::<u8>(
1929 memory_mapping,
1930 result_addr,
1931 poseidon::HASH_BYTES as u64,
1932 invoke_context.get_check_aligned(),
1933 )?;
1934 let inputs = translate_slice_of_slices::<u8>(
1935 memory_mapping,
1936 vals_addr,
1937 vals_len,
1938 invoke_context.get_check_aligned(),
1939 )?;
1940 let inputs = inputs
1941 .iter()
1942 .map(|input| input.translate(memory_mapping, invoke_context.get_check_aligned()))
1943 .collect::<Result<Vec<_>, Error>>()?;
1944
1945 let simplify_alt_bn128_syscall_error_codes = invoke_context
1946 .get_feature_set()
1947 .is_active(&feature_set::simplify_alt_bn128_syscall_error_codes::id());
1948
1949 let hash = match poseidon::hashv(parameters, endianness, inputs.as_slice()) {
1950 Ok(hash) => hash,
1951 Err(e) => {
1952 return if simplify_alt_bn128_syscall_error_codes {
1953 Ok(1)
1954 } else {
1955 Ok(e.into())
1956 };
1957 }
1958 };
1959 hash_result.copy_from_slice(&hash.to_bytes());
1960
1961 Ok(SUCCESS)
1962 }
1963);
1964
1965declare_builtin_function!(
1966 SyscallRemainingComputeUnits,
1968 fn rust(
1969 invoke_context: &mut InvokeContext,
1970 _arg1: u64,
1971 _arg2: u64,
1972 _arg3: u64,
1973 _arg4: u64,
1974 _arg5: u64,
1975 _memory_mapping: &mut MemoryMapping,
1976 ) -> Result<u64, Error> {
1977 let budget = invoke_context.get_compute_budget();
1978 consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
1979
1980 use solana_sbpf::vm::ContextObject;
1981 Ok(invoke_context.get_remaining())
1982 }
1983);
1984
1985declare_builtin_function!(
1986 SyscallAltBn128Compression,
1988 fn rust(
1989 invoke_context: &mut InvokeContext,
1990 op: u64,
1991 input_addr: u64,
1992 input_size: u64,
1993 result_addr: u64,
1994 _arg5: u64,
1995 memory_mapping: &mut MemoryMapping,
1996 ) -> Result<u64, Error> {
1997 use solana_bn254::compression::prelude::{
1998 alt_bn128_g1_compress, alt_bn128_g1_decompress, alt_bn128_g2_compress,
1999 alt_bn128_g2_decompress, ALT_BN128_G1_COMPRESS, ALT_BN128_G1_DECOMPRESS,
2000 ALT_BN128_G2_COMPRESS, ALT_BN128_G2_DECOMPRESS, G1, G1_COMPRESSED, G2, G2_COMPRESSED,
2001 };
2002 let budget = invoke_context.get_compute_budget();
2003 let base_cost = budget.syscall_base_cost;
2004 let (cost, output): (u64, usize) = match op {
2005 ALT_BN128_G1_COMPRESS => (
2006 base_cost.saturating_add(budget.alt_bn128_g1_compress),
2007 G1_COMPRESSED,
2008 ),
2009 ALT_BN128_G1_DECOMPRESS => {
2010 (base_cost.saturating_add(budget.alt_bn128_g1_decompress), G1)
2011 }
2012 ALT_BN128_G2_COMPRESS => (
2013 base_cost.saturating_add(budget.alt_bn128_g2_compress),
2014 G2_COMPRESSED,
2015 ),
2016 ALT_BN128_G2_DECOMPRESS => {
2017 (base_cost.saturating_add(budget.alt_bn128_g2_decompress), G2)
2018 }
2019 _ => {
2020 return Err(SyscallError::InvalidAttribute.into());
2021 }
2022 };
2023
2024 consume_compute_meter(invoke_context, cost)?;
2025
2026 let input = translate_slice::<u8>(
2027 memory_mapping,
2028 input_addr,
2029 input_size,
2030 invoke_context.get_check_aligned(),
2031 )?;
2032
2033 let call_result = translate_slice_mut::<u8>(
2034 memory_mapping,
2035 result_addr,
2036 output as u64,
2037 invoke_context.get_check_aligned(),
2038 )?;
2039
2040 let simplify_alt_bn128_syscall_error_codes = invoke_context
2041 .get_feature_set()
2042 .is_active(&feature_set::simplify_alt_bn128_syscall_error_codes::id());
2043
2044 match op {
2045 ALT_BN128_G1_COMPRESS => {
2046 let result_point = match alt_bn128_g1_compress(input) {
2047 Ok(result_point) => result_point,
2048 Err(e) => {
2049 return if simplify_alt_bn128_syscall_error_codes {
2050 Ok(1)
2051 } else {
2052 Ok(e.into())
2053 };
2054 }
2055 };
2056 call_result.copy_from_slice(&result_point);
2057 Ok(SUCCESS)
2058 }
2059 ALT_BN128_G1_DECOMPRESS => {
2060 let result_point = match alt_bn128_g1_decompress(input) {
2061 Ok(result_point) => result_point,
2062 Err(e) => {
2063 return if simplify_alt_bn128_syscall_error_codes {
2064 Ok(1)
2065 } else {
2066 Ok(e.into())
2067 };
2068 }
2069 };
2070 call_result.copy_from_slice(&result_point);
2071 Ok(SUCCESS)
2072 }
2073 ALT_BN128_G2_COMPRESS => {
2074 let result_point = match alt_bn128_g2_compress(input) {
2075 Ok(result_point) => result_point,
2076 Err(e) => {
2077 return if simplify_alt_bn128_syscall_error_codes {
2078 Ok(1)
2079 } else {
2080 Ok(e.into())
2081 };
2082 }
2083 };
2084 call_result.copy_from_slice(&result_point);
2085 Ok(SUCCESS)
2086 }
2087 ALT_BN128_G2_DECOMPRESS => {
2088 let result_point = match alt_bn128_g2_decompress(input) {
2089 Ok(result_point) => result_point,
2090 Err(e) => {
2091 return if simplify_alt_bn128_syscall_error_codes {
2092 Ok(1)
2093 } else {
2094 Ok(e.into())
2095 };
2096 }
2097 };
2098 call_result.copy_from_slice(&result_point);
2099 Ok(SUCCESS)
2100 }
2101 _ => Err(SyscallError::InvalidAttribute.into()),
2102 }
2103 }
2104);
2105
2106declare_builtin_function!(
2107 SyscallHash<H: HasherImpl>,
2109 fn rust(
2110 invoke_context: &mut InvokeContext,
2111 vals_addr: u64,
2112 vals_len: u64,
2113 result_addr: u64,
2114 _arg4: u64,
2115 _arg5: u64,
2116 memory_mapping: &mut MemoryMapping,
2117 ) -> Result<u64, Error> {
2118 let compute_budget = invoke_context.get_compute_budget();
2119 let hash_base_cost = H::get_base_cost(compute_budget);
2120 let hash_byte_cost = H::get_byte_cost(compute_budget);
2121 let hash_max_slices = H::get_max_slices(compute_budget);
2122 if hash_max_slices < vals_len {
2123 ic_msg!(
2124 invoke_context,
2125 "{} Hashing {} sequences in one syscall is over the limit {}",
2126 H::NAME,
2127 vals_len,
2128 hash_max_slices,
2129 );
2130 return Err(SyscallError::TooManySlices.into());
2131 }
2132
2133 consume_compute_meter(invoke_context, hash_base_cost)?;
2134
2135 let hash_result = translate_slice_mut::<u8>(
2136 memory_mapping,
2137 result_addr,
2138 std::mem::size_of::<H::Output>() as u64,
2139 invoke_context.get_check_aligned(),
2140 )?;
2141 let mut hasher = H::create_hasher();
2142 if vals_len > 0 {
2143 let vals = translate_slice_of_slices::<u8>(
2144 memory_mapping,
2145 vals_addr,
2146 vals_len,
2147 invoke_context.get_check_aligned(),
2148 )?;
2149
2150 for val in vals.iter() {
2151 let bytes = val.translate(memory_mapping, invoke_context.get_check_aligned())?;
2152 let cost = compute_budget.mem_op_base_cost.max(
2153 hash_byte_cost.saturating_mul(
2154 val.len()
2155 .checked_div(2)
2156 .expect("div by non-zero literal"),
2157 ),
2158 );
2159 consume_compute_meter(invoke_context, cost)?;
2160 hasher.hash(bytes);
2161 }
2162 }
2163 hash_result.copy_from_slice(hasher.result().as_ref());
2164 Ok(0)
2165 }
2166);
2167
2168declare_builtin_function!(
2169 SyscallGetEpochStake,
2171 fn rust(
2172 invoke_context: &mut InvokeContext,
2173 var_addr: u64,
2174 _arg2: u64,
2175 _arg3: u64,
2176 _arg4: u64,
2177 _arg5: u64,
2178 memory_mapping: &mut MemoryMapping,
2179 ) -> Result<u64, Error> {
2180 let compute_budget = invoke_context.get_compute_budget();
2181
2182 if var_addr == 0 {
2183 let compute_units = compute_budget.syscall_base_cost;
2191 consume_compute_meter(invoke_context, compute_units)?;
2192 Ok(invoke_context.get_epoch_total_stake())
2200 } else {
2201 let compute_units = compute_budget
2209 .syscall_base_cost
2210 .saturating_add(
2211 (PUBKEY_BYTES as u64)
2212 .checked_div(compute_budget.cpi_bytes_per_unit)
2213 .unwrap_or(u64::MAX),
2214 )
2215 .saturating_add(compute_budget.mem_op_base_cost);
2216 consume_compute_meter(invoke_context, compute_units)?;
2217 let check_aligned = invoke_context.get_check_aligned();
2229 let vote_address = translate_type::<Pubkey>(memory_mapping, var_addr, check_aligned)?;
2230
2231 Ok(invoke_context.get_epoch_vote_account_stake(vote_address))
2232 }
2233 }
2234);
2235
2236#[cfg(test)]
2237#[allow(clippy::arithmetic_side_effects)]
2238#[allow(clippy::indexing_slicing)]
2239mod tests {
2240 #[allow(deprecated)]
2241 use solana_sysvar::fees::Fees;
2242 use {
2243 super::*,
2244 crate::mock_create_vm,
2245 assert_matches::assert_matches,
2246 core::slice,
2247 solana_account::{create_account_shared_data_for_test, AccountSharedData},
2248 solana_clock::Clock,
2249 solana_epoch_rewards::EpochRewards,
2250 solana_epoch_schedule::EpochSchedule,
2251 solana_fee_calculator::FeeCalculator,
2252 solana_hash::HASH_BYTES,
2253 solana_instruction::Instruction,
2254 solana_last_restart_slot::LastRestartSlot,
2255 solana_program::program::check_type_assumptions,
2256 solana_program_runtime::{invoke_context::InvokeContext, with_mock_invoke_context},
2257 solana_sbpf::{
2258 error::EbpfError, memory_region::MemoryRegion, program::SBPFVersion, vm::Config,
2259 },
2260 solana_sdk_ids::{bpf_loader, bpf_loader_upgradeable, sysvar},
2261 solana_sha256_hasher::hashv,
2262 solana_slot_hashes::{self as slot_hashes, SlotHashes},
2263 solana_stable_layout::stable_instruction::StableInstruction,
2264 solana_sysvar::stake_history::{self, StakeHistory, StakeHistoryEntry},
2265 std::{mem, str::FromStr},
2266 test_case::test_case,
2267 };
2268
2269 macro_rules! assert_access_violation {
2270 ($result:expr, $va:expr, $len:expr) => {
2271 match $result.unwrap_err().downcast_ref::<EbpfError>().unwrap() {
2272 EbpfError::AccessViolation(_, va, len, _) if $va == *va && $len == *len => {}
2273 EbpfError::StackAccessViolation(_, va, len, _) if $va == *va && $len == *len => {}
2274 _ => panic!(),
2275 }
2276 };
2277 }
2278
2279 macro_rules! prepare_mockup {
2280 ($invoke_context:ident,
2281 $program_key:ident,
2282 $loader_key:expr $(,)?) => {
2283 let $program_key = Pubkey::new_unique();
2284 let transaction_accounts = vec![
2285 (
2286 $loader_key,
2287 AccountSharedData::new(0, 0, &native_loader::id()),
2288 ),
2289 ($program_key, AccountSharedData::new(0, 0, &$loader_key)),
2290 ];
2291 with_mock_invoke_context!($invoke_context, transaction_context, transaction_accounts);
2292 $invoke_context
2293 .transaction_context
2294 .get_next_instruction_context()
2295 .unwrap()
2296 .configure(&[0, 1], &[], &[]);
2297 $invoke_context.push().unwrap();
2298 };
2299 }
2300
2301 #[allow(dead_code)]
2302 struct MockSlice {
2303 vm_addr: u64,
2304 len: usize,
2305 }
2306
2307 #[test]
2308 fn test_translate() {
2309 const START: u64 = 0x100000000;
2310 const LENGTH: u64 = 1000;
2311
2312 let data = vec![0u8; LENGTH as usize];
2313 let addr = data.as_ptr() as u64;
2314 let config = Config::default();
2315 let memory_mapping = MemoryMapping::new(
2316 vec![MemoryRegion::new_readonly(&data, START)],
2317 &config,
2318 SBPFVersion::V3,
2319 )
2320 .unwrap();
2321
2322 let cases = vec![
2323 (true, START, 0, addr),
2324 (true, START, 1, addr),
2325 (true, START, LENGTH, addr),
2326 (true, START + 1, LENGTH - 1, addr + 1),
2327 (false, START + 1, LENGTH, 0),
2328 (true, START + LENGTH - 1, 1, addr + LENGTH - 1),
2329 (true, START + LENGTH, 0, addr + LENGTH),
2330 (false, START + LENGTH, 1, 0),
2331 (false, START, LENGTH + 1, 0),
2332 (false, 0, 0, 0),
2333 (false, 0, 1, 0),
2334 (false, START - 1, 0, 0),
2335 (false, START - 1, 1, 0),
2336 (true, START + LENGTH / 2, LENGTH / 2, addr + LENGTH / 2),
2337 ];
2338 for (ok, start, length, value) in cases {
2339 if ok {
2340 assert_eq!(
2341 translate(&memory_mapping, AccessType::Load, start, length).unwrap(),
2342 value
2343 )
2344 } else {
2345 assert!(translate(&memory_mapping, AccessType::Load, start, length).is_err())
2346 }
2347 }
2348 }
2349
2350 #[test]
2351 fn test_translate_type() {
2352 let config = Config::default();
2353
2354 let pubkey = solana_pubkey::new_rand();
2356 let memory_mapping = MemoryMapping::new(
2357 vec![MemoryRegion::new_readonly(bytes_of(&pubkey), 0x100000000)],
2358 &config,
2359 SBPFVersion::V3,
2360 )
2361 .unwrap();
2362 let translated_pubkey =
2363 translate_type::<Pubkey>(&memory_mapping, 0x100000000, true).unwrap();
2364 assert_eq!(pubkey, *translated_pubkey);
2365
2366 let instruction = Instruction::new_with_bincode(
2368 solana_pubkey::new_rand(),
2369 &"foobar",
2370 vec![AccountMeta::new(solana_pubkey::new_rand(), false)],
2371 );
2372 let instruction = StableInstruction::from(instruction);
2373 let memory_region = MemoryRegion::new_readonly(bytes_of(&instruction), 0x100000000);
2374 let memory_mapping =
2375 MemoryMapping::new(vec![memory_region], &config, SBPFVersion::V3).unwrap();
2376 let translated_instruction =
2377 translate_type::<StableInstruction>(&memory_mapping, 0x100000000, true).unwrap();
2378 assert_eq!(instruction, *translated_instruction);
2379
2380 let memory_region = MemoryRegion::new_readonly(&bytes_of(&instruction)[..1], 0x100000000);
2381 let memory_mapping =
2382 MemoryMapping::new(vec![memory_region], &config, SBPFVersion::V3).unwrap();
2383 assert!(translate_type::<Instruction>(&memory_mapping, 0x100000000, true).is_err());
2384 }
2385
2386 #[test]
2387 fn test_translate_slice() {
2388 let config = Config::default();
2389
2390 let good_data = vec![1u8, 2, 3, 4, 5];
2392 let data: Vec<u8> = vec![];
2393 assert_eq!(0x1 as *const u8, data.as_ptr());
2394 let memory_mapping = MemoryMapping::new(
2395 vec![MemoryRegion::new_readonly(&good_data, 0x100000000)],
2396 &config,
2397 SBPFVersion::V3,
2398 )
2399 .unwrap();
2400 let translated_data =
2401 translate_slice::<u8>(&memory_mapping, data.as_ptr() as u64, 0, true).unwrap();
2402 assert_eq!(data, translated_data);
2403 assert_eq!(0, translated_data.len());
2404
2405 let mut data = vec![1u8, 2, 3, 4, 5];
2407 let memory_mapping = MemoryMapping::new(
2408 vec![MemoryRegion::new_readonly(&data, 0x100000000)],
2409 &config,
2410 SBPFVersion::V3,
2411 )
2412 .unwrap();
2413 let translated_data =
2414 translate_slice::<u8>(&memory_mapping, 0x100000000, data.len() as u64, true).unwrap();
2415 assert_eq!(data, translated_data);
2416 *data.first_mut().unwrap() = 10;
2417 assert_eq!(data, translated_data);
2418 assert!(
2419 translate_slice::<u8>(&memory_mapping, data.as_ptr() as u64, u64::MAX, true).is_err()
2420 );
2421
2422 assert!(
2423 translate_slice::<u8>(&memory_mapping, 0x100000000 - 1, data.len() as u64, true,)
2424 .is_err()
2425 );
2426
2427 let mut data = vec![1u64, 2, 3, 4, 5];
2429 let memory_mapping = MemoryMapping::new(
2430 vec![MemoryRegion::new_readonly(
2431 bytes_of_slice(&data),
2432 0x100000000,
2433 )],
2434 &config,
2435 SBPFVersion::V3,
2436 )
2437 .unwrap();
2438 let translated_data =
2439 translate_slice::<u64>(&memory_mapping, 0x100000000, data.len() as u64, true).unwrap();
2440 assert_eq!(data, translated_data);
2441 *data.first_mut().unwrap() = 10;
2442 assert_eq!(data, translated_data);
2443 assert!(translate_slice::<u64>(&memory_mapping, 0x100000000, u64::MAX, true).is_err());
2444
2445 let mut data = vec![solana_pubkey::new_rand(); 5];
2447 let memory_mapping = MemoryMapping::new(
2448 vec![MemoryRegion::new_readonly(
2449 unsafe {
2450 slice::from_raw_parts(data.as_ptr() as *const u8, mem::size_of::<Pubkey>() * 5)
2451 },
2452 0x100000000,
2453 )],
2454 &config,
2455 SBPFVersion::V3,
2456 )
2457 .unwrap();
2458 let translated_data =
2459 translate_slice::<Pubkey>(&memory_mapping, 0x100000000, data.len() as u64, true)
2460 .unwrap();
2461 assert_eq!(data, translated_data);
2462 *data.first_mut().unwrap() = solana_pubkey::new_rand(); assert_eq!(data, translated_data);
2464 }
2465
2466 #[test]
2467 fn test_translate_string_and_do() {
2468 let string = "Gaggablaghblagh!";
2469 let config = Config::default();
2470 let memory_mapping = MemoryMapping::new(
2471 vec![MemoryRegion::new_readonly(string.as_bytes(), 0x100000000)],
2472 &config,
2473 SBPFVersion::V3,
2474 )
2475 .unwrap();
2476 assert_eq!(
2477 42,
2478 translate_string_and_do(
2479 &memory_mapping,
2480 0x100000000,
2481 string.len() as u64,
2482 true,
2483 &mut |string: &str| {
2484 assert_eq!(string, "Gaggablaghblagh!");
2485 Ok(42)
2486 }
2487 )
2488 .unwrap()
2489 );
2490 }
2491
2492 #[test]
2493 #[should_panic(expected = "Abort")]
2494 fn test_syscall_abort() {
2495 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2496 let config = Config::default();
2497 let mut memory_mapping = MemoryMapping::new(vec![], &config, SBPFVersion::V3).unwrap();
2498 let result = SyscallAbort::rust(&mut invoke_context, 0, 0, 0, 0, 0, &mut memory_mapping);
2499 result.unwrap();
2500 }
2501
2502 #[test]
2503 #[should_panic(expected = "Panic(\"Gaggablaghblagh!\", 42, 84)")]
2504 fn test_syscall_sol_panic() {
2505 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2506
2507 let string = "Gaggablaghblagh!";
2508 let config = Config::default();
2509 let mut memory_mapping = MemoryMapping::new(
2510 vec![MemoryRegion::new_readonly(string.as_bytes(), 0x100000000)],
2511 &config,
2512 SBPFVersion::V3,
2513 )
2514 .unwrap();
2515
2516 invoke_context.mock_set_remaining(string.len() as u64 - 1);
2517 let result = SyscallPanic::rust(
2518 &mut invoke_context,
2519 0x100000000,
2520 string.len() as u64,
2521 42,
2522 84,
2523 0,
2524 &mut memory_mapping,
2525 );
2526 assert_matches!(
2527 result,
2528 Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
2529 );
2530
2531 invoke_context.mock_set_remaining(string.len() as u64);
2532 let result = SyscallPanic::rust(
2533 &mut invoke_context,
2534 0x100000000,
2535 string.len() as u64,
2536 42,
2537 84,
2538 0,
2539 &mut memory_mapping,
2540 );
2541 result.unwrap();
2542 }
2543
2544 #[test]
2545 fn test_syscall_sol_log() {
2546 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2547
2548 let string = "Gaggablaghblagh!";
2549 let config = Config::default();
2550 let mut memory_mapping = MemoryMapping::new(
2551 vec![MemoryRegion::new_readonly(string.as_bytes(), 0x100000000)],
2552 &config,
2553 SBPFVersion::V3,
2554 )
2555 .unwrap();
2556
2557 invoke_context.mock_set_remaining(400 - 1);
2558 let result = SyscallLog::rust(
2559 &mut invoke_context,
2560 0x100000001, string.len() as u64,
2562 0,
2563 0,
2564 0,
2565 &mut memory_mapping,
2566 );
2567 assert_access_violation!(result, 0x100000001, string.len() as u64);
2568 let result = SyscallLog::rust(
2569 &mut invoke_context,
2570 0x100000000,
2571 string.len() as u64 * 2, 0,
2573 0,
2574 0,
2575 &mut memory_mapping,
2576 );
2577 assert_access_violation!(result, 0x100000000, string.len() as u64 * 2);
2578
2579 let result = SyscallLog::rust(
2580 &mut invoke_context,
2581 0x100000000,
2582 string.len() as u64,
2583 0,
2584 0,
2585 0,
2586 &mut memory_mapping,
2587 );
2588 result.unwrap();
2589 let result = SyscallLog::rust(
2590 &mut invoke_context,
2591 0x100000000,
2592 string.len() as u64,
2593 0,
2594 0,
2595 0,
2596 &mut memory_mapping,
2597 );
2598 assert_matches!(
2599 result,
2600 Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
2601 );
2602
2603 assert_eq!(
2604 invoke_context
2605 .get_log_collector()
2606 .unwrap()
2607 .borrow()
2608 .get_recorded_content(),
2609 &["Program log: Gaggablaghblagh!".to_string()]
2610 );
2611 }
2612
2613 #[test]
2614 fn test_syscall_sol_log_u64() {
2615 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2616 let cost = invoke_context.get_compute_budget().log_64_units;
2617
2618 invoke_context.mock_set_remaining(cost);
2619 let config = Config::default();
2620 let mut memory_mapping = MemoryMapping::new(vec![], &config, SBPFVersion::V3).unwrap();
2621 let result = SyscallLogU64::rust(&mut invoke_context, 1, 2, 3, 4, 5, &mut memory_mapping);
2622 result.unwrap();
2623
2624 assert_eq!(
2625 invoke_context
2626 .get_log_collector()
2627 .unwrap()
2628 .borrow()
2629 .get_recorded_content(),
2630 &["Program log: 0x1, 0x2, 0x3, 0x4, 0x5".to_string()]
2631 );
2632 }
2633
2634 #[test]
2635 fn test_syscall_sol_pubkey() {
2636 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2637 let cost = invoke_context.get_compute_budget().log_pubkey_units;
2638
2639 let pubkey = Pubkey::from_str("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN").unwrap();
2640 let config = Config::default();
2641 let mut memory_mapping = MemoryMapping::new(
2642 vec![MemoryRegion::new_readonly(bytes_of(&pubkey), 0x100000000)],
2643 &config,
2644 SBPFVersion::V3,
2645 )
2646 .unwrap();
2647
2648 let result = SyscallLogPubkey::rust(
2649 &mut invoke_context,
2650 0x100000001, 32,
2652 0,
2653 0,
2654 0,
2655 &mut memory_mapping,
2656 );
2657 assert_access_violation!(result, 0x100000001, 32);
2658
2659 invoke_context.mock_set_remaining(1);
2660 let result =
2661 SyscallLogPubkey::rust(&mut invoke_context, 100, 32, 0, 0, 0, &mut memory_mapping);
2662 assert_matches!(
2663 result,
2664 Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
2665 );
2666
2667 invoke_context.mock_set_remaining(cost);
2668 let result = SyscallLogPubkey::rust(
2669 &mut invoke_context,
2670 0x100000000,
2671 0,
2672 0,
2673 0,
2674 0,
2675 &mut memory_mapping,
2676 );
2677 result.unwrap();
2678
2679 assert_eq!(
2680 invoke_context
2681 .get_log_collector()
2682 .unwrap()
2683 .borrow()
2684 .get_recorded_content(),
2685 &["Program log: MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN".to_string()]
2686 );
2687 }
2688
2689 #[test]
2690 fn test_syscall_sol_alloc_free() {
2691 {
2693 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2694 mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context);
2695 let mut vm = vm.unwrap();
2696 let invoke_context = &mut vm.context_object_pointer;
2697 let memory_mapping = &mut vm.memory_mapping;
2698 let result = SyscallAllocFree::rust(
2699 invoke_context,
2700 solana_program_entrypoint::HEAP_LENGTH as u64,
2701 0,
2702 0,
2703 0,
2704 0,
2705 memory_mapping,
2706 );
2707 assert_ne!(result.unwrap(), 0);
2708 let result = SyscallAllocFree::rust(
2709 invoke_context,
2710 solana_program_entrypoint::HEAP_LENGTH as u64,
2711 0,
2712 0,
2713 0,
2714 0,
2715 memory_mapping,
2716 );
2717 assert_eq!(result.unwrap(), 0);
2718 let result =
2719 SyscallAllocFree::rust(invoke_context, u64::MAX, 0, 0, 0, 0, memory_mapping);
2720 assert_eq!(result.unwrap(), 0);
2721 }
2722
2723 {
2725 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2726 invoke_context.mock_set_feature_set(Arc::new(FeatureSet::default()));
2727 mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context);
2728 let mut vm = vm.unwrap();
2729 let invoke_context = &mut vm.context_object_pointer;
2730 let memory_mapping = &mut vm.memory_mapping;
2731 for _ in 0..100 {
2732 let result = SyscallAllocFree::rust(invoke_context, 1, 0, 0, 0, 0, memory_mapping);
2733 assert_ne!(result.unwrap(), 0);
2734 }
2735 let result = SyscallAllocFree::rust(
2736 invoke_context,
2737 solana_program_entrypoint::HEAP_LENGTH as u64,
2738 0,
2739 0,
2740 0,
2741 0,
2742 memory_mapping,
2743 );
2744 assert_eq!(result.unwrap(), 0);
2745 }
2746
2747 {
2749 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2750 mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context);
2751 let mut vm = vm.unwrap();
2752 let invoke_context = &mut vm.context_object_pointer;
2753 let memory_mapping = &mut vm.memory_mapping;
2754 for _ in 0..12 {
2755 let result = SyscallAllocFree::rust(invoke_context, 1, 0, 0, 0, 0, memory_mapping);
2756 assert_ne!(result.unwrap(), 0);
2757 }
2758 let result = SyscallAllocFree::rust(
2759 invoke_context,
2760 solana_program_entrypoint::HEAP_LENGTH as u64,
2761 0,
2762 0,
2763 0,
2764 0,
2765 memory_mapping,
2766 );
2767 assert_eq!(result.unwrap(), 0);
2768 }
2769
2770 fn aligned<T>() {
2773 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2774 mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context);
2775 let mut vm = vm.unwrap();
2776 let invoke_context = &mut vm.context_object_pointer;
2777 let memory_mapping = &mut vm.memory_mapping;
2778 let result = SyscallAllocFree::rust(
2779 invoke_context,
2780 size_of::<T>() as u64,
2781 0,
2782 0,
2783 0,
2784 0,
2785 memory_mapping,
2786 );
2787 let address = result.unwrap();
2788 assert_ne!(address, 0);
2789 assert!(address_is_aligned::<T>(address));
2790 }
2791 aligned::<u8>();
2792 aligned::<u16>();
2793 aligned::<u32>();
2794 aligned::<u64>();
2795 aligned::<u128>();
2796 }
2797
2798 #[test]
2799 fn test_syscall_sha256() {
2800 let config = Config::default();
2801 prepare_mockup!(invoke_context, program_id, bpf_loader_deprecated::id());
2802
2803 let bytes1 = "Gaggablaghblagh!";
2804 let bytes2 = "flurbos";
2805
2806 let mock_slice1 = MockSlice {
2807 vm_addr: 0x300000000,
2808 len: bytes1.len(),
2809 };
2810 let mock_slice2 = MockSlice {
2811 vm_addr: 0x400000000,
2812 len: bytes2.len(),
2813 };
2814 let bytes_to_hash = [mock_slice1, mock_slice2];
2815 let mut hash_result = [0; HASH_BYTES];
2816 let ro_len = bytes_to_hash.len() as u64;
2817 let ro_va = 0x100000000;
2818 let rw_va = 0x200000000;
2819 let mut memory_mapping = MemoryMapping::new(
2820 vec![
2821 MemoryRegion::new_readonly(bytes_of_slice(&bytes_to_hash), ro_va),
2822 MemoryRegion::new_writable(bytes_of_slice_mut(&mut hash_result), rw_va),
2823 MemoryRegion::new_readonly(bytes1.as_bytes(), bytes_to_hash[0].vm_addr),
2824 MemoryRegion::new_readonly(bytes2.as_bytes(), bytes_to_hash[1].vm_addr),
2825 ],
2826 &config,
2827 SBPFVersion::V3,
2828 )
2829 .unwrap();
2830
2831 invoke_context.mock_set_remaining(
2832 (invoke_context.get_compute_budget().sha256_base_cost
2833 + invoke_context.get_compute_budget().mem_op_base_cost.max(
2834 invoke_context
2835 .get_compute_budget()
2836 .sha256_byte_cost
2837 .saturating_mul((bytes1.len() + bytes2.len()) as u64 / 2),
2838 ))
2839 * 4,
2840 );
2841
2842 let result = SyscallHash::rust::<Sha256Hasher>(
2843 &mut invoke_context,
2844 ro_va,
2845 ro_len,
2846 rw_va,
2847 0,
2848 0,
2849 &mut memory_mapping,
2850 );
2851 result.unwrap();
2852
2853 let hash_local = hashv(&[bytes1.as_ref(), bytes2.as_ref()]).to_bytes();
2854 assert_eq!(hash_result, hash_local);
2855 let result = SyscallHash::rust::<Sha256Hasher>(
2856 &mut invoke_context,
2857 ro_va - 1, ro_len,
2859 rw_va,
2860 0,
2861 0,
2862 &mut memory_mapping,
2863 );
2864 assert_access_violation!(result, ro_va - 1, 32);
2865 let result = SyscallHash::rust::<Sha256Hasher>(
2866 &mut invoke_context,
2867 ro_va,
2868 ro_len + 1, rw_va,
2870 0,
2871 0,
2872 &mut memory_mapping,
2873 );
2874 assert_access_violation!(result, ro_va, 48);
2875 let result = SyscallHash::rust::<Sha256Hasher>(
2876 &mut invoke_context,
2877 ro_va,
2878 ro_len,
2879 rw_va - 1, 0,
2881 0,
2882 &mut memory_mapping,
2883 );
2884 assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64);
2885 let result = SyscallHash::rust::<Sha256Hasher>(
2886 &mut invoke_context,
2887 ro_va,
2888 ro_len,
2889 rw_va,
2890 0,
2891 0,
2892 &mut memory_mapping,
2893 );
2894 assert_matches!(
2895 result,
2896 Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
2897 );
2898 }
2899
2900 #[test]
2901 fn test_syscall_edwards_curve_point_validation() {
2902 use solana_curve25519::curve_syscall_traits::CURVE25519_EDWARDS;
2903
2904 let config = Config::default();
2905 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2906
2907 let valid_bytes: [u8; 32] = [
2908 201, 179, 241, 122, 180, 185, 239, 50, 183, 52, 221, 0, 153, 195, 43, 18, 22, 38, 187,
2909 206, 179, 192, 210, 58, 53, 45, 150, 98, 89, 17, 158, 11,
2910 ];
2911 let valid_bytes_va = 0x100000000;
2912
2913 let invalid_bytes: [u8; 32] = [
2914 120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84,
2915 60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79,
2916 ];
2917 let invalid_bytes_va = 0x200000000;
2918
2919 let mut memory_mapping = MemoryMapping::new(
2920 vec![
2921 MemoryRegion::new_readonly(&valid_bytes, valid_bytes_va),
2922 MemoryRegion::new_readonly(&invalid_bytes, invalid_bytes_va),
2923 ],
2924 &config,
2925 SBPFVersion::V3,
2926 )
2927 .unwrap();
2928
2929 invoke_context.mock_set_remaining(
2930 (invoke_context
2931 .get_compute_budget()
2932 .curve25519_edwards_validate_point_cost)
2933 * 2,
2934 );
2935
2936 let result = SyscallCurvePointValidation::rust(
2937 &mut invoke_context,
2938 CURVE25519_EDWARDS,
2939 valid_bytes_va,
2940 0,
2941 0,
2942 0,
2943 &mut memory_mapping,
2944 );
2945 assert_eq!(0, result.unwrap());
2946
2947 let result = SyscallCurvePointValidation::rust(
2948 &mut invoke_context,
2949 CURVE25519_EDWARDS,
2950 invalid_bytes_va,
2951 0,
2952 0,
2953 0,
2954 &mut memory_mapping,
2955 );
2956 assert_eq!(1, result.unwrap());
2957
2958 let result = SyscallCurvePointValidation::rust(
2959 &mut invoke_context,
2960 CURVE25519_EDWARDS,
2961 valid_bytes_va,
2962 0,
2963 0,
2964 0,
2965 &mut memory_mapping,
2966 );
2967 assert_matches!(
2968 result,
2969 Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
2970 );
2971 }
2972
2973 #[test]
2974 fn test_syscall_ristretto_curve_point_validation() {
2975 use solana_curve25519::curve_syscall_traits::CURVE25519_RISTRETTO;
2976
2977 let config = Config::default();
2978 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2979
2980 let valid_bytes: [u8; 32] = [
2981 226, 242, 174, 10, 106, 188, 78, 113, 168, 132, 169, 97, 197, 0, 81, 95, 88, 227, 11,
2982 106, 165, 130, 221, 141, 182, 166, 89, 69, 224, 141, 45, 118,
2983 ];
2984 let valid_bytes_va = 0x100000000;
2985
2986 let invalid_bytes: [u8; 32] = [
2987 120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84,
2988 60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79,
2989 ];
2990 let invalid_bytes_va = 0x200000000;
2991
2992 let mut memory_mapping = MemoryMapping::new(
2993 vec![
2994 MemoryRegion::new_readonly(&valid_bytes, valid_bytes_va),
2995 MemoryRegion::new_readonly(&invalid_bytes, invalid_bytes_va),
2996 ],
2997 &config,
2998 SBPFVersion::V3,
2999 )
3000 .unwrap();
3001
3002 invoke_context.mock_set_remaining(
3003 (invoke_context
3004 .get_compute_budget()
3005 .curve25519_ristretto_validate_point_cost)
3006 * 2,
3007 );
3008
3009 let result = SyscallCurvePointValidation::rust(
3010 &mut invoke_context,
3011 CURVE25519_RISTRETTO,
3012 valid_bytes_va,
3013 0,
3014 0,
3015 0,
3016 &mut memory_mapping,
3017 );
3018 assert_eq!(0, result.unwrap());
3019
3020 let result = SyscallCurvePointValidation::rust(
3021 &mut invoke_context,
3022 CURVE25519_RISTRETTO,
3023 invalid_bytes_va,
3024 0,
3025 0,
3026 0,
3027 &mut memory_mapping,
3028 );
3029 assert_eq!(1, result.unwrap());
3030
3031 let result = SyscallCurvePointValidation::rust(
3032 &mut invoke_context,
3033 CURVE25519_RISTRETTO,
3034 valid_bytes_va,
3035 0,
3036 0,
3037 0,
3038 &mut memory_mapping,
3039 );
3040 assert_matches!(
3041 result,
3042 Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3043 );
3044 }
3045
3046 #[test]
3047 fn test_syscall_edwards_curve_group_ops() {
3048 use solana_curve25519::curve_syscall_traits::{ADD, CURVE25519_EDWARDS, MUL, SUB};
3049
3050 let config = Config::default();
3051 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3052
3053 let left_point: [u8; 32] = [
3054 33, 124, 71, 170, 117, 69, 151, 247, 59, 12, 95, 125, 133, 166, 64, 5, 2, 27, 90, 27,
3055 200, 167, 59, 164, 52, 54, 52, 200, 29, 13, 34, 213,
3056 ];
3057 let left_point_va = 0x100000000;
3058 let right_point: [u8; 32] = [
3059 70, 222, 137, 221, 253, 204, 71, 51, 78, 8, 124, 1, 67, 200, 102, 225, 122, 228, 111,
3060 183, 129, 14, 131, 210, 212, 95, 109, 246, 55, 10, 159, 91,
3061 ];
3062 let right_point_va = 0x200000000;
3063 let scalar: [u8; 32] = [
3064 254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
3065 78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
3066 ];
3067 let scalar_va = 0x300000000;
3068 let invalid_point: [u8; 32] = [
3069 120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84,
3070 60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79,
3071 ];
3072 let invalid_point_va = 0x400000000;
3073 let mut result_point: [u8; 32] = [0; 32];
3074 let result_point_va = 0x500000000;
3075
3076 let mut memory_mapping = MemoryMapping::new(
3077 vec![
3078 MemoryRegion::new_readonly(bytes_of_slice(&left_point), left_point_va),
3079 MemoryRegion::new_readonly(bytes_of_slice(&right_point), right_point_va),
3080 MemoryRegion::new_readonly(bytes_of_slice(&scalar), scalar_va),
3081 MemoryRegion::new_readonly(bytes_of_slice(&invalid_point), invalid_point_va),
3082 MemoryRegion::new_writable(bytes_of_slice_mut(&mut result_point), result_point_va),
3083 ],
3084 &config,
3085 SBPFVersion::V3,
3086 )
3087 .unwrap();
3088
3089 invoke_context.mock_set_remaining(
3090 (invoke_context
3091 .get_compute_budget()
3092 .curve25519_edwards_add_cost
3093 + invoke_context
3094 .get_compute_budget()
3095 .curve25519_edwards_subtract_cost
3096 + invoke_context
3097 .get_compute_budget()
3098 .curve25519_edwards_multiply_cost)
3099 * 2,
3100 );
3101
3102 let result = SyscallCurveGroupOps::rust(
3103 &mut invoke_context,
3104 CURVE25519_EDWARDS,
3105 ADD,
3106 left_point_va,
3107 right_point_va,
3108 result_point_va,
3109 &mut memory_mapping,
3110 );
3111
3112 assert_eq!(0, result.unwrap());
3113 let expected_sum = [
3114 7, 251, 187, 86, 186, 232, 57, 242, 193, 236, 49, 200, 90, 29, 254, 82, 46, 80, 83, 70,
3115 244, 153, 23, 156, 2, 138, 207, 51, 165, 38, 200, 85,
3116 ];
3117 assert_eq!(expected_sum, result_point);
3118
3119 let result = SyscallCurveGroupOps::rust(
3120 &mut invoke_context,
3121 CURVE25519_EDWARDS,
3122 ADD,
3123 invalid_point_va,
3124 right_point_va,
3125 result_point_va,
3126 &mut memory_mapping,
3127 );
3128 assert_eq!(1, result.unwrap());
3129
3130 let result = SyscallCurveGroupOps::rust(
3131 &mut invoke_context,
3132 CURVE25519_EDWARDS,
3133 SUB,
3134 left_point_va,
3135 right_point_va,
3136 result_point_va,
3137 &mut memory_mapping,
3138 );
3139
3140 assert_eq!(0, result.unwrap());
3141 let expected_difference = [
3142 60, 87, 90, 68, 232, 25, 7, 172, 247, 120, 158, 104, 52, 127, 94, 244, 5, 79, 253, 15,
3143 48, 69, 82, 134, 155, 70, 188, 81, 108, 95, 212, 9,
3144 ];
3145 assert_eq!(expected_difference, result_point);
3146
3147 let result = SyscallCurveGroupOps::rust(
3148 &mut invoke_context,
3149 CURVE25519_EDWARDS,
3150 SUB,
3151 invalid_point_va,
3152 right_point_va,
3153 result_point_va,
3154 &mut memory_mapping,
3155 );
3156 assert_eq!(1, result.unwrap());
3157
3158 let result = SyscallCurveGroupOps::rust(
3159 &mut invoke_context,
3160 CURVE25519_EDWARDS,
3161 MUL,
3162 scalar_va,
3163 right_point_va,
3164 result_point_va,
3165 &mut memory_mapping,
3166 );
3167
3168 result.unwrap();
3169 let expected_product = [
3170 64, 150, 40, 55, 80, 49, 217, 209, 105, 229, 181, 65, 241, 68, 2, 106, 220, 234, 211,
3171 71, 159, 76, 156, 114, 242, 68, 147, 31, 243, 211, 191, 124,
3172 ];
3173 assert_eq!(expected_product, result_point);
3174
3175 let result = SyscallCurveGroupOps::rust(
3176 &mut invoke_context,
3177 CURVE25519_EDWARDS,
3178 MUL,
3179 scalar_va,
3180 invalid_point_va,
3181 result_point_va,
3182 &mut memory_mapping,
3183 );
3184 assert_eq!(1, result.unwrap());
3185
3186 let result = SyscallCurveGroupOps::rust(
3187 &mut invoke_context,
3188 CURVE25519_EDWARDS,
3189 MUL,
3190 scalar_va,
3191 invalid_point_va,
3192 result_point_va,
3193 &mut memory_mapping,
3194 );
3195 assert_matches!(
3196 result,
3197 Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3198 );
3199 }
3200
3201 #[test]
3202 fn test_syscall_ristretto_curve_group_ops() {
3203 use solana_curve25519::curve_syscall_traits::{ADD, CURVE25519_RISTRETTO, MUL, SUB};
3204
3205 let config = Config::default();
3206 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3207
3208 let left_point: [u8; 32] = [
3209 208, 165, 125, 204, 2, 100, 218, 17, 170, 194, 23, 9, 102, 156, 134, 136, 217, 190, 98,
3210 34, 183, 194, 228, 153, 92, 11, 108, 103, 28, 57, 88, 15,
3211 ];
3212 let left_point_va = 0x100000000;
3213 let right_point: [u8; 32] = [
3214 208, 241, 72, 163, 73, 53, 32, 174, 54, 194, 71, 8, 70, 181, 244, 199, 93, 147, 99,
3215 231, 162, 127, 25, 40, 39, 19, 140, 132, 112, 212, 145, 108,
3216 ];
3217 let right_point_va = 0x200000000;
3218 let scalar: [u8; 32] = [
3219 254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
3220 78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
3221 ];
3222 let scalar_va = 0x300000000;
3223 let invalid_point: [u8; 32] = [
3224 120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84,
3225 60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79,
3226 ];
3227 let invalid_point_va = 0x400000000;
3228 let mut result_point: [u8; 32] = [0; 32];
3229 let result_point_va = 0x500000000;
3230
3231 let mut memory_mapping = MemoryMapping::new(
3232 vec![
3233 MemoryRegion::new_readonly(bytes_of_slice(&left_point), left_point_va),
3234 MemoryRegion::new_readonly(bytes_of_slice(&right_point), right_point_va),
3235 MemoryRegion::new_readonly(bytes_of_slice(&scalar), scalar_va),
3236 MemoryRegion::new_readonly(bytes_of_slice(&invalid_point), invalid_point_va),
3237 MemoryRegion::new_writable(bytes_of_slice_mut(&mut result_point), result_point_va),
3238 ],
3239 &config,
3240 SBPFVersion::V3,
3241 )
3242 .unwrap();
3243
3244 invoke_context.mock_set_remaining(
3245 (invoke_context
3246 .get_compute_budget()
3247 .curve25519_ristretto_add_cost
3248 + invoke_context
3249 .get_compute_budget()
3250 .curve25519_ristretto_subtract_cost
3251 + invoke_context
3252 .get_compute_budget()
3253 .curve25519_ristretto_multiply_cost)
3254 * 2,
3255 );
3256
3257 let result = SyscallCurveGroupOps::rust(
3258 &mut invoke_context,
3259 CURVE25519_RISTRETTO,
3260 ADD,
3261 left_point_va,
3262 right_point_va,
3263 result_point_va,
3264 &mut memory_mapping,
3265 );
3266
3267 assert_eq!(0, result.unwrap());
3268 let expected_sum = [
3269 78, 173, 9, 241, 180, 224, 31, 107, 176, 210, 144, 240, 118, 73, 70, 191, 128, 119,
3270 141, 113, 125, 215, 161, 71, 49, 176, 87, 38, 180, 177, 39, 78,
3271 ];
3272 assert_eq!(expected_sum, result_point);
3273
3274 let result = SyscallCurveGroupOps::rust(
3275 &mut invoke_context,
3276 CURVE25519_RISTRETTO,
3277 ADD,
3278 invalid_point_va,
3279 right_point_va,
3280 result_point_va,
3281 &mut memory_mapping,
3282 );
3283 assert_eq!(1, result.unwrap());
3284
3285 let result = SyscallCurveGroupOps::rust(
3286 &mut invoke_context,
3287 CURVE25519_RISTRETTO,
3288 SUB,
3289 left_point_va,
3290 right_point_va,
3291 result_point_va,
3292 &mut memory_mapping,
3293 );
3294
3295 assert_eq!(0, result.unwrap());
3296 let expected_difference = [
3297 150, 72, 222, 61, 148, 79, 96, 130, 151, 176, 29, 217, 231, 211, 0, 215, 76, 86, 212,
3298 146, 110, 128, 24, 151, 187, 144, 108, 233, 221, 208, 157, 52,
3299 ];
3300 assert_eq!(expected_difference, result_point);
3301
3302 let result = SyscallCurveGroupOps::rust(
3303 &mut invoke_context,
3304 CURVE25519_RISTRETTO,
3305 SUB,
3306 invalid_point_va,
3307 right_point_va,
3308 result_point_va,
3309 &mut memory_mapping,
3310 );
3311
3312 assert_eq!(1, result.unwrap());
3313
3314 let result = SyscallCurveGroupOps::rust(
3315 &mut invoke_context,
3316 CURVE25519_RISTRETTO,
3317 MUL,
3318 scalar_va,
3319 right_point_va,
3320 result_point_va,
3321 &mut memory_mapping,
3322 );
3323
3324 result.unwrap();
3325 let expected_product = [
3326 4, 16, 46, 2, 53, 151, 201, 133, 117, 149, 232, 164, 119, 109, 136, 20, 153, 24, 124,
3327 21, 101, 124, 80, 19, 119, 100, 77, 108, 65, 187, 228, 5,
3328 ];
3329 assert_eq!(expected_product, result_point);
3330
3331 let result = SyscallCurveGroupOps::rust(
3332 &mut invoke_context,
3333 CURVE25519_RISTRETTO,
3334 MUL,
3335 scalar_va,
3336 invalid_point_va,
3337 result_point_va,
3338 &mut memory_mapping,
3339 );
3340
3341 assert_eq!(1, result.unwrap());
3342
3343 let result = SyscallCurveGroupOps::rust(
3344 &mut invoke_context,
3345 CURVE25519_RISTRETTO,
3346 MUL,
3347 scalar_va,
3348 invalid_point_va,
3349 result_point_va,
3350 &mut memory_mapping,
3351 );
3352 assert_matches!(
3353 result,
3354 Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3355 );
3356 }
3357
3358 #[test]
3359 fn test_syscall_multiscalar_multiplication() {
3360 use solana_curve25519::curve_syscall_traits::{CURVE25519_EDWARDS, CURVE25519_RISTRETTO};
3361
3362 let config = Config::default();
3363 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3364
3365 let scalar_a: [u8; 32] = [
3366 254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
3367 78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
3368 ];
3369 let scalar_b: [u8; 32] = [
3370 254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
3371 78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
3372 ];
3373
3374 let scalars = [scalar_a, scalar_b];
3375 let scalars_va = 0x100000000;
3376
3377 let edwards_point_x: [u8; 32] = [
3378 252, 31, 230, 46, 173, 95, 144, 148, 158, 157, 63, 10, 8, 68, 58, 176, 142, 192, 168,
3379 53, 61, 105, 194, 166, 43, 56, 246, 236, 28, 146, 114, 133,
3380 ];
3381 let edwards_point_y: [u8; 32] = [
3382 10, 111, 8, 236, 97, 189, 124, 69, 89, 176, 222, 39, 199, 253, 111, 11, 248, 186, 128,
3383 90, 120, 128, 248, 210, 232, 183, 93, 104, 111, 150, 7, 241,
3384 ];
3385 let edwards_points = [edwards_point_x, edwards_point_y];
3386 let edwards_points_va = 0x200000000;
3387
3388 let ristretto_point_x: [u8; 32] = [
3389 130, 35, 97, 25, 18, 199, 33, 239, 85, 143, 119, 111, 49, 51, 224, 40, 167, 185, 240,
3390 179, 25, 194, 213, 41, 14, 155, 104, 18, 181, 197, 15, 112,
3391 ];
3392 let ristretto_point_y: [u8; 32] = [
3393 152, 156, 155, 197, 152, 232, 92, 206, 219, 159, 193, 134, 121, 128, 139, 36, 56, 191,
3394 51, 143, 72, 204, 87, 76, 110, 124, 101, 96, 238, 158, 42, 108,
3395 ];
3396 let ristretto_points = [ristretto_point_x, ristretto_point_y];
3397 let ristretto_points_va = 0x300000000;
3398
3399 let mut result_point: [u8; 32] = [0; 32];
3400 let result_point_va = 0x400000000;
3401
3402 let mut memory_mapping = MemoryMapping::new(
3403 vec![
3404 MemoryRegion::new_readonly(bytes_of_slice(&scalars), scalars_va),
3405 MemoryRegion::new_readonly(bytes_of_slice(&edwards_points), edwards_points_va),
3406 MemoryRegion::new_readonly(bytes_of_slice(&ristretto_points), ristretto_points_va),
3407 MemoryRegion::new_writable(bytes_of_slice_mut(&mut result_point), result_point_va),
3408 ],
3409 &config,
3410 SBPFVersion::V3,
3411 )
3412 .unwrap();
3413
3414 invoke_context.mock_set_remaining(
3415 invoke_context
3416 .get_compute_budget()
3417 .curve25519_edwards_msm_base_cost
3418 + invoke_context
3419 .get_compute_budget()
3420 .curve25519_edwards_msm_incremental_cost
3421 + invoke_context
3422 .get_compute_budget()
3423 .curve25519_ristretto_msm_base_cost
3424 + invoke_context
3425 .get_compute_budget()
3426 .curve25519_ristretto_msm_incremental_cost,
3427 );
3428
3429 let result = SyscallCurveMultiscalarMultiplication::rust(
3430 &mut invoke_context,
3431 CURVE25519_EDWARDS,
3432 scalars_va,
3433 edwards_points_va,
3434 2,
3435 result_point_va,
3436 &mut memory_mapping,
3437 );
3438
3439 assert_eq!(0, result.unwrap());
3440 let expected_product = [
3441 30, 174, 168, 34, 160, 70, 63, 166, 236, 18, 74, 144, 185, 222, 208, 243, 5, 54, 223,
3442 172, 185, 75, 244, 26, 70, 18, 248, 46, 207, 184, 235, 60,
3443 ];
3444 assert_eq!(expected_product, result_point);
3445
3446 let result = SyscallCurveMultiscalarMultiplication::rust(
3447 &mut invoke_context,
3448 CURVE25519_RISTRETTO,
3449 scalars_va,
3450 ristretto_points_va,
3451 2,
3452 result_point_va,
3453 &mut memory_mapping,
3454 );
3455
3456 assert_eq!(0, result.unwrap());
3457 let expected_product = [
3458 78, 120, 86, 111, 152, 64, 146, 84, 14, 236, 77, 147, 237, 190, 251, 241, 136, 167, 21,
3459 94, 84, 118, 92, 140, 120, 81, 30, 246, 173, 140, 195, 86,
3460 ];
3461 assert_eq!(expected_product, result_point);
3462 }
3463
3464 #[test]
3465 fn test_syscall_multiscalar_multiplication_maximum_length_exceeded() {
3466 use solana_curve25519::curve_syscall_traits::{CURVE25519_EDWARDS, CURVE25519_RISTRETTO};
3467
3468 let config = Config::default();
3469 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3470
3471 let scalar: [u8; 32] = [
3472 254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
3473 78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
3474 ];
3475 let scalars = [scalar; 513];
3476 let scalars_va = 0x100000000;
3477
3478 let edwards_point: [u8; 32] = [
3479 252, 31, 230, 46, 173, 95, 144, 148, 158, 157, 63, 10, 8, 68, 58, 176, 142, 192, 168,
3480 53, 61, 105, 194, 166, 43, 56, 246, 236, 28, 146, 114, 133,
3481 ];
3482 let edwards_points = [edwards_point; 513];
3483 let edwards_points_va = 0x200000000;
3484
3485 let ristretto_point: [u8; 32] = [
3486 130, 35, 97, 25, 18, 199, 33, 239, 85, 143, 119, 111, 49, 51, 224, 40, 167, 185, 240,
3487 179, 25, 194, 213, 41, 14, 155, 104, 18, 181, 197, 15, 112,
3488 ];
3489 let ristretto_points = [ristretto_point; 513];
3490 let ristretto_points_va = 0x300000000;
3491
3492 let mut result_point: [u8; 32] = [0; 32];
3493 let result_point_va = 0x400000000;
3494
3495 let mut memory_mapping = MemoryMapping::new(
3496 vec![
3497 MemoryRegion::new_readonly(bytes_of_slice(&scalars), scalars_va),
3498 MemoryRegion::new_readonly(bytes_of_slice(&edwards_points), edwards_points_va),
3499 MemoryRegion::new_readonly(bytes_of_slice(&ristretto_points), ristretto_points_va),
3500 MemoryRegion::new_writable(bytes_of_slice_mut(&mut result_point), result_point_va),
3501 ],
3502 &config,
3503 SBPFVersion::V3,
3504 )
3505 .unwrap();
3506
3507 invoke_context.mock_set_remaining(500_000);
3509 let result = SyscallCurveMultiscalarMultiplication::rust(
3510 &mut invoke_context,
3511 CURVE25519_EDWARDS,
3512 scalars_va,
3513 edwards_points_va,
3514 512, result_point_va,
3516 &mut memory_mapping,
3517 );
3518
3519 assert_eq!(0, result.unwrap());
3520 let expected_product = [
3521 20, 146, 226, 37, 22, 61, 86, 249, 208, 40, 38, 11, 126, 101, 10, 82, 81, 77, 88, 209,
3522 15, 76, 82, 251, 180, 133, 84, 243, 162, 0, 11, 145,
3523 ];
3524 assert_eq!(expected_product, result_point);
3525
3526 invoke_context.mock_set_remaining(500_000);
3527 let result = SyscallCurveMultiscalarMultiplication::rust(
3528 &mut invoke_context,
3529 CURVE25519_EDWARDS,
3530 scalars_va,
3531 edwards_points_va,
3532 513, result_point_va,
3534 &mut memory_mapping,
3535 )
3536 .unwrap_err()
3537 .downcast::<SyscallError>()
3538 .unwrap();
3539
3540 assert_eq!(*result, SyscallError::InvalidLength);
3541
3542 invoke_context.mock_set_remaining(500_000);
3544 let result = SyscallCurveMultiscalarMultiplication::rust(
3545 &mut invoke_context,
3546 CURVE25519_RISTRETTO,
3547 scalars_va,
3548 ristretto_points_va,
3549 512, result_point_va,
3551 &mut memory_mapping,
3552 );
3553
3554 assert_eq!(0, result.unwrap());
3555 let expected_product = [
3556 146, 224, 127, 193, 252, 64, 196, 181, 246, 104, 27, 116, 183, 52, 200, 239, 2, 108,
3557 21, 27, 97, 44, 95, 65, 26, 218, 223, 39, 197, 132, 51, 49,
3558 ];
3559 assert_eq!(expected_product, result_point);
3560
3561 invoke_context.mock_set_remaining(500_000);
3562 let result = SyscallCurveMultiscalarMultiplication::rust(
3563 &mut invoke_context,
3564 CURVE25519_RISTRETTO,
3565 scalars_va,
3566 ristretto_points_va,
3567 513, result_point_va,
3569 &mut memory_mapping,
3570 )
3571 .unwrap_err()
3572 .downcast::<SyscallError>()
3573 .unwrap();
3574
3575 assert_eq!(*result, SyscallError::InvalidLength);
3576 }
3577
3578 fn create_filled_type<T: Default>(zero_init: bool) -> T {
3579 let mut val = T::default();
3580 let p = &mut val as *mut _ as *mut u8;
3581 for i in 0..(size_of::<T>() as isize) {
3582 unsafe {
3583 *p.offset(i) = if zero_init { 0 } else { i as u8 };
3584 }
3585 }
3586 val
3587 }
3588
3589 fn are_bytes_equal<T>(first: &T, second: &T) -> bool {
3590 let p_first = first as *const _ as *const u8;
3591 let p_second = second as *const _ as *const u8;
3592
3593 for i in 0..(size_of::<T>() as isize) {
3594 unsafe {
3595 if *p_first.offset(i) != *p_second.offset(i) {
3596 return false;
3597 }
3598 }
3599 }
3600 true
3601 }
3602
3603 #[test]
3604 #[allow(deprecated)]
3605 fn test_syscall_get_sysvar() {
3606 let config = Config::default();
3607
3608 let mut src_clock = create_filled_type::<Clock>(false);
3609 src_clock.slot = 1;
3610 src_clock.epoch_start_timestamp = 2;
3611 src_clock.epoch = 3;
3612 src_clock.leader_schedule_epoch = 4;
3613 src_clock.unix_timestamp = 5;
3614
3615 let mut src_epochschedule = create_filled_type::<EpochSchedule>(false);
3616 src_epochschedule.slots_per_epoch = 1;
3617 src_epochschedule.leader_schedule_slot_offset = 2;
3618 src_epochschedule.warmup = false;
3619 src_epochschedule.first_normal_epoch = 3;
3620 src_epochschedule.first_normal_slot = 4;
3621
3622 let mut src_fees = create_filled_type::<Fees>(false);
3623 src_fees.fee_calculator = FeeCalculator {
3624 lamports_per_signature: 1,
3625 };
3626
3627 let mut src_rent = create_filled_type::<Rent>(false);
3628 src_rent.lamports_per_byte_year = 1;
3629 src_rent.exemption_threshold = 2.0;
3630 src_rent.burn_percent = 3;
3631
3632 let mut src_rewards = create_filled_type::<EpochRewards>(false);
3633 src_rewards.distribution_starting_block_height = 42;
3634 src_rewards.num_partitions = 2;
3635 src_rewards.parent_blockhash = Hash::new_from_array([3; 32]);
3636 src_rewards.total_points = 4;
3637 src_rewards.total_rewards = 100;
3638 src_rewards.distributed_rewards = 10;
3639 src_rewards.active = true;
3640
3641 let mut src_restart = create_filled_type::<LastRestartSlot>(false);
3642 src_restart.last_restart_slot = 1;
3643
3644 let transaction_accounts = vec![
3645 (
3646 sysvar::clock::id(),
3647 create_account_shared_data_for_test(&src_clock),
3648 ),
3649 (
3650 sysvar::epoch_schedule::id(),
3651 create_account_shared_data_for_test(&src_epochschedule),
3652 ),
3653 (
3654 sysvar::fees::id(),
3655 create_account_shared_data_for_test(&src_fees),
3656 ),
3657 (
3658 sysvar::rent::id(),
3659 create_account_shared_data_for_test(&src_rent),
3660 ),
3661 (
3662 sysvar::epoch_rewards::id(),
3663 create_account_shared_data_for_test(&src_rewards),
3664 ),
3665 (
3666 sysvar::last_restart_slot::id(),
3667 create_account_shared_data_for_test(&src_restart),
3668 ),
3669 ];
3670 with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
3671
3672 {
3674 let mut got_clock_obj = Clock::default();
3675 let got_clock_obj_va = 0x100000000;
3676
3677 let mut got_clock_buf = vec![0; Clock::size_of()];
3678 let got_clock_buf_va = 0x200000000;
3679 let clock_id_va = 0x300000000;
3680
3681 let mut memory_mapping = MemoryMapping::new(
3682 vec![
3683 MemoryRegion::new_writable(bytes_of_mut(&mut got_clock_obj), got_clock_obj_va),
3684 MemoryRegion::new_writable(&mut got_clock_buf, got_clock_buf_va),
3685 MemoryRegion::new_readonly(&Clock::id().to_bytes(), clock_id_va),
3686 ],
3687 &config,
3688 SBPFVersion::V3,
3689 )
3690 .unwrap();
3691
3692 let result = SyscallGetClockSysvar::rust(
3693 &mut invoke_context,
3694 got_clock_obj_va,
3695 0,
3696 0,
3697 0,
3698 0,
3699 &mut memory_mapping,
3700 );
3701 result.unwrap();
3702 assert_eq!(got_clock_obj, src_clock);
3703
3704 let mut clean_clock = create_filled_type::<Clock>(true);
3705 clean_clock.slot = src_clock.slot;
3706 clean_clock.epoch_start_timestamp = src_clock.epoch_start_timestamp;
3707 clean_clock.epoch = src_clock.epoch;
3708 clean_clock.leader_schedule_epoch = src_clock.leader_schedule_epoch;
3709 clean_clock.unix_timestamp = src_clock.unix_timestamp;
3710 assert!(are_bytes_equal(&got_clock_obj, &clean_clock));
3711
3712 let result = SyscallGetSysvar::rust(
3713 &mut invoke_context,
3714 clock_id_va,
3715 got_clock_buf_va,
3716 0,
3717 Clock::size_of() as u64,
3718 0,
3719 &mut memory_mapping,
3720 );
3721 result.unwrap();
3722
3723 let clock_from_buf = bincode::deserialize::<Clock>(&got_clock_buf).unwrap();
3724
3725 assert_eq!(clock_from_buf, src_clock);
3726 assert!(are_bytes_equal(&clock_from_buf, &clean_clock));
3727 }
3728
3729 {
3731 let mut got_epochschedule_obj = EpochSchedule::default();
3732 let got_epochschedule_obj_va = 0x100000000;
3733
3734 let mut got_epochschedule_buf = vec![0; EpochSchedule::size_of()];
3735 let got_epochschedule_buf_va = 0x200000000;
3736 let epochschedule_id_va = 0x300000000;
3737
3738 let mut memory_mapping = MemoryMapping::new(
3739 vec![
3740 MemoryRegion::new_writable(
3741 bytes_of_mut(&mut got_epochschedule_obj),
3742 got_epochschedule_obj_va,
3743 ),
3744 MemoryRegion::new_writable(
3745 &mut got_epochschedule_buf,
3746 got_epochschedule_buf_va,
3747 ),
3748 MemoryRegion::new_readonly(
3749 &EpochSchedule::id().to_bytes(),
3750 epochschedule_id_va,
3751 ),
3752 ],
3753 &config,
3754 SBPFVersion::V3,
3755 )
3756 .unwrap();
3757
3758 let result = SyscallGetEpochScheduleSysvar::rust(
3759 &mut invoke_context,
3760 got_epochschedule_obj_va,
3761 0,
3762 0,
3763 0,
3764 0,
3765 &mut memory_mapping,
3766 );
3767 result.unwrap();
3768 assert_eq!(got_epochschedule_obj, src_epochschedule);
3769
3770 let mut clean_epochschedule = create_filled_type::<EpochSchedule>(true);
3771 clean_epochschedule.slots_per_epoch = src_epochschedule.slots_per_epoch;
3772 clean_epochschedule.leader_schedule_slot_offset =
3773 src_epochschedule.leader_schedule_slot_offset;
3774 clean_epochschedule.warmup = src_epochschedule.warmup;
3775 clean_epochschedule.first_normal_epoch = src_epochschedule.first_normal_epoch;
3776 clean_epochschedule.first_normal_slot = src_epochschedule.first_normal_slot;
3777 assert!(are_bytes_equal(
3778 &got_epochschedule_obj,
3779 &clean_epochschedule
3780 ));
3781
3782 let result = SyscallGetSysvar::rust(
3783 &mut invoke_context,
3784 epochschedule_id_va,
3785 got_epochschedule_buf_va,
3786 0,
3787 EpochSchedule::size_of() as u64,
3788 0,
3789 &mut memory_mapping,
3790 );
3791 result.unwrap();
3792
3793 let epochschedule_from_buf =
3794 bincode::deserialize::<EpochSchedule>(&got_epochschedule_buf).unwrap();
3795
3796 assert_eq!(epochschedule_from_buf, src_epochschedule);
3797
3798 assert!(are_bytes_equal(
3800 &epochschedule_from_buf.clone(),
3801 &clean_epochschedule
3802 ));
3803 }
3804
3805 {
3807 let mut got_fees = Fees::default();
3808 let got_fees_va = 0x100000000;
3809
3810 let mut memory_mapping = MemoryMapping::new(
3811 vec![MemoryRegion::new_writable(
3812 bytes_of_mut(&mut got_fees),
3813 got_fees_va,
3814 )],
3815 &config,
3816 SBPFVersion::V3,
3817 )
3818 .unwrap();
3819
3820 let result = SyscallGetFeesSysvar::rust(
3821 &mut invoke_context,
3822 got_fees_va,
3823 0,
3824 0,
3825 0,
3826 0,
3827 &mut memory_mapping,
3828 );
3829 result.unwrap();
3830 assert_eq!(got_fees, src_fees);
3831
3832 let mut clean_fees = create_filled_type::<Fees>(true);
3833 clean_fees.fee_calculator = src_fees.fee_calculator;
3834 assert!(are_bytes_equal(&got_fees, &clean_fees));
3835
3836 }
3838
3839 {
3841 let mut got_rent_obj = create_filled_type::<Rent>(true);
3842 let got_rent_obj_va = 0x100000000;
3843
3844 let mut got_rent_buf = vec![0; Rent::size_of()];
3845 let got_rent_buf_va = 0x200000000;
3846 let rent_id_va = 0x300000000;
3847
3848 let mut memory_mapping = MemoryMapping::new(
3849 vec![
3850 MemoryRegion::new_writable(bytes_of_mut(&mut got_rent_obj), got_rent_obj_va),
3851 MemoryRegion::new_writable(&mut got_rent_buf, got_rent_buf_va),
3852 MemoryRegion::new_readonly(&Rent::id().to_bytes(), rent_id_va),
3853 ],
3854 &config,
3855 SBPFVersion::V3,
3856 )
3857 .unwrap();
3858
3859 let result = SyscallGetRentSysvar::rust(
3860 &mut invoke_context,
3861 got_rent_obj_va,
3862 0,
3863 0,
3864 0,
3865 0,
3866 &mut memory_mapping,
3867 );
3868 result.unwrap();
3869 assert_eq!(got_rent_obj, src_rent);
3870
3871 let mut clean_rent = create_filled_type::<Rent>(true);
3872 clean_rent.lamports_per_byte_year = src_rent.lamports_per_byte_year;
3873 clean_rent.exemption_threshold = src_rent.exemption_threshold;
3874 clean_rent.burn_percent = src_rent.burn_percent;
3875 assert!(are_bytes_equal(&got_rent_obj, &clean_rent));
3876
3877 let result = SyscallGetSysvar::rust(
3878 &mut invoke_context,
3879 rent_id_va,
3880 got_rent_buf_va,
3881 0,
3882 Rent::size_of() as u64,
3883 0,
3884 &mut memory_mapping,
3885 );
3886 result.unwrap();
3887
3888 let rent_from_buf = bincode::deserialize::<Rent>(&got_rent_buf).unwrap();
3889
3890 assert_eq!(rent_from_buf, src_rent);
3891
3892 assert!(are_bytes_equal(&rent_from_buf.clone(), &clean_rent));
3894 }
3895
3896 {
3898 let mut got_rewards_obj = create_filled_type::<EpochRewards>(true);
3899 let got_rewards_obj_va = 0x100000000;
3900
3901 let mut got_rewards_buf = vec![0; EpochRewards::size_of()];
3902 let got_rewards_buf_va = 0x200000000;
3903 let rewards_id_va = 0x300000000;
3904
3905 let mut memory_mapping = MemoryMapping::new(
3906 vec![
3907 MemoryRegion::new_writable(
3908 bytes_of_mut(&mut got_rewards_obj),
3909 got_rewards_obj_va,
3910 ),
3911 MemoryRegion::new_writable(&mut got_rewards_buf, got_rewards_buf_va),
3912 MemoryRegion::new_readonly(&EpochRewards::id().to_bytes(), rewards_id_va),
3913 ],
3914 &config,
3915 SBPFVersion::V3,
3916 )
3917 .unwrap();
3918
3919 let result = SyscallGetEpochRewardsSysvar::rust(
3920 &mut invoke_context,
3921 got_rewards_obj_va,
3922 0,
3923 0,
3924 0,
3925 0,
3926 &mut memory_mapping,
3927 );
3928 result.unwrap();
3929 assert_eq!(got_rewards_obj, src_rewards);
3930
3931 let mut clean_rewards = create_filled_type::<EpochRewards>(true);
3932 clean_rewards.distribution_starting_block_height =
3933 src_rewards.distribution_starting_block_height;
3934 clean_rewards.num_partitions = src_rewards.num_partitions;
3935 clean_rewards.parent_blockhash = src_rewards.parent_blockhash;
3936 clean_rewards.total_points = src_rewards.total_points;
3937 clean_rewards.total_rewards = src_rewards.total_rewards;
3938 clean_rewards.distributed_rewards = src_rewards.distributed_rewards;
3939 clean_rewards.active = src_rewards.active;
3940 assert!(are_bytes_equal(&got_rewards_obj, &clean_rewards));
3941
3942 let result = SyscallGetSysvar::rust(
3943 &mut invoke_context,
3944 rewards_id_va,
3945 got_rewards_buf_va,
3946 0,
3947 EpochRewards::size_of() as u64,
3948 0,
3949 &mut memory_mapping,
3950 );
3951 result.unwrap();
3952
3953 let rewards_from_buf = bincode::deserialize::<EpochRewards>(&got_rewards_buf).unwrap();
3954
3955 assert_eq!(rewards_from_buf, src_rewards);
3956
3957 assert!(are_bytes_equal(&rewards_from_buf.clone(), &clean_rewards));
3959 }
3960
3961 {
3963 let mut got_restart_obj = LastRestartSlot::default();
3964 let got_restart_obj_va = 0x100000000;
3965
3966 let mut got_restart_buf = vec![0; LastRestartSlot::size_of()];
3967 let got_restart_buf_va = 0x200000000;
3968 let restart_id_va = 0x300000000;
3969
3970 let mut memory_mapping = MemoryMapping::new(
3971 vec![
3972 MemoryRegion::new_writable(
3973 bytes_of_mut(&mut got_restart_obj),
3974 got_restart_obj_va,
3975 ),
3976 MemoryRegion::new_writable(&mut got_restart_buf, got_restart_buf_va),
3977 MemoryRegion::new_readonly(&LastRestartSlot::id().to_bytes(), restart_id_va),
3978 ],
3979 &config,
3980 SBPFVersion::V3,
3981 )
3982 .unwrap();
3983
3984 let result = SyscallGetLastRestartSlotSysvar::rust(
3985 &mut invoke_context,
3986 got_restart_obj_va,
3987 0,
3988 0,
3989 0,
3990 0,
3991 &mut memory_mapping,
3992 );
3993 result.unwrap();
3994 assert_eq!(got_restart_obj, src_restart);
3995
3996 let mut clean_restart = create_filled_type::<LastRestartSlot>(true);
3997 clean_restart.last_restart_slot = src_restart.last_restart_slot;
3998 assert!(are_bytes_equal(&got_restart_obj, &clean_restart));
3999
4000 let result = SyscallGetSysvar::rust(
4001 &mut invoke_context,
4002 restart_id_va,
4003 got_restart_buf_va,
4004 0,
4005 LastRestartSlot::size_of() as u64,
4006 0,
4007 &mut memory_mapping,
4008 );
4009 result.unwrap();
4010
4011 let restart_from_buf =
4012 bincode::deserialize::<LastRestartSlot>(&got_restart_buf).unwrap();
4013
4014 assert_eq!(restart_from_buf, src_restart);
4015 assert!(are_bytes_equal(&restart_from_buf, &clean_restart));
4016 }
4017 }
4018
4019 #[test_case(false; "partial")]
4020 #[test_case(true; "full")]
4021 fn test_syscall_get_stake_history(filled: bool) {
4022 let config = Config::default();
4023
4024 let mut src_history = StakeHistory::default();
4025
4026 let epochs = if filled {
4027 stake_history::MAX_ENTRIES + 1
4028 } else {
4029 stake_history::MAX_ENTRIES / 2
4030 } as u64;
4031
4032 for epoch in 1..epochs {
4033 src_history.add(
4034 epoch,
4035 StakeHistoryEntry {
4036 effective: epoch * 2,
4037 activating: epoch * 3,
4038 deactivating: epoch * 5,
4039 },
4040 );
4041 }
4042
4043 let src_history = src_history;
4044
4045 let mut src_history_buf = vec![0; StakeHistory::size_of()];
4046 bincode::serialize_into(&mut src_history_buf, &src_history).unwrap();
4047
4048 let transaction_accounts = vec![(
4049 sysvar::stake_history::id(),
4050 create_account_shared_data_for_test(&src_history),
4051 )];
4052 with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4053
4054 {
4055 let mut got_history_buf = vec![0; StakeHistory::size_of()];
4056 let got_history_buf_va = 0x100000000;
4057 let history_id_va = 0x200000000;
4058
4059 let mut memory_mapping = MemoryMapping::new(
4060 vec![
4061 MemoryRegion::new_writable(&mut got_history_buf, got_history_buf_va),
4062 MemoryRegion::new_readonly(&StakeHistory::id().to_bytes(), history_id_va),
4063 ],
4064 &config,
4065 SBPFVersion::V3,
4066 )
4067 .unwrap();
4068
4069 let result = SyscallGetSysvar::rust(
4070 &mut invoke_context,
4071 history_id_va,
4072 got_history_buf_va,
4073 0,
4074 StakeHistory::size_of() as u64,
4075 0,
4076 &mut memory_mapping,
4077 );
4078 result.unwrap();
4079
4080 let history_from_buf = bincode::deserialize::<StakeHistory>(&got_history_buf).unwrap();
4081 assert_eq!(history_from_buf, src_history);
4082 }
4083 }
4084
4085 #[test_case(false; "partial")]
4086 #[test_case(true; "full")]
4087 fn test_syscall_get_slot_hashes(filled: bool) {
4088 let config = Config::default();
4089
4090 let mut src_hashes = SlotHashes::default();
4091
4092 let slots = if filled {
4093 slot_hashes::MAX_ENTRIES + 1
4094 } else {
4095 slot_hashes::MAX_ENTRIES / 2
4096 } as u64;
4097
4098 for slot in 1..slots {
4099 src_hashes.add(slot, hashv(&[&slot.to_le_bytes()]));
4100 }
4101
4102 let src_hashes = src_hashes;
4103
4104 let mut src_hashes_buf = vec![0; SlotHashes::size_of()];
4105 bincode::serialize_into(&mut src_hashes_buf, &src_hashes).unwrap();
4106
4107 let transaction_accounts = vec![(
4108 sysvar::slot_hashes::id(),
4109 create_account_shared_data_for_test(&src_hashes),
4110 )];
4111 with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4112
4113 {
4114 let mut got_hashes_buf = vec![0; SlotHashes::size_of()];
4115 let got_hashes_buf_va = 0x100000000;
4116 let hashes_id_va = 0x200000000;
4117
4118 let mut memory_mapping = MemoryMapping::new(
4119 vec![
4120 MemoryRegion::new_writable(&mut got_hashes_buf, got_hashes_buf_va),
4121 MemoryRegion::new_readonly(&SlotHashes::id().to_bytes(), hashes_id_va),
4122 ],
4123 &config,
4124 SBPFVersion::V3,
4125 )
4126 .unwrap();
4127
4128 let result = SyscallGetSysvar::rust(
4129 &mut invoke_context,
4130 hashes_id_va,
4131 got_hashes_buf_va,
4132 0,
4133 SlotHashes::size_of() as u64,
4134 0,
4135 &mut memory_mapping,
4136 );
4137 result.unwrap();
4138
4139 let hashes_from_buf = bincode::deserialize::<SlotHashes>(&got_hashes_buf).unwrap();
4140 assert_eq!(hashes_from_buf, src_hashes);
4141 }
4142 }
4143
4144 #[test]
4145 fn test_syscall_get_sysvar_errors() {
4146 let config = Config::default();
4147
4148 let mut src_clock = create_filled_type::<Clock>(false);
4149 src_clock.slot = 1;
4150 src_clock.epoch_start_timestamp = 2;
4151 src_clock.epoch = 3;
4152 src_clock.leader_schedule_epoch = 4;
4153 src_clock.unix_timestamp = 5;
4154
4155 let clock_id_va = 0x100000000;
4156
4157 let mut got_clock_buf_rw = vec![0; Clock::size_of()];
4158 let got_clock_buf_rw_va = 0x200000000;
4159
4160 let got_clock_buf_ro = vec![0; Clock::size_of()];
4161 let got_clock_buf_ro_va = 0x300000000;
4162
4163 let mut memory_mapping = MemoryMapping::new(
4164 vec![
4165 MemoryRegion::new_readonly(&Clock::id().to_bytes(), clock_id_va),
4166 MemoryRegion::new_writable(&mut got_clock_buf_rw, got_clock_buf_rw_va),
4167 MemoryRegion::new_readonly(&got_clock_buf_ro, got_clock_buf_ro_va),
4168 ],
4169 &config,
4170 SBPFVersion::V3,
4171 )
4172 .unwrap();
4173
4174 let access_violation_err =
4175 std::mem::discriminant(&EbpfError::AccessViolation(AccessType::Load, 0, 0, ""));
4176
4177 let got_clock_empty = vec![0; Clock::size_of()];
4178
4179 {
4180 with_mock_invoke_context!(invoke_context, transaction_context, vec![]);
4182
4183 let e = SyscallGetSysvar::rust(
4185 &mut invoke_context,
4186 clock_id_va + 1,
4187 got_clock_buf_rw_va,
4188 0,
4189 Clock::size_of() as u64,
4190 0,
4191 &mut memory_mapping,
4192 )
4193 .unwrap_err();
4194
4195 assert_eq!(
4196 std::mem::discriminant(e.downcast_ref::<EbpfError>().unwrap()),
4197 access_violation_err,
4198 );
4199 assert_eq!(got_clock_buf_rw, got_clock_empty);
4200
4201 let e = SyscallGetSysvar::rust(
4203 &mut invoke_context,
4204 clock_id_va,
4205 got_clock_buf_rw_va + 1,
4206 0,
4207 Clock::size_of() as u64,
4208 0,
4209 &mut memory_mapping,
4210 )
4211 .unwrap_err();
4212
4213 assert_eq!(
4214 std::mem::discriminant(e.downcast_ref::<EbpfError>().unwrap()),
4215 access_violation_err,
4216 );
4217 assert_eq!(got_clock_buf_rw, got_clock_empty);
4218
4219 let e = SyscallGetSysvar::rust(
4220 &mut invoke_context,
4221 clock_id_va,
4222 got_clock_buf_ro_va,
4223 0,
4224 Clock::size_of() as u64,
4225 0,
4226 &mut memory_mapping,
4227 )
4228 .unwrap_err();
4229
4230 assert_eq!(
4231 std::mem::discriminant(e.downcast_ref::<EbpfError>().unwrap()),
4232 access_violation_err,
4233 );
4234 assert_eq!(got_clock_buf_rw, got_clock_empty);
4235
4236 let e = SyscallGetSysvar::rust(
4238 &mut invoke_context,
4239 clock_id_va,
4240 got_clock_buf_rw_va,
4241 u64::MAX - Clock::size_of() as u64 / 2,
4242 Clock::size_of() as u64,
4243 0,
4244 &mut memory_mapping,
4245 )
4246 .unwrap_err();
4247
4248 assert_eq!(
4249 *e.downcast_ref::<InstructionError>().unwrap(),
4250 InstructionError::ArithmeticOverflow,
4251 );
4252 assert_eq!(got_clock_buf_rw, got_clock_empty);
4253
4254 let result = SyscallGetSysvar::rust(
4259 &mut invoke_context,
4260 clock_id_va,
4261 got_clock_buf_rw_va,
4262 0,
4263 Clock::size_of() as u64,
4264 0,
4265 &mut memory_mapping,
4266 )
4267 .unwrap();
4268
4269 assert_eq!(result, 2);
4270 assert_eq!(got_clock_buf_rw, got_clock_empty);
4271 }
4272
4273 {
4274 let transaction_accounts = vec![(
4275 sysvar::clock::id(),
4276 create_account_shared_data_for_test(&src_clock),
4277 )];
4278 with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4279
4280 let result = SyscallGetSysvar::rust(
4282 &mut invoke_context,
4283 clock_id_va,
4284 got_clock_buf_rw_va,
4285 1,
4286 Clock::size_of() as u64,
4287 0,
4288 &mut memory_mapping,
4289 )
4290 .unwrap();
4291
4292 assert_eq!(result, 1);
4293 assert_eq!(got_clock_buf_rw, got_clock_empty);
4294
4295 SyscallGetSysvar::rust(
4297 &mut invoke_context,
4298 clock_id_va,
4299 got_clock_buf_rw_va,
4300 0,
4301 Clock::size_of() as u64,
4302 0,
4303 &mut memory_mapping,
4304 )
4305 .unwrap();
4306
4307 let clock_from_buf = bincode::deserialize::<Clock>(&got_clock_buf_rw).unwrap();
4308
4309 assert_eq!(clock_from_buf, src_clock);
4310 }
4311 }
4312
4313 type BuiltinFunctionRustInterface<'a> = fn(
4314 &mut InvokeContext<'a>,
4315 u64,
4316 u64,
4317 u64,
4318 u64,
4319 u64,
4320 &mut MemoryMapping,
4321 ) -> Result<u64, Box<dyn std::error::Error>>;
4322
4323 fn call_program_address_common<'a, 'b: 'a>(
4324 invoke_context: &'a mut InvokeContext<'b>,
4325 seeds: &[&[u8]],
4326 program_id: &Pubkey,
4327 overlap_outputs: bool,
4328 syscall: BuiltinFunctionRustInterface<'b>,
4329 ) -> Result<(Pubkey, u8), Error> {
4330 const SEEDS_VA: u64 = 0x100000000;
4331 const PROGRAM_ID_VA: u64 = 0x200000000;
4332 const ADDRESS_VA: u64 = 0x300000000;
4333 const BUMP_SEED_VA: u64 = 0x400000000;
4334 const SEED_VA: u64 = 0x500000000;
4335
4336 let config = Config::default();
4337 let mut address = Pubkey::default();
4338 let mut bump_seed = 0;
4339 let mut regions = vec![
4340 MemoryRegion::new_readonly(bytes_of(program_id), PROGRAM_ID_VA),
4341 MemoryRegion::new_writable(bytes_of_mut(&mut address), ADDRESS_VA),
4342 MemoryRegion::new_writable(bytes_of_mut(&mut bump_seed), BUMP_SEED_VA),
4343 ];
4344
4345 let mut mock_slices = Vec::with_capacity(seeds.len());
4346 for (i, seed) in seeds.iter().enumerate() {
4347 let vm_addr = SEED_VA.saturating_add((i as u64).saturating_mul(0x100000000));
4348 let mock_slice = MockSlice {
4349 vm_addr,
4350 len: seed.len(),
4351 };
4352 mock_slices.push(mock_slice);
4353 regions.push(MemoryRegion::new_readonly(bytes_of_slice(seed), vm_addr));
4354 }
4355 regions.push(MemoryRegion::new_readonly(
4356 bytes_of_slice(&mock_slices),
4357 SEEDS_VA,
4358 ));
4359 let mut memory_mapping = MemoryMapping::new(regions, &config, SBPFVersion::V3).unwrap();
4360
4361 let result = syscall(
4362 invoke_context,
4363 SEEDS_VA,
4364 seeds.len() as u64,
4365 PROGRAM_ID_VA,
4366 ADDRESS_VA,
4367 if overlap_outputs {
4368 ADDRESS_VA
4369 } else {
4370 BUMP_SEED_VA
4371 },
4372 &mut memory_mapping,
4373 );
4374 result.map(|_| (address, bump_seed))
4375 }
4376
4377 fn create_program_address(
4378 invoke_context: &mut InvokeContext,
4379 seeds: &[&[u8]],
4380 address: &Pubkey,
4381 ) -> Result<Pubkey, Error> {
4382 let (address, _) = call_program_address_common(
4383 invoke_context,
4384 seeds,
4385 address,
4386 false,
4387 SyscallCreateProgramAddress::rust,
4388 )?;
4389 Ok(address)
4390 }
4391
4392 fn try_find_program_address(
4393 invoke_context: &mut InvokeContext,
4394 seeds: &[&[u8]],
4395 address: &Pubkey,
4396 ) -> Result<(Pubkey, u8), Error> {
4397 call_program_address_common(
4398 invoke_context,
4399 seeds,
4400 address,
4401 false,
4402 SyscallTryFindProgramAddress::rust,
4403 )
4404 }
4405
4406 #[test]
4407 fn test_set_and_get_return_data() {
4408 const SRC_VA: u64 = 0x100000000;
4409 const DST_VA: u64 = 0x200000000;
4410 const PROGRAM_ID_VA: u64 = 0x300000000;
4411 let data = vec![42; 24];
4412 let mut data_buffer = vec![0; 16];
4413 let mut id_buffer = vec![0; 32];
4414
4415 let config = Config::default();
4416 let mut memory_mapping = MemoryMapping::new(
4417 vec![
4418 MemoryRegion::new_readonly(&data, SRC_VA),
4419 MemoryRegion::new_writable(&mut data_buffer, DST_VA),
4420 MemoryRegion::new_writable(&mut id_buffer, PROGRAM_ID_VA),
4421 ],
4422 &config,
4423 SBPFVersion::V3,
4424 )
4425 .unwrap();
4426
4427 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
4428
4429 let result = SyscallSetReturnData::rust(
4430 &mut invoke_context,
4431 SRC_VA,
4432 data.len() as u64,
4433 0,
4434 0,
4435 0,
4436 &mut memory_mapping,
4437 );
4438 assert_eq!(result.unwrap(), 0);
4439
4440 let result = SyscallGetReturnData::rust(
4441 &mut invoke_context,
4442 DST_VA,
4443 data_buffer.len() as u64,
4444 PROGRAM_ID_VA,
4445 0,
4446 0,
4447 &mut memory_mapping,
4448 );
4449 assert_eq!(result.unwrap() as usize, data.len());
4450 assert_eq!(data.get(0..data_buffer.len()).unwrap(), data_buffer);
4451 assert_eq!(id_buffer, program_id.to_bytes());
4452
4453 let result = SyscallGetReturnData::rust(
4454 &mut invoke_context,
4455 PROGRAM_ID_VA,
4456 data_buffer.len() as u64,
4457 PROGRAM_ID_VA,
4458 0,
4459 0,
4460 &mut memory_mapping,
4461 );
4462 assert_matches!(
4463 result,
4464 Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping
4465 );
4466 }
4467
4468 #[test]
4469 fn test_syscall_sol_get_processed_sibling_instruction() {
4470 let transaction_accounts = (0..9)
4471 .map(|_| {
4472 (
4473 Pubkey::new_unique(),
4474 AccountSharedData::new(0, 0, &bpf_loader::id()),
4475 )
4476 })
4477 .collect::<Vec<_>>();
4478 let instruction_trace = [1, 2, 3, 2, 2, 3, 4, 3];
4479 with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4480 for (index_in_trace, stack_height) in instruction_trace.into_iter().enumerate() {
4481 while stack_height
4482 <= invoke_context
4483 .transaction_context
4484 .get_instruction_context_stack_height()
4485 {
4486 invoke_context.transaction_context.pop().unwrap();
4487 }
4488 if stack_height
4489 > invoke_context
4490 .transaction_context
4491 .get_instruction_context_stack_height()
4492 {
4493 let instruction_accounts = [InstructionAccount {
4494 index_in_transaction: index_in_trace.saturating_add(1) as IndexOfAccount,
4495 index_in_caller: 0, index_in_callee: 0,
4497 is_signer: false,
4498 is_writable: false,
4499 }];
4500 invoke_context
4501 .transaction_context
4502 .get_next_instruction_context()
4503 .unwrap()
4504 .configure(&[0], &instruction_accounts, &[index_in_trace as u8]);
4505 invoke_context.transaction_context.push().unwrap();
4506 }
4507 }
4508
4509 let syscall_base_cost = invoke_context.get_compute_budget().syscall_base_cost;
4510
4511 const VM_BASE_ADDRESS: u64 = 0x100000000;
4512 const META_OFFSET: usize = 0;
4513 const PROGRAM_ID_OFFSET: usize =
4514 META_OFFSET + std::mem::size_of::<ProcessedSiblingInstruction>();
4515 const DATA_OFFSET: usize = PROGRAM_ID_OFFSET + std::mem::size_of::<Pubkey>();
4516 const ACCOUNTS_OFFSET: usize = DATA_OFFSET + 0x100;
4517 const END_OFFSET: usize = ACCOUNTS_OFFSET + std::mem::size_of::<AccountInfo>() * 4;
4518 let mut memory = [0u8; END_OFFSET];
4519 let config = Config::default();
4520 let mut memory_mapping = MemoryMapping::new(
4521 vec![MemoryRegion::new_writable(&mut memory, VM_BASE_ADDRESS)],
4522 &config,
4523 SBPFVersion::V3,
4524 )
4525 .unwrap();
4526 let processed_sibling_instruction = translate_type_mut::<ProcessedSiblingInstruction>(
4527 &memory_mapping,
4528 VM_BASE_ADDRESS,
4529 true,
4530 )
4531 .unwrap();
4532 processed_sibling_instruction.data_len = 1;
4533 processed_sibling_instruction.accounts_len = 1;
4534 let program_id = translate_type_mut::<Pubkey>(
4535 &memory_mapping,
4536 VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
4537 true,
4538 )
4539 .unwrap();
4540 let data = translate_slice_mut::<u8>(
4541 &memory_mapping,
4542 VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
4543 processed_sibling_instruction.data_len,
4544 true,
4545 )
4546 .unwrap();
4547 let accounts = translate_slice_mut::<AccountMeta>(
4548 &memory_mapping,
4549 VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
4550 processed_sibling_instruction.accounts_len,
4551 true,
4552 )
4553 .unwrap();
4554
4555 invoke_context.mock_set_remaining(syscall_base_cost);
4556 let result = SyscallGetProcessedSiblingInstruction::rust(
4557 &mut invoke_context,
4558 0,
4559 VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
4560 VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
4561 VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
4562 VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
4563 &mut memory_mapping,
4564 );
4565 assert_eq!(result.unwrap(), 1);
4566 {
4567 let transaction_context = &invoke_context.transaction_context;
4568 assert_eq!(processed_sibling_instruction.data_len, 1);
4569 assert_eq!(processed_sibling_instruction.accounts_len, 1);
4570 assert_eq!(
4571 program_id,
4572 transaction_context.get_key_of_account_at_index(0).unwrap(),
4573 );
4574 assert_eq!(data, &[5]);
4575 assert_eq!(
4576 accounts,
4577 &[AccountMeta {
4578 pubkey: *transaction_context.get_key_of_account_at_index(6).unwrap(),
4579 is_signer: false,
4580 is_writable: false
4581 }]
4582 );
4583 }
4584
4585 invoke_context.mock_set_remaining(syscall_base_cost);
4586 let result = SyscallGetProcessedSiblingInstruction::rust(
4587 &mut invoke_context,
4588 1,
4589 VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
4590 VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
4591 VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
4592 VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
4593 &mut memory_mapping,
4594 );
4595 assert_eq!(result.unwrap(), 0);
4596
4597 invoke_context.mock_set_remaining(syscall_base_cost);
4598 let result = SyscallGetProcessedSiblingInstruction::rust(
4599 &mut invoke_context,
4600 0,
4601 VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
4602 VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
4603 VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
4604 VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
4605 &mut memory_mapping,
4606 );
4607 assert_matches!(
4608 result,
4609 Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping
4610 );
4611 }
4612
4613 #[test]
4614 fn test_create_program_address() {
4615 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
4618 let address = bpf_loader_upgradeable::id();
4619
4620 let exceeded_seed = &[127; MAX_SEED_LEN + 1];
4621 assert_matches!(
4622 create_program_address(&mut invoke_context, &[exceeded_seed], &address),
4623 Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
4624 );
4625 assert_matches!(
4626 create_program_address(
4627 &mut invoke_context,
4628 &[b"short_seed", exceeded_seed],
4629 &address,
4630 ),
4631 Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
4632 );
4633 let max_seed = &[0; MAX_SEED_LEN];
4634 assert!(create_program_address(&mut invoke_context, &[max_seed], &address).is_ok());
4635 let exceeded_seeds: &[&[u8]] = &[
4636 &[1],
4637 &[2],
4638 &[3],
4639 &[4],
4640 &[5],
4641 &[6],
4642 &[7],
4643 &[8],
4644 &[9],
4645 &[10],
4646 &[11],
4647 &[12],
4648 &[13],
4649 &[14],
4650 &[15],
4651 &[16],
4652 ];
4653 assert!(create_program_address(&mut invoke_context, exceeded_seeds, &address).is_ok());
4654 let max_seeds: &[&[u8]] = &[
4655 &[1],
4656 &[2],
4657 &[3],
4658 &[4],
4659 &[5],
4660 &[6],
4661 &[7],
4662 &[8],
4663 &[9],
4664 &[10],
4665 &[11],
4666 &[12],
4667 &[13],
4668 &[14],
4669 &[15],
4670 &[16],
4671 &[17],
4672 ];
4673 assert_matches!(
4674 create_program_address(&mut invoke_context, max_seeds, &address),
4675 Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
4676 );
4677 assert_eq!(
4678 create_program_address(&mut invoke_context, &[b"", &[1]], &address).unwrap(),
4679 "BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe"
4680 .parse()
4681 .unwrap(),
4682 );
4683 assert_eq!(
4684 create_program_address(&mut invoke_context, &["☉".as_ref(), &[0]], &address).unwrap(),
4685 "13yWmRpaTR4r5nAktwLqMpRNr28tnVUZw26rTvPSSB19"
4686 .parse()
4687 .unwrap(),
4688 );
4689 assert_eq!(
4690 create_program_address(&mut invoke_context, &[b"Talking", b"Squirrels"], &address)
4691 .unwrap(),
4692 "2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk"
4693 .parse()
4694 .unwrap(),
4695 );
4696 let public_key = Pubkey::from_str("SeedPubey1111111111111111111111111111111111").unwrap();
4697 assert_eq!(
4698 create_program_address(&mut invoke_context, &[public_key.as_ref(), &[1]], &address)
4699 .unwrap(),
4700 "976ymqVnfE32QFe6NfGDctSvVa36LWnvYxhU6G2232YL"
4701 .parse()
4702 .unwrap(),
4703 );
4704 assert_ne!(
4705 create_program_address(&mut invoke_context, &[b"Talking", b"Squirrels"], &address)
4706 .unwrap(),
4707 create_program_address(&mut invoke_context, &[b"Talking"], &address).unwrap(),
4708 );
4709 invoke_context.mock_set_remaining(0);
4710 assert_matches!(
4711 create_program_address(&mut invoke_context, &[b"", &[1]], &address),
4712 Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
4713 );
4714 }
4715
4716 #[test]
4717 fn test_find_program_address() {
4718 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
4719 let cost = invoke_context
4720 .get_compute_budget()
4721 .create_program_address_units;
4722 let address = bpf_loader_upgradeable::id();
4723 let max_tries = 256; for _ in 0..1_000 {
4726 let address = Pubkey::new_unique();
4727 invoke_context.mock_set_remaining(cost * max_tries);
4728 let (found_address, bump_seed) =
4729 try_find_program_address(&mut invoke_context, &[b"Lil'", b"Bits"], &address)
4730 .unwrap();
4731 assert_eq!(
4732 found_address,
4733 create_program_address(
4734 &mut invoke_context,
4735 &[b"Lil'", b"Bits", &[bump_seed]],
4736 &address,
4737 )
4738 .unwrap()
4739 );
4740 }
4741
4742 let seeds: &[&[u8]] = &[b""];
4743 invoke_context.mock_set_remaining(cost * max_tries);
4744 let (_, bump_seed) =
4745 try_find_program_address(&mut invoke_context, seeds, &address).unwrap();
4746 invoke_context.mock_set_remaining(cost * (max_tries - bump_seed as u64));
4747 try_find_program_address(&mut invoke_context, seeds, &address).unwrap();
4748 invoke_context.mock_set_remaining(cost * (max_tries - bump_seed as u64 - 1));
4749 assert_matches!(
4750 try_find_program_address(&mut invoke_context, seeds, &address),
4751 Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
4752 );
4753
4754 let exceeded_seed = &[127; MAX_SEED_LEN + 1];
4755 invoke_context.mock_set_remaining(cost * (max_tries - 1));
4756 assert_matches!(
4757 try_find_program_address(&mut invoke_context, &[exceeded_seed], &address),
4758 Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
4759 );
4760 let exceeded_seeds: &[&[u8]] = &[
4761 &[1],
4762 &[2],
4763 &[3],
4764 &[4],
4765 &[5],
4766 &[6],
4767 &[7],
4768 &[8],
4769 &[9],
4770 &[10],
4771 &[11],
4772 &[12],
4773 &[13],
4774 &[14],
4775 &[15],
4776 &[16],
4777 &[17],
4778 ];
4779 invoke_context.mock_set_remaining(cost * (max_tries - 1));
4780 assert_matches!(
4781 try_find_program_address(&mut invoke_context, exceeded_seeds, &address),
4782 Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
4783 );
4784
4785 assert_matches!(
4786 call_program_address_common(
4787 &mut invoke_context,
4788 seeds,
4789 &address,
4790 true,
4791 SyscallTryFindProgramAddress::rust,
4792 ),
4793 Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping
4794 );
4795 }
4796
4797 #[test]
4798 fn test_syscall_big_mod_exp() {
4799 let config = Config::default();
4800 prepare_mockup!(invoke_context, program_id, bpf_loader::id());
4801
4802 const VADDR_PARAMS: u64 = 0x100000000;
4803 const MAX_LEN: u64 = 512;
4804 const INV_LEN: u64 = MAX_LEN + 1;
4805 let data: [u8; INV_LEN as usize] = [0; INV_LEN as usize];
4806 const VADDR_DATA: u64 = 0x200000000;
4807
4808 let mut data_out: [u8; INV_LEN as usize] = [0; INV_LEN as usize];
4809 const VADDR_OUT: u64 = 0x300000000;
4810
4811 {
4813 let params_max_len = BigModExpParams {
4814 base: VADDR_DATA as *const u8,
4815 base_len: MAX_LEN,
4816 exponent: VADDR_DATA as *const u8,
4817 exponent_len: MAX_LEN,
4818 modulus: VADDR_DATA as *const u8,
4819 modulus_len: MAX_LEN,
4820 };
4821
4822 let mut memory_mapping = MemoryMapping::new(
4823 vec![
4824 MemoryRegion::new_readonly(bytes_of(¶ms_max_len), VADDR_PARAMS),
4825 MemoryRegion::new_readonly(&data, VADDR_DATA),
4826 MemoryRegion::new_writable(&mut data_out, VADDR_OUT),
4827 ],
4828 &config,
4829 SBPFVersion::V3,
4830 )
4831 .unwrap();
4832
4833 let budget = invoke_context.get_compute_budget();
4834 invoke_context.mock_set_remaining(
4835 budget.syscall_base_cost
4836 + (MAX_LEN * MAX_LEN) / budget.big_modular_exponentiation_cost_divisor
4837 + budget.big_modular_exponentiation_base_cost,
4838 );
4839
4840 let result = SyscallBigModExp::rust(
4841 &mut invoke_context,
4842 VADDR_PARAMS,
4843 VADDR_OUT,
4844 0,
4845 0,
4846 0,
4847 &mut memory_mapping,
4848 );
4849
4850 assert_eq!(result.unwrap(), 0);
4851 }
4852
4853 {
4855 let params_inv_len = BigModExpParams {
4856 base: VADDR_DATA as *const u8,
4857 base_len: INV_LEN,
4858 exponent: VADDR_DATA as *const u8,
4859 exponent_len: INV_LEN,
4860 modulus: VADDR_DATA as *const u8,
4861 modulus_len: INV_LEN,
4862 };
4863
4864 let mut memory_mapping = MemoryMapping::new(
4865 vec![
4866 MemoryRegion::new_readonly(bytes_of(¶ms_inv_len), VADDR_PARAMS),
4867 MemoryRegion::new_readonly(&data, VADDR_DATA),
4868 MemoryRegion::new_writable(&mut data_out, VADDR_OUT),
4869 ],
4870 &config,
4871 SBPFVersion::V3,
4872 )
4873 .unwrap();
4874
4875 let budget = invoke_context.get_compute_budget();
4876 invoke_context.mock_set_remaining(
4877 budget.syscall_base_cost
4878 + (INV_LEN * INV_LEN) / budget.big_modular_exponentiation_cost_divisor
4879 + budget.big_modular_exponentiation_base_cost,
4880 );
4881
4882 let result = SyscallBigModExp::rust(
4883 &mut invoke_context,
4884 VADDR_PARAMS,
4885 VADDR_OUT,
4886 0,
4887 0,
4888 0,
4889 &mut memory_mapping,
4890 );
4891
4892 assert_matches!(
4893 result,
4894 Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::InvalidLength
4895 );
4896 }
4897 }
4898
4899 #[test]
4900 fn test_syscall_get_epoch_stake_total_stake() {
4901 let config = Config::default();
4902 let mut compute_budget = ComputeBudget::default();
4903 let sysvar_cache = Arc::<SysvarCache>::default();
4904
4905 let expected_total_stake = 200_000_000_000_000u64;
4906 let expected_cus = compute_budget.syscall_base_cost;
4909
4910 compute_budget.compute_unit_limit = expected_cus;
4913
4914 with_mock_invoke_context!(invoke_context, transaction_context, vec![]);
4915 invoke_context.environment_config = EnvironmentConfig::new(
4916 Hash::default(),
4917 0,
4918 expected_total_stake,
4919 &|_| 0, Arc::<FeatureSet>::default(),
4921 &sysvar_cache,
4922 );
4923
4924 let null_pointer_var = std::ptr::null::<Pubkey>() as u64;
4925
4926 let mut memory_mapping = MemoryMapping::new(vec![], &config, SBPFVersion::V3).unwrap();
4927
4928 let result = SyscallGetEpochStake::rust(
4929 &mut invoke_context,
4930 null_pointer_var,
4931 0,
4932 0,
4933 0,
4934 0,
4935 &mut memory_mapping,
4936 )
4937 .unwrap();
4938
4939 assert_eq!(result, expected_total_stake);
4940 }
4941
4942 #[test]
4943 fn test_syscall_get_epoch_stake_vote_account_stake() {
4944 let config = Config::default();
4945 let mut compute_budget = ComputeBudget::default();
4946 let sysvar_cache = Arc::<SysvarCache>::default();
4947
4948 let expected_epoch_stake = 55_000_000_000u64;
4949 let expected_cus = compute_budget.syscall_base_cost
4954 + (PUBKEY_BYTES as u64) / compute_budget.cpi_bytes_per_unit
4955 + compute_budget.mem_op_base_cost;
4956
4957 compute_budget.compute_unit_limit = expected_cus;
4960
4961 let vote_address = Pubkey::new_unique();
4962 with_mock_invoke_context!(invoke_context, transaction_context, vec![]);
4963 let callback = |pubkey: &Pubkey| {
4964 if *pubkey == vote_address {
4965 expected_epoch_stake
4966 } else {
4967 0
4968 }
4969 };
4970 invoke_context.environment_config = EnvironmentConfig::new(
4971 Hash::default(),
4972 0,
4973 0, &callback,
4975 Arc::<FeatureSet>::default(),
4976 &sysvar_cache,
4977 );
4978
4979 {
4980 let vote_address_var = 0x100000000;
4983
4984 let mut memory_mapping = MemoryMapping::new(
4985 vec![
4986 MemoryRegion::new_readonly(&[2; 31], vote_address_var),
4988 ],
4989 &config,
4990 SBPFVersion::V3,
4991 )
4992 .unwrap();
4993
4994 let result = SyscallGetEpochStake::rust(
4995 &mut invoke_context,
4996 vote_address_var,
4997 0,
4998 0,
4999 0,
5000 0,
5001 &mut memory_mapping,
5002 );
5003
5004 assert_access_violation!(result, vote_address_var, 32);
5005 }
5006
5007 invoke_context.mock_set_remaining(compute_budget.compute_unit_limit);
5008 {
5009 let vote_address_var = 0x100000000;
5013
5014 let mut memory_mapping = MemoryMapping::new(
5015 vec![MemoryRegion::new_readonly(
5016 bytes_of(&vote_address),
5017 vote_address_var,
5018 )],
5019 &config,
5020 SBPFVersion::V3,
5021 )
5022 .unwrap();
5023
5024 let result = SyscallGetEpochStake::rust(
5025 &mut invoke_context,
5026 vote_address_var,
5027 0,
5028 0,
5029 0,
5030 0,
5031 &mut memory_mapping,
5032 )
5033 .unwrap();
5034
5035 assert_eq!(result, expected_epoch_stake);
5036 }
5037
5038 invoke_context.mock_set_remaining(compute_budget.compute_unit_limit);
5039 {
5040 let vote_address_var = 0x100000000;
5044 let not_a_vote_address = Pubkey::new_unique(); let mut memory_mapping = MemoryMapping::new(
5047 vec![MemoryRegion::new_readonly(
5048 bytes_of(¬_a_vote_address),
5049 vote_address_var,
5050 )],
5051 &config,
5052 SBPFVersion::V3,
5053 )
5054 .unwrap();
5055
5056 let result = SyscallGetEpochStake::rust(
5057 &mut invoke_context,
5058 vote_address_var,
5059 0,
5060 0,
5061 0,
5062 0,
5063 &mut memory_mapping,
5064 )
5065 .unwrap();
5066
5067 assert_eq!(result, 0); }
5069 }
5070
5071 #[test]
5072 fn test_check_type_assumptions() {
5073 check_type_assumptions();
5074 }
5075
5076 fn bytes_of<T>(val: &T) -> &[u8] {
5077 let size = mem::size_of::<T>();
5078 unsafe { slice::from_raw_parts(std::slice::from_ref(val).as_ptr().cast(), size) }
5079 }
5080
5081 fn bytes_of_mut<T>(val: &mut T) -> &mut [u8] {
5082 let size = mem::size_of::<T>();
5083 unsafe { slice::from_raw_parts_mut(slice::from_mut(val).as_mut_ptr().cast(), size) }
5084 }
5085
5086 fn bytes_of_slice<T>(val: &[T]) -> &[u8] {
5087 let size = val.len().wrapping_mul(mem::size_of::<T>());
5088 unsafe { slice::from_raw_parts(val.as_ptr().cast(), size) }
5089 }
5090
5091 fn bytes_of_slice_mut<T>(val: &mut [T]) -> &mut [u8] {
5092 let size = val.len().wrapping_mul(mem::size_of::<T>());
5093 unsafe { slice::from_raw_parts_mut(val.as_mut_ptr().cast(), size) }
5094 }
5095
5096 #[test]
5097 fn test_address_is_aligned() {
5098 for address in 0..std::mem::size_of::<u64>() {
5099 assert_eq!(address_is_aligned::<u64>(address as u64), address == 0);
5100 }
5101 }
5102}