mirror of
https://github.com/fluencelabs/marine.git
synced 2025-03-15 14:00:50 +00:00
replace old FCE with new FCE with WIT support
This commit is contained in:
parent
33aa87fa1c
commit
939c2e24c0
@ -1,59 +1,59 @@
|
|||||||
version: 2.1
|
#version: 2.1
|
||||||
jobs:
|
#jobs:
|
||||||
fce:
|
# fce:
|
||||||
docker:
|
# docker:
|
||||||
- image: circleci/rust:latest
|
# - image: circleci/rust:latest
|
||||||
environment:
|
# environment:
|
||||||
RUST_BACKTRACE: 1
|
# RUST_BACKTRACE: 1
|
||||||
#RUST_TEST_THREADS: 1
|
# #RUST_TEST_THREADS: 1
|
||||||
steps:
|
# steps:
|
||||||
- checkout
|
# - checkout
|
||||||
- restore_cache:
|
# - restore_cache:
|
||||||
keys:
|
# keys:
|
||||||
- fce01-{{ checksum "fce/Cargo.toml" }}
|
# - fce01-{{ checksum "fce/Cargo.toml" }}
|
||||||
- run: |
|
# - run: |
|
||||||
rustup toolchain install stable
|
# rustup toolchain install stable
|
||||||
rustup component add rustfmt
|
# rustup component add rustfmt
|
||||||
rustup component add clippy
|
# rustup component add clippy
|
||||||
cd fce
|
# cd fce
|
||||||
cargo fmt --all -- --check --color always
|
# cargo fmt --all -- --check --color always
|
||||||
cargo build -v --all-features
|
# cargo build -v --all-features
|
||||||
cargo test -v --all-features
|
# cargo test -v --all-features
|
||||||
cargo clippy -v
|
# cargo clippy -v
|
||||||
- save_cache:
|
# - save_cache:
|
||||||
paths:
|
# paths:
|
||||||
- ~/.cargo
|
# - ~/.cargo
|
||||||
- ~/.rustup
|
# - ~/.rustup
|
||||||
key: fce01-{{ checksum "fce/Cargo.toml" }}
|
# key: fce01-{{ checksum "fce/Cargo.toml" }}
|
||||||
wit_embedder:
|
# wit_embedder:
|
||||||
docker:
|
# docker:
|
||||||
- image: circleci/rust:latest
|
# - image: circleci/rust:latest
|
||||||
environment:
|
# environment:
|
||||||
RUST_BACKTRACE: 1
|
# RUST_BACKTRACE: 1
|
||||||
#RUST_TEST_THREADS: 1
|
# #RUST_TEST_THREADS: 1
|
||||||
steps:
|
# steps:
|
||||||
- checkout
|
# - checkout
|
||||||
- restore_cache:
|
# - restore_cache:
|
||||||
keys:
|
# keys:
|
||||||
- wit_embedder01-{{ checksum "wit_embedder/Cargo.toml" }}
|
# - wit_embedder01-{{ checksum "wit_embedder/Cargo.toml" }}
|
||||||
- run: |
|
# - run: |
|
||||||
rustup toolchain install stable
|
# rustup toolchain install stable
|
||||||
rustup component add rustfmt
|
# rustup component add rustfmt
|
||||||
rustup component add clippy
|
# rustup component add clippy
|
||||||
cd wit_embedder
|
# cd wit_embedder
|
||||||
cargo fmt --all -- --check --color always
|
# cargo fmt --all -- --check --color always
|
||||||
cargo build -v --all-features
|
# cargo build -v --all-features
|
||||||
cargo test -v --all-features
|
# cargo test -v --all-features
|
||||||
cargo clippy -v
|
# cargo clippy -v
|
||||||
- save_cache:
|
# - save_cache:
|
||||||
paths:
|
# paths:
|
||||||
- ~/.cargo
|
# - ~/.cargo
|
||||||
- ~/.rustup
|
# - ~/.rustup
|
||||||
key: wit_embedder01-{{ checksum "wit_embedder/Cargo.toml" }}
|
# key: wit_embedder01-{{ checksum "wit_embedder/Cargo.toml" }}
|
||||||
|
#
|
||||||
workflows:
|
#workflows:
|
||||||
version: 2.1
|
# version: 2.1
|
||||||
fce:
|
# fce:
|
||||||
jobs:
|
# jobs:
|
||||||
- fce
|
# - fce
|
||||||
- wit_embedder
|
# - wit_embedder
|
||||||
|
1118
Cargo.lock
generated
1118
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,10 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"fce",
|
"fce",
|
||||||
"wit_fce",
|
"tools/wit_embedder",
|
||||||
"wit_embedder",
|
"examples/export_test",
|
||||||
"wit_fce/examples/export_test",
|
"examples/ipfs_node",
|
||||||
"wit_fce/examples/ipfs_node",
|
"examples/ipfs_rpc",
|
||||||
"wit_fce/examples/ipfs_rpc",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
1975
fce/Cargo.lock
generated
1975
fce/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,36 +1,15 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "FCE"
|
name = "wit_fce"
|
||||||
description = "Fluence compute engine, virtual machine based on Wasmer for the Fluence network"
|
version = "0.2.0"
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Fluence Labs"]
|
authors = ["Fluence Labs"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "Apache-2.0"
|
|
||||||
keywords = ["fluence", "webassembly", "wasmer", "execution environment"]
|
|
||||||
categories = ["webassembly"]
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
name = "fce"
|
|
||||||
path = "src/lib.rs"
|
|
||||||
#crate-type = ["cdylib"]
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "fce_cli"
|
|
||||||
path = "src/main.rs"
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime = { git = "http://github.com/fluencelabs/wasmer", branch = "fluence" }
|
wasmer-runtime = "0.17.0"
|
||||||
wasmer-runtime-core = { git = "http://github.com/fluencelabs/wasmer", branch = "fluence" }
|
# dynamicfunc-fat-closures allows using state inside DynamicFunc
|
||||||
wasmer-wasi = { git = "http://github.com/fluencelabs/wasmer", branch = "fluence" }
|
wasmer-core = { package = "wasmer-runtime-core", version = "0.17.0", features = ["dynamicfunc-fat-closures"] }
|
||||||
failure = "0.1.7"
|
wasmer-wit = { package = "wasmer-interface-types", git = "http://github.com/fluencelabs/interface-types" }
|
||||||
lazy_static = "1.4.0"
|
wasmer-wasi = "0.17.0"
|
||||||
sha2 = "0.8.1"
|
multimap = "0.8.1"
|
||||||
rustyline = "6.1.2"
|
|
||||||
exitfailure = "0.5.1"
|
|
||||||
boolinator = "2.4.0"
|
|
||||||
parity-wasm = "0.41.0"
|
parity-wasm = "0.41.0"
|
||||||
pwasm-utils = "0.12.0"
|
pwasm-utils = "0.12.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
reqwest = "0.10.4"
|
|
||||||
bytes = "0.5.4"
|
|
||||||
tokio = { version = "0.2.20", features = ["blocking", "macros"] }
|
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#![deny(
|
|
||||||
nonstandard_style,
|
|
||||||
unused_imports,
|
|
||||||
unused_mut,
|
|
||||||
unused_variables,
|
|
||||||
unused_unsafe,
|
|
||||||
unreachable_patterns
|
|
||||||
)]
|
|
||||||
#![warn(rust_2018_idioms)]
|
|
||||||
mod misc;
|
|
||||||
mod vm;
|
|
||||||
|
|
||||||
pub use vm::config::Config;
|
|
||||||
pub use vm::fce::FCE;
|
|
||||||
pub use vm::service::FCEService;
|
|
147
fce/src/main.rs
147
fce/src/main.rs
@ -13,110 +13,65 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#![deny(
|
|
||||||
nonstandard_style,
|
|
||||||
unused_imports,
|
|
||||||
unused_mut,
|
|
||||||
unused_variables,
|
|
||||||
unused_unsafe,
|
|
||||||
unreachable_patterns
|
|
||||||
)]
|
|
||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
#![feature(get_mut_unchecked)]
|
||||||
|
#![feature(new_uninit)]
|
||||||
|
|
||||||
mod misc;
|
|
||||||
/// Command-line tool intended to test FCE VM.
|
|
||||||
mod vm;
|
mod vm;
|
||||||
|
mod misc;
|
||||||
|
|
||||||
use crate::misc::SlicePrettyPrinter;
|
use vm::IValue;
|
||||||
use crate::vm::config::Config;
|
use vm::FCE;
|
||||||
use crate::vm::fce::FCE;
|
use vm::FCEModuleConfig;
|
||||||
use crate::vm::service::FCEService;
|
use vm::FCEService;
|
||||||
|
|
||||||
use exitfailure::ExitFailure;
|
const IPFS_NODE: &str =
|
||||||
use std::fs;
|
"/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/ipfs_node_wit.wasm";
|
||||||
|
|
||||||
|
const IPFS_RPC: &str =
|
||||||
|
"/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/ipfs_rpc_wit.wasm";
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let ipfs_node_bytes = std::fs::read(IPFS_NODE).unwrap();
|
||||||
|
let ipfs_rpc_bytes = std::fs::read(IPFS_RPC).unwrap();
|
||||||
|
|
||||||
fn main() -> Result<(), ExitFailure> {
|
|
||||||
println!("Welcome to the FCE CLI:");
|
|
||||||
let mut rl = rustyline::Editor::<()>::new();
|
|
||||||
let mut fce = FCE::new();
|
let mut fce = FCE::new();
|
||||||
|
let config = FCEModuleConfig::default();
|
||||||
|
|
||||||
loop {
|
println!("loading ipfs node module");
|
||||||
let readline = rl.readline(">> ");
|
fce.register_module("node", &ipfs_node_bytes, config.clone())
|
||||||
match readline {
|
.expect("module successfully created");
|
||||||
Ok(line) => {
|
|
||||||
// TODO: improve argument parsing
|
|
||||||
let cmd: Vec<_> = line.split(' ').collect();
|
|
||||||
match cmd[0] {
|
|
||||||
"add" => {
|
|
||||||
let module_name = cmd[1].to_string();
|
|
||||||
let wasm_bytes = fs::read(cmd[2]);
|
|
||||||
if let Err(e) = wasm_bytes {
|
|
||||||
println!("failed to read wasm module: {}", e);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let config = Config::default();
|
println!("loading ipfs rpc module");
|
||||||
let result_msg =
|
fce.register_module("rpc", &ipfs_rpc_bytes, config.clone())
|
||||||
match fce.register_module(module_name, &wasm_bytes.unwrap(), config) {
|
.expect("module successfully created");
|
||||||
Ok(_) => "module successfully registered in FCE".to_string(),
|
|
||||||
Err(e) => format!("module registration failed with: {:?}", e),
|
|
||||||
};
|
|
||||||
println!("{}", result_msg);
|
|
||||||
}
|
|
||||||
"del" => {
|
|
||||||
let module_name = cmd[1];
|
|
||||||
let result_msg = match fce.unregister_module(module_name) {
|
|
||||||
Ok(_) => "module successfully deleted from FCE".to_string(),
|
|
||||||
Err(e) => format!("module deletion failed with: {:?}", e),
|
|
||||||
};
|
|
||||||
println!("{}", result_msg);
|
|
||||||
}
|
|
||||||
"execute" => {
|
|
||||||
let module_name = cmd[1];
|
|
||||||
let arg = cmd[2..].join(" ");
|
|
||||||
let result = match fce.invoke(module_name, arg.as_bytes()) {
|
|
||||||
Ok(result) => {
|
|
||||||
let outcome_copy = result.outcome.clone();
|
|
||||||
match String::from_utf8(result.outcome) {
|
|
||||||
Ok(s) => format!("result: {}", s),
|
|
||||||
Err(_) => format!("result: {:?}", outcome_copy),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => format!("execution failed with {:?}", e),
|
|
||||||
};
|
|
||||||
println!("{}", result);
|
|
||||||
}
|
|
||||||
"hash" => {
|
|
||||||
let hash = fce.compute_state_hash();
|
|
||||||
println!(
|
|
||||||
"vm state hash is {:2x}",
|
|
||||||
SlicePrettyPrinter(hash.as_slice())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
"help" => {
|
|
||||||
println!(
|
|
||||||
"Enter:\n\
|
|
||||||
add <module_name> <module_path> - to add a new Wasm module to FCE\n\
|
|
||||||
del <module_name> - to delete Wasm module to FCE\n\
|
|
||||||
execute <module_name> <arg> - to call invoke on module with module_name\n\
|
|
||||||
hash - to compute hash of internal Wasm state\n\
|
|
||||||
help - to print this message\n\
|
|
||||||
e/exit/q/quit - to exit"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
"e" | "exit" | "q" | "quit" => break,
|
|
||||||
_ => {
|
|
||||||
println!("unsupported command");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
println!("a error occurred: {}", e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
let result = fce
|
||||||
|
.call("node_rpc", "invoke", &[IValue::String("aaaa".to_string())])
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("execution result {:?}", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fn logger_log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) {
|
||||||
|
use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};
|
||||||
|
|
||||||
|
let wasm_ptr = WasmPtr::<u8, Array>::new(offset as _);
|
||||||
|
match wasm_ptr.get_utf8_string(ctx.memory(0), size as _) {
|
||||||
|
Some(msg) => print!("{}", msg),
|
||||||
|
None => print!("fce logger: incorrect UTF8 string's been supplied to logger"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn ipfs_call(ctx: &mut Ctx, ptr: i32, size: i32) {
|
||||||
|
use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};
|
||||||
|
|
||||||
|
let wasm_ptr = WasmPtr::<u8, Array>::new(ptr as _);
|
||||||
|
match wasm_ptr.get_utf8_string(ctx.memory(0), size as _) {
|
||||||
|
Some(msg) => println!("host ipfs_call: {}", msg),
|
||||||
|
None => println!("fce logger: incorrect UTF8 string's been supplied to logger"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
@ -17,35 +17,10 @@
|
|||||||
use wasmer_wasi::WasiVersion;
|
use wasmer_wasi::WasiVersion;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use wasmer_runtime::ImportObject;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone)]
|
||||||
pub struct WASIConfig {
|
pub struct FCEModuleConfig {
|
||||||
/// Desired WASI version.
|
|
||||||
pub version: WasiVersion,
|
|
||||||
|
|
||||||
/// Environment variables for loaded modules.
|
|
||||||
pub envs: Vec<Vec<u8>>,
|
|
||||||
|
|
||||||
/// List of available directories for loaded modules.
|
|
||||||
pub preopened_files: Vec<PathBuf>,
|
|
||||||
|
|
||||||
/// Mapping between paths.
|
|
||||||
pub mapped_dirs: Vec<(String, PathBuf)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for WASIConfig {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
version: WasiVersion::Latest,
|
|
||||||
envs: vec![],
|
|
||||||
preopened_files: vec![],
|
|
||||||
mapped_dirs: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct Config {
|
|
||||||
/// Maximum number of Wasm memory pages that loaded module can use.
|
/// Maximum number of Wasm memory pages that loaded module can use.
|
||||||
/// Each Wasm pages is 65536 bytes long.
|
/// Each Wasm pages is 65536 bytes long.
|
||||||
pub mem_pages_count: u32,
|
pub mem_pages_count: u32,
|
||||||
@ -54,70 +29,47 @@ pub struct Config {
|
|||||||
/// This functionality is just for debugging, and this module will be disabled in future.
|
/// This functionality is just for debugging, and this module will be disabled in future.
|
||||||
pub logger_enabled: bool,
|
pub logger_enabled: bool,
|
||||||
|
|
||||||
/// Name of the main module handler function.
|
/// Import object that will be used in module instantiation process.
|
||||||
pub invoke_fn_name: String,
|
pub import_object: ImportObject,
|
||||||
|
|
||||||
/// Name of a function that should be called for allocation memory. This function
|
/// Desired WASI version.
|
||||||
/// is used for passing array of bytes to the main module.
|
pub wasi_version: WasiVersion,
|
||||||
pub allocate_fn_name: String,
|
|
||||||
|
|
||||||
/// Name of a function that should be called for deallocation of
|
/// Environment variables for loaded modules.
|
||||||
/// previously allocated memory by allocateFunction.
|
pub wasi_envs: Vec<Vec<u8>>,
|
||||||
pub deallocate_fn_name: String,
|
|
||||||
|
|
||||||
/// Name of a functions that could be used to store one byte in current module.
|
/// List of available directories for loaded modules.
|
||||||
pub store_fn_name: String,
|
pub wasi_preopened_files: Vec<PathBuf>,
|
||||||
|
|
||||||
/// Name of a function that could be used to load one byte from current module.
|
/// Mapping between paths.
|
||||||
pub load_fn_name: String,
|
pub wasi_mapped_dirs: Vec<(String, PathBuf)>,
|
||||||
|
|
||||||
/// Config for WASI subsystem initialization. None means that module should be loaded
|
|
||||||
/// without WASI.
|
|
||||||
pub wasi_config: WASIConfig,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for FCEModuleConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
// some reasonable defaults
|
// some reasonable defaults
|
||||||
Self {
|
Self {
|
||||||
// 65536*1600 ~ 100 Mb
|
// 65536*1600 ~ 100 Mb
|
||||||
mem_pages_count: 1600,
|
mem_pages_count: 1600,
|
||||||
invoke_fn_name: "invoke".to_string(),
|
|
||||||
allocate_fn_name: "allocate".to_string(),
|
|
||||||
deallocate_fn_name: "deallocate".to_string(),
|
|
||||||
store_fn_name: "store".to_string(),
|
|
||||||
load_fn_name: "load".to_string(),
|
|
||||||
logger_enabled: true,
|
logger_enabled: true,
|
||||||
wasi_config: WASIConfig::default(),
|
import_object: ImportObject::new(),
|
||||||
|
wasi_version: WasiVersion::Latest,
|
||||||
|
wasi_envs: vec![],
|
||||||
|
wasi_preopened_files: vec![],
|
||||||
|
wasi_mapped_dirs: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
// TODO: implement debug for FCEModuleConfig
|
||||||
|
|
||||||
|
impl FCEModuleConfig {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn with_mem_pages_count(mut self, mem_pages_count: u32) -> Self {
|
pub fn with_mem_pages_count(mut self, mem_pages_count: u32) -> Self {
|
||||||
self.mem_pages_count = mem_pages_count;
|
self.mem_pages_count = mem_pages_count;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn with_invoke_fn_name(mut self, invoke_fn_name: String) -> Self {
|
|
||||||
self.invoke_fn_name = invoke_fn_name;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn with_allocate_fn_name(mut self, allocate_fn_name: String) -> Self {
|
|
||||||
self.allocate_fn_name = allocate_fn_name;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn with_deallocate_fn_name(mut self, deallocate_fn_name: String) -> Self {
|
|
||||||
self.deallocate_fn_name = deallocate_fn_name;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn with_logger_enable(mut self, logger_enable: bool) -> Self {
|
pub fn with_logger_enable(mut self, logger_enable: bool) -> Self {
|
||||||
self.logger_enabled = logger_enable;
|
self.logger_enabled = logger_enable;
|
||||||
@ -126,25 +78,25 @@ impl Config {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn with_wasi_version(mut self, wasi_version: WasiVersion) -> Self {
|
pub fn with_wasi_version(mut self, wasi_version: WasiVersion) -> Self {
|
||||||
self.wasi_config.version = wasi_version;
|
self.wasi_version = wasi_version;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn with_wasi_envs(mut self, envs: Vec<Vec<u8>>) -> Self {
|
pub fn with_wasi_envs(mut self, envs: Vec<Vec<u8>>) -> Self {
|
||||||
self.wasi_config.envs = envs;
|
self.wasi_envs = envs;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn with_wasi_preopened_files(mut self, preopened_files: Vec<PathBuf>) -> Self {
|
pub fn with_wasi_preopened_files(mut self, preopened_files: Vec<PathBuf>) -> Self {
|
||||||
self.wasi_config.preopened_files = preopened_files;
|
self.wasi_preopened_files = preopened_files;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn with_wasi_mapped_dirs(mut self, mapped_dirs: Vec<(String, PathBuf)>) -> Self {
|
pub fn with_wasi_mapped_dirs(mut self, mapped_dirs: Vec<(String, PathBuf)>) -> Self {
|
||||||
self.wasi_config.mapped_dirs = mapped_dirs;
|
self.wasi_mapped_dirs = mapped_dirs;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use wasmer_wit::errors::InstructionError;
|
||||||
use wasmer_runtime::error::{
|
use wasmer_runtime::error::{
|
||||||
CallError, CompileError, CreationError, Error as WasmerError, ResolveError, RuntimeError,
|
CallError, CompileError, CreationError, Error as WasmerError, ResolveError, RuntimeError,
|
||||||
};
|
};
|
||||||
@ -22,9 +23,6 @@ use std::error::Error;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FCEError {
|
pub enum FCEError {
|
||||||
/// Errors for I/O errors raising while opening a file.
|
|
||||||
IOError(String),
|
|
||||||
|
|
||||||
/// This error type is produced by Wasmer during resolving a Wasm function.
|
/// This error type is produced by Wasmer during resolving a Wasm function.
|
||||||
WasmerResolveError(String),
|
WasmerResolveError(String),
|
||||||
|
|
||||||
@ -43,11 +41,23 @@ pub enum FCEError {
|
|||||||
/// Indicates that there is already a module with such name.
|
/// Indicates that there is already a module with such name.
|
||||||
NonUniqueModuleName,
|
NonUniqueModuleName,
|
||||||
|
|
||||||
/// Returns where there is no module with such name.
|
/// Returns when there is no module with such name.
|
||||||
|
NoSuchFunction(String),
|
||||||
|
|
||||||
|
/// Returns when there is no module with such name.
|
||||||
NoSuchModule,
|
NoSuchModule,
|
||||||
|
|
||||||
/// Indicates that modules currently in use and couldn't be deleted.
|
/// WIT section is absent.
|
||||||
ModuleInUse,
|
NoWITSection,
|
||||||
|
|
||||||
|
/// Multiple WIT sections.
|
||||||
|
MultipleWITSections,
|
||||||
|
|
||||||
|
/// WIT section remainder isn't empty.
|
||||||
|
WITRemainderNotEmpty,
|
||||||
|
|
||||||
|
/// An error occurred while parsing WIT section.
|
||||||
|
WITParseError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for FCEError {}
|
impl Error for FCEError {}
|
||||||
@ -55,7 +65,6 @@ impl Error for FCEError {}
|
|||||||
impl std::fmt::Display for FCEError {
|
impl std::fmt::Display for FCEError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||||
match self {
|
match self {
|
||||||
FCEError::IOError(msg) => write!(f, "IOError: {}", msg),
|
|
||||||
FCEError::WasmerResolveError(msg) => write!(f, "WasmerResolveError: {}", msg),
|
FCEError::WasmerResolveError(msg) => write!(f, "WasmerResolveError: {}", msg),
|
||||||
FCEError::WasmerInvokeError(msg) => write!(f, "WasmerInvokeError: {}", msg),
|
FCEError::WasmerInvokeError(msg) => write!(f, "WasmerInvokeError: {}", msg),
|
||||||
FCEError::WasmerCompileError(msg) => write!(f, "WasmerCompileError: {}", msg),
|
FCEError::WasmerCompileError(msg) => write!(f, "WasmerCompileError: {}", msg),
|
||||||
@ -63,11 +72,24 @@ impl std::fmt::Display for FCEError {
|
|||||||
FCEError::PrepareError(msg) => {
|
FCEError::PrepareError(msg) => {
|
||||||
write!(f, "Prepare error: {}, probably module is mailformed", msg)
|
write!(f, "Prepare error: {}, probably module is mailformed", msg)
|
||||||
}
|
}
|
||||||
FCEError::NonUniqueModuleName => write!(f, "FCE already has module with such name"),
|
FCEError::NonUniqueModuleName => write!(f, "FCE already has module with such a name"),
|
||||||
FCEError::NoSuchModule => write!(f, "FCE doesn't have a module with such name"),
|
FCEError::NoSuchFunction(msg) => {
|
||||||
FCEError::ModuleInUse => {
|
write!(f, "FCE doesn't have a function with such a name: {}", msg)
|
||||||
write!(f, "Module is used by other modules and couldn't be deleted")
|
|
||||||
}
|
}
|
||||||
|
FCEError::NoSuchModule => write!(f, "FCE doesn't have a module with such a name"),
|
||||||
|
FCEError::NoWITSection => write!(
|
||||||
|
f,
|
||||||
|
"Loaded module doesn't contain WIT section that is neccessary for instantiation"
|
||||||
|
),
|
||||||
|
FCEError::MultipleWITSections => write!(
|
||||||
|
f,
|
||||||
|
"Loaded module contains multiple WIT sections that is unsupported now"
|
||||||
|
),
|
||||||
|
FCEError::WITRemainderNotEmpty => write!(
|
||||||
|
f,
|
||||||
|
"WIT section remainder isn't empty - WIT section possibly corrupted"
|
||||||
|
),
|
||||||
|
FCEError::WITParseError => write!(f, "WIT section is corrupted"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,8 +139,8 @@ impl From<WasmerError> for FCEError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<std::io::Error> for FCEError {
|
impl From<InstructionError> for FCEError {
|
||||||
fn from(err: std::io::Error) -> Self {
|
fn from(err: InstructionError) -> Self {
|
||||||
FCEError::IOError(format!("{}", err))
|
FCEError::WasmerInvokeError(format!("{}", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,76 +14,24 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::vm::module::fce_result::FCEResult;
|
use super::instance::FCEModule;
|
||||||
use crate::vm::module::{FCEModule, ModuleAPI};
|
use super::*;
|
||||||
use crate::vm::{config::Config, errors::FCEError, service::FCEService};
|
|
||||||
|
|
||||||
use sha2::{digest::generic_array::GenericArray, digest::FixedOutput};
|
use std::sync::Arc;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use wasmer_runtime::func;
|
|
||||||
use wasmer_runtime_core::import::{ImportObject, Namespace};
|
|
||||||
|
|
||||||
pub struct FCE {
|
pub struct FCE {
|
||||||
// set of modules registered inside FCE
|
// set of modules registered inside FCE
|
||||||
modules: HashMap<String, FCEModule>,
|
modules: HashMap<String, Arc<FCEModule>>,
|
||||||
|
|
||||||
// contains ABI of each registered module in specific format for Wasmer
|
|
||||||
abi_import_object: ImportObject,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FCE {
|
impl FCE {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
modules: HashMap::new(),
|
modules: HashMap::new(),
|
||||||
abi_import_object: ImportObject::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts ABI of a module into Namespace.
|
|
||||||
fn create_namespace_from_module(module: &FCEModule, config: &Config) -> Namespace {
|
|
||||||
let mut namespace = Namespace::new();
|
|
||||||
let module_abi = module.get_abi().clone();
|
|
||||||
|
|
||||||
// TODO: introduce a macro for such things
|
|
||||||
let allocate = module_abi.allocate;
|
|
||||||
namespace.insert(
|
|
||||||
config.allocate_fn_name.clone(),
|
|
||||||
func!(move |size: i32| -> i32 { allocate.call(size).expect("allocate failed") }),
|
|
||||||
);
|
|
||||||
|
|
||||||
let invoke = module_abi.invoke;
|
|
||||||
namespace.insert(
|
|
||||||
config.invoke_fn_name.clone(),
|
|
||||||
func!(move |offset: i32, size: i32| -> i32 {
|
|
||||||
invoke.call(offset, size).expect("invoke failed")
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let deallocate = module_abi.deallocate;
|
|
||||||
namespace.insert(
|
|
||||||
config.deallocate_fn_name.clone(),
|
|
||||||
func!(move |ptr: i32, size: i32| {
|
|
||||||
deallocate.call(ptr, size).expect("deallocate failed");
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let store = module_abi.store;
|
|
||||||
namespace.insert(
|
|
||||||
config.store_fn_name.clone(),
|
|
||||||
func!(move |offset: i32, value: i32| {
|
|
||||||
store.call(offset, value).expect("store failed")
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let load = module_abi.load;
|
|
||||||
namespace.insert(
|
|
||||||
config.load_fn_name.clone(),
|
|
||||||
func!(move |offset: i32| -> i32 { load.call(offset).expect("load failed") }),
|
|
||||||
);
|
|
||||||
|
|
||||||
namespace
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FCE {
|
impl Default for FCE {
|
||||||
@ -93,9 +41,17 @@ impl Default for FCE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FCEService for FCE {
|
impl FCEService for FCE {
|
||||||
fn invoke(&mut self, module_name: &str, argument: &[u8]) -> Result<FCEResult, FCEError> {
|
fn call(
|
||||||
|
&mut self,
|
||||||
|
module_name: &str,
|
||||||
|
func_name: &str,
|
||||||
|
argument: &[IValue],
|
||||||
|
) -> Result<Vec<IValue>, FCEError> {
|
||||||
match self.modules.get_mut(module_name) {
|
match self.modules.get_mut(module_name) {
|
||||||
Some(module) => module.invoke(argument),
|
// TODO: refactor errors
|
||||||
|
Some(mut module) => unsafe {
|
||||||
|
Ok(Arc::get_mut_unchecked(&mut module).call(func_name, argument)?)
|
||||||
|
},
|
||||||
None => Err(FCEError::NoSuchModule),
|
None => Err(FCEError::NoSuchModule),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,29 +60,19 @@ impl FCEService for FCE {
|
|||||||
&mut self,
|
&mut self,
|
||||||
module_name: S,
|
module_name: S,
|
||||||
wasm_bytes: &[u8],
|
wasm_bytes: &[u8],
|
||||||
config: Config,
|
config: FCEModuleConfig,
|
||||||
) -> Result<(), FCEError>
|
) -> Result<(), FCEError>
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
{
|
{
|
||||||
let prepared_wasm_bytes =
|
let _prepared_wasm_bytes =
|
||||||
crate::vm::prepare::prepare_module(wasm_bytes, config.mem_pages_count)?;
|
super::prepare::prepare_module(wasm_bytes, config.mem_pages_count)?;
|
||||||
|
|
||||||
let module = FCEModule::new(
|
let module = FCEModule::new(&wasm_bytes, config.import_object, &self.modules)?;
|
||||||
&prepared_wasm_bytes,
|
|
||||||
config.clone(),
|
|
||||||
self.abi_import_object.clone(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// registers ABI of newly registered module in abi_import_object
|
match self.modules.entry(module_name.into()) {
|
||||||
let namespace = FCE::create_namespace_from_module(&module, &config);
|
|
||||||
let module_name: String = module_name.into();
|
|
||||||
self.abi_import_object
|
|
||||||
.register(module_name.clone(), namespace);
|
|
||||||
|
|
||||||
match self.modules.entry(module_name) {
|
|
||||||
Entry::Vacant(entry) => {
|
Entry::Vacant(entry) => {
|
||||||
entry.insert(module);
|
entry.insert(Arc::new(module));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Entry::Occupied(_) => Err(FCEError::NonUniqueModuleName),
|
Entry::Occupied(_) => Err(FCEError::NonUniqueModuleName),
|
||||||
@ -143,21 +89,4 @@ impl FCEService for FCE {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_state_hash(
|
|
||||||
&mut self,
|
|
||||||
) -> GenericArray<u8, <sha2::Sha256 as FixedOutput>::OutputSize> {
|
|
||||||
use sha2::Digest;
|
|
||||||
|
|
||||||
let mut hasher = sha2::Sha256::new();
|
|
||||||
|
|
||||||
let sha256_size = 256;
|
|
||||||
let mut hash_vec: Vec<u8> = Vec::with_capacity(self.modules.len() * sha256_size);
|
|
||||||
for (_, module) in self.modules.iter_mut() {
|
|
||||||
hash_vec.extend_from_slice(module.compute_state_hash().as_slice());
|
|
||||||
}
|
|
||||||
|
|
||||||
hasher.input(hash_vec);
|
|
||||||
hasher.result()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,15 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub mod config;
|
mod fce;
|
||||||
pub mod errors;
|
mod instance;
|
||||||
pub mod fce;
|
mod fce_service;
|
||||||
pub mod service;
|
mod config;
|
||||||
|
|
||||||
mod module;
|
|
||||||
mod prepare;
|
mod prepare;
|
||||||
|
mod errors;
|
||||||
|
|
||||||
|
pub use fce::FCE;
|
||||||
|
pub use fce_service::FCEService;
|
||||||
|
pub use config::FCEModuleConfig;
|
||||||
|
pub use errors::FCEError;
|
||||||
|
pub use instance::{IType, IValue};
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use crate::vm::errors::FCEError;
|
|
||||||
|
|
||||||
/// Application binary interface of a FCE module. Different module could use such scheme for
|
|
||||||
/// communicate with each other.
|
|
||||||
///
|
|
||||||
/// Given char string req as a request, the general scheme to use this ABI by other module
|
|
||||||
/// is following:
|
|
||||||
///
|
|
||||||
/// 1. ptr = allocate(strlen(req)) that returns a pointer to the memory region enough for req
|
|
||||||
/// 2. writes req to the module memory byte-by-byte with store
|
|
||||||
/// 3. res = invoke(ptr, strlen(sql)) to execute the request
|
|
||||||
/// 4. read a result from the res by reading 4 bytes as little-endian result_size
|
|
||||||
/// and the read result_size bytes as the final result.
|
|
||||||
/// 5. deallocate(res, strlen(sql)) to clean memory.
|
|
||||||
pub(crate) trait ModuleABI {
|
|
||||||
/// Allocates a region of memory inside a module. Used for passing argument inside the module.
|
|
||||||
fn allocate(&mut self, size: i32) -> Result<i32, FCEError>;
|
|
||||||
|
|
||||||
/// Deallocates previously allocated memory region.
|
|
||||||
fn deallocate(&mut self, ptr: i32, size: i32) -> Result<(), FCEError>;
|
|
||||||
|
|
||||||
/// Calls the main entry point of a module called invoke.
|
|
||||||
fn invoke(&mut self, arg_address: i32, arg_size: i32) -> Result<i32, FCEError>;
|
|
||||||
|
|
||||||
/// Stores one byte on given address.
|
|
||||||
fn store(&mut self, address: i32, value: i32) -> Result<(), FCEError>;
|
|
||||||
|
|
||||||
/// Loads one byte from given address.
|
|
||||||
fn load(&mut self, address: i32) -> Result<i32, FCEError>;
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use crate::vm::errors::FCEError;
|
|
||||||
use crate::vm::module::fce_result::FCEResult;
|
|
||||||
|
|
||||||
use sha2::digest::generic_array::GenericArray;
|
|
||||||
use sha2::digest::FixedOutput;
|
|
||||||
|
|
||||||
/// Application interface of a FCE module. Intended to use by FCE vm.instance itself.
|
|
||||||
pub(crate) trait ModuleAPI {
|
|
||||||
/// Invokes a module supplying byte array and expecting byte array with some outcome back.
|
|
||||||
fn invoke(&mut self, argument: &[u8]) -> Result<FCEResult, FCEError>;
|
|
||||||
|
|
||||||
/// Computes hash of the internal modules state.
|
|
||||||
fn compute_state_hash(&mut self)
|
|
||||||
-> GenericArray<u8, <sha2::Sha256 as FixedOutput>::OutputSize>;
|
|
||||||
}
|
|
@ -1,220 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use crate::vm::config::Config;
|
|
||||||
use crate::vm::errors::FCEError;
|
|
||||||
use crate::vm::module::fce_result::FCEResult;
|
|
||||||
use crate::vm::module::{ModuleABI, ModuleAPI};
|
|
||||||
|
|
||||||
use sha2::digest::generic_array::GenericArray;
|
|
||||||
use sha2::digest::FixedOutput;
|
|
||||||
use wasmer_runtime::{compile, func, imports, Ctx, Func, Instance};
|
|
||||||
use wasmer_runtime_core::import::ImportObject;
|
|
||||||
use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};
|
|
||||||
use wasmer_wasi::generate_import_object_for_version;
|
|
||||||
|
|
||||||
/// Describes Application Binary Interface of a module.
|
|
||||||
/// For more details see comment in abi.rs.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub(crate) struct ABI {
|
|
||||||
// It is safe to use unwrap() while calling these functions because Option is used here
|
|
||||||
// just to allow partially initialization. And all Option fields will contain Some if
|
|
||||||
// invoking FCE::new has been succeed.
|
|
||||||
pub(crate) allocate: Func<'static, i32, i32>,
|
|
||||||
pub(crate) deallocate: Func<'static, (i32, i32), ()>,
|
|
||||||
pub(crate) invoke: Func<'static, (i32, i32), i32>,
|
|
||||||
pub(crate) store: Func<'static, (i32, i32)>,
|
|
||||||
pub(crate) load: Func<'static, i32, i32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A building block of multi-modules scheme of FCE, represents one module that corresponds
|
|
||||||
/// to a one Wasm file.
|
|
||||||
pub(crate) struct FCEModule {
|
|
||||||
instance: Instance,
|
|
||||||
abi: ABI,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FCEModule {
|
|
||||||
/// Creates a new virtual machine executor.
|
|
||||||
pub fn new(wasm_bytes: &[u8], config: Config, imports: ImportObject) -> Result<Self, FCEError> {
|
|
||||||
let logger_imports = imports! {
|
|
||||||
"logger" => {
|
|
||||||
"log_utf8_string" => func!(FCEModule::logger_log_utf8_string),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let config_copy = config.clone();
|
|
||||||
|
|
||||||
let mut import_object = generate_import_object_for_version(
|
|
||||||
config.wasi_config.version,
|
|
||||||
vec![],
|
|
||||||
config.wasi_config.envs,
|
|
||||||
config.wasi_config.preopened_files,
|
|
||||||
config.wasi_config.mapped_dirs,
|
|
||||||
);
|
|
||||||
import_object.extend(logger_imports);
|
|
||||||
import_object.extend(imports);
|
|
||||||
import_object.allow_missing_functions = false;
|
|
||||||
|
|
||||||
let instance = compile(&wasm_bytes)?.instantiate(&import_object)?;
|
|
||||||
let abi = FCEModule::create_abi(&instance, &config_copy)?;
|
|
||||||
|
|
||||||
Ok(Self { instance, abi })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
/// Extracts ABI from a module.
|
|
||||||
fn create_abi(instance: &Instance, config: &Config) -> Result<ABI, FCEError> {
|
|
||||||
unsafe {
|
|
||||||
let allocate = std::mem::transmute::<Func<'_, i32, i32>, Func<'static, _, _>>(
|
|
||||||
instance.exports.get(&config.allocate_fn_name)?
|
|
||||||
);
|
|
||||||
|
|
||||||
let deallocate = std::mem::transmute::<Func<'_, (i32, i32)>, Func<'static, _, _>>(
|
|
||||||
instance.exports.get(&config.deallocate_fn_name)?
|
|
||||||
);
|
|
||||||
|
|
||||||
let invoke = std::mem::transmute::<Func<'_, (i32, i32), i32>, Func<'static, _, _>, >(
|
|
||||||
instance.exports.get(&config.invoke_fn_name)?
|
|
||||||
);
|
|
||||||
|
|
||||||
let store = std::mem::transmute::<Func<'_, (i32, i32)>, Func<'static, _, _>>(
|
|
||||||
instance.exports.get(&config.store_fn_name)?,
|
|
||||||
);
|
|
||||||
|
|
||||||
let load = std::mem::transmute::<Func<'_, i32, i32>, Func<'static, _, _>>(
|
|
||||||
instance.exports.get(&config.load_fn_name)?,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(ABI {
|
|
||||||
allocate,
|
|
||||||
deallocate,
|
|
||||||
invoke,
|
|
||||||
store,
|
|
||||||
load,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns ABI of a module.
|
|
||||||
/// (!) Be carefull and delete all instances of ABI before dropping corresponding module.
|
|
||||||
/// There is no any internal ref counter due to the internals of Wasmer.
|
|
||||||
pub fn get_abi(&self) -> &ABI {
|
|
||||||
&self.abi
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prints utf8 string of the given size from the given offset. Called from the wasm.
|
|
||||||
fn logger_log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) {
|
|
||||||
let wasm_ptr = WasmPtr::<u8, Array>::new(offset as _);
|
|
||||||
match wasm_ptr.get_utf8_string(ctx.memory(0), size as _) {
|
|
||||||
Some(msg) => print!("{}", msg),
|
|
||||||
None => print!("fce logger: incorrect UTF8 string's been supplied to logger"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes given value on the given address to module memory.
|
|
||||||
fn write_to_mem(&mut self, address: usize, value: &[u8]) -> Result<(), FCEError> {
|
|
||||||
let memory = self.instance.context().memory(0);
|
|
||||||
|
|
||||||
for (byte_id, cell) in memory.view::<u8>()[address..(address + value.len())]
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
cell.set(value[byte_id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reads invocation result from specified address of memory.
|
|
||||||
fn read_result_from_mem(&self, address: usize) -> Result<Vec<u8>, FCEError> {
|
|
||||||
let memory = self.instance.context().memory(0);
|
|
||||||
|
|
||||||
let mut result_size: usize = 0;
|
|
||||||
|
|
||||||
for (byte_id, cell) in memory.view::<u8>()[address..address + 4].iter().enumerate() {
|
|
||||||
result_size |= (cell.get() as usize) << (8 * byte_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut result = Vec::<u8>::with_capacity(result_size);
|
|
||||||
for cell in memory.view()[(address + 4) as usize..(address + result_size + 4)].iter() {
|
|
||||||
result.push(cell.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModuleAPI for FCEModule {
|
|
||||||
fn invoke(&mut self, argument: &[u8]) -> Result<FCEResult, FCEError> {
|
|
||||||
let argument_len = argument.len() as i32;
|
|
||||||
|
|
||||||
// allocate memory for the given argument and write it to memory
|
|
||||||
let argument_address = if argument_len != 0 {
|
|
||||||
let address = self.allocate(argument_len)?;
|
|
||||||
self.write_to_mem(address as usize, argument)?;
|
|
||||||
address
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
// invoke a main module, read a result and deallocate it
|
|
||||||
let result_address = <Self as ModuleABI>::invoke(self, argument_address, argument_len)?;
|
|
||||||
let result = self.read_result_from_mem(result_address as _)?;
|
|
||||||
self.deallocate(result_address, result.len() as i32)?;
|
|
||||||
|
|
||||||
Ok(FCEResult::new(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_state_hash(
|
|
||||||
&mut self,
|
|
||||||
) -> GenericArray<u8, <sha2::Sha256 as FixedOutput>::OutputSize> {
|
|
||||||
use sha2::Digest;
|
|
||||||
|
|
||||||
let mut hasher = sha2::Sha256::new();
|
|
||||||
let memory = self.instance.context().memory(0);
|
|
||||||
|
|
||||||
let wasm_ptr = WasmPtr::<u8, Array>::new(0 as _);
|
|
||||||
let raw_mem = wasm_ptr
|
|
||||||
.deref(memory, 0, (memory.size().bytes().0 - 1) as _)
|
|
||||||
.expect("fce: internal error in compute_vm_state_hash");
|
|
||||||
let raw_mem: &[u8] = unsafe { &*(raw_mem as *const [std::cell::Cell<u8>] as *const [u8]) };
|
|
||||||
|
|
||||||
hasher.input(raw_mem);
|
|
||||||
hasher.result()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModuleABI for FCEModule {
|
|
||||||
fn allocate(&mut self, size: i32) -> Result<i32, FCEError> {
|
|
||||||
Ok(self.abi.allocate.call(size)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deallocate(&mut self, ptr: i32, size: i32) -> Result<(), FCEError> {
|
|
||||||
Ok(self.abi.deallocate.call(ptr, size)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invoke(&mut self, arg_address: i32, arg_size: i32) -> Result<i32, FCEError> {
|
|
||||||
Ok(self.abi.invoke.call(arg_address, arg_size)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn store(&mut self, address: i32, value: i32) -> Result<(), FCEError> {
|
|
||||||
Ok(self.abi.store.call(address, value)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load(&mut self, address: i32) -> Result<i32, FCEError> {
|
|
||||||
Ok(self.abi.load.call(address)?)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Default)]
|
|
||||||
pub struct FCEResult {
|
|
||||||
pub outcome: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FCEResult {
|
|
||||||
pub fn new(outcome: Vec<u8>) -> Self {
|
|
||||||
Self { outcome }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
mod abi;
|
|
||||||
mod api;
|
|
||||||
mod fce_module;
|
|
||||||
pub mod fce_result;
|
|
||||||
|
|
||||||
pub(crate) use abi::ModuleABI;
|
|
||||||
pub(crate) use api::ModuleAPI;
|
|
||||||
pub(crate) use fce_module::FCEModule;
|
|
@ -18,7 +18,7 @@
|
|||||||
// https://github.com/paritytech/substrate/blob/master/srml/contracts/src/wasm/prepare.rs
|
// https://github.com/paritytech/substrate/blob/master/srml/contracts/src/wasm/prepare.rs
|
||||||
// https://github.com/nearprotocol/nearcore/blob/master/runtime/near-vm-runner/src/prepare.rs
|
// https://github.com/nearprotocol/nearcore/blob/master/runtime/near-vm-runner/src/prepare.rs
|
||||||
|
|
||||||
use crate::vm::errors::FCEError;
|
use super::errors::FCEError;
|
||||||
|
|
||||||
use parity_wasm::{
|
use parity_wasm::{
|
||||||
builder, elements,
|
builder, elements,
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use crate::vm::config::Config;
|
|
||||||
use crate::vm::errors::FCEError;
|
|
||||||
use crate::vm::module::fce_result::FCEResult;
|
|
||||||
|
|
||||||
use sha2::digest::generic_array::GenericArray;
|
|
||||||
|
|
||||||
/// Describes a service behaviour in the Fluence network.
|
|
||||||
pub trait FCEService {
|
|
||||||
/// Invokes a module supplying byte array and expecting byte array with some outcome back.
|
|
||||||
fn invoke(&mut self, module_name: &str, argument: &[u8]) -> Result<FCEResult, FCEError>;
|
|
||||||
|
|
||||||
/// Registers new module in the FCE Service.
|
|
||||||
fn register_module<S>(
|
|
||||||
&mut self,
|
|
||||||
module_name: S,
|
|
||||||
wasm_bytes: &[u8],
|
|
||||||
config: Config,
|
|
||||||
) -> Result<(), FCEError>
|
|
||||||
where
|
|
||||||
S: Into<String>;
|
|
||||||
|
|
||||||
/// Unregisters previously registered module.
|
|
||||||
fn unregister_module(&mut self, module_name: &str) -> Result<(), FCEError>;
|
|
||||||
|
|
||||||
/// Computes hash of the internal modules state.
|
|
||||||
fn compute_state_hash(
|
|
||||||
&mut self,
|
|
||||||
) -> GenericArray<u8, <sha2::Sha256 as sha2::digest::FixedOutput>::OutputSize>;
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "wit_fce"
|
|
||||||
version = "0.2.0"
|
|
||||||
authors = ["Fluence Labs"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
wasmer-runtime = "0.17.0"
|
|
||||||
# dynamicfunc-fat-closures allows using state inside DynamicFunc
|
|
||||||
wasmer-core = { package = "wasmer-runtime-core", version = "0.17.0", features = ["dynamicfunc-fat-closures"] }
|
|
||||||
wasmer-wit = { package = "wasmer-interface-types", git = "http://github.com/fluencelabs/interface-types" }
|
|
||||||
wasmer-wasi = "0.17.0"
|
|
||||||
multimap = "0.8.1"
|
|
||||||
parity-wasm = "0.41.0"
|
|
||||||
pwasm-utils = "0.12.0"
|
|
@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
#![warn(rust_2018_idioms)]
|
|
||||||
#![feature(get_mut_unchecked)]
|
|
||||||
#![feature(new_uninit)]
|
|
||||||
|
|
||||||
mod vm;
|
|
||||||
mod misc;
|
|
||||||
|
|
||||||
use vm::IValue;
|
|
||||||
use vm::FCE;
|
|
||||||
use vm::FCEModuleConfig;
|
|
||||||
use vm::FCEService;
|
|
||||||
|
|
||||||
const IPFS_NODE: &str =
|
|
||||||
"/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/ipfs_node_wit.wasm";
|
|
||||||
|
|
||||||
const IPFS_RPC: &str =
|
|
||||||
"/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/ipfs_rpc_wit.wasm";
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let ipfs_node_bytes = std::fs::read(IPFS_NODE).unwrap();
|
|
||||||
let ipfs_rpc_bytes = std::fs::read(IPFS_RPC).unwrap();
|
|
||||||
|
|
||||||
let mut fce = FCE::new();
|
|
||||||
let config = FCEModuleConfig::default();
|
|
||||||
|
|
||||||
println!("loading ipfs node module");
|
|
||||||
fce.register_module("node", &ipfs_node_bytes, config.clone())
|
|
||||||
.expect("module successfully created");
|
|
||||||
|
|
||||||
println!("loading ipfs rpc module");
|
|
||||||
fce.register_module("rpc", &ipfs_rpc_bytes, config.clone())
|
|
||||||
.expect("module successfully created");
|
|
||||||
|
|
||||||
let result = fce
|
|
||||||
.call("node_rpc", "invoke", &[IValue::String("aaaa".to_string())])
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
println!("execution result {:?}", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
fn logger_log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) {
|
|
||||||
use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};
|
|
||||||
|
|
||||||
let wasm_ptr = WasmPtr::<u8, Array>::new(offset as _);
|
|
||||||
match wasm_ptr.get_utf8_string(ctx.memory(0), size as _) {
|
|
||||||
Some(msg) => print!("{}", msg),
|
|
||||||
None => print!("fce logger: incorrect UTF8 string's been supplied to logger"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn ipfs_call(ctx: &mut Ctx, ptr: i32, size: i32) {
|
|
||||||
use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};
|
|
||||||
|
|
||||||
let wasm_ptr = WasmPtr::<u8, Array>::new(ptr as _);
|
|
||||||
match wasm_ptr.get_utf8_string(ctx.memory(0), size as _) {
|
|
||||||
Some(msg) => println!("host ipfs_call: {}", msg),
|
|
||||||
None => println!("fce logger: incorrect UTF8 string's been supplied to logger"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
mod slice_pretty_printer;
|
|
||||||
|
|
||||||
pub use slice_pretty_printer::SlicePrettyPrinter;
|
|
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub struct SlicePrettyPrinter<'a>(pub &'a [u8]);
|
|
||||||
|
|
||||||
impl<'a> std::fmt::LowerHex for SlicePrettyPrinter<'a> {
|
|
||||||
fn fmt(&self, fmtr: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
|
||||||
fmtr.write_fmt(format_args!("0x"))?;
|
|
||||||
for byte in self.0 {
|
|
||||||
fmtr.write_fmt(format_args!("{:02x}", byte))?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> std::fmt::UpperHex for SlicePrettyPrinter<'a> {
|
|
||||||
fn fmt(&self, fmtr: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
|
||||||
fmtr.write_fmt(format_args!("0x"))?;
|
|
||||||
for byte in self.0 {
|
|
||||||
fmtr.write_fmt(format_args!("{:02X}", byte))?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,102 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use wasmer_wasi::WasiVersion;
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use wasmer_runtime::ImportObject;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct FCEModuleConfig {
|
|
||||||
/// Maximum number of Wasm memory pages that loaded module can use.
|
|
||||||
/// Each Wasm pages is 65536 bytes long.
|
|
||||||
pub mem_pages_count: u32,
|
|
||||||
|
|
||||||
/// If true, registers the logger Wasm module with name 'logger'.
|
|
||||||
/// This functionality is just for debugging, and this module will be disabled in future.
|
|
||||||
pub logger_enabled: bool,
|
|
||||||
|
|
||||||
/// Import object that will be used in module instantiation process.
|
|
||||||
pub import_object: ImportObject,
|
|
||||||
|
|
||||||
/// Desired WASI version.
|
|
||||||
pub wasi_version: WasiVersion,
|
|
||||||
|
|
||||||
/// Environment variables for loaded modules.
|
|
||||||
pub wasi_envs: Vec<Vec<u8>>,
|
|
||||||
|
|
||||||
/// List of available directories for loaded modules.
|
|
||||||
pub wasi_preopened_files: Vec<PathBuf>,
|
|
||||||
|
|
||||||
/// Mapping between paths.
|
|
||||||
pub wasi_mapped_dirs: Vec<(String, PathBuf)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for FCEModuleConfig {
|
|
||||||
fn default() -> Self {
|
|
||||||
// some reasonable defaults
|
|
||||||
Self {
|
|
||||||
// 65536*1600 ~ 100 Mb
|
|
||||||
mem_pages_count: 1600,
|
|
||||||
logger_enabled: true,
|
|
||||||
import_object: ImportObject::new(),
|
|
||||||
wasi_version: WasiVersion::Latest,
|
|
||||||
wasi_envs: vec![],
|
|
||||||
wasi_preopened_files: vec![],
|
|
||||||
wasi_mapped_dirs: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement debug for FCEModuleConfig
|
|
||||||
|
|
||||||
impl FCEModuleConfig {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn with_mem_pages_count(mut self, mem_pages_count: u32) -> Self {
|
|
||||||
self.mem_pages_count = mem_pages_count;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn with_logger_enable(mut self, logger_enable: bool) -> Self {
|
|
||||||
self.logger_enabled = logger_enable;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn with_wasi_version(mut self, wasi_version: WasiVersion) -> Self {
|
|
||||||
self.wasi_version = wasi_version;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn with_wasi_envs(mut self, envs: Vec<Vec<u8>>) -> Self {
|
|
||||||
self.wasi_envs = envs;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn with_wasi_preopened_files(mut self, preopened_files: Vec<PathBuf>) -> Self {
|
|
||||||
self.wasi_preopened_files = preopened_files;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn with_wasi_mapped_dirs(mut self, mapped_dirs: Vec<(String, PathBuf)>) -> Self {
|
|
||||||
self.wasi_mapped_dirs = mapped_dirs;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use wasmer_wit::errors::InstructionError;
|
|
||||||
use wasmer_runtime::error::{
|
|
||||||
CallError, CompileError, CreationError, Error as WasmerError, ResolveError, RuntimeError,
|
|
||||||
};
|
|
||||||
|
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum FCEError {
|
|
||||||
/// This error type is produced by Wasmer during resolving a Wasm function.
|
|
||||||
WasmerResolveError(String),
|
|
||||||
|
|
||||||
/// Error related to calling a main Wasm module.
|
|
||||||
WasmerInvokeError(String),
|
|
||||||
|
|
||||||
/// Error that raises during compilation Wasm code by Wasmer.
|
|
||||||
WasmerCreationError(String),
|
|
||||||
|
|
||||||
/// Error that raises during creation of some Wasm objects (like table and memory) by Wasmer.
|
|
||||||
WasmerCompileError(String),
|
|
||||||
|
|
||||||
/// Error that raises on the preparation step.
|
|
||||||
PrepareError(String),
|
|
||||||
|
|
||||||
/// Indicates that there is already a module with such name.
|
|
||||||
NonUniqueModuleName,
|
|
||||||
|
|
||||||
/// Returns when there is no module with such name.
|
|
||||||
NoSuchFunction(String),
|
|
||||||
|
|
||||||
/// Returns when there is no module with such name.
|
|
||||||
NoSuchModule,
|
|
||||||
|
|
||||||
/// WIT section is absent.
|
|
||||||
NoWITSection,
|
|
||||||
|
|
||||||
/// Multiple WIT sections.
|
|
||||||
MultipleWITSections,
|
|
||||||
|
|
||||||
/// WIT section remainder isn't empty.
|
|
||||||
WITRemainderNotEmpty,
|
|
||||||
|
|
||||||
/// An error occurred while parsing WIT section.
|
|
||||||
WITParseError,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for FCEError {}
|
|
||||||
|
|
||||||
impl std::fmt::Display for FCEError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
|
||||||
match self {
|
|
||||||
FCEError::WasmerResolveError(msg) => write!(f, "WasmerResolveError: {}", msg),
|
|
||||||
FCEError::WasmerInvokeError(msg) => write!(f, "WasmerInvokeError: {}", msg),
|
|
||||||
FCEError::WasmerCompileError(msg) => write!(f, "WasmerCompileError: {}", msg),
|
|
||||||
FCEError::WasmerCreationError(msg) => write!(f, "WasmerCreationError: {}", msg),
|
|
||||||
FCEError::PrepareError(msg) => {
|
|
||||||
write!(f, "Prepare error: {}, probably module is mailformed", msg)
|
|
||||||
}
|
|
||||||
FCEError::NonUniqueModuleName => write!(f, "FCE already has module with such a name"),
|
|
||||||
FCEError::NoSuchFunction(msg) => {
|
|
||||||
write!(f, "FCE doesn't have a function with such a name: {}", msg)
|
|
||||||
}
|
|
||||||
FCEError::NoSuchModule => write!(f, "FCE doesn't have a module with such a name"),
|
|
||||||
FCEError::NoWITSection => write!(
|
|
||||||
f,
|
|
||||||
"Loaded module doesn't contain WIT section that is neccessary for instantiation"
|
|
||||||
),
|
|
||||||
FCEError::MultipleWITSections => write!(
|
|
||||||
f,
|
|
||||||
"Loaded module contains multiple WIT sections that is unsupported now"
|
|
||||||
),
|
|
||||||
FCEError::WITRemainderNotEmpty => write!(
|
|
||||||
f,
|
|
||||||
"WIT section remainder isn't empty - WIT section possibly corrupted"
|
|
||||||
),
|
|
||||||
FCEError::WITParseError => write!(f, "WIT section is corrupted"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<CreationError> for FCEError {
|
|
||||||
fn from(err: CreationError) -> Self {
|
|
||||||
FCEError::WasmerCreationError(format!("{}", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<CompileError> for FCEError {
|
|
||||||
fn from(err: CompileError) -> Self {
|
|
||||||
FCEError::WasmerCompileError(format!("{}", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<parity_wasm::elements::Error> for FCEError {
|
|
||||||
fn from(err: parity_wasm::elements::Error) -> Self {
|
|
||||||
FCEError::PrepareError(format!("{}", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<CallError> for FCEError {
|
|
||||||
fn from(err: CallError) -> Self {
|
|
||||||
match err {
|
|
||||||
CallError::Resolve(err) => FCEError::WasmerResolveError(format!("{}", err)),
|
|
||||||
CallError::Runtime(err) => FCEError::WasmerInvokeError(format!("{}", err)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ResolveError> for FCEError {
|
|
||||||
fn from(err: ResolveError) -> Self {
|
|
||||||
FCEError::WasmerResolveError(format!("{}", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RuntimeError> for FCEError {
|
|
||||||
fn from(err: RuntimeError) -> Self {
|
|
||||||
FCEError::WasmerInvokeError(format!("{}", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<WasmerError> for FCEError {
|
|
||||||
fn from(err: WasmerError) -> Self {
|
|
||||||
FCEError::WasmerInvokeError(format!("{}", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<InstructionError> for FCEError {
|
|
||||||
fn from(err: InstructionError) -> Self {
|
|
||||||
FCEError::WasmerInvokeError(format!("{}", err))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::instance::FCEModule;
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::collections::hash_map::Entry;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub struct FCE {
|
|
||||||
// set of modules registered inside FCE
|
|
||||||
modules: HashMap<String, Arc<FCEModule>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FCE {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
modules: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for FCE {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FCEService for FCE {
|
|
||||||
fn call(
|
|
||||||
&mut self,
|
|
||||||
module_name: &str,
|
|
||||||
func_name: &str,
|
|
||||||
argument: &[IValue],
|
|
||||||
) -> Result<Vec<IValue>, FCEError> {
|
|
||||||
match self.modules.get_mut(module_name) {
|
|
||||||
// TODO: refactor errors
|
|
||||||
Some(mut module) => unsafe {
|
|
||||||
Ok(Arc::get_mut_unchecked(&mut module).call(func_name, argument)?)
|
|
||||||
},
|
|
||||||
None => Err(FCEError::NoSuchModule),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_module<S>(
|
|
||||||
&mut self,
|
|
||||||
module_name: S,
|
|
||||||
wasm_bytes: &[u8],
|
|
||||||
config: FCEModuleConfig,
|
|
||||||
) -> Result<(), FCEError>
|
|
||||||
where
|
|
||||||
S: Into<String>,
|
|
||||||
{
|
|
||||||
let _prepared_wasm_bytes =
|
|
||||||
super::prepare::prepare_module(wasm_bytes, config.mem_pages_count)?;
|
|
||||||
|
|
||||||
let module = FCEModule::new(&wasm_bytes, config.import_object, &self.modules)?;
|
|
||||||
|
|
||||||
match self.modules.entry(module_name.into()) {
|
|
||||||
Entry::Vacant(entry) => {
|
|
||||||
entry.insert(Arc::new(module));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Entry::Occupied(_) => Err(FCEError::NonUniqueModuleName),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unregister_module(&mut self, module_name: &str) -> Result<(), FCEError> {
|
|
||||||
match self.modules.entry(module_name.to_string()) {
|
|
||||||
Entry::Vacant(_) => Err(FCEError::NoSuchModule),
|
|
||||||
|
|
||||||
Entry::Occupied(module) => {
|
|
||||||
module.remove_entry();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
mod fce;
|
|
||||||
mod instance;
|
|
||||||
mod fce_service;
|
|
||||||
mod config;
|
|
||||||
mod prepare;
|
|
||||||
mod errors;
|
|
||||||
|
|
||||||
pub use fce::FCE;
|
|
||||||
pub use fce_service::FCEService;
|
|
||||||
pub use config::FCEModuleConfig;
|
|
||||||
pub use errors::FCEError;
|
|
||||||
pub use instance::{IType, IValue};
|
|
@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Fluence Labs Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Similar to
|
|
||||||
// https://github.com/paritytech/substrate/blob/master/srml/contracts/src/wasm/prepare.rs
|
|
||||||
// https://github.com/nearprotocol/nearcore/blob/master/runtime/near-vm-runner/src/prepare.rs
|
|
||||||
|
|
||||||
use super::errors::FCEError;
|
|
||||||
|
|
||||||
use parity_wasm::{
|
|
||||||
builder, elements,
|
|
||||||
elements::{MemorySection, MemoryType},
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ModuleBootstrapper {
|
|
||||||
module: elements::Module,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ModuleBootstrapper {
|
|
||||||
fn init(module_code: &[u8]) -> Result<Self, FCEError> {
|
|
||||||
let module = elements::deserialize_buffer(module_code)?;
|
|
||||||
|
|
||||||
Ok(Self { module })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_mem_pages_count(self, mem_pages_count: u32) -> Self {
|
|
||||||
let Self { mut module } = self;
|
|
||||||
|
|
||||||
// At now, there is could be only one memory section, so
|
|
||||||
// it needs just to extract previous initial page count,
|
|
||||||
// delete an old entry and add create a new one with updated limits
|
|
||||||
let mem_initial = match module.memory_section_mut() {
|
|
||||||
Some(section) => match section.entries_mut().pop() {
|
|
||||||
Some(entry) => entry.limits().initial(),
|
|
||||||
None => 0,
|
|
||||||
},
|
|
||||||
None => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let memory_entry = MemoryType::new(mem_initial, Some(mem_pages_count));
|
|
||||||
let mut default_mem_section = MemorySection::default();
|
|
||||||
|
|
||||||
module
|
|
||||||
.memory_section_mut()
|
|
||||||
.unwrap_or_else(|| &mut default_mem_section)
|
|
||||||
.entries_mut()
|
|
||||||
.push(memory_entry);
|
|
||||||
|
|
||||||
let builder = builder::from_module(module);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
module: builder.build(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_wasm(self) -> Result<Vec<u8>, FCEError> {
|
|
||||||
elements::serialize(self.module).map_err(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prepares a Wasm module:
|
|
||||||
/// - set memory page count
|
|
||||||
pub fn prepare_module(module: &[u8], mem_pages_count: u32) -> Result<Vec<u8>, FCEError> {
|
|
||||||
ModuleBootstrapper::init(module)?
|
|
||||||
.set_mem_pages_count(mem_pages_count)
|
|
||||||
.into_wasm()
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user