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