Using integration test module to test your actor in FVM
To help testing your application without deploying a node you can use the rust (Integration test module)[https://github.com/filecoin-project/ref-fvm/tree/master/testing/integration]. It requires to have Rust 🦀 and be a bit familiar with it.
Install rust​
Follow the official rust instruction.
Local FVM in rust​
In your project you can create a folder claled testing
where we are going to write our tests.
mkdir testing
cd testing
cargo init
In Cargo.toml
add those dependencies (you might need to upgrade the function)
[dependencies]
fvm_ipld_blockstore = { version = "0.1.1", git = "https://github.com/filecoin-project/ref-fvm", branch = "experimental/fvm-m2" }
fvm_integration_tests = { version = "0.1.0", git = "https://github.com/filecoin-project/ref-fvm", branch = "experimental/fvm-m2" }
fvm_shared = { version = "0.7.1", git = "https://github.com/filecoin-project/ref-fvm", branch = "experimental/fvm-m2" }
fvm = { version = "1.0.0-rc.2", git = "https://github.com/filecoin-project/ref-fvm", branch = "experimental/fvm-m2", default-features = false }
fvm_ipld_encoding = { version = "0.2.1", git = "https://github.com/filecoin-project/ref-fvm", branch = "experimental/fvm-m2" }
serde = { version = "1.0", features = ["derive"] }
serde_tuple = "0.5"
wabt = "0.10.0"
hex = "0.4.3"
If it id not working you might need to patch some lib as FVM is still in development.
[patch.crates-io]
fvm_ipld_encoding = { version = "0.2.1", git = "https://github.com/filecoin-project/ref-fvm", branch = "experimental/fvm-m2" }
fvm_ipld_hamt = { version = "0.5.1", git = "https://github.com/filecoin-project/ref-fvm", branch = "experimental/fvm-m2" }
fvm_ipld_amt = { version = "0.4.1", git = "https://github.com/filecoin-project/ref-fvm", branch = "experimental/fvm-m2" }
fvm_shared = { version = "0.7.1", git = "https://github.com/filecoin-project/ref-fvm", branch = "experimental/fvm-m2" }
fvm_ipld_blockstore = { version = "0.1.1", git = "https://github.com/filecoin-project/ref-fvm", branch = "experimental/fvm-m2" }
Now let's check our src/main.rs
file where we are going to run our actor in the rust FVM.
use fvm_integration_tests::tester::{Account, Tester};
use fvm_shared::message::Message;
use fvm_shared::state::StateTreeVersion;
use fvm_shared::version::NetworkVersion;
use fvm::executor::{ApplyKind, Executor};
use fvm_ipld_blockstore::MemoryBlockstore;
use fvm_ipld_blockstore::Blockstore;
use fvm_ipld_encoding::tuple::*;
use fvm_shared::address::Address;
use fvm_shared::bigint::BigInt;
use std::env;
const WASM_COMPILED_PATH: &str =
"../../build/release-final.wasm";
/// The state object.
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug, Default)]
pub struct State {
pub count: u64,
}
fn main() {
println!("tests/local-vm Hello World contract in assembly script");
let mut tester = Tester::new(
NetworkVersion::V16,
StateTreeVersion::V4,
MemoryBlockstore::default(),
)
.unwrap();
// Create sender account
let sender: [Account; 1] = tester.create_accounts().unwrap();
// Load wasm file
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 our actor state
let actor_state = State { count: 0 };
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::default())
.unwrap();
let actor = tester.state_tree.as_ref().unwrap().get_actor(&actor_address).unwrap().unwrap();
let state = tester.blockstore().clone().get(&actor.state).unwrap();
println!("Cbor hex state : {}", hex::encode(state.unwrap()));
// Instantiate machine
tester.instantiate_machine().unwrap();
println!("Calling `say_hello`");
let message = Message {
from: sender[0].1,
to: actor_address,
gas_limit: 1000000000,
method_num: 2,
..Message::default()
};
let res = tester
.executor
.unwrap()
.execute_message(message, ApplyKind::Explicit, 100)
.unwrap();
dbg!(&res);
assert_eq!(res.msg_receipt.exit_code.value(), 0);
}
This part determine the wasm file path to load.
const WASM_COMPILED_PATH: &str =
"../../build/release-final.wasm";
You will need to update the State struct so it fit your actor State.
/// The state object.
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug, Default)]
pub struct State {
pub count: u64,
}
Hello Actor has a state with only a counter in it.
Run your test​
$ cargo run