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