life is a secure & fast WebAssembly VM built for decentralized applications, written in Go by Perlin Network.
# enable go modules: https://github.com/golang/go/wiki/Modules
export GO111MODULE=on
# download the dependencies to vendor folder
go mod vendor
# build test suite runner
go build github.com/perlin-network/life/spec/test_runner
# run official test suite
python3 run_spec_tests.py /path/to/testsuite
# build main program
go build
# run your wasm program
# entry point is `app_main` by default if entry flag is omitted, array with
# param in it is optional arguements for entrypoint. params should be converted into `int`.
./life -entry 'method' /path/to/your/wasm/program.wasm [param,...]
# run your wasm program with the Polymerase AOT compilation engine enabled
./life -polymerase -entry 'method' /path/to/your/wasm/program.wasm [param,...]
Suppose we have already loaded our *.wasm module's bytecode into the variable var input []byte
.
Lets pass the bytecode into a newly instantiated virtual machine:
vm, err := exec.NewVirtualMachine(input, exec.VMConfig{}, &exec.NopResolver{}, nil)
if err != nil { // if the wasm bytecode is invalid
panic(err)
}
Lookup the function ID to a desired entry-point function titled app_main
:
entryID, ok := vm.GetFunctionExport("app_main") // can be changed to your own exported function
if !ok {
panic("entry function not found")
}
And startup the VM; printing out the result of the entry-point function:
ret, err := vm.Run(entryID)
if err != nil {
vm.PrintStackTrace()
panic(err)
}
fmt.Printf("return value = %d\n", ret)
Interested to tinker with more options? Check out our fully-documented example here .
One extremely powerful feature is that you may completely customize how WebAssembly module import functions are resolved, executed, and defined.
With import resolvers, you may now securely call external code/functions inside your WebAssembly modules which are executed through life.
Take for example the following Rust module compiled down to a WebAssembly module:
extern "C" {
fn __life_log(msg: *const u8, len: usize);
}
#[no_mangle]
pub extern "C" fn app_main() -> i32 {
let message = "This is being called outside of WebAssembly!".as_bytes();
unsafe {
__life_log(message.as_ptr(), message.len());
}
return 0;
}
We can define an import resolver into our WebAssembly virtual machine that will let us define whatever code the function __life_log
may execute in our host environment.
type Resolver struct{}
func (r *Resolver) ResolveFunc(module, field string) exec.FunctionImport {
switch module {
case "env":
switch field {
case "__life_log":
return func(vm *exec.VirtualMachine) int64 {
ptr := int(uint32(vm.GetCurrentFrame().Locals[0]))
msgLen := int(uint32(vm.GetCurrentFrame().Locals[1]))
msg := vm.Memory[ptr : ptr+msgLen]
fmt.Printf("[app] %s\n", string(msg))
return 0
}
default:
panic(fmt.Errorf("unknown import resolved: %s", field))
}
default:
panic(fmt.Errorf("unknown module: %s", module))
}
}
func (r *Resolver) ResolveGlobal(module, field string) int64 {
panic("we're not resolving global variables for now")
}
We can then include the import resolver into our WebAssembly VM:
vm, err := exec.NewVirtualMachine(input, exec.VMConfig{}, new(Resolver), nil)
if err != nil {
panic(err)
}
And have the VM run the entry-point function app_main
to see the result:
[app] This is being called from outside WebAssembly!
We benchmarked life alongside a couple of other WebAssembly implementations in different programming languages (go-interpreter/wagon, paritytech/wasmi).
Raw results are here.
We at Perlin love reaching out to the open-source community and are open to accepting issues and pull-requests.
For all code contributions, please ensure they adhere as close as possible to the following guidelines:
module_name: Change typed down as a sentence.
This allows our maintainers and everyone else to know what specific code changes you wish to address.
compiler/liveness: Implemented full liveness analysis.
exec/helpers: Added function to run the VM with time limit.
If you...
... we're hiring.
To grab our attention, just make a PR and start contributing.