// Copyright (C) 2020 Second State.
// This file is part of Rust-SSVM.
// Rust-SSVM is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
// Rust-SSVM is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
use clap::{crate_authors, crate_version, App, Arg};
use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::Read;
use rust_ssvm::create;
use rust_ssvm::host::HostContext as HostInterface;
use rust_ssvm::types::*;
struct HostContext {
storage: BTreeMap,
}
impl HostContext {
fn new() -> HostContext {
HostContext {
storage: BTreeMap::new(),
}
}
}
impl HostInterface for HostContext {
fn account_exists(&mut self, _addr: &Address) -> bool {
println!("Host: account_exists");
return true;
}
fn get_storage(&mut self, _addr: &Address, key: &Bytes32) -> Bytes32 {
println!("Host: get_storage");
let value = self.storage.get(key);
let ret: Bytes32;
match value {
Some(value) => ret = value.to_owned(),
None => ret = [0u8; BYTES32_LENGTH],
}
println!("{:?} -> {:?}", hex::encode(key), hex::encode(ret));
return ret;
}
fn set_storage(&mut self, _addr: &Address, key: &Bytes32, value: &Bytes32) -> StorageStatus {
println!("Host: set_storage");
println!("{:?} -> {:?}", hex::encode(key), hex::encode(value));
self.storage.insert(key.to_owned(), value.to_owned());
return StorageStatus::EVMC_STORAGE_MODIFIED;
}
fn get_balance(&mut self, _addr: &Address) -> Bytes32 {
println!("Host: get_balance");
return [0u8; BYTES32_LENGTH];
}
fn get_code_size(&mut self, _addr: &Address) -> usize {
println!("Host: get_code_size");
return 0;
}
fn get_code_hash(&mut self, _addr: &Address) -> Bytes32 {
println!("Host: get_code_hash");
return [0u8; BYTES32_LENGTH];
}
fn copy_code(
&mut self,
_addr: &Address,
_offset: &usize,
_buffer_data: &*mut u8,
_buffer_size: &usize,
) -> usize {
println!("Host: copy_code");
return 0;
}
fn selfdestruct(&mut self, _addr: &Address, _beneficiary: &Address) {
println!("Host: selfdestruct");
}
fn get_tx_context(&mut self) -> (Bytes32, Address, Address, i64, i64, i64, Bytes32) {
println!("Host: get_tx_context");
return (
[0u8; BYTES32_LENGTH],
[0u8; ADDRESS_LENGTH],
[0u8; ADDRESS_LENGTH],
0,
0,
0,
[0u8; BYTES32_LENGTH],
);
}
fn get_block_hash(&mut self, _number: i64) -> Bytes32 {
println!("Host: get_block_hash");
return [0u8; BYTES32_LENGTH];
}
fn emit_log(&mut self, _addr: &Address, _topics: &Vec, _data: &Bytes) {
println!("Host: emit_log");
}
fn call(
&mut self,
_kind: CallKind,
_destination: &Address,
_sender: &Address,
_value: &Bytes32,
_input: &Bytes,
_gas: i64,
_depth: i32,
_is_static: bool,
_salt: &Bytes32,
) -> (Vec, i64, Address, StatusCode) {
println!("Host: call");
return (
vec![0u8; BYTES32_LENGTH],
_gas,
[0u8; ADDRESS_LENGTH],
StatusCode::EVMC_SUCCESS,
);
}
}
impl Drop for HostContext {
fn drop(&mut self) {
println!("Dump storage:");
for (key, value) in &self.storage {
println!("{:?} -> {:?}", hex::encode(key), hex::encode(value));
}
}
}
fn read_a_file(path: &str) -> std::io::Result> {
let mut file = File::open(path)?;
let mut data = Vec::new();
file.read_to_end(&mut data)?;
return Ok(data);
}
fn main() {
let matches = App::new("Execute VM")
.version(crate_version!())
.author(crate_authors!())
.about("Demo how to execute WASM bytecode use rust-ssvm")
.arg(
Arg::with_name("file")
.short("f")
.long("file")
.takes_value(true)
.help("wasm file path"),
)
.get_matches();
let file_path = matches.value_of("file").unwrap();
// let lib_path = "Choose specific .so path";
// let (_vm, _result) = load(lib_path);
let _vm = create();
println!("Instantiate: {:?}", (_vm.get_name(), _vm.get_version()));
match read_a_file(file_path) {
Ok(code) => {
let mut host_context = HostContext::new();
let (output, gas_left, status_code) = _vm.execute(
&mut host_context,
Revision::EVMC_BYZANTIUM,
CallKind::EVMC_CALL,
false,
123,
50000000,
&[32u8; 20],
&[128u8; 20],
&[0u8; 0],
&[0u8; 32],
&code[..],
&[0u8; 32],
);
println!("Output: {:?}", hex::encode(output));
println!("GasLeft: {:?}", gas_left);
println!("Status: {:?}", status_code);
}
Err(e) => println!("Error load wasm file: {:?}, {:?}", file_path, e),
}
_vm.destroy();
}