soroban_env_host/host/
conversion.rs

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