add WIT embedder

This commit is contained in:
vms 2020-05-28 23:20:24 +03:00
parent 361427f483
commit da3b9e56ed
27 changed files with 3223 additions and 843 deletions

View File

@ -10,11 +10,12 @@ jobs:
- checkout
- restore_cache:
keys:
- fce01-{{ checksum "Cargo.toml" }}
- fce01-{{ checksum "fce/Cargo.toml" }}
- run: |
rustup toolchain install stable
rustup component add rustfmt
rustup component add clippy
cd fce
cargo fmt --all -- --check --color always
cargo build -v --all-features
cargo test -v --all-features
@ -23,7 +24,7 @@ jobs:
paths:
- ~/.cargo
- ~/.rustup
key: fce01-{{ checksum "Cargo.toml" }}
key: fce01-{{ checksum "fce/Cargo.toml" }}
workflows:
version: 2.1

1779
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,45 +1,5 @@
[package]
name = "FCE"
description = "Fluence compute engine, virtual machine based on Wasmer for the Fluence network"
version = "0.1.0"
authors = ["Fluence Labs"]
edition = "2018"
license = "Apache-2.0"
keywords = ["fluence", "webassembly", "wasmer", "execution environment"]
categories = ["webassembly"]
maintenance = { status = "actively-developed" }
[lib]
name = "fce"
path = "src/lib.rs"
#crate-type = ["cdylib"]
[[bin]]
name = "fce_cli"
path = "src/main.rs"
[dependencies]
wasmer-runtime = { git = "http://github.com/fluencelabs/wasmer", branch = "fluence" }
wasmer-runtime-core = { git = "http://github.com/fluencelabs/wasmer", branch = "fluence" }
wasmer-wasi = { git = "http://github.com/fluencelabs/wasmer", branch = "fluence" }
failure = "0.1.7"
lazy_static = "1.4.0"
sha2 = "0.8.1"
rustyline = "6.1.2"
exitfailure = "0.5.1"
boolinator = "2.4.0"
parity-wasm = "0.41.0"
pwasm-utils = "0.12.0"
[dev-dependencies]
reqwest = "0.10.4"
bytes = "0.5.4"
tokio = { version = "0.2.20", features = ["blocking", "macros"] }
[profile.release]
#opt-level = 3
#debug = false
#lto = true
#debug-assertions = false
#overflow-checks = false
#panic = "abort"
[workspace]
members = [
"fce",
"wit_embedder",
]

1975
fce/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

45
fce/Cargo.toml Normal file
View File

@ -0,0 +1,45 @@
[package]
name = "FCE"
description = "Fluence compute engine, virtual machine based on Wasmer for the Fluence network"
version = "0.1.0"
authors = ["Fluence Labs"]
edition = "2018"
license = "Apache-2.0"
keywords = ["fluence", "webassembly", "wasmer", "execution environment"]
categories = ["webassembly"]
maintenance = { status = "actively-developed" }
[lib]
name = "fce"
path = "src/lib.rs"
#crate-type = ["cdylib"]
[[bin]]
name = "fce_cli"
path = "src/main.rs"
[dependencies]
wasmer-runtime = { git = "http://github.com/fluencelabs/wasmer", branch = "fluence" }
wasmer-runtime-core = { git = "http://github.com/fluencelabs/wasmer", branch = "fluence" }
wasmer-wasi = { git = "http://github.com/fluencelabs/wasmer", branch = "fluence" }
failure = "0.1.7"
lazy_static = "1.4.0"
sha2 = "0.8.1"
rustyline = "6.1.2"
exitfailure = "0.5.1"
boolinator = "2.4.0"
parity-wasm = "0.41.0"
pwasm-utils = "0.12.0"
[dev-dependencies]
reqwest = "0.10.4"
bytes = "0.5.4"
tokio = { version = "0.2.20", features = ["blocking", "macros"] }
[profile.release]
#opt-level = 3
#debug = false
#lto = true
#debug-assertions = false
#overflow-checks = false
#panic = "abort"

22
wit_embedder/Cargo.toml Normal file
View File

@ -0,0 +1,22 @@
[package]
name = "wit_embedder"
version = "0.1.0"
authors = ["Fluence Labs"]
edition = "2018"
[dependencies]
walrus = "0.17.0"
wasmer-interface-types = { git = "https://github.com/fluencelabs/interface-types", branch = "master"}
options = "0.5.1"
either = "1.5.3"
clap = "2.33.1"
exitfailure = "0.5.1"
failure = "0.1.5"
[profile.release]
opt-level = 3
debug = false
lto = true
debug-assertions = false
overflow-checks = false
panic = "abort"

View File

@ -0,0 +1,17 @@
use std::borrow::Cow;
use walrus::{CustomSection, IdsToIndices};
pub const WIT_SECTION_NAME: &str = "interface-types";
#[derive(Debug, Clone)]
pub(crate) struct WITCustom(pub Vec<u8>);
impl CustomSection for WITCustom {
fn name(&self) -> &str {
WIT_SECTION_NAME
}
fn data(&self, _ids_to_indices: &IdsToIndices) -> Cow<[u8]> {
Cow::Borrowed(&self.0)
}
}

View File

@ -0,0 +1,35 @@
use crate::custom::WITCustom;
use std::path::PathBuf;
use walrus::ModuleConfig;
use wasmer_interface_types::{
decoders::wat::{parse, Buffer},
encoders::binary::ToBytes,
};
pub struct Config {
pub in_wasm_path: PathBuf,
pub wit: String,
pub out_wasm_path: PathBuf,
}
pub fn embed_wit(options: &Config) -> Result<(), String> {
let mut module = ModuleConfig::new()
.parse_file(&options.in_wasm_path)
.map_err(|e| format!("Failed to parse the Wasm module: {}", e))?;
let buffer = Buffer::new(&options.wit)
.map_err(|e| format!("Can't parse provided Wasm module: {}", e))?;
let ast = parse(&buffer).map_err(|e| format!("Failed to parse the WIT description: {}", e))?;
let mut bytes = vec![];
ast.to_bytes(&mut bytes)
.map_err(|_| "Failed to encode the AST into its binary representation.")?;
let custom = WITCustom(bytes);
module.customs.add(custom);
module
.emit_wasm_file(&options.out_wasm_path)
.map_err(|e| format!("Failed to emit Wasm file with bindings: {}", e))?;
Ok(())
}

View File

@ -0,0 +1,35 @@
use std::path::PathBuf;
use walrus::{IdsToIndices, ModuleConfig};
pub fn extract_wit(wasm_file: PathBuf) -> Result<String, String> {
let module = ModuleConfig::new()
.parse_file(wasm_file)
.map_err(|_| "Failed to parse the Wasm module.".to_string())?;
let sections = module
.customs
.iter()
.filter(|(_, section)| section.name() == "interface-types")
.collect::<Vec<_>>();
if sections.is_empty() {
return Err("Wasm binary doesn't contain interface types section".to_string());
}
if sections.len() > 1 {
return Err("Wasm binary contains more than one interface-types section".to_string());
}
let default_ids = IdsToIndices::default();
let wit_section_bytes = sections[0].1.data(&default_ids).into_owned();
let wit = match wasmer_interface_types::decoders::binary::parse::<()>(&wit_section_bytes) {
Ok((remainder, wit)) if remainder.is_empty() => wit,
Ok((remainder, _)) => {
return Err(format!("remainder isn't empty: {:?}", remainder));
}
Err(e) => {
return Err(format!("An error occurred while parsing: {}", e));
}
};
Ok(format!("{:?}", wit))
}

103
wit_embedder/src/main.rs Normal file
View File

@ -0,0 +1,103 @@
mod custom;
mod embedder;
mod extracter;
use clap::{App, AppSettings, Arg, SubCommand};
use embedder::Config;
use failure::err_msg;
use std::path::PathBuf;
const VERSION: &str = env!("CARGO_PKG_VERSION");
const AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
const IN_WASM_PATH: &str = "in-wasm-path";
const WIT_PATH: &str = "wit-path";
const OUT_WASM_PATH: &str = "out-wasm-path";
fn embed_wit<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("embed")
.about("embed WIT to provided Wasm file")
.args(&[
Arg::with_name(IN_WASM_PATH)
.required(true)
.takes_value(true)
.short("i")
.help("path to the wasm file"),
Arg::with_name(WIT_PATH)
.required(true)
.takes_value(true)
.short("w")
.help("path to file with WIT"),
Arg::with_name(OUT_WASM_PATH)
.takes_value(true)
.short("o")
.help("path to result file with embedded WIT"),
])
}
fn show_wit<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("show")
.about("show WIT in provided Wasm file")
.args(&[Arg::with_name(IN_WASM_PATH)
.required(true)
.takes_value(true)
.short("i")
.help("path to the wasm file")])
}
pub fn main() -> Result<(), exitfailure::ExitFailure> {
let app = App::new("CLI tool for embedding WIT to provided Wasm file")
.version(VERSION)
.author(AUTHORS)
.about(DESCRIPTION)
.setting(AppSettings::ArgRequiredElseHelp)
.subcommand(embed_wit())
.subcommand(show_wit());
match app.get_matches().subcommand() {
("embed", Some(arg)) => {
let in_wasm_path = arg.value_of(IN_WASM_PATH).unwrap();
let wit_path = arg.value_of(WIT_PATH).unwrap();
let out_wasm_path = match arg.value_of(OUT_WASM_PATH) {
Some(path) => path,
None => in_wasm_path,
};
let wit = String::from_utf8(std::fs::read(wit_path)?).unwrap();
let options = Config {
in_wasm_path: PathBuf::from(in_wasm_path),
wit,
out_wasm_path: PathBuf::from(out_wasm_path),
};
match embedder::embed_wit(&options) {
Ok(_) => {
println!("WIT successfully embedded");
}
Err(e) => {
println!("{}", e);
}
};
Ok(())
}
("show", Some(arg)) => {
let wasm_path = arg.value_of(IN_WASM_PATH).unwrap();
let wasm_path = PathBuf::from(wasm_path);
match extracter::extract_wit(wasm_path) {
Ok(wat) => {
println!("extracted WIT:\n{}", wat);
}
Err(e) => {
println!("{}", e);
}
};
Ok(())
}
c => Err(err_msg(format!("Unexpected command: {}", c.0)).into()),
}
}