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