Skip to content

Commit

Permalink
Add EnvBase::Error, remove CheckedEnv, make Env methods return Error (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
graydon authored Jan 23, 2023
1 parent d803b09 commit 96ea6dc
Show file tree
Hide file tree
Showing 46 changed files with 329 additions and 405 deletions.
1 change: 1 addition & 0 deletions soroban-env-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ static_assertions = "1.1.0"
std = ["stellar-xdr/std", "stellar-xdr/base64"]
serde = ["dep:serde", "stellar-xdr/serde"]
vm = ["wasmi"]
testutils = []

[package.metadata.docs.rs]
all-features = true
19 changes: 14 additions & 5 deletions soroban-env-common/src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ impl<E: Env, const N: usize> TryFromVal<E, RawVal> for [u8; N] {
return Err(ScHostValErrorCode::UnexpectedValType.into());
}
let bytes = unsafe { Object::unchecked_from_val(val) };
let len = unsafe { u32::unchecked_from_val(env.bytes_len(bytes)) } as usize;
let len =
unsafe { u32::unchecked_from_val(env.bytes_len(bytes).map_err(|_| ConversionError)?) }
as usize;
if len != N {
return Err(ConversionError.into());
}
let mut arr = [0u8; N];
env.bytes_copy_to_slice(bytes, RawVal::U32_ZERO, &mut arr)?;
env.bytes_copy_to_slice(bytes, RawVal::U32_ZERO, &mut arr)
.map_err(|_| ConversionError)?;
Ok(arr)
}
}
Expand All @@ -34,9 +37,12 @@ impl<E: Env> TryFromVal<E, RawVal> for Vec<u8> {
return Err(ScHostValErrorCode::UnexpectedValType.into());
}
let bytes = unsafe { Object::unchecked_from_val(val) };
let len = unsafe { u32::unchecked_from_val(env.bytes_len(bytes)) } as usize;
let len =
unsafe { u32::unchecked_from_val(env.bytes_len(bytes).map_err(|_| ConversionError)?) }
as usize;
let mut vec = vec![0u8; len];
env.bytes_copy_to_slice(bytes, RawVal::U32_ZERO, &mut vec)?;
env.bytes_copy_to_slice(bytes, RawVal::U32_ZERO, &mut vec)
.map_err(|_| ConversionError)?;
Ok(vec)
}
}
Expand All @@ -45,7 +51,10 @@ impl<E: Env> TryFromVal<E, &[u8]> for RawVal {
type Error = Status;
#[inline(always)]
fn try_from_val(env: &E, v: &&[u8]) -> Result<RawVal, Self::Error> {
Ok(env.bytes_new_from_slice(v)?.to_raw())
Ok(env
.bytes_new_from_slice(v)
.map_err(|_| ConversionError)?
.to_raw())
}
}

Expand Down
186 changes: 0 additions & 186 deletions soroban-env-common/src/checked_env.rs

This file was deleted.

6 changes: 3 additions & 3 deletions soroban-env-common/src/compare.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(feature = "std")]
use std::rc::Rc;

use crate::{BitSet, CheckedEnv, Object, RawVal, RawValConvertible, Status, Symbol, Tag};
use crate::{BitSet, Env, Object, RawVal, RawValConvertible, Status, Symbol, Tag};
use core::cmp::Ordering;

/// General trait representing the ability to compare two values of some type.
Expand Down Expand Up @@ -116,7 +116,7 @@ impl<T, C: Compare<T>> Compare<Rc<T>> for C {
// better). But we can list out any concrete Ord instances we want to support
// here.

impl<E: CheckedEnv> Compare<Object> for E {
impl<E: Env> Compare<Object> for E {
type Error = E::Error;

fn compare(&self, a: &Object, b: &Object) -> Result<Ordering, Self::Error> {
Expand All @@ -131,7 +131,7 @@ impl<E: CheckedEnv> Compare<Object> for E {
}
}

impl<E: CheckedEnv> Compare<RawVal> for E {
impl<E: Env> Compare<RawVal> for E {
type Error = E::Error;

fn compare(&self, a: &RawVal, b: &RawVal) -> Result<Ordering, Self::Error> {
Expand Down
63 changes: 53 additions & 10 deletions soroban-env-common/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,36 @@ use core::any;
/// Base trait extended by the [Env](crate::Env) trait, providing various special-case
/// functions that do _not_ simply call across cross the guest/host interface.
pub trait EnvBase: Sized + Clone {
/// The type of error returned from the environment when the environment
/// itself fails "unrecoverably", or at least in a way that the user is not
/// expected to be able to recover from, such as an internal logic error,
/// exceeding the execution budget, or being passed malformed input in a way
/// that the user-facing API does not anticipate or allow for. This type is
/// returned from _all_ environment-interface methods, and will only ever
/// take on two possible concrete types: either `Infallible` (in the
/// `Guest`) or `HostError` (in the `Host`).
///
/// The `Guest` can treat all such errors as impossible-to-observe since
/// they will result in the `Host` _trapping_ the `Guest` before returning
/// an `Error` to it. Such errors still remain present in the `Env` API so
/// that we can use the same API in both scenarios, rather than having to
/// have separate "fallible" or "infallible" environments and separate
/// conversion routines for each (as was attempted in earlier iterations).
///
/// This type is _not_ the same as an error intended to make it to the
/// user-facing API: user-facing errors should return `Ok(Status)` at the
/// environment-interface level, and then either directly handle or escalate
/// the contained `Status` code to the user as a `Status` or `Result<>` of
/// some other type, depending on the API.
type Error: core::fmt::Debug;

/// Reject an error from the environment, turning it into a panic but on
/// terms that the environment controls (eg. transforming or logging it).
/// This should only ever be called by client-side / SDK local-testing code,
/// never in the `Host`.
#[cfg(feature = "testutils")]
fn escalate_error_to_panic(&self, e: Self::Error) -> !;

/// Used for recovering the concrete type of the Host.
fn as_mut_any(&mut self) -> &mut dyn any::Any;

Expand All @@ -32,16 +62,25 @@ pub trait EnvBase: Sized + Clone {

/// Copy a slice of bytes from the caller's memory into an existing `Bytes`
/// object the host, returning a new `Bytes`.
fn bytes_copy_from_slice(&self, b: Object, b_pos: RawVal, mem: &[u8])
-> Result<Object, Status>;
fn bytes_copy_from_slice(
&self,
b: Object,
b_pos: RawVal,
mem: &[u8],
) -> Result<Object, Self::Error>;

/// Copy a slice of bytes from a `Bytes` object in the host into the
/// caller's memory.
fn bytes_copy_to_slice(&self, b: Object, b_pos: RawVal, mem: &mut [u8]) -> Result<(), Status>;
fn bytes_copy_to_slice(
&self,
b: Object,
b_pos: RawVal,
mem: &mut [u8],
) -> Result<(), Self::Error>;

/// Form a new `Bytes` object in the host from a slice of memory in the
/// caller.
fn bytes_new_from_slice(&self, mem: &[u8]) -> Result<Object, Status>;
fn bytes_new_from_slice(&self, mem: &[u8]) -> Result<Object, Self::Error>;

// As with the bytes functions above, these take _slices_ with definite
// lifetimes. The first slice is interpreted as a (very restricted)
Expand Down Expand Up @@ -69,13 +108,17 @@ pub trait EnvBase: Sized + Clone {
/// a simplified format string (supporting only positional `{}` markers) and
/// a single [RawVal] argument that will be inserted at the marker in the
/// format string.
fn log_static_fmt_val(&self, fmt: &'static str, v: RawVal) -> Result<(), Status>;
fn log_static_fmt_val(&self, fmt: &'static str, v: RawVal) -> Result<(), Self::Error>;

/// Log a formatted debugging message to the debug log (if present), passing
/// a simplified format string (supporting only positional `{}` markers) and
/// a single string-slice argument that will be inserted at the marker in
/// the format string.
fn log_static_fmt_static_str(&self, fmt: &'static str, s: &'static str) -> Result<(), Status>;
fn log_static_fmt_static_str(
&self,
fmt: &'static str,
s: &'static str,
) -> Result<(), Self::Error>;

/// Log a formatted debugging message to the debug log (if present), passing
/// a simplified format string (supporting only positional `{}` markers) and
Expand All @@ -86,7 +129,7 @@ pub trait EnvBase: Sized + Clone {
fmt: &'static str,
v: RawVal,
s: &'static str,
) -> Result<(), Status>;
) -> Result<(), Self::Error>;

/// Log a formatted debugging message to the debug log (if present), passing
/// a simplified format string (supporting only positional `{}` markers) and
Expand All @@ -97,7 +140,7 @@ pub trait EnvBase: Sized + Clone {
fmt: &'static str,
vals: &[RawVal],
strs: &[&'static str],
) -> Result<(), Status>;
) -> Result<(), Self::Error>;
}

///////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -149,7 +192,7 @@ macro_rules! host_function_helper {
=>
{
$(#[$attr])*
fn $fn_id(&self, $($arg:$type),*) -> $ret;
fn $fn_id(&self, $($arg:$type),*) -> Result<$ret, Self::Error>;
};
}

Expand Down Expand Up @@ -186,7 +229,7 @@ macro_rules! generate_env_trait {
// This macro expands to a single item: the Env trait.

/// This trait represents the interface between Host and Guest, used by
/// client contract code and implemented (via [CheckedEnv](crate::CheckedEnv)) by the host.
/// client contract code and implemented (via [Env](crate::Env)) by the host.
/// It consists of functions that take or return only 64-bit values such
/// as [RawVal] or [u64].
pub trait Env: EnvBase
Expand Down
Loading

0 comments on commit 96ea6dc

Please sign in to comment.