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