Skip to main content

soroban_sdk/
env.rs

1use core::convert::Infallible;
2
3#[cfg(target_family = "wasm")]
4pub mod internal {
5    use core::convert::Infallible;
6
7    pub use soroban_env_guest::*;
8    pub type EnvImpl = Guest;
9
10    // In the Guest case, Env::Error is already Infallible so there is no work
11    // to do to "reject an error": if an error occurs in the environment, the
12    // host will trap our VM and we'll never get here at all.
13    pub(crate) fn reject_err<T>(_env: &Guest, r: Result<T, Infallible>) -> Result<T, Infallible> {
14        r
15    }
16}
17
18#[cfg(not(target_family = "wasm"))]
19pub mod internal {
20    use core::convert::Infallible;
21
22    pub use soroban_env_host::*;
23    pub type EnvImpl = Host;
24
25    // When we have `feature="testutils"` (or are in cfg(test)) we enable feature
26    // `soroban-env-{common,host}/testutils` which in turn adds the helper method
27    // `Env::escalate_error_to_panic` to the Env trait.
28    //
29    // When this is available we want to use it, because it works in concert
30    // with a _different_ part of the host that's also `testutils`-gated: the
31    // mechanism for emulating the WASM VM error-handling semantics with native
32    // contracts. In particular when a WASM contract calls a host function that
33    // fails with some error E, the host traps the VM (not returning to it at
34    // all) and propagates E to the caller of the contract. This is simulated in
35    // the native case by returning a (nontrivial) error E to us here, which we
36    // then "reject" back to the host, which stores E in a temporary cell inside
37    // any `TestContract` frame in progress and then _panics_, unwinding back to
38    // a panic-catcher it installed when invoking the `TestContract` frame, and
39    // then extracting E from the frame and returning it to its caller. This
40    // simulates the "crash, but catching the error" behavior of the WASM case.
41    // This only works if we panic via `escalate_error_to_panic`.
42    //
43    // (The reason we don't just panic_any() here and let the panic-catcher do a
44    // type-based catch is that there might _be_ no panic-catcher around us, and
45    // we want to print out a nice error message in that case too, which
46    // panic_any() does not do us the favor of producing. This is all very
47    // subtle. See also soroban_env_host::Host::escalate_error_to_panic.)
48    #[cfg(any(test, feature = "testutils"))]
49    pub(crate) fn reject_err<T>(env: &Host, r: Result<T, HostError>) -> Result<T, Infallible> {
50        r.map_err(|e| env.escalate_error_to_panic(e))
51    }
52
53    // When we're _not_ in a cfg enabling `soroban-env-{common,host}/testutils`,
54    // there is no `Env::escalate_error_to_panic` to call, so we just panic
55    // here. But this is ok because in that case there is also no multi-contract
56    // calling machinery set up, nor probably any panic-catcher installed that
57    // we need to hide error values for the benefit of. Any panic in this case
58    // is probably going to unwind completely anyways. No special case needed.
59    #[cfg(not(any(test, feature = "testutils")))]
60    pub(crate) fn reject_err<T>(_env: &Host, r: Result<T, HostError>) -> Result<T, Infallible> {
61        r.map_err(|e| panic!("{:?}", e))
62    }
63
64    #[doc(hidden)]
65    impl<F, T> Convert<F, T> for super::Env
66    where
67        EnvImpl: Convert<F, T>,
68    {
69        type Error = <EnvImpl as Convert<F, T>>::Error;
70        fn convert(&self, f: F) -> Result<T, Self::Error> {
71            self.env_impl.convert(f)
72        }
73    }
74}
75
76pub use internal::xdr;
77pub use internal::ContractTtlExtension;
78pub use internal::ConversionError;
79pub use internal::EnvBase;
80pub use internal::Error;
81pub use internal::MapObject;
82pub use internal::SymbolStr;
83pub use internal::TryFromVal;
84pub use internal::TryIntoVal;
85pub use internal::Val;
86pub use internal::VecObject;
87
88pub trait IntoVal<E: internal::Env, T> {
89    fn into_val(&self, e: &E) -> T;
90}
91
92pub trait FromVal<E: internal::Env, T> {
93    fn from_val(e: &E, v: &T) -> Self;
94}
95
96impl<E: internal::Env, T, U> FromVal<E, T> for U
97where
98    U: TryFromVal<E, T>,
99{
100    fn from_val(e: &E, v: &T) -> Self {
101        U::try_from_val(e, v).unwrap_optimized()
102    }
103}
104
105impl<E: internal::Env, T, U> IntoVal<E, T> for U
106where
107    T: FromVal<E, Self>,
108{
109    fn into_val(&self, e: &E) -> T {
110        T::from_val(e, self)
111    }
112}
113
114use crate::auth::InvokerContractAuthEntry;
115use crate::custom_account::CustomAccount;
116use crate::unwrap::UnwrapInfallible;
117use crate::unwrap::UnwrapOptimized;
118use crate::InvokeError;
119use crate::{
120    crypto::Crypto, deploy::Deployer, events::Events, executable_refs::ExecutableRefs,
121    ledger::Ledger, logs::Logs, prng::Prng, storage::Storage, Address, Vec,
122};
123use internal::{
124    AddressObject, Bool, BytesObject, DurationObject, ExecutableTagObject, I128Object, I256Object,
125    I256Val, I64Object, MuxedAddressObject, StorageType, StringObject, Symbol, SymbolObject,
126    TimepointObject, U128Object, U256Object, U256Val, U32Val, U64Object, U64Val, Void,
127};
128
129#[doc(hidden)]
130#[derive(Clone)]
131pub struct MaybeEnv {
132    // On wasm an Env is always available.
133    #[cfg(target_family = "wasm")]
134    env: Env,
135    #[cfg(not(target_family = "wasm"))]
136    env: Option<Env>,
137}
138
139#[cfg(target_family = "wasm")]
140impl TryFrom<MaybeEnv> for Env {
141    type Error = Infallible;
142
143    fn try_from(value: MaybeEnv) -> Result<Self, Self::Error> {
144        Ok(value.env)
145    }
146}
147
148impl Default for MaybeEnv {
149    fn default() -> Self {
150        Self::none()
151    }
152}
153
154#[cfg(target_family = "wasm")]
155impl MaybeEnv {
156    // separate function to be const
157    pub const fn none() -> Self {
158        Self {
159            env: Env {
160                env_impl: internal::EnvImpl {},
161            },
162        }
163    }
164}
165
166#[cfg(not(target_family = "wasm"))]
167impl MaybeEnv {
168    // separate function to be const
169    pub const fn none() -> Self {
170        Self { env: None }
171    }
172}
173
174#[cfg(target_family = "wasm")]
175impl From<Env> for MaybeEnv {
176    fn from(value: Env) -> Self {
177        MaybeEnv { env: value }
178    }
179}
180
181#[cfg(not(target_family = "wasm"))]
182impl TryFrom<MaybeEnv> for Env {
183    type Error = ConversionError;
184
185    fn try_from(value: MaybeEnv) -> Result<Self, Self::Error> {
186        value.env.ok_or(ConversionError)
187    }
188}
189
190#[cfg(not(target_family = "wasm"))]
191impl From<Env> for MaybeEnv {
192    fn from(value: Env) -> Self {
193        MaybeEnv { env: Some(value) }
194    }
195}
196
197/// The [Env] type provides access to the environment the contract is executing
198/// within.
199///
200/// The [Env] provides access to information about the currently executing
201/// contract, who invoked it, contract data, functions for signing, hashing,
202/// etc.
203///
204/// Most types require access to an [Env] to be constructed or converted.
205#[derive(Clone)]
206pub struct Env {
207    env_impl: internal::EnvImpl,
208    #[cfg(any(test, feature = "testutils"))]
209    test_state: EnvTestState,
210}
211
212impl Default for Env {
213    #[cfg(not(any(test, feature = "testutils")))]
214    fn default() -> Self {
215        Self {
216            env_impl: Default::default(),
217        }
218    }
219
220    #[cfg(any(test, feature = "testutils"))]
221    fn default() -> Self {
222        Self::new_with_config(EnvTestConfig::default())
223    }
224}
225
226#[cfg(any(test, feature = "testutils"))]
227#[derive(Default, Clone)]
228struct LastEnv {
229    test_name: String,
230    number: usize,
231}
232
233#[cfg(any(test, feature = "testutils"))]
234thread_local! {
235    static LAST_ENV: RefCell<Option<LastEnv>> = RefCell::new(None);
236}
237
238/// The test state of an [Env].
239///
240/// An [Env] created by a test has test state. An [Env] created for a contract
241/// function invocation does not, because the host that creates it knows nothing
242/// of the SDK's test state and has none to pass on. Testutils functionality
243/// that depends on the test state panics rather than silently operating on
244/// empty state when used inside a contract function.
245#[cfg(any(test, feature = "testutils"))]
246#[derive(Clone)]
247enum EnvTestState {
248    Test {
249        test_name: Option<String>,
250        number: usize,
251        config: EnvTestConfig,
252        generators: Rc<RefCell<Generators>>,
253        auth_snapshot: Rc<RefCell<AuthSnapshot>>,
254        snapshot: Option<Rc<LedgerSnapshot>>,
255    },
256    Contract,
257}
258
259/// Adapts a [`ContractFunctionSet`] into the function set the host dispatches
260/// native contract calls to.
261///
262/// Shared by contract registration and Wasm upload, both of which hand the host
263/// a native contract to dispatch to.
264#[cfg(any(test, feature = "testutils"))]
265struct InternalContractFunctionSet<T: ContractFunctionSet>(T);
266
267#[cfg(any(test, feature = "testutils"))]
268impl<T: ContractFunctionSet> internal::ContractFunctionSet for InternalContractFunctionSet<T> {
269    fn call(&self, func: &Symbol, env_impl: &internal::EnvImpl, args: &[Val]) -> Option<Val> {
270        let env = Env {
271            env_impl: env_impl.clone(),
272            // The test state is unavailable inside the invocation, because the
273            // code is running as the contract.
274            test_state: EnvTestState::Contract,
275        };
276        self.0.call(
277            crate::Symbol::try_from_val(&env, func)
278                .unwrap_infallible()
279                .to_string()
280                .as_str(),
281            env,
282            args,
283        )
284    }
285}
286
287#[cfg(any(test, feature = "testutils"))]
288impl EnvTestState {
289    fn config_mut(&mut self) -> &mut EnvTestConfig {
290        match self {
291            Self::Test { config, .. } => config,
292            Self::Contract => panic!("the test config is unavailable inside a contract function and must be accessed only from the test code outside the contract function"),
293        }
294    }
295
296    fn generators(&self) -> &Rc<RefCell<Generators>> {
297        match self {
298            Self::Test { generators, .. } => generators,
299            Self::Contract => panic!("generating values like addresses is unavailable inside a contract function and must be done only from the test code outside the contract function"),
300        }
301    }
302
303    fn auth_snapshot(&self) -> &Rc<RefCell<AuthSnapshot>> {
304        match self {
305            Self::Test { auth_snapshot, .. } => auth_snapshot,
306            Self::Contract => {
307                panic!("the record of authorizations is unavailable inside a contract function and must be accessed only from the test code outside the contract function")
308            }
309        }
310    }
311
312    fn snapshot(&self) -> &Option<Rc<LedgerSnapshot>> {
313        match self {
314            Self::Test { snapshot, .. } => snapshot,
315            Self::Contract => {
316                panic!("the ledger snapshot is unavailable inside a contract function and must be accessed only from the test code outside the contract function")
317            }
318        }
319    }
320}
321
322/// Config for changing the default behavior of the Env when used in tests.
323#[cfg(any(test, feature = "testutils"))]
324#[derive(Clone)]
325pub struct EnvTestConfig {
326    /// Capture a test snapshot when the Env is dropped, causing a test snapshot
327    /// JSON file to be written to disk when the Env is no longer referenced.
328    /// Defaults to true.
329    pub capture_snapshot_at_drop: bool,
330    // NOTE: Next time a field needs to be added to EnvTestConfig it will be a breaking change,
331    // take the opportunity to make the current field private, new fields private, and settable via
332    // functions. Why: So that it is the last time a breaking change is needed to the type.
333}
334
335#[cfg(any(test, feature = "testutils"))]
336impl Default for EnvTestConfig {
337    fn default() -> Self {
338        Self {
339            capture_snapshot_at_drop: true,
340        }
341    }
342}
343
344impl Env {
345    /// Panic with the given error.
346    ///
347    /// Equivalent to `panic!`, but with an error value instead of a string.
348    #[doc(hidden)]
349    #[inline(always)]
350    pub fn panic_with_error<I>(&self, error: I) -> !
351    where
352        I: Into<internal::Error> + crate::SpecShakingMarker,
353    {
354        I::spec_shaking_marker();
355        self.panic_with_error_inner(error.into())
356    }
357
358    #[inline(always)]
359    fn panic_with_error_inner(&self, error: internal::Error) -> ! {
360        _ = internal::Env::fail_with_error(self, error);
361        #[cfg(target_family = "wasm")]
362        core::arch::wasm32::unreachable();
363        #[cfg(not(target_family = "wasm"))]
364        unreachable!();
365    }
366
367    /// Get a [Storage] for accessing and updating persistent data owned by the
368    /// currently executing contract.
369    #[inline(always)]
370    pub fn storage(&self) -> Storage {
371        Storage::new(self)
372    }
373
374    /// Get [Events] for publishing events associated with the
375    /// currently executing contract.
376    #[inline(always)]
377    pub fn events(&self) -> Events {
378        Events::new(self)
379    }
380
381    /// Get a [Ledger] for accessing the current ledger.
382    #[inline(always)]
383    pub fn ledger(&self) -> Ledger {
384        Ledger::new(self)
385    }
386
387    /// Get a deployer for deploying contracts.
388    #[inline(always)]
389    pub fn deployer(&self) -> Deployer {
390        Deployer::new(self)
391    }
392
393    /// Get an [ExecutableRefs] for managing the executable reference entries
394    /// owned by the currently executing contract.
395    #[inline(always)]
396    pub fn executable_refs(&self) -> ExecutableRefs {
397        ExecutableRefs::new(self)
398    }
399
400    /// Get an accessor for functions used for custom account implementation.
401    ///
402    /// The accessor's methods may only be called within `__check_auth` contract
403    /// function.
404    #[inline(always)]
405    pub fn custom_account(&self) -> CustomAccount {
406        CustomAccount::new(self)
407    }
408
409    /// Get a [Crypto] for accessing the current cryptographic functions.
410    #[inline(always)]
411    pub fn crypto(&self) -> Crypto {
412        Crypto::new(self)
413    }
414
415    /// # ⚠️ Hazardous Materials
416    ///
417    /// Get a [CryptoHazmat][crate::crypto::CryptoHazmat] for accessing the
418    /// cryptographic functions that are not generally recommended. Using them
419    /// incorrectly can introduce security vulnerabilities. Use [Crypto] if
420    /// possible.
421    #[cfg_attr(any(test, feature = "hazmat-crypto"), visibility::make(pub))]
422    #[cfg_attr(feature = "docs", doc(cfg(feature = "hazmat-crypto")))]
423    #[inline(always)]
424    pub(crate) fn crypto_hazmat(&self) -> crate::crypto::CryptoHazmat {
425        crate::crypto::CryptoHazmat::new(self)
426    }
427
428    /// Get a [Prng] for accessing the current functions which provide pseudo-randomness.
429    ///
430    /// # Warning
431    ///
432    /// **The pseudo-random generator returned is not suitable for
433    /// security-sensitive work.**
434    #[inline(always)]
435    pub fn prng(&self) -> Prng {
436        Prng::new(self)
437    }
438
439    /// Get the Address object corresponding to the current executing contract.
440    pub fn current_contract_address(&self) -> Address {
441        let address = internal::Env::get_current_contract_address(self).unwrap_infallible();
442        unsafe { Address::unchecked_new(self.clone(), address) }
443    }
444
445    #[doc(hidden)]
446    pub(crate) fn require_auth_for_args(&self, address: &Address, args: Vec<Val>) {
447        internal::Env::require_auth_for_args(self, address.to_object(), args.to_object())
448            .unwrap_infallible();
449    }
450
451    #[doc(hidden)]
452    pub(crate) fn require_auth(&self, address: &Address) {
453        internal::Env::require_auth(self, address.to_object()).unwrap_infallible();
454    }
455
456    /// Invokes a function of a contract that is registered in the [Env].
457    ///
458    /// # Panics
459    ///
460    /// Will panic if the `contract_id` does not match a registered contract,
461    /// `func` does not match a function of the referenced contract, or the
462    /// number of `args` do not match the argument count of the referenced
463    /// contract function.
464    ///
465    /// Will panic if the contract that is invoked fails or aborts in anyway.
466    ///
467    /// Will panic if the value returned from the contract cannot be converted
468    /// into the type `T`.
469    pub fn invoke_contract<T>(
470        &self,
471        contract_address: &Address,
472        func: &crate::Symbol,
473        args: Vec<Val>,
474    ) -> T
475    where
476        T: TryFromVal<Env, Val>,
477    {
478        let rv = internal::Env::call(
479            self,
480            contract_address.to_object(),
481            func.to_symbol_val(),
482            args.to_object(),
483        )
484        .unwrap_infallible();
485        T::try_from_val(self, &rv)
486            .map_err(|_| ConversionError)
487            .unwrap()
488    }
489
490    /// Invokes a function of a contract that is registered in the [Env],
491    /// returns an error if the invocation fails for any reason.
492    pub fn try_invoke_contract<T, E>(
493        &self,
494        contract_address: &Address,
495        func: &crate::Symbol,
496        args: Vec<Val>,
497    ) -> Result<Result<T, T::Error>, Result<E, InvokeError>>
498    where
499        T: TryFromVal<Env, Val>,
500        E: TryFrom<Error>,
501        E::Error: Into<InvokeError>,
502    {
503        let rv = internal::Env::try_call(
504            self,
505            contract_address.to_object(),
506            func.to_symbol_val(),
507            args.to_object(),
508        )
509        .unwrap_infallible();
510        match internal::Error::try_from_val(self, &rv) {
511            Ok(err) => Err(E::try_from(err).map_err(Into::into)),
512            Err(ConversionError) => Ok(T::try_from_val(self, &rv)),
513        }
514    }
515
516    /// Authorizes sub-contract calls on behalf of the current contract.
517    ///
518    /// All the direct calls that the current contract performs are always
519    /// considered to have been authorized. This is only needed to authorize
520    /// deeper calls that originate from the next contract call from the current
521    /// contract.
522    ///
523    /// For example, if the contract A calls contract B, contract
524    /// B calls contract C and contract C calls `A.require_auth()`, then an
525    /// entry corresponding to C call has to be passed in `auth_entries`. It
526    /// doesn't matter if contract B called `require_auth` or not. If contract A
527    /// calls contract B again, then `authorize_as_current_contract` has to be
528    /// called again with the respective entries.
529    ///
530    /// When testing a contract call that uses `authorize_as_current_contract`, avoid
531    /// using [`mock_all_auths_allowing_non_root_auth`][Self::mock_all_auths_allowing_non_root_auth].
532    /// A test that uses this mock will not fail if a missing or incorrect
533    /// `authorize_as_current_contract` call is present. It is recommended to use other
534    /// authorization mocking functions like [`mock_auths`][Self::mock_auths]
535    /// or [`set_auths`][Self::set_auths] if needed.
536    ///
537    /// ### Examples
538    /// ```
539    /// use soroban_sdk::{
540    ///     auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation},
541    ///     contract, contractimpl, vec, Address, Env, IntoVal, Symbol,
542    /// };
543    ///
544    /// // Contract C performs authorization for addr
545    /// #[contract]
546    /// pub struct ContractC;
547    ///
548    /// #[contractimpl]
549    /// impl ContractC {
550    ///     pub fn do_auth(_env: Env, addr: Address, amount: i128) -> i128 {
551    ///         addr.require_auth();
552    ///         amount
553    ///     }
554    /// }
555    ///
556    /// // Contract B performs authorization for `addr` and invokes Contract C with
557    /// // `addr` and `amount` as arguments.
558    /// #[contract]
559    /// pub struct ContractB;
560    ///
561    /// #[contractimpl]
562    /// impl ContractB {
563    ///     pub fn call_c(env: Env, addr: Address, contract_c: Address, amount: i128) -> i128 {
564    ///         addr.require_auth();
565    ///         ContractCClient::new(&env, &contract_c).do_auth(&addr, &amount)
566    ///     }
567    /// }
568    ///
569    /// // Contract A authorizes Contract B to call Contract C on its behalf with `addr` and
570    /// // `amount` as arguments.
571    /// #[contract]
572    /// pub struct ContractA;
573    ///
574    /// #[contractimpl]
575    /// impl ContractA {
576    ///     pub fn call_b(env: Env, contract_b: Address, contract_c: Address, amount: i128) -> i128 {
577    ///         let curr_contract = env.current_contract_address();
578    ///         // Authorize the sub-call Contract B makes to Contract C
579    ///         env.authorize_as_current_contract(vec![
580    ///             &env,
581    ///             InvokerContractAuthEntry::Contract(SubContractInvocation {
582    ///                 context: ContractContext {
583    ///                     contract: contract_c.clone(),
584    ///                     fn_name: Symbol::new(&env, "do_auth"),
585    ///                     args: vec![&env, curr_contract.into_val(&env), amount.into_val(&env)],
586    ///                 },
587    ///                 sub_invocations: vec![&env],
588    ///             }),
589    ///         ]);
590    ///         ContractBClient::new(&env, &contract_b).call_c(&curr_contract, &contract_c, &amount)
591    ///     }
592    /// }
593    ///
594    /// #[test]
595    /// fn test() {
596    /// # }
597    /// # fn main() {
598    ///     let env = Env::default();
599    ///     let contract_a = env.register(ContractA, ());
600    ///     let contract_b = env.register(ContractB, ());
601    ///     let contract_c = env.register(ContractC, ());
602    ///
603    ///     // Auths are not mocked to ensure `authorize_as_current_contract`
604    ///     // is working as intended. If Contract A includes additional auths, consider
605    ///     // using `mock_auths` or `set_auths` for those authorizations.
606    ///
607    ///     let client = ContractAClient::new(&env, &contract_a);
608    ///     let result = client.call_b(&contract_b, &contract_c, &100);
609    ///     assert_eq!(result, 100);
610    /// }
611    /// ```
612    pub fn authorize_as_current_contract(&self, auth_entries: Vec<InvokerContractAuthEntry>) {
613        internal::Env::authorize_as_curr_contract(self, auth_entries.to_object())
614            .unwrap_infallible();
615    }
616
617    /// Get the [Logs] for logging debug events.
618    #[inline(always)]
619    #[deprecated(note = "use [Env::logs]")]
620    #[doc(hidden)]
621    pub fn logger(&self) -> Logs {
622        self.logs()
623    }
624
625    /// Get the [Logs] for logging debug events.
626    #[inline(always)]
627    pub fn logs(&self) -> Logs {
628        Logs::new(self)
629    }
630}
631
632#[doc(hidden)]
633#[cfg(not(target_family = "wasm"))]
634impl Env {
635    pub(crate) fn is_same_env(&self, other: &Self) -> bool {
636        self.env_impl.is_same(&other.env_impl)
637    }
638}
639
640#[cfg(any(test, feature = "testutils"))]
641use crate::testutils::cost_estimate::CostEstimate;
642#[cfg(any(test, feature = "testutils"))]
643use crate::{
644    auth,
645    testutils::{
646        budget::Budget, cost_estimate::NetworkInvocationResourceLimits, default_ledger_info,
647        Address as _, AuthSnapshot, AuthorizedInvocation, ContractFunctionSet, EventsSnapshot,
648        Generators, Ledger as _, MockAuth, MockAuthContract, Register, Snapshot,
649        SnapshotSourceInput, StellarAssetContract, StellarAssetIssuer,
650    },
651    Bytes, BytesN, ConstructorArgs,
652};
653#[cfg(any(test, feature = "testutils"))]
654use core::{cell::RefCell, cell::RefMut};
655#[cfg(any(test, feature = "testutils"))]
656use internal::{InvocationEvent, InvocationResourceLimits};
657#[cfg(any(test, feature = "testutils"))]
658use soroban_ledger_snapshot::LedgerSnapshot;
659#[cfg(any(test, feature = "testutils"))]
660use std::{path::Path, rc::Rc};
661#[cfg(any(test, feature = "testutils"))]
662use xdr::{LedgerEntry, LedgerKey, LedgerKeyContractData, SorobanAuthorizationEntry};
663
664#[cfg(any(test, feature = "testutils"))]
665#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))]
666impl Env {
667    #[doc(hidden)]
668    pub fn in_contract(&self) -> bool {
669        self.env_impl.has_frame().unwrap()
670    }
671
672    #[doc(hidden)]
673    pub fn host(&self) -> &internal::Host {
674        &self.env_impl
675    }
676
677    #[doc(hidden)]
678    pub(crate) fn with_generator<T>(&self, f: impl FnOnce(RefMut<'_, Generators>) -> T) -> T {
679        f((*self.test_state.generators()).borrow_mut())
680    }
681
682    /// Create an Env with the test config.
683    pub fn new_with_config(config: EnvTestConfig) -> Env {
684        struct EmptySnapshotSource();
685
686        impl internal::storage::SnapshotSource for EmptySnapshotSource {
687            fn get(
688                &self,
689                _key: &Rc<xdr::LedgerKey>,
690            ) -> Result<Option<(Rc<xdr::LedgerEntry>, Option<u32>)>, soroban_env_host::HostError>
691            {
692                Ok(None)
693            }
694        }
695
696        let rf = Rc::new(EmptySnapshotSource());
697
698        Env::new_for_testutils(config, rf, None, None, None)
699    }
700
701    /// Change the test config of an Env.
702    pub fn set_config(&mut self, config: EnvTestConfig) {
703        *self.test_state.config_mut() = config;
704    }
705
706    /// Used by multiple constructors to configure test environments consistently.
707    fn new_for_testutils(
708        config: EnvTestConfig,
709        recording_footprint: Rc<dyn internal::storage::SnapshotSource>,
710        generators: Option<Rc<RefCell<Generators>>>,
711        ledger_info: Option<internal::LedgerInfo>,
712        snapshot: Option<Rc<LedgerSnapshot>>,
713    ) -> Env {
714        // Store in the Env the name of the test it is for, and a number so that within a test
715        // where one or more Env's have been created they can be uniquely identified relative to
716        // each other.
717
718        let test_name = match std::thread::current().name() {
719            // When doc tests are running they're all run with the thread name main. There's no way
720            // to detect which doc test is being run.
721            Some(name) if name != "main" => Some(name.to_owned()),
722            _ => None,
723        };
724        let number = if let Some(ref test_name) = test_name {
725            LAST_ENV.with_borrow_mut(|l| {
726                if let Some(last_env) = l.as_mut() {
727                    if test_name != &last_env.test_name {
728                        last_env.test_name = test_name.clone();
729                        last_env.number = 1;
730                        1
731                    } else {
732                        let next_number = last_env.number + 1;
733                        last_env.number = next_number;
734                        next_number
735                    }
736                } else {
737                    *l = Some(LastEnv {
738                        test_name: test_name.clone(),
739                        number: 1,
740                    });
741                    1
742                }
743            })
744        } else {
745            1
746        };
747
748        let storage = internal::storage::Storage::with_recording_footprint(recording_footprint);
749        let budget = internal::budget::Budget::default();
750        let env_impl = internal::EnvImpl::with_storage_and_budget(storage, budget.clone());
751        env_impl
752            .set_source_account(xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(
753                xdr::Uint256([0; 32]),
754            )))
755            .unwrap();
756        env_impl
757            .set_diagnostic_level(internal::DiagnosticLevel::Debug)
758            .unwrap();
759        env_impl.set_base_prng_seed([0; 32]).unwrap();
760
761        let auth_snapshot = Rc::new(RefCell::new(AuthSnapshot::default()));
762        let auth_snapshot_in_hook = auth_snapshot.clone();
763        env_impl
764            .set_invocation_hook(Some(Rc::new(move |host, event| {
765                match event {
766                    InvocationEvent::Start => {}
767                    InvocationEvent::Finish => {
768                        let new_auths = host
769                            .get_authenticated_authorizations()
770                            // If an error occurs getting the authenticated authorizations
771                            // it means that no auth has occurred.
772                            .unwrap();
773                        (*auth_snapshot_in_hook).borrow_mut().0.push(new_auths);
774                    }
775                }
776            })))
777            .unwrap();
778        env_impl.enable_invocation_metering();
779        env_impl
780            .set_invocation_resource_limits(Some(InvocationResourceLimits::mainnet()))
781            .unwrap();
782
783        let env = Env {
784            env_impl,
785            test_state: EnvTestState::Test {
786                test_name,
787                number,
788                config,
789                generators: generators.unwrap_or_default(),
790                snapshot,
791                auth_snapshot,
792            },
793        };
794
795        let ledger_info = ledger_info.unwrap_or_else(default_ledger_info);
796        env.ledger().set(ledger_info);
797
798        env
799    }
800
801    /// Returns the resources metered during the last top level contract
802    /// invocation.    
803    ///
804    /// In order to get non-`None` results, `enable_invocation_metering` has to
805    /// be called and at least one invocation has to happen after that.
806    ///
807    /// Take the return value with a grain of salt. The returned resources mostly
808    /// correspond only to the operations that have happened during the host
809    /// invocation, i.e. this won't try to simulate the work that happens in
810    /// production scenarios (e.g. certain XDR roundtrips). This also doesn't try
811    /// to model resources related to the transaction size.
812    ///
813    /// The returned value is as useful as the preceding setup, e.g. if a test
814    /// contract is used instead of a Wasm contract, all the costs related to
815    /// VM instantiation and execution, as well as Wasm reads/rent bumps will be
816    /// missed.
817    ///
818    /// While the resource metering may be useful for contract optimization,
819    /// keep in mind that resource and fee estimation may be imprecise. Use
820    /// simulation with RPC in order to get the exact resources for submitting
821    /// the transactions to the network.    
822    pub fn cost_estimate(&self) -> CostEstimate {
823        CostEstimate::new(self.clone())
824    }
825
826    /// Register a contract with the [Env] for testing.
827    ///
828    /// Pass the contract type when the contract is defined in the current crate
829    /// and is being registered natively. Pass the contract wasm bytes when the
830    /// contract has been loaded as wasm.
831    ///
832    /// Pass the arguments for the contract's constructor, or `()` if none. For
833    /// contracts with a constructor, use the contract's generated `Args` type
834    /// to construct the arguments with the appropriate types for invoking
835    /// the constructor during registration.
836    ///
837    /// Returns the address of the registered contract that is the same as the
838    /// contract id passed in.
839    ///
840    /// If you need to specify the address the contract should be registered at,
841    /// use [`Env::register_at`].
842    ///
843    /// ### Authorization
844    ///
845    /// If the contract has a constructor, it is called during registration
846    /// with authorization mocked: the environment switches to recording auth
847    /// for the constructor call, so any [`Address::require_auth`] calls the
848    /// constructor makes are automatically authorized and succeed regardless
849    /// of the authorization configured on the environment. Because of this,
850    /// `register` cannot be used to test a constructor's authorization.
851    ///
852    /// To test constructor authorization, deploy the contract the way it is
853    /// deployed on-chain using the deployer returned by [`Env::deployer`],
854    /// e.g. [`Deployer::with_address`] followed by
855    /// [`deploy_contract`][crate::deploy::DeployerWithAddress::deploy_contract]. Deploying
856    /// that way runs the constructor subject to the environment's
857    /// authorization, so `require_auth` behaves as it would on-chain.
858    ///
859    /// ### Examples
860    /// Register a contract defined in the current crate, by specifying the type
861    /// name:
862    /// ```
863    /// use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, BytesN, Env, Symbol};
864    ///
865    /// #[contract]
866    /// pub struct Contract;
867    ///
868    /// #[contractimpl]
869    /// impl Contract {
870    ///     pub fn __constructor(_env: Env, _input: u32) {
871    ///     }
872    /// }
873    ///
874    /// #[test]
875    /// fn test() {
876    /// # }
877    /// # fn main() {
878    ///     let env = Env::default();
879    ///     let contract_id = env.register(Contract, ContractArgs::__constructor(&123,));
880    /// }
881    /// ```
882    /// Register a contract wasm, by specifying the wasm bytes:
883    /// ```
884    /// use soroban_sdk::{testutils::Address as _, Address, BytesN, Env};
885    ///
886    /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm");
887    ///
888    /// #[test]
889    /// fn test() {
890    /// # }
891    /// # fn main() {
892    ///     let env = Env::default();
893    ///     let contract_id = env.register(WASM, ());
894    /// }
895    /// ```
896    pub fn register<'a, C, A>(&self, contract: C, constructor_args: A) -> Address
897    where
898        C: Register,
899        A: ConstructorArgs,
900    {
901        contract.register(self, None, constructor_args)
902    }
903
904    /// Register a contract with the [Env] for testing.
905    ///
906    /// Passing a contract ID for the first arguments registers the contract
907    /// with that contract ID.
908    ///
909    /// Registering a contract that is already registered replaces it.
910    /// Use re-registration with caution as it does not exist in the real
911    /// (on-chain) environment. Specifically, the new contract's constructor
912    /// will be called again during re-registration. That behavior only exists
913    /// for this test utility and is not reproducible on-chain, where contract
914    /// Wasm updates don't cause constructor to be called.
915    ///
916    /// Pass the contract type when the contract is defined in the current crate
917    /// and is being registered natively. Pass the contract wasm bytes when the
918    /// contract has been loaded as wasm.
919    ///
920    /// Returns the address of the registered contract that is the same as the
921    /// contract id passed in.
922    ///
923    /// ### Authorization
924    ///
925    /// If the contract has a constructor, it is called during registration
926    /// with authorization mocked: the environment switches to recording auth
927    /// for the constructor call, so any [`Address::require_auth`] calls the
928    /// constructor makes are automatically authorized and succeed regardless
929    /// of the authorization configured on the environment. Because of this,
930    /// `register_at` cannot be used to test a constructor's authorization.
931    ///
932    /// To test constructor authorization, deploy the contract the way it is
933    /// deployed on-chain using the deployer returned by [`Env::deployer`],
934    /// e.g. [`Deployer::with_address`] followed by
935    /// [`deploy_contract`][crate::deploy::DeployerWithAddress::deploy_contract]. Deploying
936    /// that way runs the constructor subject to the environment's
937    /// authorization, so `require_auth` behaves as it would on-chain.
938    ///
939    /// ### Examples
940    /// Register a contract defined in the current crate, by specifying the type
941    /// name:
942    /// ```
943    /// use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, BytesN, Env, Symbol};
944    ///
945    /// #[contract]
946    /// pub struct Contract;
947    ///
948    /// #[contractimpl]
949    /// impl Contract {
950    ///     pub fn __constructor(_env: Env, _input: u32) {
951    ///     }
952    /// }
953    ///
954    /// #[test]
955    /// fn test() {
956    /// # }
957    /// # fn main() {
958    ///     let env = Env::default();
959    ///     let contract_id = Address::generate(&env);
960    ///     env.register_at(&contract_id, Contract, (123_u32,));
961    /// }
962    /// ```
963    /// Register a contract wasm, by specifying the wasm bytes:
964    /// ```
965    /// use soroban_sdk::{testutils::Address as _, Address, BytesN, Env};
966    ///
967    /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm");
968    ///
969    /// #[test]
970    /// fn test() {
971    /// # }
972    /// # fn main() {
973    ///     let env = Env::default();
974    ///     let contract_id = Address::generate(&env);
975    ///     env.register_at(&contract_id, WASM, ());
976    /// }
977    /// ```
978    pub fn register_at<C, A>(
979        &self,
980        contract_id: &Address,
981        contract: C,
982        constructor_args: A,
983    ) -> Address
984    where
985        C: Register,
986        A: ConstructorArgs,
987    {
988        contract.register(self, contract_id, constructor_args)
989    }
990
991    /// Upload a contract that is defined in the current crate to the [Env] for
992    /// testing, as if it was a contract Wasm.
993    ///
994    /// Contract instances that use the returned Wasm hash as their executable,
995    /// such as instances deployed with [`Env::deployer`], dispatch their calls
996    /// to the uploaded contract.
997    ///
998    /// A new Wasm hash is generated for every call. If you need to specify the
999    /// Wasm hash the contract should be uploaded to, use [`Env::upload_at`].
1000    ///
1001    /// Returns the Wasm hash the contract was uploaded to.
1002    ///
1003    /// ### Examples
1004    /// ```
1005    /// use soroban_sdk::{contract, contractimpl, Env};
1006    ///
1007    /// #[contract]
1008    /// pub struct Contract;
1009    ///
1010    /// #[contractimpl]
1011    /// impl Contract {
1012    ///     pub fn hello(env: Env) { /* ... */ }
1013    /// }
1014    ///
1015    /// #[test]
1016    /// fn test() {
1017    /// # }
1018    /// # fn main() {
1019    ///     let env = Env::default();
1020    ///     let wasm_hash = env.upload(Contract);
1021    /// }
1022    /// ```
1023    pub fn upload<C>(&self, contract: C) -> BytesN<32>
1024    where
1025        C: ContractFunctionSet + 'static,
1026    {
1027        self.upload_at(self.with_generator(|mut g| g.wasm_hash()), contract)
1028    }
1029
1030    /// Upload a contract that is defined in the current crate to the [Env] for
1031    /// testing, as if it was a contract Wasm, at the Wasm hash specified.
1032    ///
1033    /// Contract instances that use the Wasm hash as their executable, such as
1034    /// instances deployed with [`Env::deployer`], dispatch their calls to the
1035    /// uploaded contract.
1036    ///
1037    /// Uploading to a Wasm hash that already has a contract, native or Wasm,
1038    /// uploaded to it replaces it for the purpose of contract calls. Use
1039    /// re-uploading for testing only. It does not exist in the real (on-chain)
1040    /// environment, where Wasm is immutable. Any ledger entry that already
1041    /// exists for the Wasm hash is left untouched, including a real Wasm's
1042    /// entry that a snapshot was loaded with.
1043    ///
1044    /// Returns the Wasm hash the contract was uploaded to, which is the same as
1045    /// the Wasm hash passed in.
1046    ///
1047    /// ### Examples
1048    /// ```
1049    /// use soroban_sdk::{contract, contractimpl, Env};
1050    ///
1051    /// #[contract]
1052    /// pub struct Contract;
1053    ///
1054    /// #[contractimpl]
1055    /// impl Contract {
1056    ///     pub fn hello(env: Env) { /* ... */ }
1057    /// }
1058    ///
1059    /// #[test]
1060    /// fn test() {
1061    /// # }
1062    /// # fn main() {
1063    ///     let env = Env::default();
1064    ///     env.upload_at([1u8; 32], Contract);
1065    /// }
1066    /// ```
1067    pub fn upload_at<C>(&self, wasm_hash: impl IntoVal<Env, BytesN<32>>, contract: C) -> BytesN<32>
1068    where
1069        C: ContractFunctionSet + 'static,
1070    {
1071        let wasm_hash = wasm_hash.into_val(self);
1072        self.env_impl
1073            .register_native_contract_as_wasm(
1074                Rc::new(InternalContractFunctionSet(contract)),
1075                wasm_hash.to_object(),
1076            )
1077            .unwrap();
1078        wasm_hash
1079    }
1080
1081    /// Register a contract with the [Env] for testing.
1082    ///
1083    /// Passing a contract ID for the first arguments registers the contract
1084    /// with that contract ID. Providing `None` causes the Env to generate a new
1085    /// contract ID that is assigned to the contract.
1086    ///
1087    /// If a contract has a constructor defined, then it will be called with
1088    /// no arguments. If a constructor takes arguments, use `register`.
1089    ///
1090    /// The constructor call has authorization mocked, the same as
1091    /// [`register`][Self::register]; see that function for how to test
1092    /// constructor authorization.
1093    ///
1094    /// Registering a contract that is already registered replaces it.
1095    /// Use re-registration with caution as it does not exist in the real
1096    /// (on-chain) environment. Specifically, the new contract's constructor
1097    /// will be called again during re-registration. That behavior only exists
1098    /// for this test utility and is not reproducible on-chain, where contract
1099    /// Wasm updates don't cause constructor to be called.
1100    ///
1101    /// Returns the address of the registered contract.
1102    ///
1103    /// ### Examples
1104    /// ```
1105    /// use soroban_sdk::{contract, contractimpl, BytesN, Env, Symbol};
1106    ///
1107    /// #[contract]
1108    /// pub struct HelloContract;
1109    ///
1110    /// #[contractimpl]
1111    /// impl HelloContract {
1112    ///     pub fn hello(env: Env, recipient: Symbol) -> Symbol {
1113    ///         todo!()
1114    ///     }
1115    /// }
1116    ///
1117    /// #[test]
1118    /// fn test() {
1119    /// # }
1120    /// # fn main() {
1121    ///     let env = Env::default();
1122    ///     let contract_id = env.register_contract(None, HelloContract);
1123    /// }
1124    /// ```
1125    #[deprecated(note = "use `register`")]
1126    pub fn register_contract<'a, T: ContractFunctionSet + 'static>(
1127        &self,
1128        contract_id: impl Into<Option<&'a Address>>,
1129        contract: T,
1130    ) -> Address {
1131        self.register_contract_with_constructor(contract_id, contract, ())
1132    }
1133
1134    /// Register a contract with the [Env] for testing.
1135    ///
1136    /// This acts the in the same fashion as `register_contract`, but allows
1137    /// passing arguments to the contract's constructor.
1138    ///
1139    /// Passing a contract ID for the first arguments registers the contract
1140    /// with that contract ID. Providing `None` causes the Env to generate a new
1141    /// contract ID that is assigned to the contract.
1142    ///
1143    /// Registering a contract that is already registered replaces it.
1144    /// Use re-registration with caution as it does not exist in the real
1145    /// (on-chain) environment. Specifically, the new contract's constructor
1146    /// will be called again during re-registration. That behavior only exists
1147    /// for this test utility and is not reproducible on-chain, where contract
1148    /// Wasm updates don't cause constructor to be called.
1149    ///
1150    /// Returns the address of the registered contract.
1151    pub(crate) fn register_contract_with_constructor<
1152        'a,
1153        T: ContractFunctionSet + 'static,
1154        A: ConstructorArgs,
1155    >(
1156        &self,
1157        contract_id: impl Into<Option<&'a Address>>,
1158        contract: T,
1159        constructor_args: A,
1160    ) -> Address {
1161        let contract_id = if let Some(contract_id) = contract_id.into() {
1162            contract_id.clone()
1163        } else {
1164            Address::generate(self)
1165        };
1166        // Convert the constructor arguments before switching auth managers, so
1167        // that a panic during conversion cannot leave the environment stuck in
1168        // recording auth. This matches the wasm registration path.
1169        let constructor_args = constructor_args.into_val(self).to_object();
1170        let prev_auth_manager = self.env_impl.snapshot_auth_manager().unwrap();
1171        self.env_impl
1172            .switch_to_recording_auth_inherited_from_snapshot(&prev_auth_manager)
1173            .unwrap();
1174        let register_result = self.env_impl.register_test_contract_with_constructor(
1175            contract_id.to_object(),
1176            Rc::new(InternalContractFunctionSet(contract)),
1177            constructor_args,
1178        );
1179        self.env_impl.set_auth_manager(prev_auth_manager).unwrap();
1180        register_result.unwrap();
1181        contract_id
1182    }
1183
1184    /// Register a contract in a Wasm file with the [Env] for testing.
1185    ///
1186    /// Passing a contract ID for the first arguments registers the contract
1187    /// with that contract ID. Providing `None` causes the Env to generate a new
1188    /// contract ID that is assigned to the contract.
1189    ///
1190    /// If the contract has a constructor, it is called during registration
1191    /// with authorization mocked, the same as [`register`][Self::register];
1192    /// see that function for how to test constructor authorization.
1193    ///
1194    /// Registering a contract that is already registered replaces it.
1195    /// Use re-registration with caution as it does not exist in the real
1196    /// (on-chain) environment. Specifically, the new contract's constructor
1197    /// will be called again during re-registration. That behavior only exists
1198    /// for this test utility and is not reproducible on-chain, where contract
1199    /// Wasm updates don't cause constructor to be called.
1200    ///
1201    /// Returns the address of the registered contract.
1202    ///
1203    /// ### Examples
1204    /// ```
1205    /// use soroban_sdk::{BytesN, Env};
1206    ///
1207    /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm");
1208    ///
1209    /// #[test]
1210    /// fn test() {
1211    /// # }
1212    /// # fn main() {
1213    ///     let env = Env::default();
1214    ///     env.register_contract_wasm(None, WASM);
1215    /// }
1216    /// ```
1217    #[deprecated(note = "use `register`")]
1218    pub fn register_contract_wasm<'a>(
1219        &self,
1220        contract_id: impl Into<Option<&'a Address>>,
1221        contract_wasm: impl IntoVal<Env, Bytes>,
1222    ) -> Address {
1223        let wasm_hash: BytesN<32> = self.deployer().upload_contract_wasm(contract_wasm);
1224        self.register_contract_with_optional_contract_id_and_executable(
1225            contract_id,
1226            xdr::ContractExecutable::Wasm(xdr::Hash(wasm_hash.into())),
1227            crate::vec![&self],
1228        )
1229    }
1230
1231    /// Register a contract in a Wasm file with the [Env] for testing.
1232    ///
1233    /// This acts the in the same fashion as `register_contract`, but allows
1234    /// passing arguments to the contract's constructor.
1235    ///
1236    /// Passing a contract ID for the first arguments registers the contract
1237    /// with that contract ID. Providing `None` causes the Env to generate a new
1238    /// contract ID that is assigned to the contract.
1239    ///
1240    /// Registering a contract that is already registered replaces it.
1241    /// Use re-registration with caution as it does not exist in the real
1242    /// (on-chain) environment. Specifically, the new contract's constructor
1243    /// will be called again during re-registration. That behavior only exists
1244    /// for this test utility and is not reproducible on-chain, where contract
1245    /// Wasm updates don't cause constructor to be called.
1246    ///
1247    /// Returns the address of the registered contract.
1248    pub(crate) fn register_contract_wasm_with_constructor<'a>(
1249        &self,
1250        contract_id: impl Into<Option<&'a Address>>,
1251        contract_wasm: impl IntoVal<Env, Bytes>,
1252        constructor_args: impl ConstructorArgs,
1253    ) -> Address {
1254        let wasm_hash: BytesN<32> = self.deployer().upload_contract_wasm(contract_wasm);
1255        self.register_contract_with_optional_contract_id_and_executable(
1256            contract_id,
1257            xdr::ContractExecutable::Wasm(xdr::Hash(wasm_hash.into())),
1258            constructor_args.into_val(self),
1259        )
1260    }
1261
1262    /// Register the built-in Stellar Asset Contract with provided admin address.
1263    ///
1264    /// Returns a utility struct that contains the contract ID of the registered
1265    /// token contract, as well as methods to read and update issuer flags.
1266    ///
1267    /// The contract will wrap a randomly-generated Stellar asset. This function
1268    /// is useful for using in the tests when an arbitrary token contract
1269    /// instance is needed.
1270    pub fn register_stellar_asset_contract_v2(&self, admin: Address) -> StellarAssetContract {
1271        let issuer_pk = self.with_generator(|mut g| g.address());
1272        let issuer_id = xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(xdr::Uint256(
1273            issuer_pk.clone(),
1274        )));
1275
1276        let k = Rc::new(xdr::LedgerKey::Account(xdr::LedgerKeyAccount {
1277            account_id: issuer_id.clone(),
1278        }));
1279
1280        if self.host().get_ledger_entry(&k).unwrap().is_none() {
1281            let v = Rc::new(xdr::LedgerEntry {
1282                data: xdr::LedgerEntryData::Account(xdr::AccountEntry {
1283                    account_id: issuer_id.clone(),
1284                    balance: 0,
1285                    flags: 0,
1286                    home_domain: Default::default(),
1287                    inflation_dest: None,
1288                    num_sub_entries: 0,
1289                    seq_num: xdr::SequenceNumber(0),
1290                    thresholds: xdr::Thresholds([1; 4]),
1291                    signers: xdr::VecM::default(),
1292                    ext: xdr::AccountEntryExt::V0,
1293                }),
1294                last_modified_ledger_seq: 0,
1295                ext: xdr::LedgerEntryExt::V0,
1296            });
1297            self.host().add_ledger_entry(&k, &v, None).unwrap();
1298        }
1299
1300        let asset = xdr::Asset::CreditAlphanum4(xdr::AlphaNum4 {
1301            asset_code: xdr::AssetCode4([b'a', b'a', b'a', 0]),
1302            issuer: issuer_id.clone(),
1303        });
1304        let create = xdr::HostFunction::CreateContract(xdr::CreateContractArgs {
1305            contract_id_preimage: xdr::ContractIdPreimage::Asset(asset.clone()),
1306            executable: xdr::ContractExecutable::StellarAsset,
1307        });
1308
1309        let token_id: Address = self
1310            .env_impl
1311            .invoke_function(create)
1312            .unwrap()
1313            .try_into_val(self)
1314            .unwrap();
1315
1316        let prev_auth_manager = self.env_impl.snapshot_auth_manager().unwrap();
1317        self.env_impl
1318            .switch_to_recording_auth_inherited_from_snapshot(&prev_auth_manager)
1319            .unwrap();
1320        let admin_result = self.try_invoke_contract::<(), Error>(
1321            &token_id,
1322            &soroban_sdk_macros::internal_symbol_short!("set_admin"),
1323            (admin,).try_into_val(self).unwrap(),
1324        );
1325        self.env_impl.set_auth_manager(prev_auth_manager).unwrap();
1326        admin_result.unwrap().unwrap();
1327
1328        let issuer = StellarAssetIssuer::new(self.clone(), issuer_id);
1329        StellarAssetContract::new(token_id, issuer, asset)
1330    }
1331
1332    /// Register the built-in Stellar Asset Contract with provided admin address.
1333    ///
1334    /// Returns the contract ID of the registered token contract.
1335    ///
1336    /// The contract will wrap a randomly-generated Stellar asset. This function
1337    /// is useful for using in the tests when an arbitrary token contract
1338    /// instance is needed.
1339    #[deprecated(note = "use [Env::register_stellar_asset_contract_v2]")]
1340    pub fn register_stellar_asset_contract(&self, admin: Address) -> Address {
1341        self.register_stellar_asset_contract_v2(admin).address()
1342    }
1343
1344    fn register_contract_with_optional_contract_id_and_executable<'a>(
1345        &self,
1346        contract_id: impl Into<Option<&'a Address>>,
1347        executable: xdr::ContractExecutable,
1348        constructor_args: Vec<Val>,
1349    ) -> Address {
1350        if let Some(contract_id) = contract_id.into() {
1351            self.register_contract_with_contract_id_and_executable(
1352                contract_id,
1353                executable,
1354                constructor_args,
1355            );
1356            contract_id.clone()
1357        } else {
1358            self.register_contract_with_source(executable, constructor_args)
1359        }
1360    }
1361
1362    fn register_contract_with_source(
1363        &self,
1364        executable: xdr::ContractExecutable,
1365        constructor_args: Vec<Val>,
1366    ) -> Address {
1367        let args_vec: std::vec::Vec<xdr::ScVal> =
1368            constructor_args.iter().map(|v| v.into_val(self)).collect();
1369        let constructor_args = args_vec.try_into().unwrap();
1370        let prev_auth_manager = self.env_impl.snapshot_auth_manager().unwrap();
1371        self.env_impl
1372            .switch_to_recording_auth_inherited_from_snapshot(&prev_auth_manager)
1373            .unwrap();
1374        let create_result = self
1375            .env_impl
1376            .invoke_function(xdr::HostFunction::CreateContractV2(
1377                xdr::CreateContractArgsV2 {
1378                    contract_id_preimage: xdr::ContractIdPreimage::Address(
1379                        xdr::ContractIdPreimageFromAddress {
1380                            address: xdr::ScAddress::Contract(xdr::ContractId(xdr::Hash(
1381                                self.with_generator(|mut g| g.address()),
1382                            ))),
1383                            salt: xdr::Uint256([0; 32]),
1384                        },
1385                    ),
1386                    executable,
1387                    constructor_args,
1388                },
1389            ));
1390
1391        self.env_impl.set_auth_manager(prev_auth_manager).unwrap();
1392
1393        create_result.unwrap().try_into_val(self).unwrap()
1394    }
1395
1396    /// Set authorizations and signatures in the environment which will be
1397    /// consumed by contracts when they invoke [`Address::require_auth`] or
1398    /// [`Address::require_auth_for_args`] functions.
1399    ///
1400    /// Requires valid signatures for the authorization to be successful.
1401    ///
1402    /// This function can also be called on contract clients.
1403    ///
1404    /// To mock auth for testing, without requiring valid signatures, use
1405    /// [`mock_all_auths`][Self::mock_all_auths] or
1406    /// [`mock_auths`][Self::mock_auths]. If mocking of auths is enabled,
1407    /// calling [`set_auths`][Self::set_auths] disables any mocking.
1408    pub fn set_auths(&self, auths: &[SorobanAuthorizationEntry]) {
1409        self.env_impl
1410            .set_authorization_entries(auths.to_vec())
1411            .unwrap();
1412    }
1413
1414    /// Mock authorizations in the environment which will cause matching invokes
1415    /// of [`Address::require_auth`] and [`Address::require_auth_for_args`] to
1416    /// pass.
1417    ///
1418    /// This function can also be called on contract clients.
1419    ///
1420    /// Authorizations not matching a mocked auth will fail.
1421    ///
1422    /// To mock all auths, use [`mock_all_auths`][Self::mock_all_auths].
1423    ///
1424    /// ### Examples
1425    /// ```
1426    /// use soroban_sdk::{contract, contractimpl, Env, Address, testutils::{Address as _, MockAuth, MockAuthInvoke}, IntoVal};
1427    ///
1428    /// #[contract]
1429    /// pub struct HelloContract;
1430    ///
1431    /// #[contractimpl]
1432    /// impl HelloContract {
1433    ///     pub fn hello(env: Env, from: Address) {
1434    ///         from.require_auth();
1435    ///         // TODO
1436    ///     }
1437    /// }
1438    ///
1439    /// #[test]
1440    /// fn test() {
1441    /// # }
1442    /// # fn main() {
1443    ///     let env = Env::default();
1444    ///     let contract_id = env.register(HelloContract, ());
1445    ///
1446    ///     let client = HelloContractClient::new(&env, &contract_id);
1447    ///     let addr = Address::generate(&env);
1448    ///     client.mock_auths(&[
1449    ///         MockAuth {
1450    ///             address: &addr,
1451    ///             invoke: &MockAuthInvoke {
1452    ///                 contract: &contract_id,
1453    ///                 fn_name: "hello",
1454    ///                 args: (&addr,).into_val(&env),
1455    ///                 sub_invokes: &[],
1456    ///             },
1457    ///         },
1458    ///     ]).hello(&addr);
1459    /// }
1460    /// ```
1461    pub fn mock_auths(&self, auths: &[MockAuth]) {
1462        for a in auths {
1463            self.register_at(a.address, MockAuthContract, ());
1464        }
1465        let auths = auths
1466            .iter()
1467            .cloned()
1468            .map(Into::into)
1469            .collect::<std::vec::Vec<_>>();
1470        self.env_impl.set_authorization_entries(auths).unwrap();
1471    }
1472
1473    /// Mock all calls to the [`Address::require_auth`] and
1474    /// [`Address::require_auth_for_args`] functions in invoked contracts,
1475    /// having them succeed as if authorization was provided.
1476    ///
1477    /// When mocking is enabled, if the [`Address`] being authorized is the
1478    /// address of a contract, that contract's `__check_auth` function will not
1479    /// be called, and the contract does not need to exist or be registered in
1480    /// the test.
1481    ///
1482    /// When mocking is enabled, if the [`Address`] being authorized is the
1483    /// address of an account, the account does not need to exist.
1484    ///
1485    /// This function can also be called on contract clients.
1486    ///
1487    /// To disable mocking, see [`set_auths`][Self::set_auths].
1488    ///
1489    /// To access a list of auths that have occurred, see [`auths`][Self::auths].
1490    ///
1491    /// It is not currently possible to mock a subset of auths.
1492    ///
1493    /// A test that uses `mock_all_auths` without verifying the resulting
1494    /// authorization tree via [`auths`][Self::auths] can pass even when a contract
1495    /// is missing a `require_auth` check. Use [`auths`][Self::auths] after
1496    /// the contract call to assert that the expected authorizations were required.
1497    ///
1498    /// ### Examples
1499    /// ```
1500    /// use soroban_sdk::{contract, contractimpl, Env, Address, IntoVal, symbol_short};
1501    /// use soroban_sdk::testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation};
1502    ///
1503    /// #[contract]
1504    /// pub struct HelloContract;
1505    ///
1506    /// #[contractimpl]
1507    /// impl HelloContract {
1508    ///     pub fn hello(env: Env, from: Address) {
1509    ///         from.require_auth();
1510    ///         // TODO
1511    ///     }
1512    /// }
1513    ///
1514    /// #[test]
1515    /// fn test() {
1516    /// # }
1517    /// # fn main() {
1518    ///     let env = Env::default();
1519    ///     let contract_id = env.register(HelloContract, ());
1520    ///
1521    ///     env.mock_all_auths();
1522    ///
1523    ///     let client = HelloContractClient::new(&env, &contract_id);
1524    ///     let addr = Address::generate(&env);
1525    ///     client.hello(&addr);
1526    ///
1527    ///     // Verify that the expected authorization was required.
1528    ///     assert_eq!(
1529    ///         env.auths(),
1530    ///         [(
1531    ///             addr.clone(),
1532    ///             AuthorizedInvocation {
1533    ///                 function: AuthorizedFunction::Contract((
1534    ///                     contract_id,
1535    ///                     symbol_short!("hello"),
1536    ///                     (&addr,).into_val(&env),
1537    ///                 )),
1538    ///                 sub_invocations: [].into(),
1539    ///             }
1540    ///         )]
1541    ///     );
1542    /// }
1543    /// ```
1544    pub fn mock_all_auths(&self) {
1545        self.env_impl.switch_to_recording_auth(true).unwrap();
1546    }
1547
1548    /// A version of [`mock_all_auths`][Self::mock_all_auths] that allows authorizations that are not
1549    /// present in the root invocation.
1550    ///
1551    /// Refer to [`mock_all_auths`][Self::mock_all_auths] documentation for general information and
1552    /// prefer using [`mock_all_auths`][Self::mock_all_auths] unless non-root authorization is required.
1553    ///
1554    /// The only difference from [`mock_all_auths`][Self::mock_all_auths] is that this won't return an
1555    /// error when `require_auth` hasn't been called in the root invocation for
1556    /// any given address. This is useful to test contracts that bundle calls to
1557    /// another contract without atomicity requirements (i.e. any contract call
1558    /// can be frontrun).
1559    ///
1560    /// ### Examples
1561    /// ```
1562    /// use soroban_sdk::{contract, contractimpl, Env, Address, testutils::Address as _};
1563    ///
1564    /// #[contract]
1565    /// pub struct ContractA;
1566    ///
1567    /// #[contractimpl]
1568    /// impl ContractA {
1569    ///     pub fn do_auth(env: Env, addr: Address) {
1570    ///         addr.require_auth();
1571    ///     }
1572    /// }
1573    /// #[contract]
1574    /// pub struct ContractB;
1575    ///
1576    /// #[contractimpl]
1577    /// impl ContractB {
1578    ///     pub fn call_a(env: Env, contract_a: Address, addr: Address) {
1579    ///         // Notice there is no `require_auth` call here.
1580    ///         ContractAClient::new(&env, &contract_a).do_auth(&addr);
1581    ///     }
1582    /// }
1583    /// #[test]
1584    /// fn test() {
1585    /// # }
1586    /// # fn main() {
1587    ///     let env = Env::default();
1588    ///     let contract_a = env.register(ContractA, ());
1589    ///     let contract_b = env.register(ContractB, ());
1590    ///     // The regular `env.mock_all_auths()` would result in the call
1591    ///     // failure.
1592    ///     env.mock_all_auths_allowing_non_root_auth();
1593    ///
1594    ///     let client = ContractBClient::new(&env, &contract_b);
1595    ///     let addr = Address::generate(&env);
1596    ///     client.call_a(&contract_a, &addr);
1597    /// }
1598    /// ```
1599    pub fn mock_all_auths_allowing_non_root_auth(&self) {
1600        self.env_impl.switch_to_recording_auth(false).unwrap();
1601    }
1602
1603    /// Returns a list of authorization trees that were seen during the last
1604    /// contract or authorized host function invocation.
1605    ///
1606    /// Use this in tests to verify that the expected authorizations with the
1607    /// expected arguments are required.
1608    ///
1609    /// The return value is a vector of authorizations represented by tuples of
1610    /// `(address, AuthorizedInvocation)`. `AuthorizedInvocation` describes the
1611    /// tree of `require_auth_for_args(address, args)` from the contract
1612    /// functions (or `require_auth` with all the arguments of the function
1613    /// invocation). It also might contain the authorized host functions (
1614    /// currently CreateContract is the only such function) in case if
1615    /// corresponding host functions have been called.
1616    ///
1617    /// Refer to documentation for `AuthorizedInvocation` for detailed
1618    /// information on its contents.
1619    ///
1620    /// The order of the returned vector is defined by the order of
1621    /// [`Address::require_auth`] calls. Repeated calls to
1622    /// [`Address::require_auth`] with the same address and args in the same
1623    /// tree of contract invocations will appear only once in the vector.
1624    ///
1625    /// ### Examples
1626    /// ```
1627    /// use soroban_sdk::{contract, contractimpl, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, symbol_short, Address, Symbol, Env, IntoVal};
1628    ///
1629    /// #[contract]
1630    /// pub struct Contract;
1631    ///
1632    /// #[contractimpl]
1633    /// impl Contract {
1634    ///     pub fn transfer(env: Env, address: Address, amount: i128) {
1635    ///         address.require_auth();
1636    ///     }
1637    ///     pub fn transfer2(env: Env, address: Address, amount: i128) {
1638    ///         address.require_auth_for_args((amount / 2,).into_val(&env));
1639    ///     }
1640    /// }
1641    ///
1642    /// #[test]
1643    /// fn test() {
1644    /// # }
1645    /// # #[cfg(feature = "testutils")]
1646    /// # fn main() {
1647    ///     let env = Env::default();
1648    ///     let contract_id = env.register(Contract, ());
1649    ///     let client = ContractClient::new(&env, &contract_id);
1650    ///     env.mock_all_auths();
1651    ///     let address = Address::generate(&env);
1652    ///     client.transfer(&address, &1000_i128);
1653    ///     assert_eq!(
1654    ///         env.auths(),
1655    ///         [(
1656    ///             address.clone(),
1657    ///             AuthorizedInvocation {
1658    ///                 function: AuthorizedFunction::Contract((
1659    ///                     client.address.clone(),
1660    ///                     symbol_short!("transfer"),
1661    ///                     (&address, 1000_i128,).into_val(&env)
1662    ///                 )),
1663    ///                 sub_invocations: [].into()
1664    ///             }
1665    ///         )]
1666    ///     );
1667    ///
1668    ///     client.transfer2(&address, &1000_i128);
1669    ///     assert_eq!(
1670    ///         env.auths(),
1671    ///         [(
1672    ///             address.clone(),
1673    ///             AuthorizedInvocation {
1674    ///                 function: AuthorizedFunction::Contract((
1675    ///                     client.address.clone(),
1676    ///                     symbol_short!("transfer2"),
1677    ///                     // `transfer2` requires auth for (amount / 2) == (1000 / 2) == 500.
1678    ///                     (500_i128,).into_val(&env)
1679    ///                 )),
1680    ///                 sub_invocations: [].into()
1681    ///             }
1682    ///         )]
1683    ///     );
1684    /// }
1685    /// # #[cfg(not(feature = "testutils"))]
1686    /// # fn main() { }
1687    /// ```
1688    pub fn auths(&self) -> std::vec::Vec<(Address, AuthorizedInvocation)> {
1689        (*self.test_state.auth_snapshot())
1690            .borrow()
1691            .0
1692            .last()
1693            .cloned()
1694            .unwrap_or_default()
1695            .into_iter()
1696            .map(|(sc_addr, invocation)| {
1697                (
1698                    xdr::ScVal::Address(sc_addr).try_into_val(self).unwrap(),
1699                    AuthorizedInvocation::from_xdr(self, &invocation),
1700                )
1701            })
1702            .collect()
1703    }
1704
1705    /// Invokes the special `__check_auth` function of contracts that implement
1706    /// the custom account interface.
1707    ///
1708    /// `__check_auth` can't be called outside of the host-managed `require_auth`
1709    /// calls. This test utility allows testing custom account contracts without
1710    /// the need to setup complex contract call trees and enabling the enforcing
1711    /// auth on the host side.
1712    ///
1713    /// This function requires to provide the template argument for error. Use
1714    /// `soroban_sdk::Error` if `__check_auth` doesn't return a special
1715    /// contract error and use the error with `contracterror` attribute
1716    /// otherwise.
1717    ///
1718    /// ### Examples
1719    /// ```
1720    /// use soroban_sdk::{contract, contracterror, contractimpl, testutils::{Address as _, BytesN as _}, vec, auth::Context, BytesN, Env, Vec, Val};
1721    ///
1722    /// #[contracterror]
1723    /// #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
1724    /// #[repr(u32)]
1725    /// pub enum NoopAccountError {
1726    ///     SomeError = 1,
1727    /// }
1728    /// #[contract]
1729    /// struct NoopAccountContract;
1730    /// #[contractimpl]
1731    /// impl NoopAccountContract {
1732    ///
1733    ///     #[allow(non_snake_case)]
1734    ///     pub fn __check_auth(
1735    ///         _env: Env,
1736    ///         _signature_payload: BytesN<32>,
1737    ///         signature: Val,
1738    ///         _auth_context: Vec<Context>,
1739    ///     ) -> Result<(), NoopAccountError> {
1740    ///         if signature.is_void() {
1741    ///             Err(NoopAccountError::SomeError)
1742    ///         } else {
1743    ///             Ok(())
1744    ///         }
1745    ///     }
1746    /// }
1747    /// #[test]
1748    /// fn test() {
1749    /// # }
1750    /// # fn main() {
1751    ///     let e: Env = Default::default();
1752    ///     let account_contract = NoopAccountContractClient::new(&e, &e.register(NoopAccountContract, ()));
1753    ///     // Non-successful call of `__check_auth` with a `contracterror` error.
1754    ///     assert_eq!(
1755    ///         e.try_invoke_contract_check_auth::<NoopAccountError>(
1756    ///             &account_contract.address,
1757    ///             &BytesN::from_array(&e, &[0; 32]),
1758    ///             ().into(),
1759    ///             &vec![&e],
1760    ///         ),
1761    ///         // The inner `Result` is for conversion error and will be Ok
1762    ///         // as long as a valid error type used.
1763    ///         Err(Ok(NoopAccountError::SomeError))
1764    ///     );
1765    ///     // Successful call of `__check_auth` with a `soroban_sdk::InvokeError`
1766    ///     // error - this should be compatible with any error type.
1767    ///     assert_eq!(
1768    ///         e.try_invoke_contract_check_auth::<soroban_sdk::InvokeError>(
1769    ///             &account_contract.address,
1770    ///             &BytesN::from_array(&e, &[0; 32]),
1771    ///             0_i32.into(),
1772    ///             &vec![&e],
1773    ///         ),
1774    ///         Ok(())
1775    ///     );
1776    /// }
1777    /// ```
1778    pub fn try_invoke_contract_check_auth<E>(
1779        &self,
1780        contract: &Address,
1781        signature_payload: &BytesN<32>,
1782        signature: Val,
1783        auth_context: &Vec<auth::Context>,
1784    ) -> Result<(), Result<E, InvokeError>>
1785    where
1786        E: TryFrom<Error>,
1787        E::Error: Into<InvokeError>,
1788    {
1789        let args = Vec::from_array(
1790            self,
1791            [signature_payload.to_val(), signature, auth_context.to_val()],
1792        );
1793        let res = self
1794            .host()
1795            .call_account_contract_check_auth(contract.to_object(), args.to_object());
1796        match res {
1797            Ok(rv) => Ok(rv.into_val(self)),
1798            Err(e) => Err(e.error.try_into().map_err(Into::into)),
1799        }
1800    }
1801
1802    fn register_contract_with_contract_id_and_executable(
1803        &self,
1804        contract_address: &Address,
1805        executable: xdr::ContractExecutable,
1806        constructor_args: Vec<Val>,
1807    ) {
1808        let contract_id = contract_address.contract_id();
1809        let data_key = xdr::ScVal::LedgerKeyContractInstance;
1810        let key = Rc::new(LedgerKey::ContractData(LedgerKeyContractData {
1811            contract: xdr::ScAddress::Contract(contract_id.clone()),
1812            key: data_key.clone(),
1813            durability: xdr::ContractDataDurability::Persistent,
1814        }));
1815
1816        let instance = xdr::ScContractInstance {
1817            executable,
1818            storage: Default::default(),
1819        };
1820
1821        let entry = Rc::new(LedgerEntry {
1822            ext: xdr::LedgerEntryExt::V0,
1823            last_modified_ledger_seq: 0,
1824            data: xdr::LedgerEntryData::ContractData(xdr::ContractDataEntry {
1825                contract: xdr::ScAddress::Contract(contract_id.clone()),
1826                key: data_key,
1827                val: xdr::ScVal::ContractInstance(instance),
1828                durability: xdr::ContractDataDurability::Persistent,
1829                ext: xdr::ExtensionPoint::V0,
1830            }),
1831        });
1832        let live_until_ledger = self.ledger().sequence() + 1;
1833        self.host()
1834            .add_ledger_entry(&key, &entry, Some(live_until_ledger))
1835            .unwrap();
1836        let prev_auth_manager = self.env_impl.snapshot_auth_manager().unwrap();
1837        self.env_impl
1838            .switch_to_recording_auth_inherited_from_snapshot(&prev_auth_manager)
1839            .unwrap();
1840        let call_result = self.env_impl.call_constructor_for_stored_contract_unsafe(
1841            &contract_id,
1842            constructor_args.to_object(),
1843        );
1844        self.env_impl.set_auth_manager(prev_auth_manager).unwrap();
1845        call_result.unwrap();
1846    }
1847
1848    /// Run the function as if executed by the given contract ID.
1849    ///
1850    /// Used to write or read contract data, or take other actions in tests for
1851    /// setting up tests or asserting on internal state.
1852    ///
1853    /// ### Examples
1854    /// ```
1855    /// use soroban_sdk::{contract, contractimpl, Env, Symbol};
1856    ///
1857    /// #[contract]
1858    /// pub struct HelloContract;
1859    ///
1860    /// #[contractimpl]
1861    /// impl HelloContract {
1862    ///     pub fn set_storage(env: Env, key: Symbol, val: Symbol) {
1863    ///         env.storage().persistent().set(&key, &val);
1864    ///     }
1865    /// }
1866    ///
1867    /// #[test]
1868    /// fn test() {
1869    /// # }
1870    /// # fn main() {
1871    ///     let env = Env::default();
1872    ///     let contract_id = env.register(HelloContract, ());
1873    ///     let client = HelloContractClient::new(&env, &contract_id);
1874    ///
1875    ///     let key = Symbol::new(&env, "foo");
1876    ///     let val = Symbol::new(&env, "bar");
1877    ///
1878    ///     // Set storage using the contract
1879    ///     client.set_storage(&key, &val);
1880    ///
1881    ///     // Successfully read the storage key
1882    ///     let result = env.as_contract(&contract_id, || {
1883    ///         env.storage()
1884    ///             .persistent()
1885    ///             .get::<Symbol, Symbol>(&key)
1886    ///             .unwrap()
1887    ///     });
1888    ///     assert_eq!(result, val);
1889    /// }
1890    /// ```
1891    pub fn as_contract<T>(&self, id: &Address, f: impl FnOnce() -> T) -> T {
1892        let id = id.contract_id();
1893        let func = Symbol::from_small_str("");
1894        let mut t: Option<T> = None;
1895        self.env_impl
1896            .with_test_contract_frame(id, func, || {
1897                t = Some(f());
1898                Ok(().into())
1899            })
1900            .unwrap();
1901        t.unwrap()
1902    }
1903
1904    /// Run the function as if executed by the given contract ID. Returns an
1905    /// error if the function execution fails for any reason.
1906    ///
1907    /// Used to write or read contract data, or take other actions in tests for
1908    /// setting up tests or asserting on internal state.
1909    ///
1910    /// ### Examples
1911    /// ```
1912    /// use soroban_sdk::{contract, contractimpl, xdr::{ScErrorCode, ScErrorType}, Env, Error, Symbol};
1913    ///
1914    /// #[contract]
1915    /// pub struct HelloContract;
1916    ///
1917    /// #[contractimpl]
1918    /// impl HelloContract {
1919    ///     pub fn set_storage(env: Env, key: Symbol, val: Symbol) {
1920    ///         env.storage().persistent().set(&key, &val);
1921    ///     }
1922    /// }
1923    ///
1924    /// #[test]
1925    /// fn test() {
1926    /// # }
1927    /// # fn main() {
1928    ///     let env = Env::default();
1929    ///     let contract_id = env.register(HelloContract, ());
1930    ///     let client = HelloContractClient::new(&env, &contract_id);
1931    ///
1932    ///     let key = Symbol::new(&env, "foo");
1933    ///     let val = Symbol::new(&env, "bar");
1934    ///
1935    ///     // Set storage using the contract
1936    ///     client.set_storage(&key, &val);
1937    ///
1938    ///     // Successfully read the storage key
1939    ///     let result = env.try_as_contract::<Symbol, Error>(&contract_id, || {
1940    ///         env.storage()
1941    ///             .persistent()
1942    ///             .get::<Symbol, Symbol>(&key)
1943    ///             .unwrap()
1944    ///     });
1945    ///     assert_eq!(result, Ok(val));
1946    ///
1947    ///     // Attempting to extend TTL of a non-existent key throws an error
1948    ///     let new_key = Symbol::new(&env, "baz");
1949    ///     let result = env.try_as_contract(&contract_id, || {
1950    ///         env.storage().persistent().extend_ttl(&new_key, 1, 100);
1951    ///     });
1952    ///     assert_eq!(
1953    ///         result,
1954    ///         Err(Ok(Error::from_type_and_code(
1955    ///             ScErrorType::Storage,
1956    ///             ScErrorCode::MissingValue
1957    ///         )))
1958    ///     );
1959    /// }
1960    /// ```
1961    pub fn try_as_contract<T, E>(
1962        &self,
1963        id: &Address,
1964        f: impl FnOnce() -> T,
1965    ) -> Result<T, Result<E, InvokeError>>
1966    where
1967        E: TryFrom<Error>,
1968        E::Error: Into<InvokeError>,
1969    {
1970        let id = id.contract_id();
1971        let func = Symbol::from_small_str("");
1972        let mut t: Option<T> = None;
1973        let result = self.env_impl.try_with_test_contract_frame(id, func, || {
1974            t = Some(f());
1975            Ok(().into())
1976        });
1977
1978        match result {
1979            Ok(_) => Ok(t.unwrap()),
1980            Err(e) => Err(E::try_from(e.error).map_err(Into::into)),
1981        }
1982    }
1983
1984    /// Creates a new Env loaded with the [`Snapshot`].
1985    ///
1986    /// The ledger info and state in the snapshot are loaded into the Env.
1987    ///
1988    /// Events, as an output source only, are not loaded into the Env.
1989    pub fn from_snapshot(s: Snapshot) -> Env {
1990        Env::new_for_testutils(
1991            EnvTestConfig::default(),
1992            Rc::new(s.ledger.clone()),
1993            Some(Rc::new(RefCell::new(s.generators))),
1994            Some(s.ledger.ledger_info()),
1995            Some(Rc::new(s.ledger.clone())),
1996        )
1997    }
1998
1999    /// Creates a new Env loaded with the ledger snapshot loaded from the file.
2000    ///
2001    /// The ledger info and state in the snapshot are loaded into the Env.
2002    ///
2003    /// Events, as an output source only, are not loaded into the Env.
2004    ///
2005    /// ### Panics
2006    ///
2007    /// If there is any error reading the file.
2008    pub fn from_snapshot_file(p: impl AsRef<Path>) -> Env {
2009        Self::from_snapshot(Snapshot::read_file(p).unwrap())
2010    }
2011
2012    /// Create a snapshot from the Env's current state.
2013    pub fn to_snapshot(&self) -> Snapshot {
2014        Snapshot {
2015            generators: (*self.test_state.generators()).borrow().clone(),
2016            auth: (*self.test_state.auth_snapshot()).borrow().clone(),
2017            ledger: self.to_ledger_snapshot(),
2018            events: self.to_events_snapshot(),
2019        }
2020    }
2021
2022    /// Create a snapshot file from the Env's current state.
2023    ///
2024    /// ### Panics
2025    ///
2026    /// If there is any error writing the file.
2027    pub fn to_snapshot_file(&self, p: impl AsRef<Path>) {
2028        self.to_snapshot().write_file(p).unwrap();
2029    }
2030
2031    /// Creates a new Env loaded with the snapshot source.
2032    ///
2033    /// The ledger info and state from the snapshot source are loaded into the Env.
2034    pub fn from_ledger_snapshot(input: impl Into<SnapshotSourceInput>) -> Env {
2035        let SnapshotSourceInput {
2036            source,
2037            ledger_info,
2038            snapshot,
2039        } = input.into();
2040
2041        Env::new_for_testutils(
2042            EnvTestConfig::default(), // TODO: Allow setting the config.
2043            source,
2044            None,
2045            ledger_info,
2046            snapshot,
2047        )
2048    }
2049
2050    /// Creates a new Env loaded with the ledger snapshot loaded from the file.
2051    ///
2052    /// ### Panics
2053    ///
2054    /// If there is any error reading the file.
2055    pub fn from_ledger_snapshot_file(p: impl AsRef<Path>) -> Env {
2056        Self::from_ledger_snapshot(LedgerSnapshot::read_file(p).unwrap())
2057    }
2058
2059    /// Create a snapshot from the Env's current state.
2060    pub fn to_ledger_snapshot(&self) -> LedgerSnapshot {
2061        let snapshot = self.test_state.snapshot().clone().unwrap_or_default();
2062        let mut snapshot = (*snapshot).clone();
2063        snapshot.set_ledger_info(self.ledger().get());
2064        snapshot.update_entries(&self.host().get_stored_entries().unwrap());
2065        snapshot
2066    }
2067
2068    /// Create a snapshot file from the Env's current state.
2069    ///
2070    /// ### Panics
2071    ///
2072    /// If there is any error writing the file.
2073    pub fn to_ledger_snapshot_file(&self, p: impl AsRef<Path>) {
2074        self.to_ledger_snapshot().write_file(p).unwrap();
2075    }
2076
2077    /// Create an events snapshot from the Env's current state.
2078    pub(crate) fn to_events_snapshot(&self) -> EventsSnapshot {
2079        EventsSnapshot(
2080            self.host()
2081                .get_events()
2082                .unwrap()
2083                .0
2084                .into_iter()
2085                .filter(|e| match e.event.type_ {
2086                    // Keep only system and contract events, because event
2087                    // snapshots are used in test snapshots, and intended to be
2088                    // stable over time because the goal is to record meaningful
2089                    // observable behaviors. Diagnostic events are observable,
2090                    // but events have no stability guarantees and are intended
2091                    // to be used by developers when debugging, tracing, and
2092                    // observing, not by systems that integrate.
2093                    xdr::ContractEventType::System | xdr::ContractEventType::Contract => true,
2094                    xdr::ContractEventType::Diagnostic => false,
2095                })
2096                .map(Into::into)
2097                .collect(),
2098        )
2099    }
2100
2101    /// Get the budget that tracks the resources consumed for the environment.
2102    #[deprecated(note = "use cost_estimate().budget()")]
2103    pub fn budget(&self) -> Budget {
2104        Budget::new(self.env_impl.budget_cloned())
2105    }
2106}
2107
2108#[cfg(any(test, feature = "testutils"))]
2109impl Drop for Env {
2110    fn drop(&mut self) {
2111        // If the env impl (Host) is finishable, that means this Env is the last
2112        // Env to hold a reference to the Host. The Env should only write a test
2113        // snapshot at that point when no other references to the host exist,
2114        // because it is only when there are no other references that the host
2115        // is being dropped.
2116        let EnvTestState::Test { config, .. } = &self.test_state else {
2117            return;
2118        };
2119        if self.env_impl.can_finish() && config.capture_snapshot_at_drop {
2120            self.to_test_snapshot_file();
2121        }
2122    }
2123}
2124
2125#[doc(hidden)]
2126#[cfg(any(test, feature = "testutils"))]
2127impl Env {
2128    /// Create a snapshot file for the currently executing test.
2129    ///
2130    /// Writes the file to the `test_snapshots/{test-name}.N.json` path where
2131    /// `N` is incremented for each unique `Env` in the test.
2132    ///
2133    /// Use to record the observable behavior of a test, and changes to that
2134    /// behavior over time. Commit the test snapshot file to version control and
2135    /// watch for changes in it on contract change, SDK upgrade, protocol
2136    /// upgrade, and other important events.
2137    ///
2138    /// No file will be created if the environment has no meaningful data such
2139    /// as stored entries or events.
2140    ///
2141    /// ### Panics
2142    ///
2143    /// If there is any error writing the file.
2144    pub(crate) fn to_test_snapshot_file(&self) {
2145        // If there's no test state, or no test name, we're not in a test
2146        // context, so don't write snapshots. An Env without test state would
2147        // panic if its test state were read.
2148        let EnvTestState::Test {
2149            test_name: Some(test_name),
2150            number,
2151            ..
2152        } = &self.test_state
2153        else {
2154            return;
2155        };
2156
2157        let snapshot = self.to_snapshot();
2158
2159        // Don't write a snapshot that has no data in it.
2160        if snapshot.ledger.entries().into_iter().count() == 0
2161            && snapshot.events.0.is_empty()
2162            && snapshot.auth.0.is_empty()
2163        {
2164            return;
2165        }
2166
2167        // Determine path to write test snapshots to.
2168        // Break up the test name into directories, using :: as the separator.
2169        // The :: module separator cannot be written into the filename because
2170        // some operating systems (e.g. Windows) do not allow the : character in
2171        // filenames.
2172        let test_name_path = test_name
2173            .split("::")
2174            .map(|p| std::path::Path::new(p).to_path_buf())
2175            .reduce(|p0, p1| p0.join(p1))
2176            .expect("test name to not be empty");
2177        let dir = std::path::Path::new("test_snapshots");
2178        let p = dir
2179            .join(&test_name_path)
2180            .with_extension(format!("{number}.json"));
2181
2182        // Write test snapshots to file.
2183        eprintln!("Writing test snapshot file for test {test_name:?} to {p:?}.");
2184        snapshot.write_file(p).unwrap();
2185    }
2186}
2187
2188#[doc(hidden)]
2189impl internal::EnvBase for Env {
2190    type Error = Infallible;
2191
2192    // This exists to allow code in conversion paths to upgrade an Error to an
2193    // Env::Error with some control granted to the underlying Env (and panic
2194    // paths kept out of the host). We delegate this to our env_impl and then,
2195    // since our own Error type is Infallible, immediately throw it into either
2196    // the env_impl's Error escalation path (if testing), or just plain panic.
2197    #[cfg(not(target_family = "wasm"))]
2198    fn error_from_error_val(&self, e: crate::Error) -> Self::Error {
2199        let host_err = self.env_impl.error_from_error_val(e);
2200        #[cfg(any(test, feature = "testutils"))]
2201        self.env_impl.escalate_error_to_panic(host_err);
2202        #[cfg(not(any(test, feature = "testutils")))]
2203        panic!("{:?}", host_err);
2204    }
2205
2206    // When targeting wasm we don't even need to do that, just delegate to
2207    // the Guest's impl, which calls core::arch::wasm32::unreachable.
2208    #[cfg(target_family = "wasm")]
2209    #[allow(unreachable_code)]
2210    fn error_from_error_val(&self, e: crate::Error) -> Self::Error {
2211        self.env_impl.error_from_error_val(e)
2212    }
2213
2214    fn check_protocol_version_lower_bound(&self, v: u32) -> Result<(), Self::Error> {
2215        Ok(self
2216            .env_impl
2217            .check_protocol_version_lower_bound(v)
2218            .unwrap_optimized())
2219    }
2220
2221    fn check_protocol_version_upper_bound(&self, v: u32) -> Result<(), Self::Error> {
2222        Ok(self
2223            .env_impl
2224            .check_protocol_version_upper_bound(v)
2225            .unwrap_optimized())
2226    }
2227
2228    // Note: the function `escalate_error_to_panic` only exists _on the `Env`
2229    // trait_ when the feature `soroban-env-common/testutils` is enabled. This
2230    // is because the host wants to never have this function even _compiled in_
2231    // when building for production, as it might be accidentally called (we have
2232    // mistakenly done so with conversion and comparison traits in the past).
2233    //
2234    // As a result, we only implement it here (fairly meaninglessly) when we're
2235    // in `cfg(test)` (which enables `soroban-env-host/testutils` thus
2236    // `soroban-env-common/testutils`) or when we've had our own `testutils`
2237    // feature enabled (which does the same).
2238    //
2239    // See the `internal::reject_err` functions above for more detail about what
2240    // it actually does (when implemented for real, on the host). In this
2241    // not-very-serious impl, since `Self::Error` is `Infallible`, this instance
2242    // can never actually be called and so its body is just a trivial
2243    // transformation from one empty type to another, for Type System Reasons.
2244    #[cfg(any(test, feature = "testutils"))]
2245    fn escalate_error_to_panic(&self, e: Self::Error) -> ! {
2246        match e {}
2247    }
2248
2249    fn bytes_copy_from_slice(
2250        &self,
2251        b: BytesObject,
2252        b_pos: U32Val,
2253        slice: &[u8],
2254    ) -> Result<BytesObject, Self::Error> {
2255        Ok(self
2256            .env_impl
2257            .bytes_copy_from_slice(b, b_pos, slice)
2258            .unwrap_optimized())
2259    }
2260
2261    fn bytes_copy_to_slice(
2262        &self,
2263        b: BytesObject,
2264        b_pos: U32Val,
2265        slice: &mut [u8],
2266    ) -> Result<(), Self::Error> {
2267        Ok(self
2268            .env_impl
2269            .bytes_copy_to_slice(b, b_pos, slice)
2270            .unwrap_optimized())
2271    }
2272
2273    fn bytes_new_from_slice(&self, slice: &[u8]) -> Result<BytesObject, Self::Error> {
2274        Ok(self.env_impl.bytes_new_from_slice(slice).unwrap_optimized())
2275    }
2276
2277    fn log_from_slice(&self, msg: &str, args: &[Val]) -> Result<Void, Self::Error> {
2278        Ok(self.env_impl.log_from_slice(msg, args).unwrap_optimized())
2279    }
2280
2281    fn string_copy_to_slice(
2282        &self,
2283        b: StringObject,
2284        b_pos: U32Val,
2285        slice: &mut [u8],
2286    ) -> Result<(), Self::Error> {
2287        Ok(self
2288            .env_impl
2289            .string_copy_to_slice(b, b_pos, slice)
2290            .unwrap_optimized())
2291    }
2292
2293    fn symbol_copy_to_slice(
2294        &self,
2295        b: SymbolObject,
2296        b_pos: U32Val,
2297        mem: &mut [u8],
2298    ) -> Result<(), Self::Error> {
2299        Ok(self
2300            .env_impl
2301            .symbol_copy_to_slice(b, b_pos, mem)
2302            .unwrap_optimized())
2303    }
2304
2305    fn string_new_from_slice(&self, slice: &[u8]) -> Result<StringObject, Self::Error> {
2306        Ok(self
2307            .env_impl
2308            .string_new_from_slice(slice)
2309            .unwrap_optimized())
2310    }
2311
2312    fn symbol_new_from_slice(&self, slice: &[u8]) -> Result<SymbolObject, Self::Error> {
2313        Ok(self
2314            .env_impl
2315            .symbol_new_from_slice(slice)
2316            .unwrap_optimized())
2317    }
2318
2319    fn map_new_from_slices(&self, keys: &[&str], vals: &[Val]) -> Result<MapObject, Self::Error> {
2320        Ok(self
2321            .env_impl
2322            .map_new_from_slices(keys, vals)
2323            .unwrap_optimized())
2324    }
2325
2326    fn map_unpack_to_slice(
2327        &self,
2328        map: MapObject,
2329        keys: &[&str],
2330        vals: &mut [Val],
2331    ) -> Result<Void, Self::Error> {
2332        Ok(self
2333            .env_impl
2334            .map_unpack_to_slice(map, keys, vals)
2335            .unwrap_optimized())
2336    }
2337
2338    fn sparse_map_new_from_slices(
2339        &self,
2340        keys: &[&str],
2341        vals: &[Val],
2342    ) -> Result<MapObject, Self::Error> {
2343        Ok(self
2344            .env_impl
2345            .sparse_map_new_from_slices(keys, vals)
2346            .unwrap_optimized())
2347    }
2348
2349    fn sparse_map_unpack_to_slice(
2350        &self,
2351        map: MapObject,
2352        keys: &[&str],
2353        vals: &mut [Val],
2354    ) -> Result<Void, Self::Error> {
2355        Ok(self
2356            .env_impl
2357            .sparse_map_unpack_to_slice(map, keys, vals)
2358            .unwrap_optimized())
2359    }
2360
2361    fn vec_new_from_slice(&self, vals: &[Val]) -> Result<VecObject, Self::Error> {
2362        Ok(self.env_impl.vec_new_from_slice(vals).unwrap_optimized())
2363    }
2364
2365    fn vec_unpack_to_slice(&self, vec: VecObject, vals: &mut [Val]) -> Result<Void, Self::Error> {
2366        Ok(self
2367            .env_impl
2368            .vec_unpack_to_slice(vec, vals)
2369            .unwrap_optimized())
2370    }
2371
2372    fn symbol_index_in_strs(&self, key: Symbol, strs: &[&str]) -> Result<U32Val, Self::Error> {
2373        Ok(self
2374            .env_impl
2375            .symbol_index_in_strs(key, strs)
2376            .unwrap_optimized())
2377    }
2378}
2379
2380///////////////////////////////////////////////////////////////////////////////
2381/// X-macro use: impl Env for SDK's Env
2382///////////////////////////////////////////////////////////////////////////////
2383
2384// This is a helper macro used only by impl_env_for_sdk below. It consumes a
2385// token-tree of the form:
2386//
2387//  {fn $fn_id:ident $args:tt -> $ret:ty}
2388//
2389// and produces the the corresponding method definition to be used in the
2390// SDK's Env implementation of the Env (calling through to the corresponding
2391// guest or host implementation).
2392macro_rules! sdk_function_helper {
2393    {$mod_id:ident, fn $fn_id:ident($($arg:ident:$type:ty),*) -> $ret:ty}
2394    =>
2395    {
2396        fn $fn_id(&self, $($arg:$type),*) -> Result<$ret, Self::Error> {
2397            internal::reject_err(&self.env_impl, self.env_impl.$fn_id($($arg),*))
2398        }
2399    };
2400}
2401
2402// This is a callback macro that pattern-matches the token-tree passed by the
2403// x-macro (call_macro_with_all_host_functions) and produces a suite of
2404// forwarding-method definitions, which it places in the body of the declaration
2405// of the implementation of Env for the SDK's Env.
2406macro_rules! impl_env_for_sdk {
2407    {
2408        $(
2409            // This outer pattern matches a single 'mod' block of the token-tree
2410            // passed from the x-macro to this macro. It is embedded in a `$()*`
2411            // pattern-repetition matcher so that it will match all provided
2412            // 'mod' blocks provided.
2413            $(#[$mod_attr:meta])*
2414            mod $mod_id:ident $mod_str:literal
2415            {
2416                $(
2417                    // This inner pattern matches a single function description
2418                    // inside a 'mod' block in the token-tree passed from the
2419                    // x-macro to this macro. It is embedded in a `$()*`
2420                    // pattern-repetition matcher so that it will match all such
2421                    // descriptions.
2422                    $(#[$fn_attr:meta])*
2423                    { $fn_str:literal, $($min_proto:literal)?, $($max_proto:literal)?, fn $fn_id:ident $args:tt -> $ret:ty }
2424                )*
2425            }
2426        )*
2427    }
2428
2429    =>  // The part of the macro above this line is a matcher; below is its expansion.
2430
2431    {
2432        // This macro expands to a single item: the implementation of Env for
2433        // the SDK's Env struct used by client contract code running in a WASM VM.
2434        #[doc(hidden)]
2435        impl internal::Env for Env
2436        {
2437            $(
2438                $(
2439                    // This invokes the guest_function_helper! macro above
2440                    // passing only the relevant parts of the declaration
2441                    // matched by the inner pattern above. It is embedded in two
2442                    // nested `$()*` pattern-repetition expanders that
2443                    // correspond to the pattern-repetition matchers in the
2444                    // match section, but we ignore the structure of the 'mod'
2445                    // block repetition-level from the outer pattern in the
2446                    // expansion, flattening all functions from all 'mod' blocks
2447                    // into the implementation of Env for Guest.
2448                    sdk_function_helper!{$mod_id, fn $fn_id $args -> $ret}
2449                )*
2450            )*
2451        }
2452    };
2453}
2454
2455// Here we invoke the x-macro passing generate_env_trait as its callback macro.
2456internal::call_macro_with_all_host_functions! { impl_env_for_sdk }