diff --git a/Cargo.lock b/Cargo.lock
index 94275f1ff5f..2ec6039cf82 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1610,6 +1610,17 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3"
+[[package]]
+name = "atomic_enum"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99e1aca718ea7b89985790c94aad72d77533063fe00bc497bb79a7c2dae6a661"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.71",
+]
+
[[package]]
name = "attohttpc"
version = "0.24.1"
@@ -5955,6 +5966,7 @@ name = "gear-cli"
version = "1.6.2"
dependencies = [
"clap 4.5.9",
+ "derive_more 0.99.18",
"frame-benchmarking",
"frame-benchmarking-cli",
"frame-system",
@@ -6377,19 +6389,21 @@ dependencies = [
name = "gear-sandbox-host"
version = "1.6.2"
dependencies = [
+ "atomic_enum",
"defer",
"environmental",
"gear-sandbox-env",
"gear-wasmer-cache",
"log",
"parity-scale-codec",
+ "region",
"sp-allocator",
"sp-wasm-interface-common",
"tempfile",
"thiserror",
"wasmer",
"wasmer-types",
- "wasmi 0.13.2",
+ "wasmi 0.38.0",
]
[[package]]
@@ -8450,7 +8464,7 @@ dependencies = [
"log",
"region",
"wasmer",
- "wasmi 0.13.2",
+ "wasmi 0.38.0",
"wasmprinter",
"wat",
]
@@ -9920,6 +9934,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389"
+[[package]]
+name = "multi-stash"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "685a9ac4b61f4e728e1d2c6a7844609c16527aeb5e6c865915c08e619c16410f"
+
[[package]]
name = "multiaddr"
version = "0.17.1"
@@ -16539,6 +16559,17 @@ version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e75b72ee54e2f93c3ea1354066162be893ee5e25773ab743de3e088cecbb4f31"
+[[package]]
+name = "string-interner"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c6a0d765f5807e98a091107bae0a56ea3799f66a5de47b2c84c94a39c09974e"
+dependencies = [
+ "cfg-if",
+ "hashbrown 0.14.5",
+ "serde",
+]
+
[[package]]
name = "strsim"
version = "0.8.0"
@@ -18605,6 +18636,22 @@ dependencies = [
"wasmparser-nostd",
]
+[[package]]
+name = "wasmi"
+version = "0.38.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b07e84e3bcdab2f4301827623260ada2557596ca462f7470b60f5182a25270b1"
+dependencies = [
+ "arrayvec 0.7.4",
+ "multi-stash",
+ "smallvec",
+ "spin 0.9.8",
+ "wasmi_collections",
+ "wasmi_core 0.38.0",
+ "wasmi_ir",
+ "wasmparser-nostd",
+]
+
[[package]]
name = "wasmi-validation"
version = "0.5.0"
@@ -18619,6 +18666,17 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "104a7f73be44570cac297b3035d76b169d6599637631cf37a1703326a0727073"
+[[package]]
+name = "wasmi_collections"
+version = "0.38.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d0fd5f4f2c4fe0c98554bb7293108ed2b1d0c124dce0974f999de7d517d37bc"
+dependencies = [
+ "ahash 0.8.11",
+ "hashbrown 0.14.5",
+ "string-interner",
+]
+
[[package]]
name = "wasmi_core"
version = "0.2.1"
@@ -18644,6 +18702,27 @@ dependencies = [
"paste",
]
+[[package]]
+name = "wasmi_core"
+version = "0.38.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a5f7bbd933a0fb3bac6c541f8bd90c0c8adcd91bb3ac088a2088995325b3d9"
+dependencies = [
+ "downcast-rs",
+ "libm",
+ "num-traits",
+ "paste",
+]
+
+[[package]]
+name = "wasmi_ir"
+version = "0.38.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a3345445247388df2b5b35250a30c9209c27c8d2c6db1bf4c89b65636264bf9"
+dependencies = [
+ "wasmi_core 0.38.0",
+]
+
[[package]]
name = "wasmparser"
version = "0.102.0"
diff --git a/Cargo.toml b/Cargo.toml
index 94d6641b6e1..564b668f00b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -308,9 +308,7 @@ ethexe-rpc = { path = "ethexe/rpc", default-features = false }
ethexe-common = { path = "ethexe/common" }
# Common executor between `sandbox-host` and `lazy-pages-fuzzer`
-sandbox-wasmi = { package = "wasmi", git = "https://github.com/gear-tech/wasmi", branch = "v0.13.2-sign-ext", features = [
- "virtual_memory",
-] }
+wasmi = { package = "wasmi", version = "0.38"}
# Substrate deps
binary-merkle-tree = { version = "4.0.0-dev", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-v1.4.0", default-features = false }
@@ -503,6 +501,7 @@ demo-wat = { path = "examples/wat" }
#
# TODO: remove these dependencies (from this file?) or add more docs.
+atomic_enum = "0.3.0"
cfg-if = "1.0.0" # gear-lazy-pages
cargo-http-registry = "0.1.6" # crates-io
errno = "0.3" # gear-lazy-pages
diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml
index 3de1a1494d6..4fc0a0f4ce0 100644
--- a/node/cli/Cargo.toml
+++ b/node/cli/Cargo.toml
@@ -23,6 +23,7 @@ clap = { workspace = true, features = ["derive"] }
mimalloc = { workspace = true, default-features = false }
log = { workspace = true, features = ["std"] }
futures.workspace = true
+derive_more.workspace = true
# Gear
runtime-primitives.workspace = true
diff --git a/node/cli/src/cli.rs b/node/cli/src/cli.rs
index e5af588fc9c..0f1b0f40fba 100644
--- a/node/cli/src/cli.rs
+++ b/node/cli/src/cli.rs
@@ -17,6 +17,29 @@
// along with this program. If not, see .
use clap::Parser;
+use std::str::FromStr;
+
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Parser, derive_more::Display)]
+pub enum SandboxBackend {
+ #[display(fmt = "wasmer")]
+ Wasmer,
+ #[display(fmt = "wasmi")]
+ Wasmi,
+}
+
+// TODO: use `derive_more::FromStr` when derive_more dependency is updated to 1.0
+impl FromStr for SandboxBackend {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result {
+ match s.to_lowercase().as_str() {
+ "wasmer" => Ok(SandboxBackend::Wasmer),
+ "wasmi" => Ok(SandboxBackend::Wasmi),
+ _ => Err(format!("Unknown sandbox executor: {}", s)),
+ }
+ }
+}
#[allow(missing_docs)]
#[derive(Debug, Parser)]
@@ -26,6 +49,10 @@ pub struct RunCmd {
#[command(flatten)]
pub base: sc_cli::RunCmd,
+ /// The Wasm host executor to use in program sandbox.
+ #[arg(long, default_value_t = SandboxBackend::Wasmer)]
+ pub sandbox_backend: SandboxBackend,
+
/// The upper limit for the amount of gas a validator can burn in one block.
#[arg(long)]
pub max_gas: Option,
diff --git a/node/cli/src/command.rs b/node/cli/src/command.rs
index 3b1e57182cc..19eb0d854a7 100644
--- a/node/cli/src/command.rs
+++ b/node/cli/src/command.rs
@@ -16,7 +16,10 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-use crate::cli::{Cli, Subcommand};
+use crate::{
+ cli::{Cli, Subcommand},
+ SandboxBackend,
+};
use runtime_primitives::Block;
use sc_cli::{ChainSpec, SubstrateCli};
use sc_service::config::BasePath;
@@ -130,6 +133,11 @@ macro_rules! unwrap_client {
pub fn run() -> sc_cli::Result<()> {
let cli = Cli::from_args();
+ gear_runtime_interface::sandbox_init(match cli.run.sandbox_backend {
+ SandboxBackend::Wasmer => gear_runtime_interface::SandboxBackend::Wasmer,
+ SandboxBackend::Wasmi => gear_runtime_interface::SandboxBackend::Wasmi,
+ });
+
let old_base = BasePath::from_project("", "", "gear-node");
let new_base = BasePath::from_project("", "", &Cli::executable_name());
if old_base.path().exists() && !new_base.path().exists() {
diff --git a/runtime-interface/sandbox/src/detail.rs b/runtime-interface/sandbox/src/detail.rs
index 647b0b76d1e..28ac3f1127a 100644
--- a/runtime-interface/sandbox/src/detail.rs
+++ b/runtime-interface/sandbox/src/detail.rs
@@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-use core::cell::RefCell;
+use core::{cell::RefCell, sync::atomic::Ordering};
use codec::{Decode, Encode};
use gear_sandbox_host::sandbox::{self as sandbox_env, env::Instantiate};
@@ -32,10 +32,10 @@ struct Sandboxes {
}
impl Sandboxes {
- pub fn new() -> Self {
+ pub fn new(sandbox_backend: sandbox_env::SandboxBackend) -> Self {
Self {
store_data_key: 0,
- store: sandbox_env::SandboxComponents::new(sandbox_env::SandboxBackend::Wasmer),
+ store: sandbox_env::SandboxComponents::new(sandbox_backend),
}
}
@@ -61,8 +61,21 @@ impl Sandboxes {
}
}
+// Global sandbox backend type selector
+static SANDBOX_BACKEND_TYPE: sandbox_env::AtomicSandboxBackend =
+ sandbox_env::AtomicSandboxBackend::new(sandbox_env::SandboxBackend::Wasmer);
+
thread_local! {
- static SANDBOXES: RefCell = RefCell::new(Sandboxes::new());
+ static SANDBOXES: RefCell = {
+ let sandbox_backend = SANDBOX_BACKEND_TYPE.load(Ordering::SeqCst);
+ RefCell::new(Sandboxes::new(sandbox_backend))
+ }
+}
+
+/// Sets the global sandbox backend type.
+/// Buy default, it's set to `Wasmer`, so in case of `Wasmer` it's not necessary to call this function.
+pub fn init(sandbox_backend: sandbox_env::SandboxBackend) {
+ SANDBOX_BACKEND_TYPE.store(sandbox_backend, Ordering::SeqCst);
}
struct SupervisorContext<'a, 'b> {
diff --git a/runtime-interface/sandbox/src/lib.rs b/runtime-interface/sandbox/src/lib.rs
index cac05370ae2..4830f369266 100644
--- a/runtime-interface/sandbox/src/lib.rs
+++ b/runtime-interface/sandbox/src/lib.rs
@@ -21,13 +21,16 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
-pub use gear_sandbox_host::sandbox::env::Instantiate;
+pub use gear_sandbox_host::sandbox::{env::Instantiate, SandboxBackend};
use sp_runtime_interface::{runtime_interface, Pointer};
use sp_wasm_interface::HostPointer;
#[cfg(feature = "std")]
pub mod detail;
+#[cfg(feature = "std")]
+pub use detail::init;
+
/// Wasm-only interface that provides functions for interacting with the sandbox.
#[runtime_interface(wasm_only)]
pub trait Sandbox {
diff --git a/runtime-interface/src/lib.rs b/runtime-interface/src/lib.rs
index 5ce2809ca84..4eb02cc090c 100644
--- a/runtime-interface/src/lib.rs
+++ b/runtime-interface/src/lib.rs
@@ -50,7 +50,9 @@ use {
pub use gear_sandbox_interface::sandbox;
#[cfg(feature = "std")]
-pub use gear_sandbox_interface::{detail as sandbox_detail, Instantiate};
+pub use gear_sandbox_interface::{
+ detail as sandbox_detail, init as sandbox_init, Instantiate, SandboxBackend,
+};
const _: () = assert!(size_of::() >= size_of::());
diff --git a/sandbox/host/Cargo.toml b/sandbox/host/Cargo.toml
index df634883545..ac7a4949df5 100644
--- a/sandbox/host/Cargo.toml
+++ b/sandbox/host/Cargo.toml
@@ -15,6 +15,7 @@ rust-version.workspace = true
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
+atomic_enum.workspace = true
codec = { workspace = true, features = ["std"] }
defer.workspace = true
environmental.workspace = true
@@ -22,13 +23,16 @@ thiserror.workspace = true
log = { workspace = true, features = ["std"] }
wasmer.workspace = true
wasmer-types.workspace = true
-sandbox-wasmi.workspace = true
+wasmi.workspace = true
sp-allocator = { workspace = true, features = ["std"] }
sp-wasm-interface-common = { workspace = true, features = ["std"] }
gear-sandbox-env = { workspace = true, features = ["std"] }
gear-wasmer-cache = { workspace = true, optional = true }
tempfile = { workspace = true, optional = true }
+region.workspace = true
[features]
default = ["wasmer-cache"]
wasmer-cache = ["gear-wasmer-cache", "tempfile"]
+# See wasmi/extra-checks for more information.
+wasmi-extra-checks = ["wasmi/extra-checks"]
diff --git a/sandbox/host/src/error.rs b/sandbox/host/src/error.rs
index 28d1945e88e..e39dfac783b 100644
--- a/sandbox/host/src/error.rs
+++ b/sandbox/host/src/error.rs
@@ -26,7 +26,7 @@ pub type Result = std::result::Result;
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
- Wasmi(#[from] sandbox_wasmi::Error),
+ Wasmi(#[from] wasmi::Error),
#[error("Sandbox error: {0}")]
Sandbox(String),
@@ -107,10 +107,10 @@ pub enum Error {
AbortedDueToTrap(MessageWithBacktrace),
}
-impl sandbox_wasmi::HostError for Error {}
+impl wasmi::core::HostError for Error {}
-impl From<&'static str> for Error {
- fn from(err: &'static str) -> Error {
+impl From<&'_ str> for Error {
+ fn from(err: &'_ str) -> Error {
Error::Other(err.into())
}
}
diff --git a/sandbox/host/src/lib.rs b/sandbox/host/src/lib.rs
index 24997b5e6f2..f144ded1301 100644
--- a/sandbox/host/src/lib.rs
+++ b/sandbox/host/src/lib.rs
@@ -25,4 +25,6 @@ pub mod error;
pub mod sandbox;
pub mod util;
+pub(crate) mod store_refcell;
+
use log as _;
diff --git a/sandbox/host/src/sandbox.rs b/sandbox/host/src/sandbox.rs
index 2efdc0093de..b323b31a110 100644
--- a/sandbox/host/src/sandbox.rs
+++ b/sandbox/host/src/sandbox.rs
@@ -44,8 +44,8 @@ use self::{
},
wasmi_backend::{
get_global as wasmi_get_global, instantiate as wasmi_instantiate, invoke as wasmi_invoke,
- new_memory as wasmi_new_memory, set_global as wasmi_set_global,
- MemoryWrapper as WasmiMemoryWrapper,
+ new_memory as wasmi_new_memory, set_global as wasmi_set_global, Backend as WasmiBackend,
+ MemoryWrapper as WasmiMemoryWrapper, StoreRefCell as WasmiStoreRefCell,
},
};
@@ -165,19 +165,15 @@ pub trait SupervisorContext {
fn deallocate_memory(&mut self, ptr: Pointer) -> SandboxResult<()>;
}
-/// Implementation of [`Externals`] that allows execution of guest module with
-/// [externals][`Externals`] that might refer functions defined by supervisor.
-///
-/// [`Externals`]: ../wasmi/trait.Externals.html
-pub struct GuestExternals<'a> {
- /// Instance of sandboxed module to be dispatched
- sandbox_instance: &'a SandboxInstance,
-}
-
/// Module instance in terms of selected backend
enum BackendInstanceBundle {
/// Wasmi module instance
- Wasmi(sandbox_wasmi::ModuleRef),
+ Wasmi {
+ /// Wasmer module instance
+ instance: wasmi::Instance,
+ /// Wasmer store
+ store: Rc,
+ },
/// Wasmer module instance and store
Wasmer {
@@ -204,7 +200,6 @@ enum BackendInstanceBundle {
/// [`invoke`]: #method.invoke
pub struct SandboxInstance {
backend_instance: BackendInstanceBundle,
- guest_to_supervisor_mapping: GuestToSupervisorFunctionMapping,
}
impl SandboxInstance {
@@ -219,8 +214,8 @@ impl SandboxInstance {
supervisor_context: &mut dyn SupervisorContext,
) -> std::result::Result