use fvm::call_manager::backtrace::Cause;
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::RawBytes;
use fvm_ipld_encoding::tuple::*;
use fvm_shared::address::Address;
use fvm_shared::econ::TokenAmount;
use fvm_shared::error::ErrorNumber;
use fvm_shared::message::Message;
use fvm_shared::state::StateTreeVersion;
use fvm_shared::version::NetworkVersion;
use fvm_test_actors::wasm_bin::MALFORMED_SYSCALL_ACTOR_BINARY;
use num_traits::Zero;
mod bundles;
use bundles::*;
const WAT_UNKNOWN_SYSCALL: &str = r#"
(module
(type $t0 (func))
(type $t1 (func (param i32) (result i32)))
;; Non existing syscall
(import "vm" "do_not_exist" (func $fvm_sdk::sys::vm::do_not_exist::syscall (type $t0)))
(func $invoke (export "invoke") (type $t1) (param $p0 i32) (result i32)
(call $fvm_sdk::sys::vm::do_not_exist::syscall)
(unreachable))
(memory $memory (export "memory") 16)
(global $__data_end (export "__data_end") i32 (i32.const 1048576))
(global $__heap_base (export "__heap_base") i32 (i32.const 1048576)))
"#;
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug, Default)]
pub struct State {
pub count: i64,
}
fn instantiate_tester(
wasm_bin: &[u8],
) -> (Account, Tester<MemoryBlockstore, DummyExterns>, Address) {
let mut tester = new_tester(
NetworkVersion::V21,
StateTreeVersion::V5,
MemoryBlockstore::default(),
)
.unwrap();
let sender: [Account; 1] = tester.create_accounts().unwrap();
let actor_state = State::default();
let state_cid = tester.set_state(&actor_state).unwrap();
let actor_address = Address::new_id(10000);
tester
.set_actor_from_bin(wasm_bin, state_cid, actor_address, TokenAmount::zero())
.unwrap();
(sender[0], tester, actor_address)
}
#[test]
fn non_existing_syscall() {
let wasm_bin = wat::parse_str(WAT_UNKNOWN_SYSCALL).unwrap();
let (sender, mut tester, actor_address) = instantiate_tester(&wasm_bin);
tester.instantiate_machine(DummyExterns).unwrap();
let params = RawBytes::new(Vec::<u8>::new());
let message = Message {
from: sender.1,
to: actor_address,
gas_limit: 1000000000,
method_num: 1,
params,
..Message::default()
};
let res = tester
.executor
.as_mut()
.unwrap()
.execute_message(message, ApplyKind::Explicit, 100)
.unwrap();
assert_eq!(
res.msg_receipt.exit_code.value(),
10,
"exit code should be internal VM assertion failed"
);
match res.failure_info.as_ref().unwrap() {
ApplyFailure::MessageBacktrace(backtrace) => {
assert!(
backtrace
.cause
.as_ref()
.unwrap()
.to_string()
.contains("unknown import"),
"error cause should be unknown import"
);
}
_ => panic!("transaction result should have a backtrace"),
}
}
#[test]
fn malformed_syscall_parameter() {
let wasm_bin = MALFORMED_SYSCALL_ACTOR_BINARY;
let (sender, mut tester, actor_address) = instantiate_tester(wasm_bin);
tester.instantiate_machine(DummyExterns).unwrap();
let params = RawBytes::new(Vec::<u8>::new());
let message = Message {
from: sender.1,
to: actor_address,
gas_limit: 1000000000,
method_num: 1,
params,
..Message::default()
};
let res = tester
.executor
.as_mut()
.unwrap()
.execute_message(message, ApplyKind::Explicit, 100)
.unwrap();
assert_eq!(res.msg_receipt.exit_code.value(), 4);
match res.failure_info.as_ref().unwrap() {
ApplyFailure::MessageBacktrace(backtrace) => match backtrace.cause.as_ref().unwrap() {
Cause::Syscall { error, message, .. } => {
assert!(message.contains("invalid proof type"));
match error {
ErrorNumber::IllegalArgument => {}
_ => panic!("error type should be IllegalArgument"),
}
}
_ => panic!("failure cause should be syscall"),
},
_ => panic!("transaction result should have a backtrace"),
}
}