diff --git a/Cargo.lock b/Cargo.lock index 038df488..0639ca3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1657,6 +1657,7 @@ name = "wasmer-runtime-core" version = "0.16.2" source = "git+http://github.com/fluencelabs/wasmer?branch=fluence#c3e9e367828d5c3a8d2e96e9ea6a09224e872a59" dependencies = [ + "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "blake3 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index cdc56976..5d220b90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,9 +37,9 @@ 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" +#opt-level = 3 +#debug = false +#lto = true +#debug-assertions = false +#overflow-checks = false +#panic = "abort" diff --git a/src/lib.rs b/src/lib.rs index d2cab149..ebed27e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,5 +27,5 @@ mod misc; mod vm; pub use vm::config::Config; -pub use vm::frank::Frank; -pub use vm::service::FrankService; +pub use vm::fce::FCE; +pub use vm::service::FCEService; diff --git a/src/main.rs b/src/main.rs index 4eb1ea9e..df880bac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,13 +25,13 @@ #![warn(rust_2018_idioms)] mod misc; -/// Command-line tool intended to test Frank VM. +/// Command-line tool intended to test FCE VM. mod vm; use crate::misc::SlicePrettyPrinter; use crate::vm::config::Config; -use crate::vm::frank::Frank; -use crate::vm::service::FrankService; +use crate::vm::fce::FCE; +use crate::vm::service::FCEService; use exitfailure::ExitFailure; use std::fs; @@ -39,7 +39,7 @@ use std::fs; fn main() -> Result<(), ExitFailure> { println!("Welcome to the FCE CLI:"); let mut rl = rustyline::Editor::<()>::new(); - let mut frank = Frank::new(); + let mut fce = FCE::new(); loop { let readline = rl.readline(">> "); @@ -57,20 +57,17 @@ fn main() -> Result<(), ExitFailure> { } let config = Config::default(); - let result_msg = match frank.register_module( - module_name, - &wasm_bytes.unwrap(), - config, - ) { - Ok(_) => "module successfully registered in Frank".to_string(), - Err(e) => format!("module registration failed with: {:?}", e), - }; + let result_msg = + match fce.register_module(module_name, &wasm_bytes.unwrap(), config) { + 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 frank.unregister_module(module_name) { - Ok(_) => "module successfully deleted from Frank".to_string(), + 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); @@ -78,7 +75,7 @@ fn main() -> Result<(), ExitFailure> { "execute" => { let module_name = cmd[1]; let arg = cmd[2..].join(" "); - let result = match frank.invoke(module_name, arg.as_bytes()) { + let result = match fce.invoke(module_name, arg.as_bytes()) { Ok(result) => { let outcome_copy = result.outcome.clone(); match String::from_utf8(result.outcome) { @@ -91,7 +88,7 @@ fn main() -> Result<(), ExitFailure> { println!("{}", result); } "hash" => { - let hash = frank.compute_state_hash(); + let hash = fce.compute_state_hash(); println!( "vm state hash is {:2x}", SlicePrettyPrinter(hash.as_slice()) @@ -100,8 +97,8 @@ fn main() -> Result<(), ExitFailure> { "help" => { println!( "Enter:\n\ - add - to add a new Wasm module to Frank\n\ - del - to delete Wasm module to Frank\n\ + add - to add a new Wasm module to FCE\n\ + del - to delete Wasm module to FCE\n\ execute - to call invoke on module with module_name\n\ hash - to compute hash of internal Wasm state\n\ help - to print this message\n\ diff --git a/src/vm/errors.rs b/src/vm/errors.rs index 9f3f0933..483ce920 100644 --- a/src/vm/errors.rs +++ b/src/vm/errors.rs @@ -21,7 +21,7 @@ use wasmer_runtime::error::{ use std::error::Error; #[derive(Debug)] -pub enum FrankError { +pub enum FCEError { /// Errors for I/O errors raising while opening a file. IOError(String), @@ -47,72 +47,72 @@ pub enum FrankError { NoSuchModule, } -impl Error for FrankError {} +impl Error for FCEError {} -impl std::fmt::Display for FrankError { +impl std::fmt::Display for FCEError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match self { - FrankError::IOError(msg) => write!(f, "IOError: {}", msg), - FrankError::WasmerResolveError(msg) => write!(f, "WasmerResolveError: {}", msg), - FrankError::WasmerInvokeError(msg) => write!(f, "WasmerInvokeError: {}", msg), - FrankError::WasmerCompileError(msg) => write!(f, "WasmerCompileError: {}", msg), - FrankError::WasmerCreationError(msg) => write!(f, "WasmerCreationError: {}", msg), - FrankError::PrepareError(msg) => { + FCEError::IOError(msg) => write!(f, "IOError: {}", msg), + 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) } - FrankError::NonUniqueModuleName => write!(f, "Frank already has module with such name"), - FrankError::NoSuchModule => write!(f, "Frank doesn't have a module with such name"), + FCEError::NonUniqueModuleName => write!(f, "FCE already has module with such name"), + FCEError::NoSuchModule => write!(f, "FCE doesn't have a module with such name"), } } } -impl From for FrankError { +impl From for FCEError { fn from(err: CreationError) -> Self { - FrankError::WasmerCreationError(format!("{}", err)) + FCEError::WasmerCreationError(format!("{}", err)) } } -impl From for FrankError { +impl From for FCEError { fn from(err: CompileError) -> Self { - FrankError::WasmerCompileError(format!("{}", err)) + FCEError::WasmerCompileError(format!("{}", err)) } } -impl From for FrankError { +impl From for FCEError { fn from(err: parity_wasm::elements::Error) -> Self { - FrankError::PrepareError(format!("{}", err)) + FCEError::PrepareError(format!("{}", err)) } } -impl From for FrankError { +impl From for FCEError { fn from(err: CallError) -> Self { match err { - CallError::Resolve(err) => FrankError::WasmerResolveError(format!("{}", err)), - CallError::Runtime(err) => FrankError::WasmerInvokeError(format!("{}", err)), + CallError::Resolve(err) => FCEError::WasmerResolveError(format!("{}", err)), + CallError::Runtime(err) => FCEError::WasmerInvokeError(format!("{}", err)), } } } -impl From for FrankError { +impl From for FCEError { fn from(err: ResolveError) -> Self { - FrankError::WasmerResolveError(format!("{}", err)) + FCEError::WasmerResolveError(format!("{}", err)) } } -impl From for FrankError { +impl From for FCEError { fn from(err: RuntimeError) -> Self { - FrankError::WasmerInvokeError(format!("{}", err)) + FCEError::WasmerInvokeError(format!("{}", err)) } } -impl From for FrankError { +impl From for FCEError { fn from(err: WasmerError) -> Self { - FrankError::WasmerInvokeError(format!("{}", err)) + FCEError::WasmerInvokeError(format!("{}", err)) } } -impl From for FrankError { +impl From for FCEError { fn from(err: std::io::Error) -> Self { - FrankError::IOError(format!("{}", err)) + FCEError::IOError(format!("{}", err)) } } diff --git a/src/vm/frank.rs b/src/vm/fce.rs similarity index 84% rename from src/vm/frank.rs rename to src/vm/fce.rs index 7e47bd16..33be2458 100644 --- a/src/vm/frank.rs +++ b/src/vm/fce.rs @@ -14,9 +14,9 @@ * limitations under the License. */ -use crate::vm::module::frank_result::FrankResult; -use crate::vm::module::{FrankModule, ModuleAPI}; -use crate::vm::{config::Config, errors::FrankError, service::FrankService}; +use crate::vm::module::fce_result::FCEResult; +use crate::vm::module::{FCEModule, ModuleAPI}; +use crate::vm::{config::Config, errors::FCEError, service::FCEService}; use sha2::{digest::generic_array::GenericArray, digest::FixedOutput}; use std::collections::hash_map::Entry; @@ -24,15 +24,15 @@ use std::collections::HashMap; use wasmer_runtime::func; use wasmer_runtime_core::import::{ImportObject, Namespace}; -pub struct Frank { - // set of modules registered inside Frank - modules: HashMap, +pub struct FCE { + // set of modules registered inside FCE + modules: HashMap, // contains ABI of each registered module in specific format for Wasmer abi_import_object: ImportObject, } -impl Frank { +impl FCE { pub fn new() -> Self { Self { modules: HashMap::new(), @@ -41,7 +41,7 @@ impl Frank { } /// Extracts ABI of a module into Namespace. - fn create_import_object(module: &FrankModule, config: &Config) -> Namespace { + fn create_import_object(module: &FCEModule, config: &Config) -> Namespace { let mut namespace = Namespace::new(); let module_abi = module.get_abi(); @@ -86,17 +86,17 @@ impl Frank { } } -impl Default for Frank { +impl Default for FCE { fn default() -> Self { Self::new() } } -impl FrankService for Frank { - fn invoke(&mut self, module_name: &str, argument: &[u8]) -> Result { +impl FCEService for FCE { + fn invoke(&mut self, module_name: &str, argument: &[u8]) -> Result { match self.modules.get_mut(module_name) { Some(module) => module.invoke(argument), - None => Err(FrankError::NoSuchModule), + None => Err(FCEError::NoSuchModule), } } @@ -105,21 +105,21 @@ impl FrankService for Frank { module_name: S, wasm_bytes: &[u8], config: Config, - ) -> Result<(), FrankError> + ) -> Result<(), FCEError> where S: Into, { let prepared_wasm_bytes = crate::vm::prepare::prepare_module(wasm_bytes, config.mem_pages_count)?; - let module = FrankModule::new( + let module = FCEModule::new( &prepared_wasm_bytes, config.clone(), self.abi_import_object.clone(), )?; // registers ABI of newly registered module in abi_import_object - let namespace = Frank::create_import_object(&module, &config); + let namespace = FCE::create_import_object(&module, &config); let module_name: String = module_name.into(); self.abi_import_object .register(module_name.clone(), namespace); @@ -129,14 +129,14 @@ impl FrankService for Frank { entry.insert(module); Ok(()) } - Entry::Occupied(_) => Err(FrankError::NonUniqueModuleName), + Entry::Occupied(_) => Err(FCEError::NonUniqueModuleName), } } - fn unregister_module(&mut self, module_name: &str) -> Result<(), FrankError> { + fn unregister_module(&mut self, module_name: &str) -> Result<(), FCEError> { self.modules .remove(module_name) - .ok_or_else(|| FrankError::NoSuchModule)?; + .ok_or_else(|| FCEError::NoSuchModule)?; // unregister abi from a dispatcher Ok(()) diff --git a/src/vm/mod.rs b/src/vm/mod.rs index d8244384..856d9111 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -16,7 +16,7 @@ pub mod config; pub mod errors; -pub mod frank; +pub mod fce; pub mod service; mod module; diff --git a/src/vm/module/abi.rs b/src/vm/module/abi.rs index d1c52447..43c72830 100644 --- a/src/vm/module/abi.rs +++ b/src/vm/module/abi.rs @@ -16,7 +16,7 @@ use wasmer_runtime::Func; -/// Application binary interface of a Frank module. Different module could use such scheme for +/// 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 @@ -32,7 +32,7 @@ use wasmer_runtime::Func; pub(crate) struct ModuleABI<'a> { // 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 Frank::new has been succeed. + // invoking FCE::new has been succeed. /// Allocates a region of memory inside a module. Used for passing argument inside the module. pub(crate) allocate: Option>, diff --git a/src/vm/module/api.rs b/src/vm/module/api.rs index 7b063203..efdc010e 100644 --- a/src/vm/module/api.rs +++ b/src/vm/module/api.rs @@ -14,16 +14,16 @@ * limitations under the License. */ -use crate::vm::errors::FrankError; -use crate::vm::module::frank_result::FrankResult; +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 Frank module. Intended to use by Frank instance itself. +/// Application interface of a FCE module. Intended to use by FCE 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; + fn invoke(&mut self, argument: &[u8]) -> Result; /// Computes hash of the internal modules state. fn compute_state_hash(&mut self) diff --git a/src/vm/module/frank_module.rs b/src/vm/module/fce_module.rs similarity index 87% rename from src/vm/module/frank_module.rs rename to src/vm/module/fce_module.rs index 9e9599db..a10fb348 100644 --- a/src/vm/module/frank_module.rs +++ b/src/vm/module/fce_module.rs @@ -15,8 +15,8 @@ */ use crate::vm::config::Config; -use crate::vm::errors::FrankError; -use crate::vm::module::frank_result::FrankResult; +use crate::vm::errors::FCEError; +use crate::vm::module::fce_result::FCEResult; use crate::vm::module::{ModuleABI, ModuleAPI}; use sha2::digest::generic_array::GenericArray; @@ -26,21 +26,17 @@ use wasmer_runtime_core::import::ImportObject; use wasmer_runtime_core::memory::ptr::{Array, WasmPtr}; use wasmer_wasi::generate_import_object_for_version; -pub(crate) struct FrankModule { +pub(crate) struct FCEModule { instance: &'static Instance, abi: ModuleABI<'static>, } -impl FrankModule { +impl FCEModule { /// Creates a new virtual machine executor. - pub fn new( - wasm_bytes: &[u8], - config: Config, - imports: ImportObject, - ) -> Result { + pub fn new(wasm_bytes: &[u8], config: Config, imports: ImportObject) -> Result { let logger_imports = imports! { "logger" => { - "log_utf8_string" => func!(FrankModule::logger_log_utf8_string), + "log_utf8_string" => func!(FCEModule::logger_log_utf8_string), }, }; @@ -77,12 +73,12 @@ impl FrankModule { let wasm_ptr = WasmPtr::::new(offset as _); match wasm_ptr.get_utf8_string(ctx.memory(0), size as _) { Some(msg) => print!("{}", msg), - None => print!("frank logger: incorrect UTF8 string's been supplied to logger"), + 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<(), FrankError> { + 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::()[address..(address + value.len())] @@ -96,7 +92,7 @@ impl FrankModule { } /// Reads invocation result from specified address of memory. - fn read_result_from_mem(&self, address: usize) -> Result, FrankError> { + fn read_result_from_mem(&self, address: usize) -> Result, FCEError> { let memory = self.instance.context().memory(0); let mut result_size: usize = 0; @@ -114,8 +110,8 @@ impl FrankModule { } } -impl ModuleAPI for FrankModule { - fn invoke(&mut self, argument: &[u8]) -> Result { +impl ModuleAPI for FCEModule { + fn invoke(&mut self, argument: &[u8]) -> Result { // allocate memory for the given argument and write it to memory let argument_len = argument.len() as i32; let argument_address = if argument_len != 0 { @@ -141,7 +137,7 @@ impl ModuleAPI for FrankModule { .unwrap() .call(result_address, result.len() as i32)?; - Ok(FrankResult::new(result)) + Ok(FCEResult::new(result)) } fn compute_state_hash( @@ -155,7 +151,7 @@ impl ModuleAPI for FrankModule { let wasm_ptr = WasmPtr::::new(0 as _); let raw_mem = wasm_ptr .deref(memory, 0, (memory.size().bytes().0 - 1) as _) - .expect("frank: internal error in compute_vm_state_hash"); + .expect("fce: internal error in compute_vm_state_hash"); let raw_mem: &[u8] = unsafe { &*(raw_mem as *const [std::cell::Cell] as *const [u8]) }; hasher.input(raw_mem); @@ -163,6 +159,6 @@ impl ModuleAPI for FrankModule { } } -impl Drop for FrankModule { +impl Drop for FCEModule { fn drop(&mut self) {} } diff --git a/src/vm/module/frank_result.rs b/src/vm/module/fce_result.rs similarity index 94% rename from src/vm/module/frank_result.rs rename to src/vm/module/fce_result.rs index 8fc0484d..ebeb4884 100644 --- a/src/vm/module/frank_result.rs +++ b/src/vm/module/fce_result.rs @@ -15,11 +15,11 @@ */ #[derive(Clone, Debug, PartialEq, Default)] -pub struct FrankResult { +pub struct FCEResult { pub outcome: Vec, } -impl FrankResult { +impl FCEResult { pub fn new(outcome: Vec) -> Self { Self { outcome } } diff --git a/src/vm/module/mod.rs b/src/vm/module/mod.rs index c4400449..92b744de 100644 --- a/src/vm/module/mod.rs +++ b/src/vm/module/mod.rs @@ -16,9 +16,9 @@ mod abi; mod api; -mod frank_module; -pub mod frank_result; +mod fce_module; +pub mod fce_result; pub(crate) use abi::ModuleABI; pub(crate) use api::ModuleAPI; -pub(crate) use frank_module::FrankModule; +pub(crate) use fce_module::FCEModule; diff --git a/src/vm/prepare.rs b/src/vm/prepare.rs index 125e52cd..fab55dea 100644 --- a/src/vm/prepare.rs +++ b/src/vm/prepare.rs @@ -18,7 +18,7 @@ // 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 crate::vm::errors::FrankError; +use crate::vm::errors::FCEError; use parity_wasm::{ builder, elements, @@ -30,7 +30,7 @@ struct ModuleBootstrapper { } impl<'a> ModuleBootstrapper { - fn init(module_code: &[u8]) -> Result { + fn init(module_code: &[u8]) -> Result { let module = elements::deserialize_buffer(module_code)?; Ok(Self { module }) @@ -66,14 +66,14 @@ impl<'a> ModuleBootstrapper { } } - fn into_wasm(self) -> Result, FrankError> { + fn into_wasm(self) -> Result, 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, FrankError> { +pub fn prepare_module(module: &[u8], mem_pages_count: u32) -> Result, FCEError> { ModuleBootstrapper::init(module)? .set_mem_pages_count(mem_pages_count) .into_wasm() diff --git a/src/vm/service.rs b/src/vm/service.rs index 555fd13f..8562cc35 100644 --- a/src/vm/service.rs +++ b/src/vm/service.rs @@ -15,28 +15,28 @@ */ use crate::vm::config::Config; -use crate::vm::errors::FrankError; -use crate::vm::module::frank_result::FrankResult; +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 FrankService { +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; + fn invoke(&mut self, module_name: &str, argument: &[u8]) -> Result; - /// Registers new module in the Frank Service. + /// Registers new module in the FCE Service. fn register_module( &mut self, module_name: S, wasm_bytes: &[u8], config: Config, - ) -> Result<(), FrankError> + ) -> Result<(), FCEError> where S: Into; /// Unregisters previously registered module. - fn unregister_module(&mut self, module_name: &str) -> Result<(), FrankError>; + fn unregister_module(&mut self, module_name: &str) -> Result<(), FCEError>; /// Computes hash of the internal modules state. fn compute_state_hash( diff --git a/tests/single_module.rs b/tests/single_module.rs index 141db342..191002f8 100644 --- a/tests/single_module.rs +++ b/tests/single_module.rs @@ -16,7 +16,7 @@ mod downloader; -use fce::{Config, Frank, FrankService}; +use fce::{Config, FCEService, FCE}; const REDIS_DOWNLOAD_URL: &str = "https://github.com/fluencelabs/redis/releases/download/0.8.0_w/redis.wasm"; @@ -27,27 +27,26 @@ const SQLITE_DOWNLOAD_URL: &str = async fn redis() { let wasm_bytes = downloader::download(REDIS_DOWNLOAD_URL).await; - let mut frank = Frank::new(); + let mut fce = FCE::new(); let module_name = "redis"; let config = Config::default(); - frank - .register_module(module_name, wasm_bytes.as_ref(), config) - .unwrap_or_else(|e| panic!("can't create Frank: {:?}", e)); + fce.register_module(module_name, wasm_bytes.as_ref(), config) + .unwrap_or_else(|e| panic!("can't create FCE: {:?}", e)); - let result1 = frank + let result1 = fce .invoke(module_name, "SET A 10".as_bytes()) .unwrap_or_else(|e| panic!("error while FCE invocation: {:?}", e)); - let result2 = frank + let result2 = fce .invoke(module_name, "SADD B 20".as_bytes()) .unwrap_or_else(|e| panic!("error while FCE invocation: {:?}", e)); - let result3 = frank + let result3 = fce .invoke(module_name, "GET A".as_bytes()) .unwrap_or_else(|e| panic!("error while FCE invocation: {:?}", e)); - let result4 = frank + let result4 = fce .invoke(module_name, "SMEMBERS B".as_bytes()) .unwrap_or_else(|e| panic!("error while FCE invocation: {:?}", e)); - let result5 = frank + let result5 = fce .invoke( module_name, "eval \"redis.call('incr', 'A') return redis.call('get', 'A') * 8 + 5\" 0".as_bytes(), @@ -71,27 +70,26 @@ async fn redis() { async fn sqlite() { let wasm_bytes = downloader::download(SQLITE_DOWNLOAD_URL).await; - let mut frank = Frank::new(); + let mut fce = FCE::new(); let module_name = "sqlite"; let config = Config::default(); - frank - .register_module(module_name, wasm_bytes.as_ref(), config) - .unwrap_or_else(|e| panic!("can't create Frank: {:?}", e)); + fce.register_module(module_name, wasm_bytes.as_ref(), config) + .unwrap_or_else(|e| panic!("can't create FCE: {:?}", e)); - let result1 = frank + let result1 = fce .invoke( module_name, "CREATE VIRTUAL TABLE users USING FTS5(body)".as_bytes(), ) .unwrap_or_else(|e| panic!("error while FCE invocation: {:?}", e)); - let result2 = frank + let result2 = fce .invoke( module_name, "INSERT INTO users(body) VALUES('AB'), ('BC'), ('CD'), ('DE')".as_bytes(), ) .unwrap_or_else(|e| panic!("error while FCE invocation: {:?}", e)); - let result3 = frank + let result3 = fce .invoke( module_name, "SELECT * FROM users WHERE users MATCH 'A* OR B*'".as_bytes(),