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