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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 }
566
567 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}