Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix sdk assertion macros #660

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 27 additions & 37 deletions sdk/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,42 @@
// assertion
#[macro_export]
macro_rules! assert {
($cond:expr, $(,)?) => {{
let res = std::panic::catch_unwind(|| {
core::assert!($cond);
});
if res.is_err() {
let panic_msg = match res.err() {
Some(err) => match err.downcast::<String>() {
Ok(panic_msg_box) => Some(panic_msg_box.as_str()),
Err(err) => None,
},
None => unreachable!(),
};
($cond:expr $(,)?) => ({
std::panic::set_hook(Box::new(|info| {
$crate::vm::abort(ExitCode::USR_ASSERTION_FAILED.value(), Some(&format!("{}", info)))
}));

$crate::vm::abort(
fvm_shared::error::ExitCode::USR_ASSERTION_FAILED.value(),
panic_msg,
);
}
core::assert!($cond);
});
($cond:expr, $($arg:tt)+) => {{
std::panic::set_hook(Box::new(|info| {
$crate::vm::abort(ExitCode::USR_ASSERTION_FAILED.value(), Some(&format!("{}", info)))
}));

core::assert!($cond, "{}", format_args!($($arg)+));
}};
}

// Utility macro to generate macro code for assert_eq and assert_ne
macro_rules! assert2 {
macro_rules! assert_gen {
($assert_macro:ident) => {
with_dollar_sign! {
($d:tt) => {
#[macro_export]
macro_rules! $assert_macro {
($d left:expr, $d right:expr $d(,$d arg:tt)*) => {
let res = std::panic::catch_unwind(|| {
core::$assert_macro!($d left, $d right);
});
if res.is_err() {
let panic_msg = match res.err() {
Some(err) => match err.downcast::<String>() {
Ok(panic_msg_box) => Some(panic_msg_box.as_str()),
Err(err) => None,
},
None => unreachable!(),
};
($d left:expr, $d right:expr $d(,)?) => {
std::panic::set_hook(Box::new(|info| {
$d crate::vm::abort(ExitCode::USR_ASSERTION_FAILED.value(), Some(&format!("{}", info)))
}));

core::$assert_macro!($d left, $d right);
};
($d left:expr, $d right:expr, $d($d arg:tt)+) => {
std::panic::set_hook(Box::new(|info| {
$d crate::vm::abort(ExitCode::USR_ASSERTION_FAILED.value(), Some(&format!("{}", info)))
}));

$crate::vm::abort(
fvm_shared::error::ExitCode::USR_ASSERTION_FAILED.value(),
panic_msg,
);
}
core::$assert_macro!($d left, $d right, "{}", format_args!($d($d arg)+));
};
}
}
Expand All @@ -65,8 +55,8 @@ macro_rules! with_dollar_sign {

// Wrapper around the assert_eq macro to have a hand on which exit code we want to give to our failed
// assertion
assert2!(assert_eq);
assert_gen!(assert_eq);

// Wrapper around the assert_ne macro to have a hand on which exit code we want to give to our failed
// assertion
assert2!(assert_ne);
assert_gen!(assert_ne);
1 change: 1 addition & 0 deletions testing/integration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ fil_ipld_actor = { path = 'tests/fil-ipld-actor', version = '0.1' }
fil_malformed_syscall_actor = { path = "tests/fil-malformed-syscall-actor", version = "0.1" }
fil_integer_overflow_actor = { path = "tests/fil-integer-overflow-actor", version = "0.1" }
fil_syscall_actor = { path = "tests/fil-syscall-actor", version = "0.1" }
fil_sdk_macro_actor = { path = "tests/fil-sdk-macro-actor", version = "0.1" }

[features]
default = ["fvm/testing", "fvm_shared/testing"]
Expand Down
11 changes: 11 additions & 0 deletions testing/integration/tests/fil-sdk-macro-actor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "fil_sdk_macro_actor"
version = "0.1.0"
edition = "2021"

[dependencies]
fvm_sdk = { version = "2.0.0-alpha.1", path = "../../../../sdk", features = ["testing"] }
fvm_shared = { version = "0.8.0", path = "../../../../shared" }

[build-dependencies]
wasm-builder = "3.0.1"
12 changes: 12 additions & 0 deletions testing/integration/tests/fil-sdk-macro-actor/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn main() {
use wasm_builder::WasmBuilder;
WasmBuilder::new()
.with_current_project()
.import_memory()
.append_to_rust_flags("-Ctarget-feature=+crt-static")
.append_to_rust_flags("-Cpanic=abort")
.append_to_rust_flags("-Coverflow-checks=true")
.append_to_rust_flags("-Clto=true")
.append_to_rust_flags("-Copt-level=z")
.build()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nightly
35 changes: 35 additions & 0 deletions testing/integration/tests/fil-sdk-macro-actor/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use fvm_sdk::vm::abort;
use fvm_sdk::NO_DATA_BLOCK_ID;
use fvm_shared::error::ExitCode;

/// Placeholder invoke for testing
#[no_mangle]
pub fn invoke(_: u32) -> u32 {
// Conduct method dispatch. Handle input parameters and return data.
match fvm_sdk::message::method_number() {
// Set initial value
1 => {
// Should have no consequence on the test
fvm_sdk::assert!(true);
// Should exit with an Exit Code 24 and the custom message
fvm_sdk::assert!(false, "hello world");
}
2 => {
// Should have no consequence on the test
fvm_sdk::assert_eq!(1, 1);
// Should exit with an Exit Code 24 and the custom message
fvm_sdk::assert_eq!(0, 1, "throw non equal");
}
3 => {
// Should have no consequence on the test
fvm_sdk::assert_ne!(0, 1);
// Should exit with an Exit Code 24 and the custom message
fvm_sdk::assert_ne!(1, 1, "throw equal");
}
_ => abort(
ExitCode::USR_UNHANDLED_MESSAGE.value(),
Some("unrecognized method"),
),
}
NO_DATA_BLOCK_ID
}
133 changes: 133 additions & 0 deletions testing/integration/tests/fil_sdk_macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use std::env;

use fvm::executor::{ApplyFailure, ApplyKind, Executor};
use fvm_integration_tests::dummy::DummyExterns;
use fvm_integration_tests::tester::{Account, Tester};
use fvm_ipld_blockstore::MemoryBlockstore;
use fvm_ipld_encoding::tuple::*;
use fvm_shared::address::Address;
use fvm_shared::bigint::BigInt;
use fvm_shared::message::Message;
use fvm_shared::state::StateTreeVersion;
use fvm_shared::version::NetworkVersion;
use num_traits::Zero;

const WASM_COMPILED_PATH: &str =
"../../target/debug/wbuild/fil_sdk_macro_actor/fil_sdk_macro_actor.compact.wasm";

/// The state object.
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug, Default)]
pub struct State {
pub count: u64,
}

#[test]
fn sdk_macro() {
// Instantiate tester
let mut tester = Tester::new(
NetworkVersion::V15,
StateTreeVersion::V4,
MemoryBlockstore::default(),
)
.unwrap();

let sender: [Account; 1] = tester.create_accounts().unwrap();

// Get wasm bin
let wasm_path = env::current_dir()
.unwrap()
.join(WASM_COMPILED_PATH)
.canonicalize()
.unwrap();
let wasm_bin = std::fs::read(wasm_path).expect("Unable to read file");

// Set actor state
let actor_state = State::default();
let state_cid = tester.set_state(&actor_state).unwrap();

// Set actor
let actor_address = Address::new_id(10000);

tester
.set_actor_from_bin(&wasm_bin, state_cid, actor_address, BigInt::zero())
.unwrap();

// Instantiate machine
tester.instantiate_machine(DummyExterns).unwrap();

// Send message
let message = Message {
from: sender[0].1,
to: actor_address,
gas_limit: 1000000000,
method_num: 1,
..Message::default()
};

let res = tester
.executor
.as_mut()
.unwrap()
.execute_message(message, ApplyKind::Explicit, 100)
.unwrap();

// Test assert!
match res.failure_info.unwrap() {
ApplyFailure::MessageBacktrace(backtrace) => {
assert_eq!(backtrace.frames[0].code.value(), 24);
assert!(backtrace.frames[0].message.contains("hello world"));
}
_ => panic!("failure should be message backtrace"),
}

// Send message
let message = Message {
from: sender[0].1,
to: actor_address,
gas_limit: 1000000000,
method_num: 2,
sequence: 1,
..Message::default()
};

let res = tester
.executor
.as_mut()
.unwrap()
.execute_message(message, ApplyKind::Explicit, 100)
.unwrap();

// Test assert_eq!
match res.failure_info.unwrap() {
ApplyFailure::MessageBacktrace(backtrace) => {
assert_eq!(backtrace.frames[0].code.value(), 24);
assert!(backtrace.frames[0].message.contains("throw non equal"));
}
_ => panic!("failure should be message backtrace"),
}

// Send message
let message = Message {
from: sender[0].1,
to: actor_address,
gas_limit: 1000000000,
method_num: 3,
sequence: 2,
..Message::default()
};

let res = tester
.executor
.unwrap()
.execute_message(message, ApplyKind::Explicit, 100)
.unwrap();

// Test assert_ne!
match res.failure_info.unwrap() {
ApplyFailure::MessageBacktrace(backtrace) => {
assert_eq!(backtrace.frames[0].code.value(), 24);
assert!(backtrace.frames[0].message.contains("throw equal"));
}
_ => panic!("failure should be message backtrace"),
}
}