mod utils;
use ewasm::{Execute, RootRuntime};
use std::{cell::RefCell, rc::Rc};
use utils::escape;
use wabt::wat2wasm;
fn compile_wat(child_code: &str) -> Vec<u8> {
let child_asm = wat2wasm(child_code).unwrap();
wat2wasm(format!(
r#"
(module
(import "env" "eth2_loadModule" (func $load (param i32) (param i32) (param i32)))
(import "env" "eth2_expose" (func $expose (param i32) (param i32)))
(import "env" "eth2_return" (func $return (param i32) (param i32) (result i32)))
(import "env" "eth2_argument" (func $argument (param i32) (param i32) (result i32)))
(import
"env"
"eth2_callModule"
(func
$call
(param i32)
(param i32)
(param i32)
(param i32)
(param i32)
(param i32)
(param i32)
(result i32)))
(memory (export "memory") 1)
(data (i32.const 0) "some_func")
(data (i32.const 10) "main")
(data (i32.const 22) "{}")
(func $some_func
(export "some_func")
(result i32)
(; Read the argument, and check the result ;)
(drop (call $argument (i32.const 89) (i32.const 4)))
(if (i32.ne (i32.load (i32.const 89)) (i32.const 9999))
(then (unreachable)))
(; Return a value to the caller ;)
(i32.store (i32.const 99) (i32.const 8888))
(drop (call $return (i32.const 99) (i32.const 4)))
(i32.const 6654))
(func $main (export "main")
(call $expose (i32.const 0) (i32.const 9))
(call $load (i32.const 0) (i32.const 22) (i32.const {}))
(i32.store (i32.const 14) (i32.const 1234))
(drop
(call
$call
(i32.const 0) (; Slot ;)
(i32.const 10) (; Name Offset ;)
(i32.const 4) (; Name Length ;)
(i32.const 14) (; Argument Offset ;)
(i32.const 4) (; Argument Length ;)
(i32.const 18) (; Return Offset ;)
(i32.const 4) (; Return Length ;)
)
)
(; Check the returned buffer from the child runtime ;)
(if
(i32.ne (i32.load (i32.const 18)) (i32.const 4321))
(then (unreachable)))
)
)
"#,
escape(&child_asm),
child_asm.len(),
))
.unwrap()
}
#[test]
fn call() {
let child_code = r#"
(module
(import
"env"
"eth2_return"
(func
$eth2_return
(param i32)
(param i32)
(result i32)))
(import
"env"
"eth2_argument"
(func
$eth2_argument
(param i32)
(param i32)
(result i32)))
(import
"env"
"eth2_call"
(func
$eth2_call
(param i32)
(param i32)
(param i32)
(param i32)
(param i32)
(param i32)
(result i32)))
(memory (export "memory") 1)
(data (i32.const 0) "some_func")
(func $main (export "main") (result i32) (local $x i32)
(; Check that the argument provided by the caller is 1234 ;)
(drop (call $eth2_argument (i32.const 10) (i32.const 4)))
(if
(i32.ne (i32.load (i32.const 10)) (i32.const 1234))
(then (unreachable)))
(; Return a value to the caller ;)
(i32.store (i32.const 10) (i32.const 4321))
(drop (call $eth2_return (i32.const 10) (i32.const 4)))
(i32.store (i32.const 10) (i32.const 9999))
(set_local $x
(call
$eth2_call
(i32.const 0)
(i32.const 9)
(i32.const 10)
(i32.const 4)
(i32.const 15)
(i32.const 4)))
(if
(i32.ne (get_local $x) (i32.const 6654))
(then (unreachable)))
(if
(i32.ne (i32.load (i32.const 15)) (i32.const 8888))
(then (unreachable))
)
(i32.const 6301)
)
)
"#;
let code = compile_wat(child_code);
let mut runtime = RootRuntime::new(&code, &[], [0u8; 32]);
runtime.execute();
}
#[test]
fn print() {
let child_code = r#"
(module
(import
"env"
"eth2_return"
(func
$eth2_return
(param i32)
(param i32)
(result i32)))
(import "env" "print" (func $print (param i32) (param i32)))
(memory (export "memory") 1)
(data (i32.const 0) "hello world")
(func $main (export "main") (result i32) (local $x i32)
(; print data ;)
(call $print (i32.const 0) (i32.const 11))
(; Return a value to the caller ;)
(i32.store (i32.const 10) (i32.const 4321))
(call $eth2_return (i32.const 10) (i32.const 4))
)
)
"#;
let code = compile_wat(child_code);
let result = Rc::new(RefCell::new(String::new()));
let mut runtime = RootRuntime::new(&code, &[], [0u8; 32]);
runtime.set_logger(|b| {
*result.borrow_mut() = b.to_string();
});
let _ = runtime.execute();
assert_eq!(*result.borrow(), "hello world");
}