soroban_env_host/host/
conversion.rs

1use std::rc::Rc;
2
3use crate::host_object::{MemHostObjectType, MuxedScAddress};
4use crate::{
5    budget::{AsBudget, DepthLimiter},
6    crypto::metered_scalar::MeteredScalar,
7    err,
8    host::metered_clone::{
9        charge_shallow_copy, MeteredAlloc, MeteredClone, MeteredContainer, MeteredIterator,
10    },
11    host_object::{HostMap, HostObject, HostVec},
12    num::{i256_from_pieces, i256_into_pieces, u256_from_pieces, u256_into_pieces},
13    xdr::{
14        self, int128_helpers, AccountId, ContractCostType, ContractDataDurability, Hash,
15        Int128Parts, Int256Parts, LedgerKey, LedgerKeyContractData, ScAddress, ScBytes,
16        ScErrorCode, ScErrorType, ScMap, ScMapEntry, ScSymbol, ScVal, ScVec, UInt128Parts,
17        UInt256Parts, Uint256, VecM,
18    },
19    AddressObject, BytesObject, Convert, Host, HostError, Object, ScValObjRef, ScValObject, Symbol,
20    SymbolObject, TryFromVal, TryIntoVal, U256Val, U32Val, Val, VecObject,
21};
22
23use super::ErrorHandler;
24
25impl Host {
26    // Notes on metering: free
27    pub(crate) fn usize_to_u32(&self, u: usize) -> Result<u32, HostError> {
28        match u32::try_from(u) {
29            Ok(v) => Ok(v),
30            Err(_) => Err(self.err(
31                ScErrorType::Value,
32                ScErrorCode::ArithDomain,
33                "provided usize does not fit in u32",
34                &[],
35            )),
36        }
37    }
38
39    // Notes on metering: free
40    pub(crate) fn usize_to_u32val(&self, u: usize) -> Result<U32Val, HostError> {
41        self.usize_to_u32(u).map(|v| v.into())
42    }
43
44    pub(crate) fn u256_from_account(&self, account_id: &AccountId) -> Result<Uint256, HostError> {
45        let crate::xdr::PublicKey::PublicKeyTypeEd25519(ed25519) =
46            account_id.metered_clone(self)?.0;
47        Ok(ed25519)
48    }
49
50    // Notes on metering: free
51    pub(crate) fn u8_from_u32val_input(
52        &self,
53        name: &'static str,
54        r: U32Val,
55    ) -> Result<u8, HostError> {
56        let u: u32 = r.into();
57        match u8::try_from(u) {
58            Ok(v) => Ok(v),
59            Err(_) => Err(self.err(
60                ScErrorType::Value,
61                ScErrorCode::ArithDomain,
62                "expecting U32Val less than 256",
63                &[r.to_val(), name.try_into_val(self)?],
64            )),
65        }
66    }
67
68    pub(crate) fn hash_from_bytesobj_input(
69        &self,
70        name: &'static str,
71        hash: BytesObject,
72    ) -> Result<Hash, HostError> {
73        static_assertions::assert_eq_size!([u8; 32], Hash);
74        self.fixed_length_bytes_from_bytesobj_input::<Hash, 32>(name, hash)
75    }
76
77    pub(crate) fn u256_from_bytesobj_input(
78        &self,
79        name: &'static str,
80        u256: BytesObject,
81    ) -> Result<Uint256, HostError> {
82        static_assertions::assert_eq_size!([u8; 32], Uint256);
83        self.fixed_length_bytes_from_bytesobj_input::<Uint256, 32>(name, u256)
84    }
85
86    pub(crate) fn fixed_length_bytes_from_slice<T, const N: usize>(
87        &self,
88        name: &'static str,
89        bytes_arr: &[u8],
90    ) -> Result<T, HostError>
91    where
92        T: From<[u8; N]>,
93    {
94        match <[u8; N]>::try_from(bytes_arr) {
95            Ok(arr) => {
96                self.charge_budget(ContractCostType::MemCpy, Some(N as u64))?;
97                Ok(arr.into())
98            }
99            Err(_) => Err(err!(
100                self,
101                (ScErrorType::Object, ScErrorCode::UnexpectedSize),
102                "expected fixed-length bytes slice, got slice with different size",
103                name,
104                N,
105                bytes_arr.len()
106            )),
107        }
108    }
109
110    pub(crate) fn fixed_length_bytes_from_bytesobj_input<T, const N: usize>(
111        &self,
112        name: &'static str,
113        obj: BytesObject,
114    ) -> Result<T, HostError>
115    where
116        T: From<[u8; N]>,
117    {
118        self.visit_obj(obj, |bytes: &ScBytes| {
119            self.fixed_length_bytes_from_slice(name, bytes.as_slice())
120        })
121    }
122
123    pub(crate) fn account_id_from_bytesobj(&self, k: BytesObject) -> Result<AccountId, HostError> {
124        self.visit_obj(k, |bytes: &ScBytes| {
125            Ok(AccountId(xdr::PublicKey::PublicKeyTypeEd25519(
126                self.fixed_length_bytes_from_slice("account_id", bytes.as_slice())?,
127            )))
128        })
129    }
130
131    pub(crate) fn storage_key_for_address(
132        &self,
133        contract: ScAddress,
134        key: ScVal,
135        durability: ContractDataDurability,
136    ) -> Result<Rc<LedgerKey>, HostError> {
137        Rc::metered_new(
138            LedgerKey::ContractData(LedgerKeyContractData {
139                contract,
140                key,
141                durability,
142            }),
143            self,
144        )
145    }
146
147    pub(crate) fn storage_key_from_scval(
148        &self,
149        key: ScVal,
150        durability: ContractDataDurability,
151    ) -> Result<Rc<LedgerKey>, HostError> {
152        let contract_id = self.get_current_contract_id_internal()?;
153        self.storage_key_for_address(ScAddress::Contract(contract_id), key, durability)
154    }
155
156    /// Converts a [`Val`] to an [`ScVal`] and combines it with the currently-executing
157    /// [`ContractID`] to produce a [`Key`], that can be used to access ledger [`Storage`].
158    // Notes on metering: covered by components.
159    pub(crate) fn storage_key_from_val(
160        &self,
161        k: Val,
162        durability: ContractDataDurability,
163    ) -> Result<Rc<LedgerKey>, HostError> {
164        let key_scval = self.from_host_val_for_storage(k)?;
165        self.storage_key_from_scval(key_scval, durability)
166    }
167
168    /// Converts a binary search result into a u64. `res` is `Some(index)` if
169    /// the value was found at `index`, or `Err(index)` if the value was not
170    /// found and would've needed to be inserted at `index`. Returns a
171    /// Some(res_u64) where:
172    /// - The high 32 bits is 0x0000_0001 if element existed or 0x0000_0000 if
173    ///   it didn't
174    /// - The low 32 bits contains the u32 representation of the `index` Err(_)
175    ///   if the `index` fails to be converted to an u32.
176    pub(crate) fn u64_from_binary_search_result(
177        &self,
178        res: Result<usize, usize>,
179    ) -> Result<u64, HostError> {
180        match res {
181            Ok(u) => {
182                let v = self.usize_to_u32(u)?;
183                Ok(u64::from(v) | (1_u64 << u32::BITS))
184            }
185            Err(u) => {
186                let v = self.usize_to_u32(u)?;
187                Ok(u64::from(v))
188            }
189        }
190    }
191
192    pub(crate) fn call_args_from_obj(&self, args: VecObject) -> Result<Vec<Val>, HostError> {
193        self.visit_obj(args, |hv: &HostVec| hv.to_vec(self.as_budget()))
194    }
195
196    // Metering: covered by vals_to_vec
197    pub(crate) fn vecobject_to_scval_vec(&self, args: VecObject) -> Result<VecM<ScVal>, HostError> {
198        self.visit_obj(args, |hv: &HostVec| self.vals_to_scval_vec(hv.as_slice()))
199    }
200
201    pub(crate) fn vals_to_scval_vec(&self, vals: &[Val]) -> Result<VecM<ScVal>, HostError> {
202        vals.iter()
203            .map(|v| self.from_host_val(*v))
204            .metered_collect::<Result<Vec<ScVal>, HostError>>(self)??
205            .try_into()
206            .map_err(|_| {
207                err!(
208                    self,
209                    (ScErrorType::Object, ScErrorCode::ExceededLimit),
210                    "vector size limit exceeded",
211                    vals.len()
212                )
213            })
214    }
215
216    pub(crate) fn scvals_to_val_vec(&self, scvals: &[ScVal]) -> Result<Vec<Val>, HostError> {
217        scvals
218            .iter()
219            .map(|scv| self.to_host_val(scv))
220            .metered_collect::<Result<Vec<Val>, HostError>>(self)?
221    }
222
223    pub(crate) fn bytesobj_from_internal_contract_id(
224        &self,
225    ) -> Result<Option<BytesObject>, HostError> {
226        if let Some(id) = self.get_current_contract_id_opt_internal()? {
227            let obj = self.add_host_object::<ScBytes>(
228                self.metered_slice_to_vec(id.0.as_slice())?.try_into()?,
229            )?;
230            Ok(Some(obj))
231        } else {
232            Ok(None)
233        }
234    }
235
236    pub(crate) fn scbytes_from_vec(&self, v: Vec<u8>) -> Result<ScBytes, HostError> {
237        Ok(ScBytes(v.try_into()?))
238    }
239
240    pub(crate) fn metered_slice_to_vec(&self, s: &[u8]) -> Result<Vec<u8>, HostError> {
241        Vec::<u8>::charge_bulk_init_cpy(s.len() as u64, self)?;
242        Ok(s.to_vec())
243    }
244
245    // metering: covered
246    pub(crate) fn scbytes_from_slice(&self, s: &[u8]) -> Result<ScBytes, HostError> {
247        self.scbytes_from_vec(self.metered_slice_to_vec(s)?)
248    }
249
250    pub(crate) fn scbytes_from_hash(&self, hash: &Hash) -> Result<ScBytes, HostError> {
251        self.scbytes_from_slice(hash.as_slice())
252    }
253
254    pub fn scaddress_from_address(&self, address: AddressObject) -> Result<ScAddress, HostError> {
255        self.visit_obj(address, |addr: &ScAddress| addr.metered_clone(self))
256    }
257
258    pub(crate) fn scsymbol_from_symbol(&self, symbol: Symbol) -> Result<ScSymbol, HostError> {
259        if let Ok(sobj) = SymbolObject::try_from(symbol) {
260            self.visit_obj(sobj, |sym: &ScSymbol| sym.metered_clone(self))
261        } else {
262            self.map_err(ScSymbol::try_from_val(self, &symbol))
263        }
264    }
265
266    pub(crate) fn host_map_to_scmap(&self, map: &HostMap) -> Result<ScMap, HostError> {
267        let mut mv = Vec::<ScMapEntry>::with_metered_capacity(map.len(), self)?;
268        for (k, v) in map.iter(self)? {
269            let key = self.from_host_val(*k)?;
270            let val = self.from_host_val(*v)?;
271            mv.push(ScMapEntry { key, val });
272        }
273        Ok(ScMap(self.map_err(mv.try_into())?))
274    }
275
276    // This function is almost identical to `host_map_to_scmap`, and should only
277    // be used for creating the instance storage map.
278    pub(crate) fn instance_storage_map_to_scmap(&self, map: &HostMap) -> Result<ScMap, HostError> {
279        let mut mv = Vec::<ScMapEntry>::with_metered_capacity(map.len(), self)?;
280        for (k, v) in map.iter(self)? {
281            // This is the only difference point compared to `host_map_to_scmap`:
282            // we convert the key according to the storage key conversion rules
283            // instead of the general value conversion rules.
284            let key = self.from_host_val_for_storage(*k)?;
285            let val = self.from_host_val(*v)?;
286            mv.push(ScMapEntry { key, val });
287        }
288        Ok(ScMap(self.map_err(mv.try_into())?))
289    }
290
291    /// Convert a VecObject of U256Val elements to a Vec of MeteredScalar
292    pub(crate) fn metered_scalar_vec_from_vecobj<S>(
293        &self,
294        vp: VecObject,
295    ) -> Result<Vec<S>, HostError>
296    where
297        S: MeteredScalar,
298    {
299        self.visit_obj(vp, |hv: &HostVec| {
300            let mut scalars: Vec<S> = Vec::with_metered_capacity(hv.len(), self)?;
301            for val in hv.iter() {
302                let u256_val = U256Val::try_from(*val).map_err(|_| {
303                    self.err(
304                        ScErrorType::Crypto,
305                        ScErrorCode::InvalidInput,
306                        "element must be U256Val",
307                        std::slice::from_ref(val),
308                    )
309                })?;
310                let scalar = S::from_u256val(self, u256_val)?;
311                scalars.push(scalar);
312            }
313            Ok(scalars)
314        })
315    }
316
317    /// Convert a Vec of MeteredScalar to a VecObject of U256Val elements
318    pub(crate) fn metered_scalar_vec_to_vecobj<S>(
319        &self,
320        scalars: Vec<S>,
321    ) -> Result<VecObject, HostError>
322    where
323        S: MeteredScalar,
324    {
325        let vals = scalars
326            .into_iter()
327            .map(|s| s.into_u256val(self))
328            .metered_collect::<Result<Vec<_>, HostError>>(self)??;
329
330        let host_vec =
331            HostVec::from_exact_iter(vals.into_iter().map(|v| v.to_val()), self.budget_ref())?;
332
333        self.add_host_object(host_vec)
334    }
335
336    /// Convert a VecObject representing a HostVec<HostVec<U256Val>> elements to a Vec<Vec<MeteredScalar>>
337    pub(crate) fn metered_scalar_vec_of_vec_from_vecobj<S>(
338        &self,
339        vp: VecObject,
340    ) -> Result<Vec<Vec<S>>, HostError>
341    where
342        S: MeteredScalar,
343    {
344        self.visit_obj(vp, |hv: &HostVec| {
345            let n_rows = hv.len();
346            let mut result = Vec::with_metered_capacity(n_rows, self)?;
347            for row_val in hv.iter() {
348                let row_obj = VecObject::try_from(*row_val).map_err(|_| {
349                    self.err(
350                        ScErrorType::Crypto,
351                        ScErrorCode::InvalidInput,
352                        "poseidon_permutation: row must be a vector",
353                        std::slice::from_ref(row_val),
354                    )
355                })?;
356
357                let row_vec = self.metered_scalar_vec_from_vecobj::<S>(row_obj)?;
358                result.push(row_vec);
359            }
360            Ok(result)
361        })
362    }
363}
364
365impl Convert<&Object, ScValObject> for Host {
366    type Error = HostError;
367    fn convert(&self, ob: &Object) -> Result<ScValObject, Self::Error> {
368        self.from_host_obj(*ob)
369    }
370}
371
372impl Convert<Object, ScValObject> for Host {
373    type Error = HostError;
374    fn convert(&self, ob: Object) -> Result<ScValObject, Self::Error> {
375        self.from_host_obj(ob)
376    }
377}
378
379impl<'a> Convert<&ScValObjRef<'a>, Object> for Host {
380    type Error = HostError;
381    fn convert(&self, ob: &ScValObjRef<'a>) -> Result<Object, Self::Error> {
382        self.to_host_obj(ob)
383    }
384}
385
386impl<'a> Convert<ScValObjRef<'a>, Object> for Host {
387    type Error = HostError;
388    fn convert(&self, ob: ScValObjRef<'a>) -> Result<Object, Self::Error> {
389        self.to_host_obj(&ob)
390    }
391}
392
393impl Host {
394    pub(crate) fn check_val_representable_scval(&self, scval: &ScVal) -> Result<(), HostError> {
395        if Val::can_represent_scval(&scval) {
396            Ok(())
397        } else {
398            Err(self.err(
399                ScErrorType::Value,
400                ScErrorCode::InternalError,
401                "unexpected non-Val-representable ScVal type",
402                &[Val::from_u32(scval.discriminant() as u32).into()],
403            ))
404        }
405    }
406
407    pub(crate) fn from_host_val(&self, val: Val) -> Result<ScVal, HostError> {
408        // This is the depth limit checkpoint for `Val`->`ScVal` conversion.
409        // Metering of val conversion happens only if an object is encountered,
410        // and is done inside `from_host_obj`.
411        let _span = tracy_span!("Val to ScVal");
412        let scval = self.budget_cloned().with_limited_depth(|_| {
413            ScVal::try_from_val(self, &val)
414                .map_err(|cerr| self.error(cerr, "failed to convert host value to ScVal", &[val]))
415        })?;
416        // This is a check of internal logical consistency: we came _from_ a Val
417        // so the ScVal definitely should have been representable.
418        self.check_val_representable_scval(&scval)?;
419        Ok(scval)
420    }
421
422    pub(crate) fn from_host_val_for_storage(&self, val: Val) -> Result<ScVal, HostError> {
423        let _span = tracy_span!("Val to ScVal");
424        *self.try_borrow_storage_key_conversion_active_mut()? = true;
425        let scval = self.budget_cloned().with_limited_depth(|_| {
426            ScVal::try_from_val(self, &val)
427                .map_err(|cerr| self.error(cerr, "failed to convert host value to ScVal", &[val]))
428        })?;
429        *self.try_borrow_storage_key_conversion_active_mut()? = false;
430        self.check_val_representable_scval(&scval)?;
431        Ok(scval)
432    }
433
434    pub(crate) fn to_host_val(&self, v: &ScVal) -> Result<Val, HostError> {
435        let _span = tracy_span!("ScVal to Val");
436        // This is the depth limit checkpoint for `ScVal`->`Val` conversion.
437        // Metering of val conversion happens only if an object is encountered,
438        // and is done inside `to_host_obj`.
439        self.budget_cloned().with_limited_depth(|_| {
440            v.try_into_val(self)
441                .map_err(|cerr| self.error(cerr, "failed to convert ScVal to host value", &[]))
442        })
443    }
444
445    // Version of `to_host_val` for the internal cases where the value has to
446    // be valid by construction (e.g. read from ledger).
447    pub(crate) fn to_valid_host_val(&self, v: &ScVal) -> Result<Val, HostError> {
448        self.to_host_val(v).map_err(|e| {
449            if e.error.is_type(ScErrorType::Budget) {
450                e
451            } else {
452                self.err(
453                    ScErrorType::Value,
454                    ScErrorCode::InternalError,
455                    "unexpected non-Val-representable ScVal in internal conversion",
456                    &[],
457                )
458            }
459        })
460    }
461
462    pub(crate) fn from_host_obj(&self, ob: impl Into<Object>) -> Result<ScValObject, HostError> {
463        unsafe {
464            let objref: Object = ob.into();
465            self.visit_obj_untyped(objref, |ho| {
466                let val = match ho {
467                    HostObject::Vec(vv) => {
468                        Vec::<ScVal>::charge_bulk_init_cpy(vv.len() as u64, self)?;
469                        let sv = vv.iter().map(|e| self.from_host_val(*e)).collect::<Result<
470                            Vec<ScVal>,
471                            HostError,
472                        >>(
473                        )?;
474                        ScVal::Vec(Some(ScVec(self.map_err(sv.try_into())?)))
475                    }
476                    HostObject::Map(mm) => ScVal::Map(Some(self.host_map_to_scmap(mm)?)),
477                    HostObject::U64(u) => {
478                        charge_shallow_copy::<u64>(1, self)?;
479                        ScVal::U64(*u)
480                    }
481                    HostObject::I64(i) => {
482                        charge_shallow_copy::<i64>(1, self)?;
483                        ScVal::I64(*i)
484                    }
485                    HostObject::TimePoint(tp) => ScVal::Timepoint(tp.metered_clone(self)?),
486                    HostObject::Duration(d) => ScVal::Duration(d.metered_clone(self)?),
487                    HostObject::U128(u) => {
488                        charge_shallow_copy::<u128>(1, self)?;
489                        ScVal::U128(UInt128Parts {
490                            hi: int128_helpers::u128_hi(*u),
491                            lo: int128_helpers::u128_lo(*u),
492                        })
493                    }
494                    HostObject::I128(i) => {
495                        charge_shallow_copy::<i128>(1, self)?;
496                        ScVal::I128(Int128Parts {
497                            hi: int128_helpers::i128_hi(*i),
498                            lo: int128_helpers::i128_lo(*i),
499                        })
500                    }
501                    HostObject::U256(u) => {
502                        charge_shallow_copy::<u128>(2, self)?;
503                        let (hi_hi, hi_lo, lo_hi, lo_lo) = u256_into_pieces(*u);
504                        ScVal::U256(UInt256Parts {
505                            hi_hi,
506                            hi_lo,
507                            lo_hi,
508                            lo_lo,
509                        })
510                    }
511                    HostObject::I256(i) => {
512                        charge_shallow_copy::<i128>(2, self)?;
513                        let (hi_hi, hi_lo, lo_hi, lo_lo) = i256_into_pieces(*i);
514                        ScVal::I256(Int256Parts {
515                            hi_hi,
516                            hi_lo,
517                            lo_hi,
518                            lo_lo,
519                        })
520                    }
521                    HostObject::Bytes(b) => ScVal::Bytes(b.metered_clone(self)?),
522                    HostObject::String(s) => ScVal::String(s.metered_clone(self)?),
523                    HostObject::Symbol(s) => ScVal::Symbol(s.metered_clone(self)?),
524                    HostObject::Address(addr) => ScVal::Address(addr.metered_clone(self)?),
525                    HostObject::MuxedAddress(addr) => {
526                        if *self.try_borrow_storage_key_conversion_active()? {
527                            return Err(self.err(
528                                ScErrorType::Storage,
529                                ScErrorCode::InvalidInput,
530                                "muxed addresses should not be used in the storage keys",
531                                &[objref.to_val()],
532                            ));
533                        }
534                        ScVal::Address(addr.0.metered_clone(self)?)
535                    }
536                };
537                Ok(ScValObject::unchecked_from_val(val))
538            })
539        }
540    }
541
542    pub(crate) fn to_host_obj(&self, ob: &ScValObjRef<'_>) -> Result<Object, HostError> {
543        let val: &ScVal = (*ob).into();
544        match val {
545            // Here we have to make sure host object conversion is charged in each variant
546            // below. There is no otherwise ubiquitous metering for ScVal->Val conversion,
547            // since most of them happen in the "common" crate with no access to the host.
548            ScVal::Vec(Some(v)) => {
549                let mut vv = Vec::<Val>::with_metered_capacity(v.len(), self)?;
550                for e in v.iter() {
551                    vv.push(self.to_host_val(e)?)
552                }
553                Ok(self.add_host_object(HostVec::from_vec(vv)?)?.into())
554            }
555            ScVal::Map(Some(m)) => {
556                let mut mm = Vec::<(Val, Val)>::with_metered_capacity(m.len(), self)?;
557                for pair in m.iter() {
558                    let k = self.to_host_val(&pair.key)?;
559                    let v = self.to_host_val(&pair.val)?;
560                    mm.push((k, v))
561                }
562                Ok(self
563                    .add_host_object(HostMap::from_map_with_host(mm, self)?)?
564                    .into())
565            }
566            ScVal::Vec(None) => Err(self.err(
567                ScErrorType::Value,
568                ScErrorCode::InvalidInput,
569                "ScVal::Vec body missing",
570                &[],
571            )),
572            ScVal::Map(None) => Err(self.err(
573                ScErrorType::Value,
574                ScErrorCode::InvalidInput,
575                "ScVal::Map body missing",
576                &[],
577            )),
578            ScVal::U64(u) => {
579                charge_shallow_copy::<u64>(1, self)?;
580                Ok(self.add_host_object(*u)?.into())
581            }
582            ScVal::I64(i) => {
583                charge_shallow_copy::<i64>(1, self)?;
584                Ok(self.add_host_object(*i)?.into())
585            }
586            ScVal::Timepoint(t) => Ok(self.add_host_object(t.metered_clone(self)?)?.into()),
587            ScVal::Duration(d) => Ok(self.add_host_object(d.metered_clone(self)?)?.into()),
588            ScVal::U128(u) => {
589                charge_shallow_copy::<u128>(1, self)?;
590                Ok(self
591                    .add_host_object(int128_helpers::u128_from_pieces(u.hi, u.lo))?
592                    .into())
593            }
594            ScVal::I128(i) => {
595                charge_shallow_copy::<i128>(1, self)?;
596                Ok(self
597                    .add_host_object(int128_helpers::i128_from_pieces(i.hi, i.lo))?
598                    .into())
599            }
600            ScVal::U256(u) => {
601                charge_shallow_copy::<u128>(2, self)?;
602                Ok(self
603                    .add_host_object(u256_from_pieces(u.hi_hi, u.hi_lo, u.lo_hi, u.lo_lo))?
604                    .into())
605            }
606            ScVal::I256(i) => {
607                charge_shallow_copy::<i128>(2, self)?;
608                Ok(self
609                    .add_host_object(i256_from_pieces(i.hi_hi, i.hi_lo, i.lo_hi, i.lo_lo))?
610                    .into())
611            }
612            ScVal::Bytes(b) => Ok(self.add_host_object(b.metered_clone(self)?)?.into()),
613            ScVal::String(s) => Ok(self.add_host_object(s.metered_clone(self)?)?.into()),
614            // Similarly to `ScMap`, not every `SCSymbol` XDR is valid. Thus it has to be
615            // created with the respective fallible conversion method.
616            ScVal::Symbol(s) => Ok(self
617                .add_host_object(ScSymbol::try_from_bytes(
618                    self,
619                    s.0.metered_clone(self.as_budget())?.into(),
620                )?)?
621                .into()),
622
623            ScVal::Address(addr) => {
624                match addr {
625                    ScAddress::Account(_) | ScAddress::Contract(_) => {
626                        Ok(self.add_host_object(addr.metered_clone(self)?)?.into())
627                    }
628                    ScAddress::MuxedAccount(_) => Ok(self
629                        .add_host_object(MuxedScAddress(addr.metered_clone(self)?))?
630                        .into()),
631                    _ => Err(self.err(
632                        ScErrorType::Object,
633                        ScErrorCode::UnexpectedType,
634                        "encountered unsupported ScAddress type",
635                        &[],
636                    )),
637                }
638                // ,
639            }
640
641            // None of the following cases should have made it into this function, they
642            // are excluded by the ScValObjRef::classify function.
643            ScVal::Bool(_)
644            | ScVal::Void
645            | ScVal::Error(_)
646            | ScVal::U32(_)
647            | ScVal::I32(_)
648            | ScVal::LedgerKeyNonce(_)
649            | ScVal::ContractInstance(_)
650            | ScVal::LedgerKeyContractInstance => Err(self.err(
651                ScErrorType::Value,
652                ScErrorCode::InternalError,
653                "converting ScValObjRef on non-object ScVal type",
654                &[],
655            )),
656        }
657    }
658}