Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Bump wasmtime to 5.0.0 (and a few other deps) #13160

Merged
merged 10 commits into from Feb 6, 2023
173 changes: 88 additions & 85 deletions Cargo.lock

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions client/executor/wasmtime/Cargo.toml
Expand Up @@ -19,14 +19,14 @@ log = "0.4.17"

# When bumping wasmtime do not forget to also bump rustix
# to exactly the same version as used by wasmtime!
wasmtime = { version = "1.0.0", default-features = false, features = [
wasmtime = { version = "4.0.0", default-features = false, features = [
"cache",
"cranelift",
"jitdump",
"parallel-compilation",
"memory-init-cow",
"pooling-allocator",
"pooling-allocator"
] }
anyhow = "1.0.68"
sc-allocator = { version = "4.1.0-dev", path = "../../allocator" }
sc-executor-common = { version = "0.10.0-dev", path = "../common" }
sp-runtime-interface = { version = "7.0.0", path = "../../../primitives/runtime-interface" }
Expand All @@ -38,7 +38,7 @@ sp-wasm-interface = { version = "7.0.0", path = "../../../primitives/wasm-interf
# By default rustix directly calls the appropriate syscalls completely bypassing libc;
# this doesn't have any actual benefits for us besides making it harder to debug memory
# problems (since then `mmap` etc. cannot be easily hooked into).
rustix = { version = "0.35.9", default-features = false, features = ["std", "mm", "fs", "param", "use-libc"] }
rustix = { version = "0.36.0", default-features = false, features = ["std", "mm", "fs", "param", "use-libc"] }
once_cell = "1.12.0"

[dev-dependencies]
Expand All @@ -48,3 +48,4 @@ sp-io = { version = "7.0.0", path = "../../../primitives/io" }
tempfile = "3.3.0"
paste = "1.0"
codec = { package = "parity-scale-codec", version = "3.0.0" }
cargo_metadata = "0.15.2"
4 changes: 2 additions & 2 deletions client/executor/wasmtime/src/imports.rs
Expand Up @@ -20,7 +20,7 @@ use crate::{host::HostContext, runtime::StoreData};
use sc_executor_common::error::WasmError;
use sp_wasm_interface::{FunctionContext, HostFunctions};
use std::collections::HashMap;
use wasmtime::{ExternType, FuncType, ImportType, Linker, Module, Trap};
use wasmtime::{ExternType, FuncType, ImportType, Linker, Module};

/// Goes over all imports of a module and prepares the given linker for instantiation of the module.
/// Returns an error if there are imports that cannot be satisfied.
Expand Down Expand Up @@ -67,7 +67,7 @@ where
log::debug!("Missing import: '{}' {:?}", name, func_ty);
linker
.func_new("env", &name, func_ty.clone(), move |_, _, _| {
Err(Trap::new(error.clone()))
Err(anyhow::anyhow!("{error}"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't that just a Box<Error>?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error here is a String, and this needs to return anyhow::Error since that's what wasmtime requires. But I guess I could useanyhow::Error::msg(error.clone()) instead of anyhow!.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The macro wasn't the problem :D But I still think that Box::<dyn StdError>::from(error.to_string()).into() should work :D

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is... quite the Rube Goldberg contraption. (:

From what I can see that doesn't work though as Box<E> only implements Error when E is Sized, and dyn StdError is not Sized.

})
.expect("adding a missing import stub can only fail when the item already exists, and it is missing here; qed");
}
Expand Down
30 changes: 10 additions & 20 deletions client/executor/wasmtime/src/instance_wrapper.rs
Expand Up @@ -76,27 +76,17 @@ impl EntryPoint {
.as_mut()
.expect("host state cannot be empty while a function is being called; qed");

// The logic to print out a backtrace is somewhat complicated,
// so let's get wasmtime to print it out for us.
let mut backtrace_string = trap.to_string();
let suffix = "\nwasm backtrace:";
if let Some(index) = backtrace_string.find(suffix) {
// Get rid of the error message and just grab the backtrace,
// since we're storing the error message ourselves separately.
backtrace_string.replace_range(0..index + suffix.len(), "");
}
let backtrace = trap.downcast_ref::<wasmtime::WasmBacktrace>().map(|backtrace| {
// The logic to print out a backtrace is somewhat complicated,
// so let's get wasmtime to print it out for us.
Backtrace { backtrace_string: backtrace.to_string() }
});

let backtrace = Backtrace { backtrace_string };
if let Some(error) = host_state.take_panic_message() {
koute marked this conversation as resolved.
Show resolved Hide resolved
Error::AbortedDueToPanic(MessageWithBacktrace {
message: error,
backtrace: Some(backtrace),
})
Error::AbortedDueToPanic(MessageWithBacktrace { message: error, backtrace })
} else {
Error::AbortedDueToTrap(MessageWithBacktrace {
message: trap.display_reason().to_string(),
backtrace: Some(backtrace),
})
let message = trap.root_cause().to_string();
Error::AbortedDueToTrap(MessageWithBacktrace { message, backtrace })
}
})
}
Expand All @@ -106,7 +96,7 @@ impl EntryPoint {
ctx: impl AsContext,
) -> std::result::Result<Self, &'static str> {
let entrypoint = func
.typed::<(u32, u32), u64, _>(ctx)
.typed::<(u32, u32), u64>(ctx)
.map_err(|_| "Invalid signature for direct entry point")?;
Ok(Self { call_type: EntryPointType::Direct { entrypoint } })
}
Expand All @@ -117,7 +107,7 @@ impl EntryPoint {
ctx: impl AsContext,
) -> std::result::Result<Self, &'static str> {
let dispatcher = dispatcher
.typed::<(u32, u32, u32), u64, _>(ctx)
.typed::<(u32, u32, u32), u64>(ctx)
.map_err(|_| "Invalid signature for wrapped entry point")?;
Ok(Self { call_type: EntryPointType::Wrapped { func, dispatcher } })
}
Expand Down
40 changes: 19 additions & 21 deletions client/executor/wasmtime/src/runtime.rs
Expand Up @@ -365,29 +365,27 @@ fn common_config(semantics: &Semantics) -> std::result::Result<wasmtime::Config,
MAX_WASM_PAGES
};

config.allocation_strategy(wasmtime::InstanceAllocationStrategy::Pooling {
strategy: wasmtime::PoolingAllocationStrategy::ReuseAffinity,

let mut pooling_config = wasmtime::PoolingAllocationConfig::default();
pooling_config
.strategy(wasmtime::PoolingAllocationStrategy::ReuseAffinity)
// Pooling needs a bunch of hard limits to be set; if we go over
// any of these then the instantiation will fail.
instance_limits: wasmtime::InstanceLimits {
// Current minimum values for kusama (as of 2022-04-14):
// size: 32384
// table_elements: 1249
// memory_pages: 2070
size: 64 * 1024,
table_elements: 3072,
memory_pages,

// We can only have a single of those.
tables: 1,
memories: 1,

// This determines how many instances of the module can be
// instantiated in parallel from the same `Module`.
count: 32,
},
});
//
// Current minimum values for kusama (as of 2022-04-14):
// size: 32384
// table_elements: 1249
// memory_pages: 2070
.instance_size(64 * 1024)
.instance_table_elements(3072)
.instance_memory_pages(memory_pages)
// We can only have a single of those.
.instance_tables(1)
.instance_memories(1)
// This determines how many instances of the module can be
// instantiated in parallel from the same `Module`.
.instance_count(32);

config.allocation_strategy(wasmtime::InstanceAllocationStrategy::Pooling(pooling_config));
}

Ok(config)
Expand Down
35 changes: 33 additions & 2 deletions client/executor/wasmtime/src/tests.rs
Expand Up @@ -226,8 +226,8 @@ fn deep_call_stack_wat(depth: usize) -> String {

// We need two limits here since depending on whether the code is compiled in debug
// or in release mode the maximum call depth is slightly different.
const CALL_DEPTH_LOWER_LIMIT: usize = 65478;
const CALL_DEPTH_UPPER_LIMIT: usize = 65514;
const CALL_DEPTH_LOWER_LIMIT: usize = 65456;
const CALL_DEPTH_UPPER_LIMIT: usize = 65509;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So does that mean that we are actually using more stack size per level? And thus need reduce the limit?

Copy link
Contributor Author

@koute koute Jan 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, slightly more stack space is being used, but should be fine since it's not per level as far as I can see as it doesn't look multiplicative (I'm guessing wasmtime just has a few more local variables on the code path when entering into WASM or something like that.)


test_wasm_execution!(test_consume_under_1mb_of_stack_does_not_trap);
fn test_consume_under_1mb_of_stack_does_not_trap(instantiation_strategy: InstantiationStrategy) {
Expand Down Expand Up @@ -555,3 +555,34 @@ fn test_instances_without_reuse_are_not_leaked() {
instance.call_export("test_empty_return", &[0]).unwrap();
}
}

#[test]
fn test_rustix_version_matches_with_wasmtime() {
let metadata = cargo_metadata::MetadataCommand::new()
.manifest_path("../../../Cargo.toml")
.exec()
.unwrap();

let wasmtime_rustix = metadata
.packages
.iter()
.find(|pkg| pkg.name == "wasmtime-runtime")
.unwrap()
.dependencies
.iter()
.find(|dep| dep.name == "rustix")
.unwrap();
let our_rustix = metadata
.packages
.iter()
.find(|pkg| pkg.name == "sc-executor-wasmtime")
.unwrap()
.dependencies
.iter()
.find(|dep| dep.name == "rustix")
.unwrap();

if wasmtime_rustix.req != our_rustix.req {
panic!("our version of rustix ({0}) doesn't match wasmtime's ({1}); bump the version in `sc-executor-wasmtime`'s `Cargo.toml' to '{1}' and try again", our_rustix.req, wasmtime_rustix.req);
}
}
Expand Up @@ -371,14 +371,14 @@ fn generate_host_function_implementation(
registry.register_static(
#crate_::sp_wasm_interface::Function::name(&#struct_name),
|mut caller: #crate_::sp_wasm_interface::wasmtime::Caller<T::State>, #(#ffi_args_prototype),*|
-> std::result::Result<#ffi_return_ty, #crate_::sp_wasm_interface::wasmtime::Trap>
-> std::result::Result<#ffi_return_ty, #crate_::sp_wasm_interface::anyhow::Error>
{
T::with_function_context(caller, move |__function_context__| {
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
#struct_name::call(
__function_context__,
#(#ffi_names,)*
).map_err(#crate_::sp_wasm_interface::wasmtime::Trap::new)
).map_err(#crate_::sp_wasm_interface::anyhow::Error::msg)
}));
match result {
Ok(result) => result,
Expand All @@ -391,7 +391,7 @@ fn generate_host_function_implementation(
} else {
"host code panicked while being called by the runtime".to_owned()
};
return Err(#crate_::sp_wasm_interface::wasmtime::Trap::new(message));
return Err(#crate_::sp_wasm_interface::anyhow::Error::msg(message));
}
}
})
Expand Down
4 changes: 3 additions & 1 deletion primitives/wasm-interface/Cargo.toml
Expand Up @@ -18,9 +18,11 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features =
impl-trait-for-tuples = "0.2.2"
log = { version = "0.4.17", optional = true }
wasmi = { version = "0.13", optional = true }
wasmtime = { version = "1.0.0", default-features = false, optional = true }
wasmtime = { version = "4.0.0", default-features = false, optional = true }
anyhow = { version = "1.0.68", optional = true }
sp-std = { version = "5.0.0", default-features = false, path = "../std" }

[features]
default = [ "std" ]
std = [ "codec/std", "log", "sp-std/std", "wasmi", "wasmtime" ]
wasmtime = [ "dep:wasmtime", "anyhow" ]
3 changes: 3 additions & 0 deletions primitives/wasm-interface/src/lib.rs
Expand Up @@ -41,6 +41,9 @@ macro_rules! if_wasmtime_is_enabled {
if_wasmtime_is_enabled! {
// Reexport wasmtime so that its types are accessible from the procedural macro.
pub use wasmtime;

// Wasmtime uses anyhow types but doesn't reexport them.
pub use anyhow;
}

/// Result type used by traits in this crate.
Expand Down
2 changes: 1 addition & 1 deletion utils/wasm-builder/Cargo.toml
Expand Up @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
ansi_term = "0.12.1"
build-helper = "0.1.1"
cargo_metadata = "0.14.2"
cargo_metadata = "0.15.2"
strum = { version = "0.24.1", features = ["derive"] }
tempfile = "3.1.0"
toml = "0.5.4"
Expand Down