1use core::{cell::RefCell, cmp::Ordering, fmt::Debug};
2use std::rc::Rc;
3
4use crate::{
5 auth::AuthorizationManager,
6 budget::{AsBudget, Budget},
7 events::{diagnostic::DiagnosticLevel, Events, InternalEventsBuffer},
8 host_object::{HostMap, HostObject, HostVec},
9 impl_bignum_host_fns, impl_bignum_host_fns_rhs_u32, impl_wrapping_obj_from_num,
10 impl_wrapping_obj_to_num,
11 num::*,
12 storage::Storage,
13 vm::{CustomContextVM, ModuleCache},
14 xdr::{
15 int128_helpers, AccountId, Asset, ContractCostType, ContractEventType, ContractExecutable,
16 ContractIdPreimage, ContractIdPreimageFromAddress, CreateContractArgs, Duration, Hash,
17 LedgerEntryData, PublicKey, ScAddress, ScBytes, ScErrorCode, ScErrorType, ScString,
18 ScSymbol, ScVal, TimePoint, Uint256,
19 },
20 AddressObject, Bool, BytesObject, Compare, ConversionError, EnvBase, Error, LedgerInfo,
21 MapObject, Object, StorageType, StringObject, Symbol, SymbolObject, TryFromVal, Val, VecObject,
22 VmCaller, VmCallerEnv, Void,
23};
24
25mod comparison;
26mod conversion;
27pub(crate) mod crypto;
28mod data_helper;
29mod declared_size;
30pub(crate) mod error;
31pub(crate) mod frame;
32pub(crate) mod ledger_info_helper;
33mod lifecycle;
34mod mem_helper;
35pub(crate) mod metered_clone;
36pub(crate) mod metered_hash;
37pub(crate) mod metered_map;
38pub(crate) mod metered_vector;
39pub(crate) mod metered_xdr;
40mod num;
41mod prng;
42pub(crate) mod trace;
43mod validity;
44
45pub use error::HostError;
46pub use prng::{Seed, SEED_BYTES};
47pub use trace::{TraceEvent, TraceHook, TraceRecord, TraceState};
48
49use self::{
50 frame::{Context, ContractReentryMode},
51 mem_helper::{MemFnArgs, MemFnArgsCustomVm, MemFnArgsCustomVmMut},
52 metered_clone::{MeteredClone, MeteredContainer},
53 metered_xdr::metered_write_xdr,
54 prng::Prng,
55};
56
57use crate::host::error::TryBorrowOrErr;
58#[cfg(any(test, feature = "testutils"))]
59pub use frame::ContractFunctionSet;
60pub(crate) use frame::Frame;
61#[cfg(any(test, feature = "recording_mode"))]
62use rand_chacha::ChaCha20Rng;
63use soroban_env_common::SymbolSmall;
64
65#[cfg(any(test, feature = "testutils"))]
66#[derive(Clone, Copy)]
67pub enum ContractInvocationEvent {
68 Start,
69 Finish,
70}
71
72#[cfg(any(test, feature = "testutils"))]
73pub type ContractInvocationHook = Rc<dyn for<'a> Fn(&'a Host, ContractInvocationEvent) -> ()>;
74
75#[cfg(any(test, feature = "testutils"))]
76#[derive(Clone, Default)]
77pub struct CoverageScoreboard {
78 pub vm_to_vm_calls: usize,
79}
80
81#[derive(Clone, Default)]
82struct HostImpl {
83 module_cache: RefCell<Option<ModuleCache>>,
84 shared_linker: RefCell<Option<wasmi::Linker<Host>>>,
85 source_account: RefCell<Option<AccountId>>,
86 ledger: RefCell<Option<LedgerInfo>>,
87 objects: RefCell<Vec<HostObject>>,
88 storage: RefCell<Storage>,
89 context_stack: RefCell<Vec<Context>>,
90 budget: Budget,
96 events: RefCell<InternalEventsBuffer>,
97 authorization_manager: RefCell<AuthorizationManager>,
98 diagnostic_level: RefCell<DiagnosticLevel>,
104 base_prng: RefCell<Option<Prng>>,
105 #[cfg(any(test, feature = "recording_mode"))]
112 recording_auth_nonce_prng: RefCell<Option<ChaCha20Rng>>,
113 #[cfg(any(test, feature = "testutils"))]
116 test_prng: RefCell<Option<ChaCha20Rng>>,
117 #[cfg(any(test, feature = "testutils"))]
122 contracts: RefCell<std::collections::BTreeMap<Hash, Rc<dyn ContractFunctionSet>>>,
123 #[cfg(any(test, feature = "testutils"))]
130 previous_authorization_manager: RefCell<Option<AuthorizationManager>>,
131 #[doc(hidden)]
135 trace_hook: RefCell<Option<TraceHook>>,
136 #[doc(hidden)]
140 #[cfg(any(test, feature = "testutils"))]
141 top_contract_invocation_hook: RefCell<Option<ContractInvocationHook>>,
142
143 #[doc(hidden)]
149 #[cfg(any(test, feature = "testutils"))]
150 coverage_scoreboard: RefCell<CoverageScoreboard>,
151
152 #[doc(hidden)]
153 #[cfg(any(test, feature = "recording_mode"))]
154 suppress_diagnostic_events: RefCell<bool>,
155
156 #[doc(hidden)]
161 #[cfg(any(test, feature = "recording_mode"))]
162 need_to_build_module_cache: RefCell<bool>,
163}
164
165#[derive(Clone)]
167pub struct Host(Rc<HostImpl>);
168
169#[allow(clippy::derivable_impls)]
170impl Default for Host {
171 fn default() -> Self {
172 #[cfg(all(not(target_family = "wasm"), feature = "tracy"))]
173 let _client = tracy_client::Client::start();
174 Self(Default::default())
175 }
176}
177
178macro_rules! impl_checked_borrow_helpers {
179 ($field:ident, $t:ty, $borrow:ident, $borrow_mut:ident) => {
180 impl Host {
181 #[allow(dead_code, unused_imports)]
182 pub(crate) fn $borrow(&self) -> Result<std::cell::Ref<'_, $t>, HostError> {
183 use crate::host::error::TryBorrowOrErr;
184 self.0.$field.try_borrow_or_err_with(
185 self,
186 concat!("host.0.", stringify!($field), ".try_borrow failed"),
187 )
188 }
189 #[allow(dead_code, unused_imports)]
190 pub(crate) fn $borrow_mut(&self) -> Result<std::cell::RefMut<'_, $t>, HostError> {
191 use crate::host::error::TryBorrowOrErr;
192 self.0.$field.try_borrow_mut_or_err_with(
193 self,
194 concat!("host.0.", stringify!($field), ".try_borrow_mut failed"),
195 )
196 }
197 }
198 };
199}
200impl_checked_borrow_helpers!(
201 module_cache,
202 Option<ModuleCache>,
203 try_borrow_module_cache,
204 try_borrow_module_cache_mut
205);
206impl_checked_borrow_helpers!(
207 shared_linker,
208 Option<wasmi::Linker<Host>>,
209 try_borrow_linker,
210 try_borrow_linker_mut
211);
212impl_checked_borrow_helpers!(
213 source_account,
214 Option<AccountId>,
215 try_borrow_source_account,
216 try_borrow_source_account_mut
217);
218impl_checked_borrow_helpers!(
219 ledger,
220 Option<LedgerInfo>,
221 try_borrow_ledger,
222 try_borrow_ledger_mut
223);
224impl_checked_borrow_helpers!(
225 objects,
226 Vec<HostObject>,
227 try_borrow_objects,
228 try_borrow_objects_mut
229);
230impl_checked_borrow_helpers!(storage, Storage, try_borrow_storage, try_borrow_storage_mut);
231impl_checked_borrow_helpers!(
232 context_stack,
233 Vec<Context>,
234 try_borrow_context_stack,
235 try_borrow_context_stack_mut
236);
237impl_checked_borrow_helpers!(
238 events,
239 InternalEventsBuffer,
240 try_borrow_events,
241 try_borrow_events_mut
242);
243impl_checked_borrow_helpers!(
244 authorization_manager,
245 AuthorizationManager,
246 try_borrow_authorization_manager,
247 try_borrow_authorization_manager_mut
248);
249
250impl_checked_borrow_helpers!(
256 base_prng,
257 Option<Prng>,
258 try_borrow_base_prng,
259 try_borrow_base_prng_mut
260);
261
262#[cfg(any(test, feature = "recording_mode"))]
263impl_checked_borrow_helpers!(
264 recording_auth_nonce_prng,
265 Option<ChaCha20Rng>,
266 try_borrow_recording_auth_nonce_prng,
267 try_borrow_recording_auth_nonce_prng_mut
268);
269
270#[cfg(any(test, feature = "testutils"))]
271impl_checked_borrow_helpers!(
272 test_prng,
273 Option<ChaCha20Rng>,
274 try_borrow_test_prng,
275 try_borrow_test_prng_mut
276);
277
278#[cfg(any(test, feature = "testutils"))]
279impl_checked_borrow_helpers!(contracts, std::collections::BTreeMap<Hash, Rc<dyn ContractFunctionSet>>, try_borrow_contracts, try_borrow_contracts_mut);
280
281#[cfg(any(test, feature = "testutils"))]
282impl_checked_borrow_helpers!(
283 previous_authorization_manager,
284 Option<AuthorizationManager>,
285 try_borrow_previous_authorization_manager,
286 try_borrow_previous_authorization_manager_mut
287);
288
289impl_checked_borrow_helpers!(
290 trace_hook,
291 Option<TraceHook>,
292 try_borrow_trace_hook,
293 try_borrow_trace_hook_mut
294);
295
296#[cfg(any(test, feature = "testutils"))]
297impl_checked_borrow_helpers!(
298 top_contract_invocation_hook,
299 Option<ContractInvocationHook>,
300 try_borrow_top_contract_invocation_hook,
301 try_borrow_top_contract_invocation_hook_mut
302);
303
304#[cfg(any(test, feature = "testutils"))]
305impl_checked_borrow_helpers!(
306 coverage_scoreboard,
307 CoverageScoreboard,
308 try_borrow_coverage_scoreboard,
309 try_borrow_coverage_scoreboard_mut
310);
311
312#[cfg(any(test, feature = "recording_mode"))]
313impl_checked_borrow_helpers!(
314 suppress_diagnostic_events,
315 bool,
316 try_borrow_suppress_diagnostic_events,
317 try_borrow_suppress_diagnostic_events_mut
318);
319
320#[cfg(any(test, feature = "recording_mode"))]
321impl_checked_borrow_helpers!(
322 need_to_build_module_cache,
323 bool,
324 try_borrow_need_to_build_module_cache,
325 try_borrow_need_to_build_module_cache_mut
326);
327
328impl Debug for HostImpl {
329 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
330 write!(f, "HostImpl(...)")
331 }
332}
333
334impl Debug for Host {
335 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
336 write!(f, "Host({:x})", Rc::<HostImpl>::as_ptr(&self.0) as usize)
337 }
338}
339
340impl Host {
341 pub fn vec_new_from_linear_memory_mem<M: CustomContextVM>(
342 &self,
343 m: M,
344 vals_pos: U32Val,
345 len: U32Val,
346 ) -> Result<VecObject, HostError> {
347 let MemFnArgsCustomVm { pos, len, .. } = self.get_mem_fn_args_custom_vm(&m, vals_pos, len);
348 Vec::<Val>::charge_bulk_init_cpy(len as u64, self)?;
349 let mut vals: Vec<Val> = vec![Val::VOID.to_val(); len as usize];
350 self.charge_budget(
352 ContractCostType::MemCpy,
353 Some((len as u64).saturating_mul(8)),
354 )?;
355 self.metered_vm_read_vals_from_linear_memory_mem::<8, Val, M>(
356 &m,
357 pos,
358 vals.as_mut_slice(),
359 |buf| Ok(Val::from_payload(u64::from_le_bytes(*buf))),
360 )?;
361
362 for v in vals.iter() {
363 self.check_val_integrity(*v)?;
364 }
365 self.add_host_object(HostVec::from_vec(vals)?)
366 }
367
368 pub fn map_unpack_to_linear_memory_fn_mem<M: CustomContextVM>(
369 &self,
370 m: &mut M,
371 map: MapObject,
372 keys_pos: U32Val,
373 vals_pos: U32Val,
374 len: U32Val,
375 ) -> Result<Void, HostError> {
376 let MemFnArgsCustomVmMut {
377 pos: keys_pos, len, ..
378 } = self.get_mem_fn_args_custom_vm_mut(m, keys_pos, len);
379 self.visit_obj(map, |mapobj: &HostMap| {
380 if mapobj.len() != len as usize {
381 return Err(self.err(
382 ScErrorType::Object,
383 ScErrorCode::UnexpectedSize,
384 "differing host map and output slice lengths when unpacking map to linear memory",
385 &[],
386 ));
387 }
388 self.metered_vm_scan_slices_in_linear_memory_mem(
390 m,
391 keys_pos,
392 len as usize,
393 |n, slice| {
394 let sym = Symbol::try_from(
395 mapobj.get_at_index(n, self).map_err(|he|
396 if he.error.is_type(ScErrorType::Budget) {
397 he
398 } else {
399 self.err(
400 ScErrorType::Object,
401 ScErrorCode::IndexBounds,
402 "vector out of bounds while unpacking map to linear memory",
403 &[],
404 )
405 }
406 )?.0
407 )?;
408 self.check_symbol_matches(slice, sym)?;
409 Ok(())
410 },
411 )?;
412
413 self.charge_budget(ContractCostType::MemCpy, Some((len as u64).saturating_mul(8)))?;
416
417 self.metered_vm_write_vals_to_linear_memory_mem(
418 m,
419 vals_pos.into(),
420 mapobj.map.as_slice(),
421 |pair| {
422 Ok(u64::to_le_bytes(
423 pair.1.get_payload(),
424 ))
425 },
426 )?;
427
428 Ok(())
429 })?;
430
431 Ok(Val::VOID)
432 }
433
434 pub fn bytes_new_from_linear_memory_mem<M: CustomContextVM>(
435 &self,
436 m: M,
437 lm_pos: U32Val,
438 len: U32Val,
439 ) -> Result<BytesObject, HostError> {
440 self.memobj_new_from_linear_memory_mem::<ScBytes, M>(&m, lm_pos, len)
441 }
442
443 pub fn string_new_from_linear_memory_mem<M: CustomContextVM>(
444 &self,
445 m: M,
446 lm_pos: U32Val,
447 len: U32Val,
448 ) -> Result<StringObject, HostError> {
449 self.memobj_new_from_linear_memory_mem::<ScString, M>(&m, lm_pos, len)
450 }
451
452 pub fn symbol_new_from_linear_memory_mem<M: CustomContextVM>(
453 &self,
454 m: M,
455 lm_pos: U32Val,
456 len: U32Val,
457 ) -> Result<SymbolObject, HostError> {
458 self.memobj_new_from_linear_memory_mem::<ScSymbol, M>(&m, lm_pos, len)
459 }
460
461 pub fn symbol_index_in_linear_memory_mem<M: CustomContextVM>(
462 &self,
463 m: M,
464 sym: Symbol,
465 lm_pos: U32Val,
466 len: U32Val,
467 ) -> Result<U32Val, HostError> {
468 let MemFnArgsCustomVm { mem, pos, len } = self.get_mem_fn_args_custom_vm(&m, lm_pos, len);
469 let mut found = None;
470 self.metered_vm_scan_slices_in_linear_memory_mem(mem, pos, len as usize, |i, slice| {
471 if self.symbol_matches(slice, sym)? {
472 if found.is_none() {
473 found = Some(self.usize_to_u32(i)?)
474 }
475 }
476 Ok(())
477 })?;
478 match found {
479 None => Err(self.err(
480 ScErrorType::Value,
481 ScErrorCode::MissingValue,
482 "symbol not found in linear memory slices",
483 &[sym.to_val()],
484 )),
485 Some(idx) => Ok(U32Val::from(idx)),
486 }
487 }
488
489 pub fn vec_unpack_to_linear_memory_mem<M: CustomContextVM>(
490 &self,
491 m: &mut M,
492 vec: VecObject,
493 vals_pos: U32Val,
494 len: U32Val,
495 ) -> Result<Void, HostError> {
496 let MemFnArgsCustomVmMut { mem, pos, len } =
497 self.get_mem_fn_args_custom_vm_mut(m, vals_pos, len);
498 self.visit_obj(vec, |vecobj: &HostVec| {
499 if vecobj.len() != len as usize {
500 return Err(self.err(
501 ScErrorType::Object,
502 ScErrorCode::UnexpectedSize,
503 "differing host vector and output vector lengths when unpacking vec to linear memory",
504 &[],
505 ));
506 }
507 self.charge_budget(ContractCostType::MemCpy, Some((len as u64).saturating_mul(8)))?;
509 self.metered_vm_write_vals_to_linear_memory_mem(
510 mem,
511 pos,
512 vecobj.as_slice(),
513 |x| {
514 Ok(u64::to_le_bytes(
515 x.get_payload(),
516 ))
517 },
518 )
519 })?;
520 Ok(Val::VOID)
521 }
522
523 pub fn bytes_copy_to_linear_memory_mem<M: CustomContextVM>(
524 &self,
525 m: &mut M,
526 b: BytesObject,
527 b_pos: U32Val,
528 lm_pos: U32Val,
529 len: U32Val,
530 ) -> Result<Void, HostError> {
531 self.memobj_copy_to_linear_memory_mem::<ScBytes, M>(m, b, b_pos, lm_pos, len)?;
532 Ok(Val::VOID)
533 }
534
535 pub fn with_storage_and_budget(storage: Storage, budget: Budget) -> Self {
539 #[cfg(all(not(target_family = "wasm"), feature = "tracy"))]
540 let _client = tracy_client::Client::start();
541 Self(Rc::new(HostImpl {
542 module_cache: RefCell::new(None),
543 shared_linker: RefCell::new(None),
544 source_account: RefCell::new(None),
545 ledger: RefCell::new(None),
546 objects: Default::default(),
547 storage: RefCell::new(storage),
548 context_stack: Default::default(),
549 budget,
550 events: Default::default(),
551 authorization_manager: RefCell::new(
552 AuthorizationManager::new_enforcing_without_authorizations(),
553 ),
554 diagnostic_level: Default::default(),
555 base_prng: RefCell::new(None),
556 #[cfg(any(test, feature = "recording_mode"))]
557 recording_auth_nonce_prng: RefCell::new(None),
558 #[cfg(any(test, feature = "testutils"))]
559 test_prng: RefCell::new(None),
560 #[cfg(any(test, feature = "testutils"))]
561 contracts: Default::default(),
562 #[cfg(any(test, feature = "testutils"))]
563 previous_authorization_manager: RefCell::new(None),
564 trace_hook: RefCell::new(None),
565 #[cfg(any(test, feature = "testutils"))]
566 top_contract_invocation_hook: RefCell::new(None),
567 #[cfg(any(test, feature = "testutils"))]
568 coverage_scoreboard: Default::default(),
569 #[cfg(any(test, feature = "recording_mode"))]
570 suppress_diagnostic_events: RefCell::new(false),
571 #[cfg(any(test, feature = "recording_mode"))]
572 need_to_build_module_cache: RefCell::new(false),
573 }))
574 }
575
576 pub fn build_module_cache_if_needed(&self) -> Result<(), HostError> {
577 if self.get_ledger_protocol_version()? >= ModuleCache::MIN_LEDGER_VERSION
578 && self.try_borrow_module_cache()?.is_none()
579 {
580 let cache = ModuleCache::new(self)?;
581 let linker = cache.make_linker(self)?;
582 *self.try_borrow_module_cache_mut()? = Some(cache);
583 *self.try_borrow_linker_mut()? = Some(linker);
584 }
585 Ok(())
586 }
587
588 #[cfg(any(test, feature = "recording_mode"))]
589 pub fn in_storage_recording_mode(&self) -> Result<bool, HostError> {
590 if let crate::storage::FootprintMode::Recording(_) = self.try_borrow_storage()?.mode {
591 Ok(true)
592 } else {
593 Ok(false)
594 }
595 }
596
597 #[cfg(any(test, feature = "recording_mode"))]
598 pub fn clear_module_cache(&self) -> Result<(), HostError> {
599 *self.try_borrow_module_cache_mut()? = None;
600 *self.try_borrow_linker_mut()? = None;
601 Ok(())
602 }
603
604 #[cfg(any(test, feature = "recording_mode"))]
605 pub fn rebuild_module_cache(&self) -> Result<(), HostError> {
606 self.clear_module_cache()?;
607 self.build_module_cache_if_needed()
608 }
609
610 pub fn set_source_account(&self, source_account: AccountId) -> Result<(), HostError> {
611 *self.try_borrow_source_account_mut()? = Some(source_account);
612 Ok(())
613 }
614
615 #[cfg(any(test, feature = "testutils"))]
616 pub fn remove_source_account(&self) -> Result<(), HostError> {
617 *self.try_borrow_source_account_mut()? = None;
618 Ok(())
619 }
620
621 #[cfg(any(test, feature = "testutils"))]
622 pub(crate) fn source_account_id(&self) -> Result<Option<AccountId>, HostError> {
623 self.try_borrow_source_account()?.metered_clone(self)
624 }
625
626 #[cfg(any(test, feature = "testutils"))]
627 pub(crate) fn with_test_prng<T>(
628 &self,
629 f: impl FnOnce(&mut ChaCha20Rng) -> Result<T, HostError>,
630 ) -> Result<T, HostError> {
631 let mut opt = self.try_borrow_test_prng_mut()?;
632 if let Some(p) = opt.as_mut() {
633 f(p)
634 } else {
635 Err(self.err(
636 ScErrorType::Context,
637 ScErrorCode::InternalError,
638 "missing test PRNG",
639 &[],
640 ))
641 }
642 }
643
644 #[cfg(any(test, feature = "recording_mode"))]
645 pub(crate) fn with_recording_auth_nonce_prng<T>(
646 &self,
647 f: impl FnOnce(&mut ChaCha20Rng) -> Result<T, HostError>,
648 ) -> Result<T, HostError> {
649 let mut opt = self.try_borrow_recording_auth_nonce_prng_mut()?;
650 if let Some(p) = opt.as_mut() {
651 f(p)
652 } else {
653 Err(self.err(
654 ScErrorType::Context,
655 ScErrorCode::InternalError,
656 "missing recording-auth nonce PRNG",
657 &[],
658 ))
659 }
660 }
661
662 pub fn source_account_address(&self) -> Result<Option<AddressObject>, HostError> {
663 if let Some(acc) = self.try_borrow_source_account()?.as_ref() {
664 Ok(Some(self.add_host_object(ScAddress::Account(
665 acc.metered_clone(self)?,
666 ))?))
667 } else {
668 Ok(None)
669 }
670 }
671
672 #[cfg(any(test, feature = "recording_mode"))]
673 pub fn switch_to_enforcing_storage(&self) -> Result<(), HostError> {
674 self.with_mut_storage(|storage| {
675 storage.mode = crate::storage::FootprintMode::Enforcing;
676 Ok(())
677 })
678 }
679
680 #[cfg(any(test, feature = "recording_mode"))]
681 pub fn switch_to_recording_auth(&self, disable_non_root_auth: bool) -> Result<(), HostError> {
682 *self.try_borrow_authorization_manager_mut()? =
683 AuthorizationManager::new_recording(disable_non_root_auth);
684 Ok(())
685 }
686
687 pub fn set_authorization_entries(
688 &self,
689 auth_entries: Vec<soroban_env_common::xdr::SorobanAuthorizationEntry>,
690 ) -> Result<(), HostError> {
691 let new_auth_manager = AuthorizationManager::new_enforcing(self, auth_entries)?;
692 *self.try_borrow_authorization_manager_mut()? = new_auth_manager;
693 Ok(())
694 }
695
696 #[allow(unused_variables)]
697 pub fn set_base_prng_seed(&self, seed: prng::Seed) -> Result<(), HostError> {
698 let mut base_prng = Prng::new_from_seed(seed, self.budget_ref())?;
699 let recording_auth_nonce_prng = base_prng.unmetered_raw_sub_prng();
703 let test_prng = base_prng.unmetered_raw_sub_prng();
704 #[cfg(any(test, feature = "testutils"))]
705 {
706 *self.try_borrow_test_prng_mut()? = Some(test_prng);
707 }
708 #[cfg(any(test, feature = "recording_mode"))]
709 {
710 *self.try_borrow_recording_auth_nonce_prng_mut()? = Some(recording_auth_nonce_prng);
711 }
712 *self.try_borrow_base_prng_mut()? = Some(base_prng);
713 Ok(())
714 }
715
716 pub fn get_ledger_info(&self) -> Result<Option<LedgerInfo>, HostError> {
717 let info = self.try_borrow_ledger()?;
718
719 Ok(info.clone())
720 }
721
722 pub fn set_ledger_info(&self, info: LedgerInfo) -> Result<(), HostError> {
723 *self.try_borrow_ledger_mut()? = Some(info);
724 Ok(())
725 }
726
727 pub fn with_ledger_info<F, T>(&self, f: F) -> Result<T, HostError>
728 where
729 F: FnOnce(&LedgerInfo) -> Result<T, HostError>,
730 {
731 match self.try_borrow_ledger()?.as_ref() {
732 None => Err(self.err(
733 ScErrorType::Context,
734 ScErrorCode::InternalError,
735 "missing ledger info",
736 &[],
737 )),
738 Some(li) => f(li),
739 }
740 }
741
742 pub fn with_mut_ledger_info<F>(&self, mut f: F) -> Result<(), HostError>
743 where
744 F: FnMut(&mut LedgerInfo),
745 {
746 match self.try_borrow_ledger_mut()?.as_mut() {
747 None => Err(self.err(
748 ScErrorType::Context,
749 ScErrorCode::InternalError,
750 "missing ledger info",
751 &[],
752 )),
753 Some(li) => {
754 f(li);
755 Ok(())
756 }
757 }
758 }
759
760 pub fn get_ledger_protocol_version(&self) -> Result<u32, HostError> {
761 self.with_ledger_info(|li| Ok(li.protocol_version))
762 }
763
764 pub(crate) fn budget_ref(&self) -> &Budget {
765 &self.0.budget
766 }
767
768 pub fn budget_cloned(&self) -> Budget {
769 self.0.budget.clone()
770 }
771
772 pub fn charge_budget(&self, ty: ContractCostType, input: Option<u64>) -> Result<(), HostError> {
773 self.0.budget.charge(ty, input)
774 }
775
776 pub fn set_shadow_budget_limits(&self, cpu: u64, mem: u64) -> Result<(), HostError> {
777 self.0.budget.set_shadow_limits(cpu, mem)
778 }
779
780 pub fn set_diagnostic_level(&self, diagnostic_level: DiagnosticLevel) -> Result<(), HostError> {
781 *self.0.diagnostic_level.try_borrow_mut_or_err()? = diagnostic_level;
782 Ok(())
783 }
784
785 pub fn enable_debug(&self) -> Result<(), HostError> {
787 self.set_diagnostic_level(DiagnosticLevel::Debug)
788 }
789
790 pub(crate) fn with_debug_mode<F>(&self, f: F)
810 where
811 F: FnOnce() -> Result<(), HostError>,
812 {
813 if let Ok(cell) = self.0.diagnostic_level.try_borrow_or_err() {
814 if matches!(*cell, DiagnosticLevel::Debug) {
815 return self.budget_ref().with_shadow_mode(f);
816 }
817 }
818 }
819
820 #[cfg(any(test, feature = "recording_mode"))]
825 pub(crate) fn with_suppressed_diagnostic_events<F>(&self, f: F) -> Result<(), HostError>
826 where
827 F: FnOnce() -> Result<(), HostError>,
828 {
829 *self.try_borrow_suppress_diagnostic_events_mut()? = true;
830 f()?;
831 *self.try_borrow_suppress_diagnostic_events_mut()? = false;
832 Ok(())
833 }
834
835 pub fn can_finish(&self) -> bool {
840 Rc::strong_count(&self.0) == 1
841 }
842
843 pub fn try_finish(self) -> Result<(Storage, Events), HostError> {
850 let events = self.try_borrow_events()?.externalize(&self)?;
851 Rc::try_unwrap(self.0)
852 .map(|host_impl| {
853 let storage = host_impl.storage.into_inner();
854 (storage, events)
855 })
856 .map_err(|_| {
857 Error::from_type_and_code(ScErrorType::Context, ScErrorCode::InternalError).into()
858 })
859 }
860}
861
862macro_rules! call_trace_env_call {
863 ($self:expr, $($arg:expr),*) => {
864 if $self.tracing_enabled()
865 {
866 $self.trace_env_call(function_short_name!(), &[$(&$arg),*])?;
867 }
868 };
869}
870
871macro_rules! call_trace_env_ret {
872 ($self:expr, $arg:expr) => {{
873 if $self.tracing_enabled() {
874 let dyn_res: Result<&dyn core::fmt::Debug, &HostError> = match &$arg {
875 Ok(ref ok) => Ok(ok),
876 Err(err) => Err(err),
877 };
878 $self.trace_env_ret(function_short_name!(), &dyn_res)?;
879 }
880 }};
881}
882
883impl EnvBase for Host {
885 type Error = HostError;
886
887 fn error_from_error_val(&self, e: soroban_env_common::Error) -> Self::Error {
888 self.error(e, "promoting Error to HostError", &[])
889 }
890
891 fn check_obj_integrity(&self, obj: Object) -> Result<(), HostError> {
892 use crate::{xdr, Tag};
893 self.visit_obj_untyped(obj, |hobj| match (hobj, obj.to_val().get_tag()) {
894 (HostObject::Vec(_), Tag::VecObject)
895 | (HostObject::Map(_), Tag::MapObject)
896 | (HostObject::U64(_), Tag::U64Object)
897 | (HostObject::I64(_), Tag::I64Object)
898 | (HostObject::TimePoint(_), Tag::TimepointObject)
899 | (HostObject::Duration(_), Tag::DurationObject)
900 | (HostObject::U128(_), Tag::U128Object)
901 | (HostObject::I128(_), Tag::I128Object)
902 | (HostObject::U256(_), Tag::U256Object)
903 | (HostObject::I256(_), Tag::I256Object)
904 | (HostObject::Bytes(_), Tag::BytesObject)
905 | (HostObject::String(_), Tag::StringObject)
906 | (HostObject::Symbol(_), Tag::SymbolObject)
907 | (HostObject::Address(_), Tag::AddressObject) => Ok(()),
908 _ => Err(self.err(
909 xdr::ScErrorType::Value,
910 xdr::ScErrorCode::InvalidInput,
911 "mis-tagged object reference",
912 &[],
913 )),
914 })
915 }
916
917 #[cfg(feature = "testutils")]
958 fn escalate_error_to_panic(&self, e: Self::Error) -> ! {
959 let _ = self.with_current_frame_opt(|f| {
960 if let Some(Frame::TestContract(frame)) = f {
961 if let Ok(mut panic) = frame.panic.try_borrow_mut() {
962 *panic = Some(e.error);
963 }
964 }
965 Ok(())
966 });
967 let escalation = self.error(e.error, "escalating error to panic", &[]);
968 panic!("{:?}", escalation)
969 }
970
971 fn augment_err_result<T>(&self, mut x: Result<T, Self::Error>) -> Result<T, Self::Error> {
972 if let Err(e) = &mut x {
973 if e.info.is_none() {
974 e.info = self.maybe_get_debug_info()
975 }
976 }
977 x
978 }
979
980 fn tracing_enabled(&self) -> bool {
981 match self.try_borrow_trace_hook() {
982 Ok(hook) => hook.is_some(),
983 Err(_) => false,
984 }
985 }
986
987 fn trace_env_call(&self, fname: &'static str, args: &[&dyn Debug]) -> Result<(), HostError> {
988 self.call_any_lifecycle_hook(TraceEvent::EnvCall(fname, args))
989 }
990
991 fn trace_env_ret(
992 &self,
993 fname: &'static str,
994 res: &Result<&dyn Debug, &HostError>,
995 ) -> Result<(), HostError> {
996 self.call_any_lifecycle_hook(TraceEvent::EnvRet(fname, res))
997 }
998
999 fn check_same_env(&self, other: &Self) -> Result<(), Self::Error> {
1000 if Rc::ptr_eq(&self.0, &other.0) {
1001 Ok(())
1002 } else {
1003 Err(self.err(
1004 ScErrorType::Context,
1005 ScErrorCode::InternalError,
1006 "check_same_env on different Hosts",
1007 &[],
1008 ))
1009 }
1010 }
1011
1012 fn bytes_copy_from_slice(
1013 &self,
1014 b: BytesObject,
1015 b_pos: U32Val,
1016 slice: &[u8],
1017 ) -> Result<BytesObject, HostError> {
1018 call_trace_env_call!(self, b, b_pos, slice.len());
1019 let res = self.memobj_copy_from_slice::<ScBytes>(b, b_pos, slice);
1020 call_trace_env_ret!(self, res);
1021 res
1022 }
1023
1024 fn bytes_copy_to_slice(
1025 &self,
1026 b: BytesObject,
1027 b_pos: U32Val,
1028 slice: &mut [u8],
1029 ) -> Result<(), HostError> {
1030 call_trace_env_call!(self, b, b_pos, slice.len());
1031 let res = self.memobj_copy_to_slice::<ScBytes>(b, b_pos, slice);
1032 call_trace_env_ret!(self, res);
1033 res
1034 }
1035
1036 fn string_copy_to_slice(
1037 &self,
1038 b: StringObject,
1039 b_pos: U32Val,
1040 slice: &mut [u8],
1041 ) -> Result<(), HostError> {
1042 call_trace_env_call!(self, b, b_pos, slice.len());
1043 let res = self.memobj_copy_to_slice::<ScString>(b, b_pos, slice);
1044 call_trace_env_ret!(self, res);
1045 res
1046 }
1047
1048 fn symbol_copy_to_slice(
1049 &self,
1050 s: SymbolObject,
1051 b_pos: U32Val,
1052 slice: &mut [u8],
1053 ) -> Result<(), HostError> {
1054 call_trace_env_call!(self, s, b_pos, slice.len());
1055 let res = self.memobj_copy_to_slice::<ScSymbol>(s, b_pos, slice);
1056 call_trace_env_ret!(self, res);
1057 res
1058 }
1059
1060 fn bytes_new_from_slice(&self, mem: &[u8]) -> Result<BytesObject, HostError> {
1061 call_trace_env_call!(self, mem.len());
1062 let res = self.add_host_object(self.scbytes_from_slice(mem)?);
1063 call_trace_env_ret!(self, res);
1064 res
1065 }
1066
1067 fn string_new_from_slice(&self, s: &[u8]) -> Result<StringObject, HostError> {
1068 call_trace_env_call!(self, s.len());
1069 let res = self.add_host_object(ScString(self.metered_slice_to_vec(s)?.try_into()?));
1070 call_trace_env_ret!(self, res);
1071 res
1072 }
1073
1074 fn symbol_new_from_slice(&self, s: &[u8]) -> Result<SymbolObject, HostError> {
1075 call_trace_env_call!(self, s.len());
1076 self.charge_budget(ContractCostType::MemCmp, Some(s.len() as u64))?;
1080 for b in s {
1081 SymbolSmall::validate_byte(*b).map_err(|_| {
1082 self.err(
1083 ScErrorType::Value,
1084 ScErrorCode::InvalidInput,
1085 "byte is not allowed in Symbol",
1086 &[(*b as u32).into()],
1087 )
1088 })?;
1089 }
1090 let res = self.add_host_object(ScSymbol(self.metered_slice_to_vec(s)?.try_into()?));
1091 call_trace_env_ret!(self, res);
1092 res
1093 }
1094
1095 fn map_new_from_slices(&self, keys: &[&str], vals: &[Val]) -> Result<MapObject, HostError> {
1096 call_trace_env_call!(self, keys.len());
1097 if keys.len() != vals.len() {
1098 return Err(self.err(
1099 ScErrorType::Object,
1100 ScErrorCode::UnexpectedSize,
1101 "differing key and value slice lengths when creating map from slices",
1102 &[],
1103 ));
1104 }
1105 Vec::<(Val, Val)>::charge_bulk_init_cpy(keys.len() as u64, self)?;
1106 let map_vec = keys
1107 .iter()
1108 .zip(vals.iter().copied())
1109 .map(|(key_str, val)| {
1110 let sym = Symbol::try_from_val(self, key_str)?;
1111 self.check_val_integrity(val)?;
1112 Ok((sym.to_val(), val))
1113 })
1114 .collect::<Result<Vec<(Val, Val)>, HostError>>()?;
1115 let map = HostMap::from_map(map_vec, self)?;
1116 let res = self.add_host_object(map);
1117 call_trace_env_ret!(self, res);
1118 res
1119 }
1120
1121 fn map_unpack_to_slice(
1122 &self,
1123 map: MapObject,
1124 keys: &[&str],
1125 vals: &mut [Val],
1126 ) -> Result<Void, HostError> {
1127 call_trace_env_call!(self, map, keys.len());
1128 if keys.len() != vals.len() {
1129 return Err(self.err(
1130 ScErrorType::Object,
1131 ScErrorCode::UnexpectedSize,
1132 "differing key and value slice lengths when unpacking map to slice",
1133 &[],
1134 ));
1135 }
1136 self.visit_obj(map, |hm: &HostMap| {
1137 if hm.len() != vals.len() {
1138 return Err(self.err(
1139 ScErrorType::Object,
1140 ScErrorCode::UnexpectedSize,
1141 "differing host map and output slice lengths when unpacking map to slice",
1142 &[],
1143 ));
1144 }
1145
1146 for (ik, mk) in keys.iter().zip(hm.keys(self)?) {
1147 let sym: Symbol = mk.try_into()?;
1148 self.check_symbol_matches(ik.as_bytes(), sym)?;
1149 }
1150
1151 metered_clone::charge_shallow_copy::<Val>(keys.len() as u64, self)?;
1152 for (iv, mv) in vals.iter_mut().zip(hm.values(self)?) {
1153 *iv = *mv;
1154 }
1155 Ok(())
1156 })?;
1157 let res = Ok(Val::VOID);
1158 call_trace_env_ret!(self, res);
1159 res
1160 }
1161
1162 fn vec_new_from_slice(&self, vals: &[Val]) -> Result<VecObject, Self::Error> {
1163 call_trace_env_call!(self, vals.len());
1164 let vec = HostVec::from_exact_iter(vals.iter().cloned(), self.budget_ref())?;
1165 for v in vec.iter() {
1166 self.check_val_integrity(*v)?;
1167 }
1168 let res = self.add_host_object(vec);
1169 call_trace_env_ret!(self, res);
1170 res
1171 }
1172
1173 fn vec_unpack_to_slice(&self, vec: VecObject, vals: &mut [Val]) -> Result<Void, Self::Error> {
1174 call_trace_env_call!(self, vec, vals.len());
1175 self.visit_obj(vec, |hv: &HostVec| {
1176 if hv.len() != vals.len() {
1177 return Err(self.err(
1178 ScErrorType::Object,
1179 ScErrorCode::UnexpectedSize,
1180 "differing host vector and output vector lengths when unpacking vec to slice",
1181 &[],
1182 ));
1183 }
1184 metered_clone::charge_shallow_copy::<Val>(hv.len() as u64, self)?;
1185 vals.copy_from_slice(hv.as_slice());
1186 Ok(())
1187 })?;
1188 let res = Ok(Val::VOID);
1189 call_trace_env_ret!(self, res);
1190 res
1191 }
1192
1193 fn symbol_index_in_strs(&self, sym: Symbol, slices: &[&str]) -> Result<U32Val, Self::Error> {
1194 call_trace_env_call!(self, sym, slices.len());
1195 let mut found = None;
1196 for (i, slice) in slices.iter().enumerate() {
1197 if self.symbol_matches(slice.as_bytes(), sym)? && found.is_none() {
1198 found = Some(i)
1199 }
1200 }
1201 let res = match found {
1202 None => Err(self.err(
1203 ScErrorType::Value,
1204 ScErrorCode::InvalidInput,
1205 "symbol not found in slice of strs",
1206 &[sym.to_val()],
1207 )),
1208 Some(idx) => Ok(U32Val::from(self.usize_to_u32(idx)?)),
1209 };
1210 call_trace_env_ret!(self, res);
1211 res
1212 }
1213
1214 fn log_from_slice(&self, msg: &str, vals: &[Val]) -> Result<Void, HostError> {
1215 call_trace_env_call!(self, msg.len(), vals.len());
1216 self.log_diagnostics(msg, vals);
1217 let res = Ok(Void::from(()));
1218 call_trace_env_ret!(self, res);
1219 res
1220 }
1221
1222 fn check_protocol_version_lower_bound(&self, lower: u32) -> Result<(), Self::Error> {
1223 self.with_ledger_info(|li| {
1224 let proto = li.protocol_version;
1225 if proto < lower {
1226 Err(self.err(
1227 ScErrorType::Context,
1228 ScErrorCode::IndexBounds,
1229 "ledger protocol {} is less than specified lower bound {}",
1230 &[Val::from_u32(proto).into(), Val::from_u32(lower).into()],
1231 ))
1232 } else {
1233 Ok(())
1234 }
1235 })
1236 }
1237
1238 fn check_protocol_version_upper_bound(&self, upper: u32) -> Result<(), Self::Error> {
1239 self.with_ledger_info(|li| {
1240 let proto = li.protocol_version;
1241 if proto > upper {
1242 Err(self.err(
1243 ScErrorType::Context,
1244 ScErrorCode::IndexBounds,
1245 "ledger protocol {} is larger than specified upper bound {}",
1246 &[Val::from_u32(proto).into(), Val::from_u32(upper).into()],
1247 ))
1248 } else {
1249 Ok(())
1250 }
1251 })
1252 }
1253}
1254
1255impl VmCallerEnv for Host {
1256 type VmUserState = Host;
1257
1258 fn log_from_linear_memory(
1262 &self,
1263 vmcaller: &mut VmCaller<Host>,
1264 msg_pos: U32Val,
1265 msg_len: U32Val,
1266 vals_pos: U32Val,
1267 vals_len: U32Val,
1268 ) -> Result<Void, HostError> {
1269 self.with_debug_mode(|| {
1270 let MemFnArgs { vm, pos, len } = self.get_mem_fn_args(msg_pos, msg_len)?;
1271 Vec::<u8>::charge_bulk_init_cpy(len as u64, self)?;
1272 let mut msg: Vec<u8> = vec![0u8; len as usize];
1273 self.metered_vm_read_bytes_from_linear_memory(vmcaller, &vm, pos, &mut msg)?;
1274 Vec::<u8>::charge_bulk_init_cpy(len as u64, self)?;
1276 let msg = String::from_utf8_lossy(&msg);
1277
1278 let MemFnArgs { vm, pos, len } = self.get_mem_fn_args(vals_pos, vals_len)?;
1279 Vec::<Val>::charge_bulk_init_cpy((len as u64).saturating_add(1), self)?;
1280 let mut vals: Vec<Val> = vec![Val::VOID.to_val(); len as usize];
1281 self.charge_budget(
1283 ContractCostType::MemCpy,
1284 Some((len as u64).saturating_mul(8)),
1285 )?;
1286 self.metered_vm_read_vals_from_linear_memory::<8, Val>(
1287 vmcaller,
1288 &vm,
1289 pos,
1290 vals.as_mut_slice(),
1291 |buf| self.relative_to_absolute(Val::from_payload(u64::from_le_bytes(*buf))),
1292 )?;
1293 self.log_diagnostics(&msg, &vals);
1294 Ok(())
1295 });
1296
1297 Ok(Val::VOID)
1298 }
1299
1300 fn obj_cmp(&self, _vmcaller: &mut VmCaller<Host>, a: Val, b: Val) -> Result<i64, HostError> {
1302 let res = match {
1303 match (Object::try_from(a), Object::try_from(b)) {
1304 (Ok(a), Ok(b)) => self.visit_obj_untyped(a, |ao| {
1306 self.visit_obj_untyped(b, |bo| Ok(Some(self.compare(&ao, &bo)?)))
1308 })?,
1309
1310 (Ok(a), Err(_)) => self
1312 .visit_obj_untyped(a, |aobj| aobj.try_compare_to_small(self.as_budget(), b))?,
1313 (Err(_), Ok(b)) => self.visit_obj_untyped(b, |bobj| {
1315 let ord = bobj.try_compare_to_small(self.as_budget(), a)?;
1316 Ok(match ord {
1317 Some(Ordering::Less) => Some(Ordering::Greater),
1318 Some(Ordering::Greater) => Some(Ordering::Less),
1319 other => other,
1320 })
1321 })?,
1322 (Err(_), Err(_)) => {
1324 return Err(self.err(
1325 ScErrorType::Value,
1326 ScErrorCode::UnexpectedType,
1327 "two non-object args to obj_cmp",
1328 &[a, b],
1329 ));
1330 }
1331 }
1332 } {
1333 Some(res) => res,
1335
1336 None => {
1339 let atype = a.get_tag().get_scval_type();
1340 let btype = b.get_tag().get_scval_type();
1341 if atype == btype {
1342 return Err(self.err(
1344 ScErrorType::Value,
1345 ScErrorCode::InternalError,
1346 "equal-tagged values rejected by small-value obj_cmp",
1347 &[a, b],
1348 ));
1349 }
1350 atype.cmp(&btype)
1351 }
1352 };
1353 Ok(match res {
1355 Ordering::Less => -1,
1356 Ordering::Equal => 0,
1357 Ordering::Greater => 1,
1358 })
1359 }
1360
1361 fn contract_event(
1362 &self,
1363 _vmcaller: &mut VmCaller<Host>,
1364 topics: VecObject,
1365 data: Val,
1366 ) -> Result<Void, HostError> {
1367 self.record_contract_event(ContractEventType::Contract, topics, data)?;
1368 Ok(Val::VOID)
1369 }
1370
1371 fn get_ledger_version(&self, _vmcaller: &mut VmCaller<Host>) -> Result<U32Val, Self::Error> {
1372 Ok(self.get_ledger_protocol_version()?.into())
1373 }
1374
1375 fn get_ledger_sequence(&self, _vmcaller: &mut VmCaller<Host>) -> Result<U32Val, Self::Error> {
1376 self.with_ledger_info(|li| Ok(li.sequence_number.into()))
1377 }
1378
1379 fn get_ledger_timestamp(&self, _vmcaller: &mut VmCaller<Host>) -> Result<U64Val, Self::Error> {
1380 self.with_ledger_info(|li| Ok(U64Val::try_from_val(self, &li.timestamp)?))
1381 }
1382
1383 fn fail_with_error(
1384 &self,
1385 _vmcaller: &mut VmCaller<Self::VmUserState>,
1386 error: Error,
1387 ) -> Result<Void, Self::Error> {
1388 if error.is_type(ScErrorType::Contract) {
1389 Err(self.error(
1390 error,
1391 "failing with contract error",
1392 &[U32Val::from(error.get_code()).to_val()],
1393 ))
1394 } else {
1395 Err(self.err(
1396 ScErrorType::Context,
1397 ScErrorCode::UnexpectedType,
1398 "contract attempted to fail with non-ContractError error code",
1399 &[error.to_val()],
1400 ))
1401 }
1402 }
1403
1404 fn get_ledger_network_id(
1405 &self,
1406 _vmcaller: &mut VmCaller<Host>,
1407 ) -> Result<BytesObject, Self::Error> {
1408 self.with_ledger_info(|li| {
1409 self.add_host_object(self.scbytes_from_slice(li.network_id.as_slice())?)
1411 })
1412 }
1413
1414 fn get_current_contract_address(
1416 &self,
1417 _vmcaller: &mut VmCaller<Host>,
1418 ) -> Result<AddressObject, HostError> {
1419 self.add_host_object(ScAddress::Contract(
1421 self.get_current_contract_id_internal()?,
1422 ))
1423 }
1424
1425 fn get_max_live_until_ledger(
1426 &self,
1427 _vmcaller: &mut VmCaller<Host>,
1428 ) -> Result<U32Val, Self::Error> {
1429 Ok(self.max_live_until_ledger()?.into())
1430 }
1431
1432 impl_wrapping_obj_from_num!(obj_from_u64, u64, U64Object, u64);
1437 impl_wrapping_obj_to_num!(obj_to_u64, u64, U64Object, u64);
1438 impl_wrapping_obj_from_num!(obj_from_i64, i64, I64Object, i64);
1439 impl_wrapping_obj_to_num!(obj_to_i64, i64, I64Object, i64);
1440 impl_wrapping_obj_from_num!(timepoint_obj_from_u64, TimePoint, TimepointObject, u64);
1441 impl_wrapping_obj_to_num!(timepoint_obj_to_u64, TimePoint, TimepointObject, u64);
1442 impl_wrapping_obj_from_num!(duration_obj_from_u64, Duration, DurationObject, u64);
1443 impl_wrapping_obj_to_num!(duration_obj_to_u64, Duration, DurationObject, u64);
1444
1445 fn obj_from_u128_pieces(
1446 &self,
1447 _vmcaller: &mut VmCaller<Self::VmUserState>,
1448 hi: u64,
1449 lo: u64,
1450 ) -> Result<U128Object, Self::Error> {
1451 self.add_host_object(int128_helpers::u128_from_pieces(hi, lo))
1452 }
1453
1454 fn obj_to_u128_lo64(
1455 &self,
1456 _vmcaller: &mut VmCaller<Self::VmUserState>,
1457 obj: U128Object,
1458 ) -> Result<u64, Self::Error> {
1459 self.visit_obj(obj, |u: &u128| Ok(int128_helpers::u128_lo(*u)))
1460 }
1461
1462 fn obj_to_u128_hi64(
1463 &self,
1464 _vmcaller: &mut VmCaller<Self::VmUserState>,
1465 obj: U128Object,
1466 ) -> Result<u64, Self::Error> {
1467 self.visit_obj(obj, |u: &u128| Ok(int128_helpers::u128_hi(*u)))
1468 }
1469
1470 fn obj_from_i128_pieces(
1471 &self,
1472 _vmcaller: &mut VmCaller<Self::VmUserState>,
1473 hi: i64,
1474 lo: u64,
1475 ) -> Result<I128Object, Self::Error> {
1476 self.add_host_object(int128_helpers::i128_from_pieces(hi, lo))
1477 }
1478
1479 fn obj_to_i128_lo64(
1480 &self,
1481 _vmcaller: &mut VmCaller<Self::VmUserState>,
1482 obj: I128Object,
1483 ) -> Result<u64, Self::Error> {
1484 self.visit_obj(obj, |i: &i128| Ok(int128_helpers::i128_lo(*i)))
1485 }
1486
1487 fn obj_to_i128_hi64(
1488 &self,
1489 _vmcaller: &mut VmCaller<Self::VmUserState>,
1490 obj: I128Object,
1491 ) -> Result<i64, Self::Error> {
1492 self.visit_obj(obj, |i: &i128| Ok(int128_helpers::i128_hi(*i)))
1493 }
1494
1495 fn obj_from_u256_pieces(
1496 &self,
1497 _vmcaller: &mut VmCaller<Self::VmUserState>,
1498 hi_hi: u64,
1499 hi_lo: u64,
1500 lo_hi: u64,
1501 lo_lo: u64,
1502 ) -> Result<U256Object, Self::Error> {
1503 self.add_host_object(u256_from_pieces(hi_hi, hi_lo, lo_hi, lo_lo))
1504 }
1505
1506 fn u256_val_from_be_bytes(
1507 &self,
1508 _vmcaller: &mut VmCaller<Self::VmUserState>,
1509 bytes: BytesObject,
1510 ) -> Result<U256Val, HostError> {
1511 let num = self.visit_obj(bytes, |b: &ScBytes| {
1512 Ok(U256::from_be_bytes(self.fixed_length_bytes_from_slice(
1513 "U256 bytes",
1514 b.as_slice(),
1515 )?))
1516 })?;
1517 self.map_err(U256Val::try_from_val(self, &num))
1518 }
1519
1520 fn u256_val_to_be_bytes(
1521 &self,
1522 _vmcaller: &mut VmCaller<Self::VmUserState>,
1523 val: U256Val,
1524 ) -> Result<BytesObject, HostError> {
1525 if let Ok(so) = U256Small::try_from(val) {
1526 self.add_host_object(self.scbytes_from_slice(&U256::from(so).to_be_bytes())?)
1527 } else {
1528 let obj = val.try_into()?;
1529 let scb = self.visit_obj(obj, |u: &U256| self.scbytes_from_slice(&u.to_be_bytes()))?;
1530 self.add_host_object(scb)
1531 }
1532 }
1533
1534 fn obj_to_u256_hi_hi(
1535 &self,
1536 _vmcaller: &mut VmCaller<Self::VmUserState>,
1537 obj: U256Object,
1538 ) -> Result<u64, HostError> {
1539 self.visit_obj(obj, |u: &U256| {
1540 let (hi_hi, _, _, _) = u256_into_pieces(*u);
1541 Ok(hi_hi)
1542 })
1543 }
1544
1545 fn obj_to_u256_hi_lo(
1546 &self,
1547 _vmcaller: &mut VmCaller<Self::VmUserState>,
1548 obj: U256Object,
1549 ) -> Result<u64, HostError> {
1550 self.visit_obj(obj, |u: &U256| {
1551 let (_, hi_lo, _, _) = u256_into_pieces(*u);
1552 Ok(hi_lo)
1553 })
1554 }
1555
1556 fn obj_to_u256_lo_hi(
1557 &self,
1558 _vmcaller: &mut VmCaller<Self::VmUserState>,
1559 obj: U256Object,
1560 ) -> Result<u64, HostError> {
1561 self.visit_obj(obj, |u: &U256| {
1562 let (_, _, lo_hi, _) = u256_into_pieces(*u);
1563 Ok(lo_hi)
1564 })
1565 }
1566
1567 fn obj_to_u256_lo_lo(
1568 &self,
1569 _vmcaller: &mut VmCaller<Self::VmUserState>,
1570 obj: U256Object,
1571 ) -> Result<u64, HostError> {
1572 self.visit_obj(obj, |u: &U256| {
1573 let (_, _, _, lo_lo) = u256_into_pieces(*u);
1574 Ok(lo_lo)
1575 })
1576 }
1577
1578 fn obj_from_i256_pieces(
1579 &self,
1580 _vmcaller: &mut VmCaller<Self::VmUserState>,
1581 hi_hi: i64,
1582 hi_lo: u64,
1583 lo_hi: u64,
1584 lo_lo: u64,
1585 ) -> Result<I256Object, Self::Error> {
1586 self.add_host_object(i256_from_pieces(hi_hi, hi_lo, lo_hi, lo_lo))
1587 }
1588
1589 fn i256_val_from_be_bytes(
1590 &self,
1591 _vmcaller: &mut VmCaller<Self::VmUserState>,
1592 bytes: BytesObject,
1593 ) -> Result<I256Val, HostError> {
1594 let num = self.visit_obj(bytes, |b: &ScBytes| {
1595 Ok(I256::from_be_bytes(self.fixed_length_bytes_from_slice(
1596 "I256 bytes",
1597 b.as_slice(),
1598 )?))
1599 })?;
1600 I256Val::try_from_val(self, &num).map_err(|_| ConversionError.into())
1601 }
1602
1603 fn i256_val_to_be_bytes(
1604 &self,
1605 _vmcaller: &mut VmCaller<Self::VmUserState>,
1606 val: I256Val,
1607 ) -> Result<BytesObject, HostError> {
1608 if let Ok(so) = I256Small::try_from(val) {
1609 self.add_host_object(self.scbytes_from_slice(&I256::from(so).to_be_bytes())?)
1610 } else {
1611 let obj = val.try_into()?;
1612 let scb = self.visit_obj(obj, |i: &I256| self.scbytes_from_slice(&i.to_be_bytes()))?;
1613 self.add_host_object(scb)
1614 }
1615 }
1616
1617 fn obj_to_i256_hi_hi(
1618 &self,
1619 _vmcaller: &mut VmCaller<Self::VmUserState>,
1620 obj: I256Object,
1621 ) -> Result<i64, HostError> {
1622 self.visit_obj(obj, |i: &I256| {
1623 let (hi_hi, _, _, _) = i256_into_pieces(*i);
1624 Ok(hi_hi)
1625 })
1626 }
1627
1628 fn obj_to_i256_hi_lo(
1629 &self,
1630 _vmcaller: &mut VmCaller<Self::VmUserState>,
1631 obj: I256Object,
1632 ) -> Result<u64, HostError> {
1633 self.visit_obj(obj, |i: &I256| {
1634 let (_, hi_lo, _, _) = i256_into_pieces(*i);
1635 Ok(hi_lo)
1636 })
1637 }
1638
1639 fn obj_to_i256_lo_hi(
1640 &self,
1641 _vmcaller: &mut VmCaller<Self::VmUserState>,
1642 obj: I256Object,
1643 ) -> Result<u64, HostError> {
1644 self.visit_obj(obj, |i: &I256| {
1645 let (_, _, lo_hi, _) = i256_into_pieces(*i);
1646 Ok(lo_hi)
1647 })
1648 }
1649
1650 fn obj_to_i256_lo_lo(
1651 &self,
1652 _vmcaller: &mut VmCaller<Self::VmUserState>,
1653 obj: I256Object,
1654 ) -> Result<u64, HostError> {
1655 self.visit_obj(obj, |i: &I256| {
1656 let (_, _, _, lo_lo) = i256_into_pieces(*i);
1657 Ok(lo_lo)
1658 })
1659 }
1660
1661 impl_bignum_host_fns!(u256_add, checked_add, U256, U256Val, Int256AddSub);
1662 impl_bignum_host_fns!(u256_sub, checked_sub, U256, U256Val, Int256AddSub);
1663 impl_bignum_host_fns!(u256_mul, checked_mul, U256, U256Val, Int256Mul);
1664 impl_bignum_host_fns!(u256_div, checked_div, U256, U256Val, Int256Div);
1665 impl_bignum_host_fns!(
1666 u256_rem_euclid,
1667 checked_rem_euclid,
1668 U256,
1669 U256Val,
1670 Int256Div
1671 );
1672 impl_bignum_host_fns_rhs_u32!(u256_pow, checked_pow, U256, U256Val, Int256Pow);
1673 impl_bignum_host_fns_rhs_u32!(u256_shl, checked_shl, U256, U256Val, Int256Shift);
1674 impl_bignum_host_fns_rhs_u32!(u256_shr, checked_shr, U256, U256Val, Int256Shift);
1675
1676 impl_bignum_host_fns!(i256_add, checked_add, I256, I256Val, Int256AddSub);
1677 impl_bignum_host_fns!(i256_sub, checked_sub, I256, I256Val, Int256AddSub);
1678 impl_bignum_host_fns!(i256_mul, checked_mul, I256, I256Val, Int256Mul);
1679 impl_bignum_host_fns!(i256_div, checked_div, I256, I256Val, Int256Div);
1680 impl_bignum_host_fns!(
1681 i256_rem_euclid,
1682 checked_rem_euclid,
1683 I256,
1684 I256Val,
1685 Int256Div
1686 );
1687 impl_bignum_host_fns_rhs_u32!(i256_pow, checked_pow, I256, I256Val, Int256Pow);
1688 impl_bignum_host_fns_rhs_u32!(i256_shl, checked_shl, I256, I256Val, Int256Shift);
1689 impl_bignum_host_fns_rhs_u32!(i256_shr, checked_shr, I256, I256Val, Int256Shift);
1690
1691 fn map_new(&self, _vmcaller: &mut VmCaller<Host>) -> Result<MapObject, HostError> {
1695 self.add_host_object(HostMap::new())
1696 }
1697
1698 fn map_put(
1699 &self,
1700 _vmcaller: &mut VmCaller<Host>,
1701 m: MapObject,
1702 k: Val,
1703 v: Val,
1704 ) -> Result<MapObject, HostError> {
1705 let mnew = self.visit_obj(m, |hm: &HostMap| hm.insert(k, v, self))?;
1706 self.add_host_object(mnew)
1707 }
1708
1709 fn map_get(
1710 &self,
1711 _vmcaller: &mut VmCaller<Host>,
1712 m: MapObject,
1713 k: Val,
1714 ) -> Result<Val, HostError> {
1715 self.visit_obj(m, |hm: &HostMap| {
1716 hm.get(&k, self)?.copied().ok_or_else(|| {
1717 self.err(
1718 ScErrorType::Object,
1719 ScErrorCode::MissingValue,
1720 "map key not found in map_get",
1721 &[m.to_val(), k],
1722 )
1723 })
1724 })
1725 }
1726
1727 fn map_del(
1728 &self,
1729 _vmcaller: &mut VmCaller<Host>,
1730 m: MapObject,
1731 k: Val,
1732 ) -> Result<MapObject, HostError> {
1733 match self.visit_obj(m, |hm: &HostMap| hm.remove(&k, self))? {
1734 Some((mnew, _)) => Ok(self.add_host_object(mnew)?),
1735 None => Err(self.err(
1736 ScErrorType::Object,
1737 ScErrorCode::MissingValue,
1738 "map key not found in map_del",
1739 &[m.to_val(), k],
1740 )),
1741 }
1742 }
1743
1744 fn map_len(&self, _vmcaller: &mut VmCaller<Host>, m: MapObject) -> Result<U32Val, HostError> {
1745 let len = self.visit_obj(m, |hm: &HostMap| Ok(hm.len()))?;
1746 self.usize_to_u32val(len)
1747 }
1748
1749 fn map_has(
1750 &self,
1751 _vmcaller: &mut VmCaller<Host>,
1752 m: MapObject,
1753 k: Val,
1754 ) -> Result<Bool, HostError> {
1755 self.visit_obj(m, |hm: &HostMap| Ok(hm.contains_key(&k, self)?.into()))
1756 }
1757
1758 fn map_key_by_pos(
1759 &self,
1760 _vmcaller: &mut VmCaller<Host>,
1761 m: MapObject,
1762 i: U32Val,
1763 ) -> Result<Val, HostError> {
1764 let i: u32 = i.into();
1765 self.visit_obj(m, |hm: &HostMap| {
1766 hm.get_at_index(i as usize, self).map(|r| r.0)
1767 })
1768 }
1769
1770 fn map_val_by_pos(
1771 &self,
1772 _vmcaller: &mut VmCaller<Host>,
1773 m: MapObject,
1774 i: U32Val,
1775 ) -> Result<Val, HostError> {
1776 let i: u32 = i.into();
1777 self.visit_obj(m, |hm: &HostMap| {
1778 hm.get_at_index(i as usize, self).map(|r| r.1)
1779 })
1780 }
1781
1782 fn map_keys(
1783 &self,
1784 _vmcaller: &mut VmCaller<Host>,
1785 m: MapObject,
1786 ) -> Result<VecObject, HostError> {
1787 let vec = self.visit_obj(m, |hm: &HostMap| {
1788 HostVec::from_exact_iter(hm.keys(self)?.cloned(), self.budget_ref())
1789 })?;
1790 self.add_host_object(vec)
1791 }
1792
1793 fn map_values(
1794 &self,
1795 _vmcaller: &mut VmCaller<Host>,
1796 m: MapObject,
1797 ) -> Result<VecObject, HostError> {
1798 let vec = self.visit_obj(m, |hm: &HostMap| {
1799 HostVec::from_exact_iter(hm.values(self)?.cloned(), self.budget_ref())
1800 })?;
1801 self.add_host_object(vec)
1802 }
1803
1804 fn map_new_from_linear_memory(
1805 &self,
1806 vmcaller: &mut VmCaller<Host>,
1807 keys_pos: U32Val,
1808 vals_pos: U32Val,
1809 len: U32Val,
1810 ) -> Result<MapObject, HostError> {
1811 let MemFnArgs {
1813 vm,
1814 pos: keys_pos,
1815 len,
1816 } = self.get_mem_fn_args(keys_pos, len)?;
1817 let mut key_syms = Vec::<Symbol>::with_metered_capacity(len as usize, self)?;
1818 self.metered_vm_scan_slices_in_linear_memory(
1819 vmcaller,
1820 &vm,
1821 keys_pos,
1822 len as usize,
1823 |_n, slice| {
1824 self.charge_budget(ContractCostType::MemCpy, Some(slice.len() as u64))?;
1827 let scsym = ScSymbol(slice.try_into()?);
1828 let sym = Symbol::try_from(self.to_valid_host_val(&ScVal::Symbol(scsym))?)?;
1829 key_syms.push(sym);
1830 Ok(())
1831 },
1832 )?;
1833
1834 let vals_pos: u32 = vals_pos.into();
1836 Vec::<Val>::charge_bulk_init_cpy(len as u64, self)?;
1837 let mut vals: Vec<Val> = vec![Val::VOID.into(); len as usize];
1838 self.charge_budget(
1840 ContractCostType::MemCpy,
1841 Some((len as u64).saturating_mul(8)),
1842 )?;
1843 self.metered_vm_read_vals_from_linear_memory::<8, Val>(
1844 vmcaller,
1845 &vm,
1846 vals_pos,
1847 vals.as_mut_slice(),
1848 |buf| self.relative_to_absolute(Val::from_payload(u64::from_le_bytes(*buf))),
1849 )?;
1850 for v in vals.iter() {
1851 self.check_val_integrity(*v)?;
1852 }
1853
1854 let pair_iter = key_syms
1856 .iter()
1857 .map(|s| s.to_val())
1858 .zip(vals.iter().cloned());
1859 let map = HostMap::from_exact_iter(pair_iter, self)?;
1860 self.add_host_object(map)
1861 }
1862
1863 fn map_unpack_to_linear_memory(
1864 &self,
1865 vmcaller: &mut VmCaller<Host>,
1866 map: MapObject,
1867 keys_pos: U32Val,
1868 vals_pos: U32Val,
1869 len: U32Val,
1870 ) -> Result<Void, HostError> {
1871 let MemFnArgs {
1872 vm,
1873 pos: keys_pos,
1874 len,
1875 } = self.get_mem_fn_args(keys_pos, len)?;
1876 self.visit_obj(map, |mapobj: &HostMap| {
1877 if mapobj.len() != len as usize {
1878 return Err(self.err(
1879 ScErrorType::Object,
1880 ScErrorCode::UnexpectedSize,
1881 "differing host map and output slice lengths when unpacking map to linear memory",
1882 &[],
1883 ));
1884 }
1885 self.metered_vm_scan_slices_in_linear_memory(
1887 vmcaller,
1888 &vm,
1889 keys_pos,
1890 len as usize,
1891 |n, slice| {
1892 let sym = Symbol::try_from(
1893 mapobj.get_at_index(n, self).map_err(|he|
1894 if he.error.is_type(ScErrorType::Budget) {
1895 he
1896 } else {
1897 self.err(
1898 ScErrorType::Object,
1899 ScErrorCode::IndexBounds,
1900 "vector out of bounds while unpacking map to linear memory",
1901 &[],
1902 )
1903 }
1904 )?.0
1905 )?;
1906 self.check_symbol_matches(slice, sym)?;
1907 Ok(())
1908 },
1909 )?;
1910
1911 self.charge_budget(ContractCostType::MemCpy, Some((len as u64).saturating_mul(8)))?;
1914 self.metered_vm_write_vals_to_linear_memory(
1915 vmcaller,
1916 &vm,
1917 vals_pos.into(),
1918 mapobj.map.as_slice(),
1919 |pair| {
1920 Ok(u64::to_le_bytes(
1921 self.absolute_to_relative(pair.1)?.get_payload(),
1922 ))
1923 },
1924 )?;
1925 Ok(())
1926 })?;
1927
1928 Ok(Val::VOID)
1929 }
1930
1931 fn vec_new(&self, _vmcaller: &mut VmCaller<Host>) -> Result<VecObject, HostError> {
1935 self.add_host_object(HostVec::new())
1936 }
1937
1938 fn vec_put(
1939 &self,
1940 _vmcaller: &mut VmCaller<Host>,
1941 v: VecObject,
1942 i: U32Val,
1943 x: Val,
1944 ) -> Result<VecObject, HostError> {
1945 let i: u32 = i.into();
1946 let vnew = self.visit_obj(v, |hv: &HostVec| {
1947 self.validate_index_lt_bound(i, hv.len())?;
1948 hv.set(i as usize, x, self.as_budget())
1949 })?;
1950 self.add_host_object(vnew)
1951 }
1952
1953 fn vec_get(
1954 &self,
1955 _vmcaller: &mut VmCaller<Host>,
1956 v: VecObject,
1957 i: U32Val,
1958 ) -> Result<Val, HostError> {
1959 let i: u32 = i.into();
1960 self.visit_obj(v, |hv: &HostVec| {
1961 self.validate_index_lt_bound(i, hv.len())?;
1962 hv.get(i as usize, self.as_budget()).map(|r| *r)
1963 })
1964 }
1965
1966 fn vec_del(
1967 &self,
1968 _vmcaller: &mut VmCaller<Host>,
1969 v: VecObject,
1970 i: U32Val,
1971 ) -> Result<VecObject, HostError> {
1972 let i: u32 = i.into();
1973 let vnew = self.visit_obj(v, |hv: &HostVec| {
1974 self.validate_index_lt_bound(i, hv.len())?;
1975 hv.remove(i as usize, self.as_budget())
1976 })?;
1977 self.add_host_object(vnew)
1978 }
1979
1980 fn vec_len(&self, _vmcaller: &mut VmCaller<Host>, v: VecObject) -> Result<U32Val, HostError> {
1981 let len = self.visit_obj(v, |hv: &HostVec| Ok(hv.len()))?;
1982 self.usize_to_u32val(len)
1983 }
1984
1985 fn vec_push_front(
1986 &self,
1987 _vmcaller: &mut VmCaller<Host>,
1988 v: VecObject,
1989 x: Val,
1990 ) -> Result<VecObject, HostError> {
1991 let vnew = self.visit_obj(v, |hv: &HostVec| hv.push_front(x, self.as_budget()))?;
1992 self.add_host_object(vnew)
1993 }
1994
1995 fn vec_pop_front(
1996 &self,
1997 _vmcaller: &mut VmCaller<Host>,
1998 v: VecObject,
1999 ) -> Result<VecObject, HostError> {
2000 let vnew = self.visit_obj(v, |hv: &HostVec| hv.pop_front(self.as_budget()))?;
2001 self.add_host_object(vnew)
2002 }
2003
2004 fn vec_push_back(
2005 &self,
2006 _vmcaller: &mut VmCaller<Host>,
2007 v: VecObject,
2008 x: Val,
2009 ) -> Result<VecObject, HostError> {
2010 let vnew = self.visit_obj(v, |hv: &HostVec| hv.push_back(x, self.as_budget()))?;
2011 self.add_host_object(vnew)
2012 }
2013
2014 fn vec_pop_back(
2015 &self,
2016 _vmcaller: &mut VmCaller<Host>,
2017 v: VecObject,
2018 ) -> Result<VecObject, HostError> {
2019 let vnew = self.visit_obj(v, |hv: &HostVec| hv.pop_back(self.as_budget()))?;
2020 self.add_host_object(vnew)
2021 }
2022
2023 fn vec_front(&self, _vmcaller: &mut VmCaller<Host>, v: VecObject) -> Result<Val, HostError> {
2024 self.visit_obj(v, |hv: &HostVec| {
2025 hv.front(self.as_budget()).map(|hval| *hval)
2026 })
2027 }
2028
2029 fn vec_back(&self, _vmcaller: &mut VmCaller<Host>, v: VecObject) -> Result<Val, HostError> {
2030 self.visit_obj(v, |hv: &HostVec| {
2031 hv.back(self.as_budget()).map(|hval| *hval)
2032 })
2033 }
2034
2035 fn vec_insert(
2036 &self,
2037 _vmcaller: &mut VmCaller<Host>,
2038 v: VecObject,
2039 i: U32Val,
2040 x: Val,
2041 ) -> Result<VecObject, HostError> {
2042 let i: u32 = i.into();
2043 let vnew = self.visit_obj(v, |hv: &HostVec| {
2044 self.validate_index_le_bound(i, hv.len())?;
2045 hv.insert(i as usize, x, self.as_budget())
2046 })?;
2047 self.add_host_object(vnew)
2048 }
2049
2050 fn vec_append(
2051 &self,
2052 _vmcaller: &mut VmCaller<Host>,
2053 v1: VecObject,
2054 v2: VecObject,
2055 ) -> Result<VecObject, HostError> {
2056 let vnew = self.visit_obj(v1, |hv1: &HostVec| {
2057 self.visit_obj(v2, |hv2: &HostVec| {
2058 if hv1.len() > u32::MAX as usize - hv2.len() {
2059 Err(self.err_arith_overflow())
2060 } else {
2061 hv1.append(hv2, self.as_budget())
2062 }
2063 })
2064 })?;
2065 self.add_host_object(vnew)
2066 }
2067
2068 fn vec_slice(
2069 &self,
2070 _vmcaller: &mut VmCaller<Host>,
2071 v: VecObject,
2072 start: U32Val,
2073 end: U32Val,
2074 ) -> Result<VecObject, HostError> {
2075 let start: u32 = start.into();
2076 let end: u32 = end.into();
2077 let vnew = self.visit_obj(v, |hv: &HostVec| {
2078 let range = self.valid_range_from_start_end_bound(start, end, hv.len())?;
2079 hv.slice(range, self.as_budget())
2080 })?;
2081 self.add_host_object(vnew)
2082 }
2083
2084 fn vec_first_index_of(
2085 &self,
2086 _vmcaller: &mut VmCaller<Host>,
2087 v: VecObject,
2088 x: Val,
2089 ) -> Result<Val, Self::Error> {
2090 self.visit_obj(v, |hv: &HostVec| {
2091 Ok(
2092 match hv.first_index_of(|other| self.compare(&x, other), self.as_budget())? {
2093 Some(u) => self.usize_to_u32val(u)?.into(),
2094 None => Val::VOID.into(),
2095 },
2096 )
2097 })
2098 }
2099
2100 fn vec_last_index_of(
2101 &self,
2102 _vmcaller: &mut VmCaller<Host>,
2103 v: VecObject,
2104 x: Val,
2105 ) -> Result<Val, Self::Error> {
2106 self.visit_obj(v, |hv: &HostVec| {
2107 Ok(
2108 match hv.last_index_of(|other| self.compare(&x, other), self.as_budget())? {
2109 Some(u) => self.usize_to_u32val(u)?.into(),
2110 None => Val::VOID.into(),
2111 },
2112 )
2113 })
2114 }
2115
2116 fn vec_binary_search(
2117 &self,
2118 _vmcaller: &mut VmCaller<Host>,
2119 v: VecObject,
2120 x: Val,
2121 ) -> Result<u64, Self::Error> {
2122 self.visit_obj(v, |hv: &HostVec| {
2123 let res = hv.binary_search_by(|probe| self.compare(probe, &x), self.as_budget())?;
2124 self.u64_from_binary_search_result(res)
2125 })
2126 }
2127
2128 fn vec_new_from_linear_memory(
2129 &self,
2130 vmcaller: &mut VmCaller<Host>,
2131 vals_pos: U32Val,
2132 len: U32Val,
2133 ) -> Result<VecObject, HostError> {
2134 let MemFnArgs { vm, pos, len } = self.get_mem_fn_args(vals_pos, len)?;
2135 Vec::<Val>::charge_bulk_init_cpy(len as u64, self)?;
2136 let mut vals: Vec<Val> = vec![Val::VOID.to_val(); len as usize];
2137 self.charge_budget(
2139 ContractCostType::MemCpy,
2140 Some((len as u64).saturating_mul(8)),
2141 )?;
2142 self.metered_vm_read_vals_from_linear_memory::<8, Val>(
2143 vmcaller,
2144 &vm,
2145 pos,
2146 vals.as_mut_slice(),
2147 |buf| self.relative_to_absolute(Val::from_payload(u64::from_le_bytes(*buf))),
2148 )?;
2149 for v in vals.iter() {
2150 self.check_val_integrity(*v)?;
2151 }
2152 self.add_host_object(HostVec::from_vec(vals)?)
2153 }
2154
2155 fn vec_unpack_to_linear_memory(
2156 &self,
2157 vmcaller: &mut VmCaller<Host>,
2158 vec: VecObject,
2159 vals_pos: U32Val,
2160 len: U32Val,
2161 ) -> Result<Void, HostError> {
2162 let MemFnArgs { vm, pos, len } = self.get_mem_fn_args(vals_pos, len)?;
2163 self.visit_obj(vec, |vecobj: &HostVec| {
2164 if vecobj.len() != len as usize {
2165 return Err(self.err(
2166 ScErrorType::Object,
2167 ScErrorCode::UnexpectedSize,
2168 "differing host vector and output vector lengths when unpacking vec to linear memory",
2169 &[],
2170 ));
2171 }
2172 self.charge_budget(ContractCostType::MemCpy, Some((len as u64).saturating_mul(8)))?;
2174 self.metered_vm_write_vals_to_linear_memory(
2175 vmcaller,
2176 &vm,
2177 pos,
2178 vecobj.as_slice(),
2179 |x| {
2180 Ok(u64::to_le_bytes(
2181 self.absolute_to_relative(*x)?.get_payload(),
2182 ))
2183 },
2184 )
2185 })?;
2186 Ok(Val::VOID)
2187 }
2188
2189 fn put_contract_data(
2194 &self,
2195 _vmcaller: &mut VmCaller<Host>,
2196 k: Val,
2197 v: Val,
2198 t: StorageType,
2199 ) -> Result<Void, HostError> {
2200 match t {
2201 StorageType::Temporary | StorageType::Persistent => {
2202 self.put_contract_data_into_ledger(k, v, t)?
2203 }
2204 StorageType::Instance => self.with_mut_instance_storage(|s| {
2205 s.map = s.map.insert(k, v, self)?;
2206 Ok(())
2207 })?,
2208 };
2209
2210 Ok(Val::VOID)
2211 }
2212
2213 fn has_contract_data(
2215 &self,
2216 _vmcaller: &mut VmCaller<Host>,
2217 k: Val,
2218 t: StorageType,
2219 ) -> Result<Bool, HostError> {
2220 let res = match t {
2221 StorageType::Temporary | StorageType::Persistent => {
2222 let key = self.storage_key_from_val(k, t.try_into()?)?;
2223 self.try_borrow_storage_mut()?
2224 .has_with_host(&key, self, Some(k))?
2225 }
2226 StorageType::Instance => {
2227 self.with_instance_storage(|s| Ok(s.map.get(&k, self)?.is_some()))?
2228 }
2229 };
2230
2231 Ok(Val::from_bool(res))
2232 }
2233
2234 fn get_contract_data(
2236 &self,
2237 _vmcaller: &mut VmCaller<Host>,
2238 k: Val,
2239 t: StorageType,
2240 ) -> Result<Val, HostError> {
2241 match t {
2242 StorageType::Temporary | StorageType::Persistent => {
2243 let key = self.storage_key_from_val(k, t.try_into()?)?;
2244 let entry = self
2245 .try_borrow_storage_mut()?
2246 .get_with_host(&key, self, Some(k))?;
2247 match &entry.data {
2248 LedgerEntryData::ContractData(e) => Ok(self.to_valid_host_val(&e.val)?),
2249 _ => Err(self.err(
2250 ScErrorType::Storage,
2251 ScErrorCode::InternalError,
2252 "expected contract data ledger entry",
2253 &[],
2254 )),
2255 }
2256 }
2257 StorageType::Instance => self.with_instance_storage(|s| {
2258 s.map
2259 .get(&k, self)?
2260 .ok_or_else(|| {
2261 self.err(
2262 ScErrorType::Storage,
2263 ScErrorCode::MissingValue,
2264 "key is missing from instance storage",
2265 &[k],
2266 )
2267 })
2268 .copied()
2269 }),
2270 }
2271 }
2272
2273 fn del_contract_data(
2275 &self,
2276 _vmcaller: &mut VmCaller<Host>,
2277 k: Val,
2278 t: StorageType,
2279 ) -> Result<Void, HostError> {
2280 match t {
2281 StorageType::Temporary | StorageType::Persistent => {
2282 let key = self.storage_key_from_val(k, t.try_into()?)?;
2283 self.try_borrow_storage_mut()?
2284 .del_with_host(&key, self, Some(k))?;
2285 }
2286 StorageType::Instance => {
2287 self.with_mut_instance_storage(|s| {
2288 if let Some((new_map, _)) = s.map.remove(&k, self)? {
2289 s.map = new_map;
2290 }
2291 Ok(())
2292 })?;
2293 }
2294 }
2295
2296 Ok(Val::VOID)
2297 }
2298
2299 fn extend_contract_data_ttl(
2301 &self,
2302 _vmcaller: &mut VmCaller<Host>,
2303 k: Val,
2304 t: StorageType,
2305 threshold: U32Val,
2306 extend_to: U32Val,
2307 ) -> Result<Void, HostError> {
2308 if matches!(t, StorageType::Instance) {
2309 return Err(self.err(
2310 ScErrorType::Storage,
2311 ScErrorCode::InvalidAction,
2312 "instance storage should be extended via `extend_current_contract_instance_and_code_ttl` function only",
2313 &[],
2314 ))?;
2315 }
2316 let key = self.storage_key_from_val(k, t.try_into()?)?;
2317 self.try_borrow_storage_mut()?.extend_ttl(
2318 self,
2319 key,
2320 threshold.into(),
2321 extend_to.into(),
2322 Some(k),
2323 )?;
2324 Ok(Val::VOID)
2325 }
2326
2327 fn extend_current_contract_instance_and_code_ttl(
2328 &self,
2329 _vmcaller: &mut VmCaller<Host>,
2330 threshold: U32Val,
2331 extend_to: U32Val,
2332 ) -> Result<Void, HostError> {
2333 let contract_id = self.get_current_contract_id_internal()?;
2334 let key = self.contract_instance_ledger_key(&contract_id)?;
2335 self.extend_contract_instance_ttl_from_contract_id(
2336 key.clone(),
2337 threshold.into(),
2338 extend_to.into(),
2339 )?;
2340 self.extend_contract_code_ttl_from_contract_id(key, threshold.into(), extend_to.into())?;
2341 Ok(Val::VOID)
2342 }
2343
2344 fn extend_contract_instance_ttl(
2345 &self,
2346 _vmcaller: &mut VmCaller<Self::VmUserState>,
2347 contract: AddressObject,
2348 threshold: U32Val,
2349 extend_to: U32Val,
2350 ) -> Result<Void, Self::Error> {
2351 let contract_id = self.contract_id_from_address(contract)?;
2352 let key = self.contract_instance_ledger_key(&contract_id)?;
2353
2354 self.extend_contract_instance_ttl_from_contract_id(
2355 key,
2356 threshold.into(),
2357 extend_to.into(),
2358 )?;
2359
2360 Ok(Val::VOID)
2361 }
2362
2363 fn extend_contract_instance_and_code_ttl(
2364 &self,
2365 _vmcaller: &mut VmCaller<Self::VmUserState>,
2366 contract: AddressObject,
2367 threshold: U32Val,
2368 extend_to: U32Val,
2369 ) -> Result<Void, Self::Error> {
2370 let contract_id = self.contract_id_from_address(contract)?;
2371 let key = self.contract_instance_ledger_key(&contract_id)?;
2372 self.extend_contract_instance_ttl_from_contract_id(
2373 key.clone(),
2374 threshold.into(),
2375 extend_to.into(),
2376 )?;
2377 self.extend_contract_code_ttl_from_contract_id(key, threshold.into(), extend_to.into())?;
2378 Ok(Val::VOID)
2379 }
2380
2381 fn extend_contract_code_ttl(
2382 &self,
2383 _vmcaller: &mut VmCaller<Self::VmUserState>,
2384 contract: AddressObject,
2385 threshold: U32Val,
2386 extend_to: U32Val,
2387 ) -> Result<Void, Self::Error> {
2388 let contract_id = self.contract_id_from_address(contract)?;
2389 let key = self.contract_instance_ledger_key(&contract_id)?;
2390
2391 self.extend_contract_code_ttl_from_contract_id(key, threshold.into(), extend_to.into())?;
2392
2393 Ok(Val::VOID)
2394 }
2395
2396 fn create_contract(
2398 &self,
2399 _vmcaller: &mut VmCaller<Host>,
2400 deployer: AddressObject,
2401 wasm_hash: BytesObject,
2402 salt: BytesObject,
2403 ) -> Result<AddressObject, HostError> {
2404 let contract_id_preimage = ContractIdPreimage::Address(ContractIdPreimageFromAddress {
2405 address: self.visit_obj(deployer, |addr: &ScAddress| addr.metered_clone(self))?,
2406 salt: self.u256_from_bytesobj_input("contract_id_salt", salt)?,
2407 });
2408 let executable =
2409 ContractExecutable::Wasm(self.hash_from_bytesobj_input("wasm_hash", wasm_hash)?);
2410 let args = CreateContractArgs {
2411 contract_id_preimage,
2412 executable,
2413 };
2414 self.create_contract_internal(Some(deployer), args)
2415 }
2416
2417 fn create_asset_contract(
2419 &self,
2420 _vmcaller: &mut VmCaller<Host>,
2421 serialized_asset: BytesObject,
2422 ) -> Result<AddressObject, HostError> {
2423 let asset: Asset = self.metered_from_xdr_obj(serialized_asset)?;
2424 let contract_id_preimage = ContractIdPreimage::Asset(asset);
2425 let executable = ContractExecutable::StellarAsset;
2426 let args = CreateContractArgs {
2427 contract_id_preimage,
2428 executable,
2429 };
2430 self.create_contract_internal(None, args)
2433 }
2434
2435 fn get_contract_id(
2437 &self,
2438 _vmcaller: &mut VmCaller<Host>,
2439 deployer: AddressObject,
2440 salt: BytesObject,
2441 ) -> Result<AddressObject, HostError> {
2442 let hash_id = self.get_contract_id_hash(deployer, salt)?;
2443 self.add_host_object(ScAddress::Contract(hash_id))
2444 }
2445
2446 fn get_asset_contract_id(
2448 &self,
2449 _vmcaller: &mut VmCaller<Host>,
2450 serialized_asset: BytesObject,
2451 ) -> Result<AddressObject, HostError> {
2452 let asset: Asset = self.metered_from_xdr_obj(serialized_asset)?;
2453 let hash_id = self.get_asset_contract_id_hash(asset)?;
2454 self.add_host_object(ScAddress::Contract(hash_id))
2455 }
2456
2457 fn upload_wasm(
2458 &self,
2459 _vmcaller: &mut VmCaller<Host>,
2460 wasm: BytesObject,
2461 ) -> Result<BytesObject, HostError> {
2462 let wasm_vec =
2463 self.visit_obj(wasm, |bytes: &ScBytes| bytes.as_vec().metered_clone(self))?;
2464 self.upload_contract_wasm(wasm_vec)
2465 }
2466
2467 fn update_current_contract_wasm(
2468 &self,
2469 _vmcaller: &mut VmCaller<Host>,
2470 hash: BytesObject,
2471 ) -> Result<Void, HostError> {
2472 let wasm_hash = self.hash_from_bytesobj_input("wasm_hash", hash)?;
2473 if !self.wasm_exists(&wasm_hash)? {
2474 return Err(self.err(
2475 ScErrorType::Storage,
2476 ScErrorCode::MissingValue,
2477 "Wasm does not exist",
2478 &[hash.to_val()],
2479 ));
2480 }
2481 let curr_contract_id = self.get_current_contract_id_internal()?;
2482 let key = self.contract_instance_ledger_key(&curr_contract_id)?;
2483 let old_instance = self.retrieve_contract_instance_from_storage(&key)?;
2484 let new_executable = ContractExecutable::Wasm(wasm_hash);
2485 self.emit_update_contract_event(&old_instance.executable, &new_executable)?;
2486 self.store_contract_instance(Some(new_executable), None, curr_contract_id, &key)?;
2487 Ok(Val::VOID)
2488 }
2489
2490 fn call(
2495 &self,
2496 _vmcaller: &mut VmCaller<Host>,
2497 contract_address: AddressObject,
2498 func: Symbol,
2499 args: VecObject,
2500 ) -> Result<Val, HostError> {
2501 let argvec = self.call_args_from_obj(args)?;
2502 let res = self.call_n_internal(
2505 &self.contract_id_from_address(contract_address)?,
2506 func,
2507 argvec.as_slice(),
2508 ContractReentryMode::Prohibited,
2509 false,
2510 );
2511 if let Err(e) = &res {
2512 self.error(
2513 e.error,
2514 "contract call failed",
2515 &[func.to_val(), args.to_val()],
2516 );
2517 }
2518 res
2519 }
2520
2521 fn try_call(
2523 &self,
2524 _vmcaller: &mut VmCaller<Host>,
2525 contract_address: AddressObject,
2526 func: Symbol,
2527 args: VecObject,
2528 ) -> Result<Val, HostError> {
2529 let argvec = self.call_args_from_obj(args)?;
2530 let res = self.call_n_internal(
2535 &self.contract_id_from_address(contract_address)?,
2536 func,
2537 argvec.as_slice(),
2538 ContractReentryMode::Prohibited,
2539 false,
2540 );
2541 match res {
2542 Ok(rv) => Ok(rv),
2543 Err(e) => {
2544 self.error(
2545 e.error,
2546 "contract try_call failed",
2547 &[func.to_val(), args.to_val()],
2548 );
2549 if e.is_recoverable() {
2553 if e.error.is_type(ScErrorType::Contract) {
2556 Ok(e.error.to_val())
2557 } else {
2558 Ok(Error::from_type_and_code(
2568 ScErrorType::Context,
2569 ScErrorCode::InvalidAction,
2570 )
2571 .to_val())
2572 }
2573 } else {
2574 Err(e)
2575 }
2576 }
2577 }
2578 }
2579
2580 fn serialize_to_bytes(
2585 &self,
2586 _vmcaller: &mut VmCaller<Host>,
2587 v: Val,
2588 ) -> Result<BytesObject, HostError> {
2589 let scv = self.from_host_val(v)?;
2590 let mut buf = Vec::<u8>::new();
2591 metered_write_xdr(self.budget_ref(), &scv, &mut buf)?;
2592 self.add_host_object(self.scbytes_from_vec(buf)?)
2593 }
2594
2595 fn deserialize_from_bytes(
2597 &self,
2598 _vmcaller: &mut VmCaller<Host>,
2599 b: BytesObject,
2600 ) -> Result<Val, HostError> {
2601 let scv = self.visit_obj(b, |hv: &ScBytes| {
2602 self.metered_from_xdr::<ScVal>(hv.as_slice())
2603 })?;
2604 if Val::can_represent_scval_recursive(&scv) {
2610 self.to_host_val(&scv)
2611 } else {
2612 Err(self.err(
2613 ScErrorType::Value,
2614 ScErrorCode::UnexpectedType,
2615 "Deserialized ScVal type cannot be represented as Val",
2616 &[(scv.discriminant() as i32).into()],
2617 ))
2618 }
2619 }
2620
2621 fn string_copy_to_linear_memory(
2622 &self,
2623 vmcaller: &mut VmCaller<Host>,
2624 s: StringObject,
2625 s_pos: U32Val,
2626 lm_pos: U32Val,
2627 len: U32Val,
2628 ) -> Result<Void, HostError> {
2629 self.memobj_copy_to_linear_memory::<ScString>(vmcaller, s, s_pos, lm_pos, len)?;
2630 Ok(Val::VOID)
2631 }
2632
2633 fn symbol_copy_to_linear_memory(
2634 &self,
2635 vmcaller: &mut VmCaller<Host>,
2636 s: SymbolObject,
2637 s_pos: U32Val,
2638 lm_pos: U32Val,
2639 len: U32Val,
2640 ) -> Result<Void, HostError> {
2641 self.memobj_copy_to_linear_memory::<ScSymbol>(vmcaller, s, s_pos, lm_pos, len)?;
2642 Ok(Val::VOID)
2643 }
2644
2645 fn bytes_copy_to_linear_memory(
2646 &self,
2647 vmcaller: &mut VmCaller<Host>,
2648 b: BytesObject,
2649 b_pos: U32Val,
2650 lm_pos: U32Val,
2651 len: U32Val,
2652 ) -> Result<Void, HostError> {
2653 self.memobj_copy_to_linear_memory::<ScBytes>(vmcaller, b, b_pos, lm_pos, len)?;
2654 Ok(Val::VOID)
2655 }
2656
2657 fn bytes_copy_from_linear_memory(
2658 &self,
2659 vmcaller: &mut VmCaller<Host>,
2660 b: BytesObject,
2661 b_pos: U32Val,
2662 lm_pos: U32Val,
2663 len: U32Val,
2664 ) -> Result<BytesObject, HostError> {
2665 self.memobj_copy_from_linear_memory::<ScBytes>(vmcaller, b, b_pos, lm_pos, len)
2666 }
2667
2668 fn bytes_new_from_linear_memory(
2669 &self,
2670 vmcaller: &mut VmCaller<Host>,
2671 lm_pos: U32Val,
2672 len: U32Val,
2673 ) -> Result<BytesObject, HostError> {
2674 self.memobj_new_from_linear_memory::<ScBytes>(vmcaller, lm_pos, len)
2675 }
2676
2677 fn string_new_from_linear_memory(
2678 &self,
2679 vmcaller: &mut VmCaller<Host>,
2680 lm_pos: U32Val,
2681 len: U32Val,
2682 ) -> Result<StringObject, HostError> {
2683 self.memobj_new_from_linear_memory::<ScString>(vmcaller, lm_pos, len)
2684 }
2685
2686 fn symbol_new_from_linear_memory(
2687 &self,
2688 vmcaller: &mut VmCaller<Host>,
2689 lm_pos: U32Val,
2690 len: U32Val,
2691 ) -> Result<SymbolObject, HostError> {
2692 self.memobj_new_from_linear_memory::<ScSymbol>(vmcaller, lm_pos, len)
2693 }
2694
2695 fn symbol_index_in_linear_memory(
2697 &self,
2698 vmcaller: &mut VmCaller<Host>,
2699 sym: Symbol,
2700 lm_pos: U32Val,
2701 len: U32Val,
2702 ) -> Result<U32Val, HostError> {
2703 let MemFnArgs { vm, pos, len } = self.get_mem_fn_args(lm_pos, len)?;
2704 let mut found = None;
2705 self.metered_vm_scan_slices_in_linear_memory(
2706 vmcaller,
2707 &vm,
2708 pos,
2709 len as usize,
2710 |i, slice| {
2711 if self.symbol_matches(slice, sym)? {
2712 if found.is_none() {
2713 found = Some(self.usize_to_u32(i)?)
2714 }
2715 }
2716 Ok(())
2717 },
2718 )?;
2719 match found {
2720 None => Err(self.err(
2721 ScErrorType::Value,
2722 ScErrorCode::MissingValue,
2723 "symbol not found in linear memory slices",
2724 &[sym.to_val()],
2725 )),
2726 Some(idx) => Ok(U32Val::from(idx)),
2727 }
2728 }
2729
2730 fn bytes_new(&self, _vmcaller: &mut VmCaller<Host>) -> Result<BytesObject, HostError> {
2732 self.add_host_object(self.scbytes_from_vec(Vec::<u8>::new())?)
2733 }
2734
2735 fn bytes_put(
2737 &self,
2738 _vmcaller: &mut VmCaller<Host>,
2739 b: BytesObject,
2740 iv: U32Val,
2741 u: U32Val,
2742 ) -> Result<BytesObject, HostError> {
2743 let i: u32 = iv.into();
2744 let u = self.u8_from_u32val_input("u", u)?;
2745 let vnew = self.visit_obj(b, |hv: &ScBytes| {
2746 let mut vnew: Vec<u8> = hv.metered_clone(self)?.into();
2747 match vnew.get_mut(i as usize) {
2748 None => Err(self.err(
2749 ScErrorType::Object,
2750 ScErrorCode::IndexBounds,
2751 "bytes_put out of bounds",
2752 &[iv.to_val()],
2753 )),
2754 Some(v) => {
2755 *v = u;
2756 Ok(ScBytes(vnew.try_into()?))
2757 }
2758 }
2759 })?;
2760 self.add_host_object(vnew)
2761 }
2762
2763 fn bytes_get(
2765 &self,
2766 _vmcaller: &mut VmCaller<Host>,
2767 b: BytesObject,
2768 iv: U32Val,
2769 ) -> Result<U32Val, HostError> {
2770 let i: u32 = iv.into();
2771 self.visit_obj(b, |hv: &ScBytes| {
2772 hv.get(i as usize)
2773 .map(|u| U32Val::from(u32::from(*u)))
2774 .ok_or_else(|| {
2775 self.err(
2776 ScErrorType::Object,
2777 ScErrorCode::IndexBounds,
2778 "bytes_get out of bounds",
2779 &[iv.to_val()],
2780 )
2781 })
2782 })
2783 }
2784
2785 fn bytes_del(
2786 &self,
2787 _vmcaller: &mut VmCaller<Host>,
2788 b: BytesObject,
2789 i: U32Val,
2790 ) -> Result<BytesObject, HostError> {
2791 let i: u32 = i.into();
2792 let vnew = self.visit_obj(b, |hv: &ScBytes| {
2793 self.validate_index_lt_bound(i, hv.len())?;
2794 let mut vnew: Vec<u8> = hv.metered_clone(self)?.into();
2795 let n_elts = (hv.len() as u64).checked_sub(i as u64).ok_or_else(|| {
2797 Error::from_type_and_code(ScErrorType::Context, ScErrorCode::InternalError)
2798 })?;
2799 metered_clone::charge_shallow_copy::<u8>(n_elts, self)?;
2802 vnew.remove(i as usize);
2803 Ok(ScBytes(vnew.try_into()?))
2804 })?;
2805 self.add_host_object(vnew)
2806 }
2807
2808 fn bytes_len(
2810 &self,
2811 _vmcaller: &mut VmCaller<Host>,
2812 b: BytesObject,
2813 ) -> Result<U32Val, HostError> {
2814 let len = self.visit_obj(b, |hv: &ScBytes| Ok(hv.len()))?;
2815 self.usize_to_u32val(len)
2816 }
2817
2818 fn string_len(
2820 &self,
2821 _vmcaller: &mut VmCaller<Host>,
2822 b: StringObject,
2823 ) -> Result<U32Val, HostError> {
2824 let len = self.visit_obj(b, |hv: &ScString| Ok(hv.len()))?;
2825 self.usize_to_u32val(len)
2826 }
2827
2828 fn symbol_len(
2830 &self,
2831 _vmcaller: &mut VmCaller<Host>,
2832 b: SymbolObject,
2833 ) -> Result<U32Val, HostError> {
2834 let len = self.visit_obj(b, |hv: &ScSymbol| Ok(hv.len()))?;
2835 self.usize_to_u32val(len)
2836 }
2837
2838 fn bytes_push(
2840 &self,
2841 _vmcaller: &mut VmCaller<Host>,
2842 b: BytesObject,
2843 u: U32Val,
2844 ) -> Result<BytesObject, HostError> {
2845 let u = self.u8_from_u32val_input("u", u)?;
2846 let vnew = self.visit_obj(b, |hv: &ScBytes| {
2847 let len = self.validate_usize_sum_fits_in_u32(hv.len(), 1)?;
2850 let mut vnew = Vec::<u8>::with_metered_capacity(len, self)?;
2851 vnew.extend_from_slice(hv.as_slice());
2852 vnew.push(u);
2853 Ok(ScBytes(vnew.try_into()?))
2854 })?;
2855 self.add_host_object(vnew)
2856 }
2857
2858 fn bytes_pop(
2860 &self,
2861 _vmcaller: &mut VmCaller<Host>,
2862 b: BytesObject,
2863 ) -> Result<BytesObject, HostError> {
2864 let vnew = self.visit_obj(b, |hv: &ScBytes| {
2865 let mut vnew: Vec<u8> = hv.metered_clone(self)?.into();
2866 if vnew.pop().is_none() {
2869 return Err(self.err(
2870 ScErrorType::Object,
2871 ScErrorCode::IndexBounds,
2872 "bytes_pop out of bounds",
2873 &[],
2874 ));
2875 }
2876 Ok(ScBytes(vnew.try_into()?))
2877 })?;
2878 self.add_host_object(vnew)
2879 }
2880
2881 fn bytes_front(
2883 &self,
2884 _vmcaller: &mut VmCaller<Host>,
2885 b: BytesObject,
2886 ) -> Result<U32Val, HostError> {
2887 self.visit_obj(b, |hv: &ScBytes| {
2888 hv.first()
2889 .map(|u| U32Val::from(u32::from(*u)))
2890 .ok_or_else(|| {
2891 self.err(
2892 ScErrorType::Object,
2893 ScErrorCode::IndexBounds,
2894 "bytes_front out of bounds",
2895 &[],
2896 )
2897 })
2898 })
2899 }
2900
2901 fn bytes_back(
2903 &self,
2904 _vmcaller: &mut VmCaller<Host>,
2905 b: BytesObject,
2906 ) -> Result<U32Val, HostError> {
2907 self.visit_obj(b, |hv: &ScBytes| {
2908 hv.last()
2909 .map(|u| U32Val::from(u32::from(*u)))
2910 .ok_or_else(|| {
2911 self.err(
2912 ScErrorType::Object,
2913 ScErrorCode::IndexBounds,
2914 "bytes_back out of bounds",
2915 &[],
2916 )
2917 })
2918 })
2919 }
2920
2921 fn bytes_insert(
2922 &self,
2923 _vmcaller: &mut VmCaller<Host>,
2924 b: BytesObject,
2925 i: U32Val,
2926 u: U32Val,
2927 ) -> Result<BytesObject, HostError> {
2928 let i: u32 = i.into();
2929 let u = self.u8_from_u32val_input("u", u)?;
2930 let vnew = self.visit_obj(b, |hv: &ScBytes| {
2931 self.validate_index_le_bound(i, hv.len())?;
2932 let len = self.validate_usize_sum_fits_in_u32(hv.len(), 1)?;
2935 let mut vnew = Vec::<u8>::with_metered_capacity(len, self)?;
2936 vnew.extend_from_slice(hv.as_slice());
2937 vnew.insert(i as usize, u);
2938 Ok(ScBytes(vnew.try_into()?))
2939 })?;
2940 self.add_host_object(vnew)
2941 }
2942
2943 fn bytes_append(
2944 &self,
2945 _vmcaller: &mut VmCaller<Host>,
2946 b1: BytesObject,
2947 b2: BytesObject,
2948 ) -> Result<BytesObject, HostError> {
2949 let vnew = self.visit_obj(b1, |sb1: &ScBytes| {
2950 self.visit_obj(b2, |sb2: &ScBytes| {
2951 let len = self.validate_usize_sum_fits_in_u32(sb1.len(), sb2.len())?;
2954 let mut vnew = Vec::<u8>::with_metered_capacity(len, self)?;
2955 vnew.extend_from_slice(sb1.as_slice());
2956 vnew.extend_from_slice(sb2.as_slice());
2957 Ok(vnew)
2958 })
2959 })?;
2960 self.add_host_object(ScBytes(vnew.try_into()?))
2961 }
2962
2963 fn bytes_slice(
2964 &self,
2965 _vmcaller: &mut VmCaller<Host>,
2966 b: BytesObject,
2967 start: U32Val,
2968 end: U32Val,
2969 ) -> Result<BytesObject, HostError> {
2970 let start: u32 = start.into();
2971 let end: u32 = end.into();
2972 let vnew = self.visit_obj(b, |hv: &ScBytes| {
2973 let range = self.valid_range_from_start_end_bound(start, end, hv.len())?;
2974 self.metered_slice_to_vec(
2975 &hv.as_slice()
2976 .get(range)
2977 .ok_or_else(|| self.err_oob_object_index(None))?,
2978 )
2979 })?;
2980 self.add_host_object(self.scbytes_from_vec(vnew)?)
2981 }
2982
2983 fn compute_hash_sha256(
2988 &self,
2989 _vmcaller: &mut VmCaller<Host>,
2990 x: BytesObject,
2991 ) -> Result<BytesObject, HostError> {
2992 let hash = self.sha256_hash_from_bytesobj_input(x)?;
2993 self.add_host_object(self.scbytes_from_vec(hash)?)
2994 }
2995
2996 fn compute_hash_keccak256(
2998 &self,
2999 _vmcaller: &mut VmCaller<Host>,
3000 x: BytesObject,
3001 ) -> Result<BytesObject, HostError> {
3002 let hash = self.keccak256_hash_from_bytesobj_input(x)?;
3003 self.add_host_object(self.scbytes_from_vec(hash)?)
3004 }
3005
3006 fn verify_sig_ed25519(
3008 &self,
3009 _vmcaller: &mut VmCaller<Host>,
3010 k: BytesObject,
3011 x: BytesObject,
3012 s: BytesObject,
3013 ) -> Result<Void, HostError> {
3014 let verifying_key = self.ed25519_pub_key_from_bytesobj_input(k)?;
3015 let sig = self.ed25519_signature_from_bytesobj_input("sig", s)?;
3016 let res = self.visit_obj(x, |payload: &ScBytes| {
3017 self.verify_sig_ed25519_internal(payload.as_slice(), &verifying_key, &sig)
3018 });
3019 Ok(res?.into())
3020 }
3021
3022 fn recover_key_ecdsa_secp256k1(
3023 &self,
3024 _vmcaller: &mut VmCaller<Host>,
3025 msg_digest: BytesObject,
3026 signature: BytesObject,
3027 recovery_id: U32Val,
3028 ) -> Result<BytesObject, HostError> {
3029 let sig = self.ecdsa_signature_from_bytesobj_input::<k256::Secp256k1>(signature)?;
3030 let rid = self.secp256k1_recovery_id_from_u32val(recovery_id)?;
3031 let hash = self.hash_from_bytesobj_input("msg_digest", msg_digest)?;
3032 let rk = self.recover_key_ecdsa_secp256k1_internal(&hash, &sig, rid)?;
3033 self.add_host_object(rk)
3034 }
3035
3036 fn verify_sig_ecdsa_secp256r1(
3037 &self,
3038 _vmcaller: &mut VmCaller<Host>,
3039 public_key: BytesObject,
3040 msg_digest: BytesObject,
3041 signature: BytesObject,
3042 ) -> Result<Void, HostError> {
3043 let pk = self.secp256r1_public_key_from_bytesobj_input(public_key)?;
3044 let sig = self.ecdsa_signature_from_bytesobj_input::<p256::NistP256>(signature)?;
3045 let msg_hash = self.hash_from_bytesobj_input("msg_digest", msg_digest)?;
3046 let res = self.secp256r1_verify_signature(&pk, &msg_hash, &sig)?;
3047 Ok(res.into())
3048 }
3049
3050 fn dummy0(&self, _vmcaller: &mut VmCaller<Self::VmUserState>) -> Result<Val, Self::Error> {
3054 Ok(().into())
3055 }
3056
3057 fn protocol_gated_dummy(
3058 &self,
3059 _vmcaller: &mut VmCaller<Self::VmUserState>,
3060 ) -> Result<Val, Self::Error> {
3061 Ok(().into())
3062 }
3063
3064 fn require_auth_for_args(
3068 &self,
3069 _vmcaller: &mut VmCaller<Self::VmUserState>,
3070 address: AddressObject,
3071 args: VecObject,
3072 ) -> Result<Void, Self::Error> {
3073 let args = self.visit_obj(args, |a: &HostVec| a.to_vec(self.budget_ref()))?;
3074 Ok(self
3075 .try_borrow_authorization_manager()?
3076 .require_auth(self, address, args)?
3077 .into())
3078 }
3079
3080 fn require_auth(
3081 &self,
3082 _vmcaller: &mut VmCaller<Self::VmUserState>,
3083 address: AddressObject,
3084 ) -> Result<Void, Self::Error> {
3085 let args = self.with_current_frame(|f| {
3086 let args = match f {
3087 Frame::ContractVM { args, .. } => args,
3088 Frame::HostFunction(_) => {
3089 return Err(self.err(
3090 ScErrorType::Context,
3091 ScErrorCode::InternalError,
3092 "require_auth is not suppported for host fns",
3093 &[],
3094 ));
3095 }
3096 Frame::StellarAssetContract(_, _, args, _) => args,
3097 #[cfg(any(test, feature = "testutils"))]
3098 Frame::TestContract(c) => &c.args,
3099 };
3100 args.metered_clone(self)
3101 })?;
3102
3103 Ok(self
3104 .try_borrow_authorization_manager()?
3105 .require_auth(self, address, args)?
3106 .into())
3107 }
3108
3109 fn authorize_as_curr_contract(
3110 &self,
3111 _vmcaller: &mut VmCaller<Self::VmUserState>,
3112 auth_entries: VecObject,
3113 ) -> Result<Void, HostError> {
3114 Ok(self
3115 .try_borrow_authorization_manager()?
3116 .add_invoker_contract_auth_with_curr_contract_as_invoker(self, auth_entries)?
3117 .into())
3118 }
3119
3120 fn address_to_strkey(
3121 &self,
3122 _vmcaller: &mut VmCaller<Self::VmUserState>,
3123 address: AddressObject,
3124 ) -> Result<StringObject, Self::Error> {
3125 let strkey = self.visit_obj(address, |addr: &ScAddress| {
3126 const PAYLOAD_LEN: u64 = 32 + 3;
3131 Vec::<u8>::charge_bulk_init_cpy(PAYLOAD_LEN + (PAYLOAD_LEN * 8 + 4) / 5, self)?;
3132 let strkey = match addr {
3133 ScAddress::Account(acc_id) => {
3134 let AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(ed25519))) = acc_id;
3135 let strkey = stellar_strkey::Strkey::PublicKeyEd25519(
3136 stellar_strkey::ed25519::PublicKey(ed25519.metered_clone(self)?),
3137 );
3138 strkey
3139 }
3140 ScAddress::Contract(Hash(h)) => stellar_strkey::Strkey::Contract(
3141 stellar_strkey::Contract(h.metered_clone(self)?),
3142 ),
3143 };
3144 Ok(strkey.to_string())
3145 })?;
3146 self.add_host_object(ScString(strkey.try_into()?))
3147 }
3148
3149 fn strkey_to_address(
3150 &self,
3151 _vmcaller: &mut VmCaller<Self::VmUserState>,
3152 strkey_obj: Val,
3153 ) -> Result<AddressObject, Self::Error> {
3154 let strkey_obj = Object::try_from(strkey_obj).map_err(|_| {
3155 self.err(
3156 ScErrorType::Value,
3157 ScErrorCode::UnexpectedType,
3158 "strkey is not an object",
3159 &[strkey_obj],
3160 )
3161 })?;
3162 let sc_addr = self.visit_obj_untyped(strkey_obj, |key_obj: &HostObject| {
3163 let key = match key_obj {
3164 HostObject::Bytes(b) => b.as_slice(),
3165 HostObject::String(s) => s.as_slice(),
3166 _ => {
3167 return Err(self.err(
3168 ScErrorType::Value,
3169 ScErrorCode::UnexpectedType,
3170 "strkey is not a string or bytes object",
3171 &[strkey_obj.to_val()],
3172 ));
3173 }
3174 };
3175 const PAYLOAD_LEN: u64 = 32 + 3;
3176 let expected_key_len = (PAYLOAD_LEN * 8 + 4) / 5;
3177 if expected_key_len != key.len() as u64 {
3178 return Err(self.err(
3179 ScErrorType::Value,
3180 ScErrorCode::InvalidInput,
3181 "unexpected strkey length",
3182 &[strkey_obj.to_val()],
3183 ));
3184 }
3185 Vec::<u8>::charge_bulk_init_cpy(key.len() as u64, self)?;
3187 let key_str = String::from_utf8_lossy(key);
3188 Vec::<u8>::charge_bulk_init_cpy(PAYLOAD_LEN + PAYLOAD_LEN, self)?;
3191 let strkey = stellar_strkey::Strkey::from_string(&key_str).map_err(|_| {
3192 self.err(
3193 ScErrorType::Value,
3194 ScErrorCode::InvalidInput,
3195 "couldn't process the string as strkey",
3196 &[strkey_obj.to_val()],
3197 )
3198 })?;
3199 match strkey {
3200 stellar_strkey::Strkey::PublicKeyEd25519(pk) => Ok(ScAddress::Account(AccountId(
3201 PublicKey::PublicKeyTypeEd25519(Uint256(pk.0)),
3202 ))),
3203
3204 stellar_strkey::Strkey::Contract(c) => Ok(ScAddress::Contract(Hash(c.0))),
3205 _ => {
3206 return Err(self.err(
3207 ScErrorType::Value,
3208 ScErrorCode::InvalidInput,
3209 "incorrect strkey type",
3210 &[strkey_obj.to_val()],
3211 ));
3212 }
3213 }
3214 })?;
3215 self.add_host_object(sc_addr)
3216 }
3217
3218 fn prng_reseed(
3222 &self,
3223 _vmcaller: &mut VmCaller<Self::VmUserState>,
3224 seed: BytesObject,
3225 ) -> Result<Void, Self::Error> {
3226 self.visit_obj(seed, |bytes: &ScBytes| {
3227 let slice: &[u8] = bytes.as_ref();
3228 self.charge_budget(ContractCostType::MemCpy, Some(prng::SEED_BYTES))?;
3229 if let Ok(seed32) = slice.try_into() {
3230 self.with_current_prng(|prng| {
3231 *prng = Prng::new_from_seed(seed32, self.budget_ref())?;
3232 Ok(())
3233 })?;
3234 Ok(Val::VOID)
3235 } else if let Ok(len) = u32::try_from(slice.len()) {
3236 Err(self.err(
3237 ScErrorType::Value,
3238 ScErrorCode::UnexpectedSize,
3239 "Unexpected size of BytesObject in prng_reseed",
3240 &[U32Val::from(len).to_val()],
3241 ))
3242 } else {
3243 Err(self.err(
3244 ScErrorType::Value,
3245 ScErrorCode::UnexpectedSize,
3246 "Unexpected size of BytesObject in prng_reseed",
3247 &[],
3248 ))
3249 }
3250 })
3251 }
3252
3253 fn prng_bytes_new(
3254 &self,
3255 _vmcaller: &mut VmCaller<Self::VmUserState>,
3256 length: U32Val,
3257 ) -> Result<BytesObject, Self::Error> {
3258 self.add_host_object(
3259 self.with_current_prng(|prng| prng.bytes_new(length.into(), self.as_budget()))?,
3260 )
3261 }
3262
3263 fn prng_u64_in_inclusive_range(
3264 &self,
3265 _vmcaller: &mut VmCaller<Self::VmUserState>,
3266 lo: u64,
3267 hi: u64,
3268 ) -> Result<u64, Self::Error> {
3269 self.with_current_prng(|prng| prng.u64_in_inclusive_range(lo..=hi, self.as_budget()))
3270 }
3271
3272 fn prng_vec_shuffle(
3273 &self,
3274 _vmcaller: &mut VmCaller<Self::VmUserState>,
3275 vec: VecObject,
3276 ) -> Result<VecObject, Self::Error> {
3277 let vnew = self.visit_obj(vec, |v: &HostVec| {
3278 self.with_current_prng(|prng| prng.vec_shuffle(v, self.as_budget()))
3279 })?;
3280 self.add_host_object(vnew)
3281 }
3282 }
3284
3285#[cfg(feature = "bench")]
3286impl Host {
3287 pub fn inject_val(&self, v: &ScVal) -> Result<Val, HostError> {
3290 self.to_host_val(v).map(Into::into)
3291 }
3292}
3293
3294#[cfg(any(test, feature = "testutils"))]
3295impl Host {
3296 pub fn set_top_contract_invocation_hook(
3305 &self,
3306 hook: Option<ContractInvocationHook>,
3307 ) -> Result<(), HostError> {
3308 *self.try_borrow_top_contract_invocation_hook_mut()? = hook;
3309 Ok(())
3310 }
3311
3312 #[allow(dead_code)]
3316 pub fn with_budget<T, F>(&self, f: F) -> Result<T, HostError>
3317 where
3318 F: FnOnce(Budget) -> Result<T, HostError>,
3319 {
3320 f(self.0.budget.clone())
3321 }
3322
3323 pub fn get_contract_instance_live_until_ledger(
3326 &self,
3327 contract: AddressObject,
3328 ) -> Result<u32, HostError> {
3329 let contract_id = self.contract_id_from_address(contract)?;
3330 let key = self.contract_instance_ledger_key(&contract_id)?;
3331 let (_, live_until) = self
3332 .try_borrow_storage_mut()?
3333 .get_with_live_until_ledger(&key, self, None)?;
3334 live_until.ok_or_else(|| {
3335 self.err(
3336 ScErrorType::Storage,
3337 ScErrorCode::InternalError,
3338 "unexpected contract instance without TTL",
3339 &[contract.into()],
3340 )
3341 })
3342 }
3343
3344 pub fn get_contract_code_live_until_ledger(
3347 &self,
3348 contract: AddressObject,
3349 ) -> Result<u32, HostError> {
3350 let contract_id = self.contract_id_from_address(contract)?;
3351 let key = self.contract_instance_ledger_key(&contract_id)?;
3352 match self
3353 .retrieve_contract_instance_from_storage(&key)?
3354 .executable
3355 {
3356 ContractExecutable::Wasm(wasm_hash) => {
3357 let key = self.contract_code_ledger_key(&wasm_hash)?;
3358 let (_, live_until) = self
3359 .try_borrow_storage_mut()?
3360 .get_with_live_until_ledger(&key, self, None)?;
3361 live_until.ok_or_else(|| {
3362 self.err(
3363 ScErrorType::Storage,
3364 ScErrorCode::InternalError,
3365 "unexpected contract code without TTL for a contract",
3366 &[contract.into()],
3367 )
3368 })
3369 }
3370 ContractExecutable::StellarAsset => Err(self.err(
3371 ScErrorType::Storage,
3372 ScErrorCode::InvalidInput,
3373 "Stellar Asset Contracts don't have contract code",
3374 &[],
3375 )),
3376 }
3377 }
3378
3379 pub fn get_contract_data_live_until_ledger(
3384 &self,
3385 key: Val,
3386 storage_type: StorageType,
3387 ) -> Result<u32, HostError> {
3388 let ledger_key = match storage_type {
3389 StorageType::Temporary | StorageType::Persistent => {
3390 self.storage_key_from_val(key, storage_type.try_into()?)?
3391 }
3392 StorageType::Instance => {
3393 return Err(self.err(
3394 ScErrorType::Storage,
3395 ScErrorCode::InvalidAction,
3396 "`get_contract_data_live_until_ledger` doesn't support instance storage, use `get_contract_instance_live_until_ledger` instead.",
3397 &[],
3398 ));
3399 }
3400 };
3401 let (_, live_until) = self.try_borrow_storage_mut()?.get_with_live_until_ledger(
3402 &ledger_key,
3403 self,
3404 Some(key),
3405 )?;
3406 live_until.ok_or_else(|| {
3407 self.err(
3408 ScErrorType::Storage,
3409 ScErrorCode::InternalError,
3410 "unexpected contract data without TTL",
3411 &[key],
3412 )
3413 })
3414 }
3415}
3416
3417impl Host {
3418 #[allow(dead_code)]
3419 pub(crate) fn set_trace_hook(&self, hook: Option<TraceHook>) -> Result<(), HostError> {
3420 self.call_any_lifecycle_hook(TraceEvent::End)?;
3421 *self.try_borrow_trace_hook_mut()? = hook;
3422 self.call_any_lifecycle_hook(TraceEvent::Begin)?;
3423 Ok(())
3424 }
3425
3426 pub(crate) fn call_any_lifecycle_hook(&self, event: TraceEvent) -> Result<(), HostError> {
3427 match &*self.try_borrow_trace_hook()? {
3428 Some(hook) => hook(self, event),
3429 None => Ok(()),
3430 }
3431 }
3432}