# Rust SSVM This project provides SSVM a Rust interface by using [EVMC](https://github.com/ethereum/evmc) (Ethereum Client-VM Connector API) to binding SSVM and host written in Rust. We extend evmc rust binding module to include [evmc-client](https://github.com/second-state/evmc/releases/tag/v6.3.1-rust-evmc-client) base on evmc version 6.3.1 for now. The software architecture of **evmc-client** was inspired by [go-ethereum](https://github.com/ethereum/go-ethereum) about how to use EVMC connect Ewasm VM ([Hera](https://github.com/ewasm/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 environment Build rust-ssvm you need prepare a build ssvm environment and include rust compile tool. - Reuse ssvm build environment docker image ```bash > docker pull secondstate/ssvm ``` - Fetch rust-ssvm source code ```bash > git clone --recursive git@github.com:second-state/rust-ssvm.git ``` - Start docker container ```bash > docker run -it \ -v $(pwd)/rust-ssvm:/root/rust-ssvm \ secondstate/ssvm:latest ``` - Install rust compile tool ```bash (docker) $ curl https://sh.rustup.rs -sSf | sh (docker) $ source ~/.cargo/env ``` - Build rust-ssvm lib ```bash (docker) $ cd ~/rust-ssvm && cargo build -v ``` ## Example 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](examples/fib.yul) written in Yul language. > [Yul](https://solidity.readthedocs.io/en/latest/yul.html) is an intermediate language designed by Ethereum fundaction. > The other project of our company call [SOLL](https://github.com/second-state/SOLL) could help you compile Yul to EWASM. [(more...)](https://github.com/second-state/SOLL/blob/master/doc/guides/DevGuide.md#compile-and-execute-yul-code) ```bash (docker) $ cd ~/rust-ssvm && cargo run --example execute_vm -v -- -f=examples/fib.wasm ``` The result should be the same as the following content. ```bash 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. ```diff void setErrorLoggingLevel() { el::Loggers::addFlag(el::LoggingFlag::HierarchicalLogging); - el::Loggers::setLoggingLevel(el::Level::Error); + el::Loggers::setLoggingLevel(el::Level::Debug); } ``` ## EWASM Test Refer to the [EWASM Test Guide](./docs/EWASM_TEST.md) for more details. ## License Rust SSVM has dual license, including [AGPL 3.0 license](LICENSE.AGPL-3.0) and [APACHE-2 license](LICENSE.APACHE-2).