soroban_env_host/host/
conversion.rs

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