soroban_env_host/
host.rs

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