contracts: Change define_env! to expect a Result<T, DispatchError> for every function (#7762)

* Make host functions return TrapReason

This avoids the need to manually store any trap reasons
to the `Runtime` from the host function. This adds the following
benefits:

* It properly composes with the upcoming chain extensions
* Missing to set a trap value is now a compile error

* review: Remove superflous .into()
This commit is contained in:
Alexander Theißen
2020-12-29 13:58:23 +01:00
committed by GitHub
parent dd8e7587cb
commit ab876be9e9
5 changed files with 146 additions and 156 deletions
@@ -96,7 +96,7 @@ macro_rules! unmarshall_then_body {
#[inline(always)]
pub fn constrain_closure<R, F>(f: F) -> F
where
F: FnOnce() -> Result<R, sp_sandbox::HostError>,
F: FnOnce() -> Result<R, crate::wasm::runtime::TrapReason>,
{
f
}
@@ -109,14 +109,20 @@ macro_rules! unmarshall_then_body_then_marshall {
>(|| {
unmarshall_then_body!($body, $ctx, $args_iter, $( $names : $params ),*)
});
let r = body()?;
let r = body().map_err(|reason| {
$ctx.set_trap_reason(reason);
sp_sandbox::HostError
})?;
return Ok(sp_sandbox::ReturnValue::Value({ use $crate::wasm::env_def::ConvertibleToWasm; r.to_typed_value() }))
});
( $args_iter:ident, $ctx:ident, ( $( $names:ident : $params:ty ),* ) => $body:tt ) => ({
let body = $crate::wasm::env_def::macros::constrain_closure::<(), _>(|| {
unmarshall_then_body!($body, $ctx, $args_iter, $( $names : $params ),*)
});
body()?;
body().map_err(|reason| {
$ctx.set_trap_reason(reason);
sp_sandbox::HostError
})?;
return Ok(sp_sandbox::ReturnValue::Unit)
})
}
@@ -207,15 +213,24 @@ mod tests {
use parity_wasm::elements::ValueType;
use sp_runtime::traits::Zero;
use sp_sandbox::{ReturnValue, Value};
use crate::wasm::tests::MockExt;
use crate::wasm::Runtime;
use crate::exec::Ext;
use crate::gas::Gas;
use crate::{
wasm::{Runtime, runtime::TrapReason, tests::MockExt},
exec::Ext,
gas::Gas,
};
struct TestRuntime {
value: u32,
}
impl TestRuntime {
fn set_trap_reason(&mut self, _reason: TrapReason) {}
}
#[test]
fn macro_unmarshall_then_body_then_marshall_value_or_trap() {
fn test_value(
_ctx: &mut u32,
_ctx: &mut TestRuntime,
args: &[sp_sandbox::Value],
) -> Result<ReturnValue, sp_sandbox::HostError> {
let mut args = args.iter();
@@ -224,7 +239,7 @@ mod tests {
_ctx,
(a: u32, b: u32) -> u32 => {
if b == 0 {
Err(sp_sandbox::HostError)
Err(crate::wasm::runtime::TrapReason::Termination)
} else {
Ok(a / b)
}
@@ -232,7 +247,7 @@ mod tests {
)
}
let ctx = &mut 0;
let ctx = &mut TestRuntime { value: 0 };
assert_eq!(
test_value(ctx, &[Value::I32(15), Value::I32(3)]).unwrap(),
ReturnValue::Value(Value::I32(5)),
@@ -243,7 +258,7 @@ mod tests {
#[test]
fn macro_unmarshall_then_body_then_marshall_unit() {
fn test_unit(
ctx: &mut u32,
ctx: &mut TestRuntime,
args: &[sp_sandbox::Value],
) -> Result<ReturnValue, sp_sandbox::HostError> {
let mut args = args.iter();
@@ -251,16 +266,16 @@ mod tests {
args,
ctx,
(a: u32, b: u32) => {
*ctx = a + b;
ctx.value = a + b;
Ok(())
}
)
}
let ctx = &mut 0;
let ctx = &mut TestRuntime { value: 0 };
let result = test_unit(ctx, &[Value::I32(2), Value::I32(3)]).unwrap();
assert_eq!(result, ReturnValue::Unit);
assert_eq!(*ctx, 5);
assert_eq!(ctx.value, 5);
}
#[test]
@@ -270,7 +285,7 @@ mod tests {
if !amount.is_zero() {
Ok(())
} else {
Err(sp_sandbox::HostError)
Err(TrapReason::Termination)
}
});
let _f: fn(&mut Runtime<MockExt>, &[sp_sandbox::Value])
@@ -322,7 +337,7 @@ mod tests {
if !amount.is_zero() {
Ok(())
} else {
Err(sp_sandbox::HostError)
Err(crate::wasm::runtime::TrapReason::Termination)
}
},
);