This project provides SSVM a Rust interface by using EVMC (Ethereum Client-VM Connector API) to binding SSVM and host written in Rust.
We extend evmc rust binding module to include evmc-client base on evmc version 6.3.1 for now.
The software architecture of evmc-client was inspired by go-ethereum about how to use EVMC connect Ewasm VM (Hera) with host written in golang.
- EVMC-Client design architecture
evmc-client : ┌───────────────────────────────────────────────┐
stack diagram │ evmc-client │
├───────────────────────────────────────────────┤
│ lib.rs (pub interface) │
├─────────────────────────────────┬─────────────┤
│ host.rs (hook host context) │ loader.rs │
go-ethereum : ┆ ┆
sequential diagram ┆ ┆
┌───────────────────┐
┌───────────────────┐ ┌────────────────────┐ ┌─────────────────────────┐ │ C module │
│geth/core/vm/evm.go│ │geth/core/vm/evmc.go│ │evmc/bindings/.../evmc.go│ │ex. loader and hera│
└─────────┬─────────┘ └─────────┬──────────┘ └────────────┬────────────┘ └─────────┬─────────┘
NewEVM │ NewEVMC │ │ │
─────────>│────────────────────>│ │ │
│ CreateVM ─┤ │ │
│ │ Load │ ╔═══════════╗
│ │ ───────────────────────>│ ║ Loader ░║
│ │ │ evmc_load_and_create ╚═══════════╝
│ │ │───────────────────────>│
│ │ │ load EVMC VM .so ─┤
│ │ │ call evmc_create ─┤
│ │ │ │
│ │ return Instance{handle} │ return evmc_instance │
│<─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │<─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│
│ │ │ │
run │ Run │ │ │
─────────>│────────────────────>│ │ ╔═══════════╗
│ │ Execute │ ║ EVMC VM ░║
│ │ ───────────────────────>│ ║ ex. Hera ║
│ │ │ evmc_execute ╚═══════════╝
│ │ │───────────────────────>│
│ │ │ execute ─┤
│ │ return output, gasLeft, │ │
│ │ err │return evmc_result │
│<─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │<─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│
│ │ │ │
Build rust-ssvm you need prepare a build ssvm environment and include rust compile tool.
- Reuse ssvm build environment docker image
> docker pull secondstate/ssvm
- Fetch rust-ssvm source code
> git clone --recursive [email protected]:second-state/rust-ssvm.git
- Start docker container
> docker run -it \
-v $(pwd)/rust-ssvm:/root/rust-ssvm \
secondstate/ssvm:latest
- Install rust compile tool
(docker) $ curl https://sh.rustup.rs -sSf | sh
(docker) $ source ~/.cargo/env
- Build rust-ssvm lib
(docker) $ cd ~/rust-ssvm && cargo build -v
We provide a simple demo show how to launch a ssvm instance and call vm execute function with a dummy HostContext (host functions) and fib.wasm
demo bytecode.
- The HostContext traits need implemented by chain's backend.
- The
fib.wasm
was generated from fib.yul written in Yul language.
Yul is an intermediate language designed by Ethereum fundaction.
The other project of our company call SOLL could help you compile Yul to EWASM. (more...)
(docker) $ cd ~/rust-ssvm && cargo run --example execute_vm -v -- -f=examples/fib.wasm
The result should be the same as the following content.
Instantiate: ("ssvm", "0.4.0")
Host: get_storage
"0000000000000000000000000000000000000000000000000000000000000000" -> "0000000000000000000000000000000000000000000000000000000000000000"
Host: set_storage
"0000000000000000000000000000000000000000000000000000000000000000" -> "0000000000000000000000000000000000000000000000000000000000000001"
Host: get_storage
"0000000000000000000000000000000000000000000000000000000000000001" -> "0000000000000000000000000000000000000000000000000000000000000000"
Host: set_storage
"0000000000000000000000000000000000000000000000000000000000000001" -> "0000000000000000000000000000000000000000000000000000000000000001"
Host: get_storage
"0000000000000000000000000000000000000000000000000000000000000002" -> "0000000000000000000000000000000000000000000000000000000000000000"
Host: set_storage
"0000000000000000000000000000000000000000000000000000000000000002" -> "0000000000000000000000000000000000000000000000000000000000000002"
Host: get_storage
"0000000000000000000000000000000000000000000000000000000000000003" -> "0000000000000000000000000000000000000000000000000000000000000000"
Host: set_storage
"0000000000000000000000000000000000000000000000000000000000000003" -> "0000000000000000000000000000000000000000000000000000000000000003"
Host: get_storage
"0000000000000000000000000000000000000000000000000000000000000004" -> "0000000000000000000000000000000000000000000000000000000000000000"
Host: set_storage
"0000000000000000000000000000000000000000000000000000000000000004" -> "0000000000000000000000000000000000000000000000000000000000000005"
Host: get_storage
"0000000000000000000000000000000000000000000000000000000000000005" -> "0000000000000000000000000000000000000000000000000000000000000000"
Host: set_storage
"0000000000000000000000000000000000000000000000000000000000000005" -> "0000000000000000000000000000000000000000000000000000000000000008"
Host: get_storage
"0000000000000000000000000000000000000000000000000000000000000006" -> "0000000000000000000000000000000000000000000000000000000000000000"
Host: set_storage
"0000000000000000000000000000000000000000000000000000000000000006" -> "000000000000000000000000000000000000000000000000000000000000000d"
Host: get_storage
"0000000000000000000000000000000000000000000000000000000000000007" -> "0000000000000000000000000000000000000000000000000000000000000000"
Host: set_storage
"0000000000000000000000000000000000000000000000000000000000000007" -> "0000000000000000000000000000000000000000000000000000000000000015"
Host: get_storage
"0000000000000000000000000000000000000000000000000000000000000008" -> "0000000000000000000000000000000000000000000000000000000000000000"
Host: set_storage
"0000000000000000000000000000000000000000000000000000000000000008" -> "0000000000000000000000000000000000000000000000000000000000000022"
Host: get_storage
"0000000000000000000000000000000000000000000000000000000000000009" -> "0000000000000000000000000000000000000000000000000000000000000000"
Host: set_storage
"0000000000000000000000000000000000000000000000000000000000000009" -> "0000000000000000000000000000000000000000000000000000000000000037"
Dump storage:
"0000000000000000000000000000000000000000000000000000000000000000" -> "0000000000000000000000000000000000000000000000000000000000000001"
"0000000000000000000000000000000000000000000000000000000000000001" -> "0000000000000000000000000000000000000000000000000000000000000001"
"0000000000000000000000000000000000000000000000000000000000000002" -> "0000000000000000000000000000000000000000000000000000000000000002"
"0000000000000000000000000000000000000000000000000000000000000003" -> "0000000000000000000000000000000000000000000000000000000000000003"
"0000000000000000000000000000000000000000000000000000000000000004" -> "0000000000000000000000000000000000000000000000000000000000000005"
"0000000000000000000000000000000000000000000000000000000000000005" -> "0000000000000000000000000000000000000000000000000000000000000008"
"0000000000000000000000000000000000000000000000000000000000000006" -> "000000000000000000000000000000000000000000000000000000000000000d"
"0000000000000000000000000000000000000000000000000000000000000007" -> "0000000000000000000000000000000000000000000000000000000000000015"
"0000000000000000000000000000000000000000000000000000000000000008" -> "0000000000000000000000000000000000000000000000000000000000000022"
"0000000000000000000000000000000000000000000000000000000000000009" -> "0000000000000000000000000000000000000000000000000000000000000037"
Output: "0000000000000000000000000000000000000000000000000000000000000037"
GasLeft: 49800000
Status: EVMC_SUCCESS
If you want to see more runtime information inside SSVM, you can modify rust-ssvm/SSVM/lib/support/log.cpp as below.
void setErrorLoggingLevel() {
el::Loggers::addFlag(el::LoggingFlag::HierarchicalLogging);
- el::Loggers::setLoggingLevel(el::Level::Error);
+ el::Loggers::setLoggingLevel(el::Level::Debug);
}
Refer to the EWASM Test Guide for more details.
Rust SSVM has dual license, including AGPL 3.0 license and APACHE-2 license.