sc_executor_wasmtime/
runtime.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Defines the compiled Wasm runtime that uses Wasmtime internally.
20
21use crate::{
22	host::HostState,
23	instance_wrapper::{EntryPoint, InstanceWrapper, MemoryWrapper},
24	util::{self, replace_strategy_if_broken},
25};
26
27use parking_lot::Mutex;
28use sc_allocator::{AllocationStats, FreeingBumpHeapAllocator};
29use sc_executor_common::{
30	error::{Error, Result, WasmError},
31	runtime_blob::RuntimeBlob,
32	util::checked_range,
33	wasm_runtime::{HeapAllocStrategy, WasmInstance, WasmModule},
34};
35use sp_runtime_interface::unpack_ptr_and_len;
36use sp_wasm_interface::{HostFunctions, Pointer, WordSize};
37use std::{
38	path::{Path, PathBuf},
39	sync::{
40		atomic::{AtomicBool, Ordering},
41		Arc,
42	},
43};
44use wasmtime::{AsContext, Engine, Memory};
45
46const MAX_INSTANCE_COUNT: u32 = 64;
47
48#[derive(Default)]
49pub(crate) struct StoreData {
50	/// This will only be set when we call into the runtime.
51	pub(crate) host_state: Option<HostState>,
52	/// This will be always set once the store is initialized.
53	pub(crate) memory: Option<Memory>,
54}
55
56impl StoreData {
57	/// Returns a mutable reference to the host state.
58	pub fn host_state_mut(&mut self) -> Option<&mut HostState> {
59		self.host_state.as_mut()
60	}
61
62	/// Returns the host memory.
63	pub fn memory(&self) -> Memory {
64		self.memory.expect("memory is always set; qed")
65	}
66}
67
68pub(crate) type Store = wasmtime::Store<StoreData>;
69
70enum Strategy {
71	RecreateInstance(InstanceCreator),
72}
73
74struct InstanceCreator {
75	engine: Engine,
76	instance_pre: Arc<wasmtime::InstancePre<StoreData>>,
77	instance_counter: Arc<InstanceCounter>,
78}
79
80impl InstanceCreator {
81	fn instantiate(&mut self) -> Result<InstanceWrapper> {
82		InstanceWrapper::new(&self.engine, &self.instance_pre, self.instance_counter.clone())
83	}
84}
85
86/// A handle for releasing an instance acquired by [`InstanceCounter::acquire_instance`].
87pub(crate) struct ReleaseInstanceHandle {
88	counter: Arc<InstanceCounter>,
89}
90
91impl Drop for ReleaseInstanceHandle {
92	fn drop(&mut self) {
93		{
94			let mut counter = self.counter.counter.lock();
95			*counter = counter.saturating_sub(1);
96		}
97
98		self.counter.wait_for_instance.notify_one();
99	}
100}
101
102/// Keeps track on the number of parallel instances.
103///
104/// The runtime cache keeps track on the number of parallel instances. The maximum number in the
105/// cache is less than what we have configured as [`MAX_INSTANCE_COUNT`] for wasmtime. However, the
106/// cache will create on demand instances if required. This instance counter will ensure that we are
107/// blocking when we are trying to create too many instances.
108#[derive(Default)]
109pub(crate) struct InstanceCounter {
110	counter: Mutex<u32>,
111	wait_for_instance: parking_lot::Condvar,
112}
113
114impl InstanceCounter {
115	/// Acquire an instance.
116	///
117	/// Blocks if there is no free instance available.
118	///
119	/// The returned [`ReleaseInstanceHandle`] should be dropped when the instance isn't used
120	/// anymore.
121	pub fn acquire_instance(self: Arc<Self>) -> ReleaseInstanceHandle {
122		let mut counter = self.counter.lock();
123
124		while *counter >= MAX_INSTANCE_COUNT {
125			self.wait_for_instance.wait(&mut counter);
126		}
127		*counter += 1;
128
129		ReleaseInstanceHandle { counter: self.clone() }
130	}
131}
132
133/// A `WasmModule` implementation using wasmtime to compile the runtime module to machine code
134/// and execute the compiled code.
135pub struct WasmtimeRuntime {
136	engine: Engine,
137	instance_pre: Arc<wasmtime::InstancePre<StoreData>>,
138	instantiation_strategy: InternalInstantiationStrategy,
139	instance_counter: Arc<InstanceCounter>,
140}
141
142impl WasmModule for WasmtimeRuntime {
143	fn new_instance(&self) -> Result<Box<dyn WasmInstance>> {
144		let strategy = match self.instantiation_strategy {
145			InternalInstantiationStrategy::Builtin => Strategy::RecreateInstance(InstanceCreator {
146				engine: self.engine.clone(),
147				instance_pre: self.instance_pre.clone(),
148				instance_counter: self.instance_counter.clone(),
149			}),
150		};
151
152		Ok(Box::new(WasmtimeInstance { strategy }))
153	}
154}
155
156/// A `WasmInstance` implementation that reuses compiled module and spawns instances
157/// to execute the compiled code.
158pub struct WasmtimeInstance {
159	strategy: Strategy,
160}
161
162impl WasmtimeInstance {
163	fn call_impl(
164		&mut self,
165		method: &str,
166		data: &[u8],
167		allocation_stats: &mut Option<AllocationStats>,
168	) -> Result<Vec<u8>> {
169		match &mut self.strategy {
170			Strategy::RecreateInstance(ref mut instance_creator) => {
171				let mut instance_wrapper = instance_creator.instantiate()?;
172				let heap_base = instance_wrapper.extract_heap_base()?;
173				let entrypoint = instance_wrapper.resolve_entrypoint(method)?;
174				let allocator = FreeingBumpHeapAllocator::new(heap_base);
175
176				perform_call(data, &mut instance_wrapper, entrypoint, allocator, allocation_stats)
177			},
178		}
179	}
180}
181
182impl WasmInstance for WasmtimeInstance {
183	fn call_with_allocation_stats(
184		&mut self,
185		method: &str,
186		data: &[u8],
187	) -> (Result<Vec<u8>>, Option<AllocationStats>) {
188		let mut allocation_stats = None;
189		let result = self.call_impl(method, data, &mut allocation_stats);
190		(result, allocation_stats)
191	}
192}
193
194/// Prepare a directory structure and a config file to enable wasmtime caching.
195///
196/// In case of an error the caching will not be enabled.
197fn setup_wasmtime_caching(
198	cache_path: &Path,
199	config: &mut wasmtime::Config,
200) -> std::result::Result<(), String> {
201	use std::fs;
202
203	let wasmtime_cache_root = cache_path.join("wasmtime");
204	fs::create_dir_all(&wasmtime_cache_root)
205		.map_err(|err| format!("cannot create the dirs to cache: {}", err))?;
206
207	// Canonicalize the path after creating the directories.
208	let wasmtime_cache_root = wasmtime_cache_root
209		.canonicalize()
210		.map_err(|err| format!("failed to canonicalize the path: {}", err))?;
211
212	// Write the cache config file
213	let cache_config_path = wasmtime_cache_root.join("cache-config.toml");
214	let config_content = format!(
215		"\
216[cache]
217enabled = true
218directory = \"{cache_dir}\"
219",
220		cache_dir = wasmtime_cache_root.display()
221	);
222	fs::write(&cache_config_path, config_content)
223		.map_err(|err| format!("cannot write the cache config: {}", err))?;
224
225	config
226		.cache_config_load(cache_config_path)
227		.map_err(|err| format!("failed to parse the config: {:#}", err))?;
228
229	Ok(())
230}
231
232fn common_config(semantics: &Semantics) -> std::result::Result<wasmtime::Config, WasmError> {
233	let mut config = wasmtime::Config::new();
234	config.cranelift_opt_level(wasmtime::OptLevel::SpeedAndSize);
235	config.cranelift_nan_canonicalization(semantics.canonicalize_nans);
236
237	// Since wasmtime 6.0.0 the default for this is `true`, but that heavily regresses
238	// the contracts pallet's performance, so disable it for now.
239	#[allow(deprecated)]
240	config.cranelift_use_egraphs(false);
241
242	let profiler = match std::env::var_os("WASMTIME_PROFILING_STRATEGY") {
243		Some(os_string) if os_string == "jitdump" => wasmtime::ProfilingStrategy::JitDump,
244		None => wasmtime::ProfilingStrategy::None,
245		Some(_) => {
246			// Remember if we have already logged a warning due to an unknown profiling strategy.
247			static UNKNOWN_PROFILING_STRATEGY: AtomicBool = AtomicBool::new(false);
248			// Make sure that the warning will not be relogged regularly.
249			if !UNKNOWN_PROFILING_STRATEGY.swap(true, Ordering::Relaxed) {
250				log::warn!("WASMTIME_PROFILING_STRATEGY is set to unknown value, ignored.");
251			}
252			wasmtime::ProfilingStrategy::None
253		},
254	};
255	config.profiler(profiler);
256
257	let native_stack_max = match semantics.deterministic_stack_limit {
258		Some(DeterministicStackLimit { native_stack_max, .. }) => native_stack_max,
259
260		// In `wasmtime` 0.35 the default stack size limit was changed from 1MB to 512KB.
261		//
262		// This broke at least one parachain which depended on the original 1MB limit,
263		// so here we restore it to what it was originally.
264		None => 1024 * 1024,
265	};
266
267	config.max_wasm_stack(native_stack_max as usize);
268
269	config.parallel_compilation(semantics.parallel_compilation);
270
271	// Be clear and specific about the extensions we support. If an update brings new features
272	// they should be introduced here as well.
273	config.wasm_reference_types(semantics.wasm_reference_types);
274	config.wasm_simd(semantics.wasm_simd);
275	config.wasm_bulk_memory(semantics.wasm_bulk_memory);
276	config.wasm_multi_value(semantics.wasm_multi_value);
277	config.wasm_multi_memory(false);
278	config.wasm_threads(false);
279	config.wasm_memory64(false);
280
281	let (use_pooling, use_cow) = match semantics.instantiation_strategy {
282		InstantiationStrategy::PoolingCopyOnWrite => (true, true),
283		InstantiationStrategy::Pooling => (true, false),
284		InstantiationStrategy::RecreateInstanceCopyOnWrite => (false, true),
285		InstantiationStrategy::RecreateInstance => (false, false),
286	};
287
288	const WASM_PAGE_SIZE: u64 = 65536;
289
290	config.memory_init_cow(use_cow);
291	config.memory_guaranteed_dense_image_size(match semantics.heap_alloc_strategy {
292		HeapAllocStrategy::Dynamic { maximum_pages } =>
293			maximum_pages.map(|p| p as u64 * WASM_PAGE_SIZE).unwrap_or(u64::MAX),
294		HeapAllocStrategy::Static { .. } => u64::MAX,
295	});
296
297	if use_pooling {
298		const MAX_WASM_PAGES: u64 = 0x10000;
299
300		let memory_pages = match semantics.heap_alloc_strategy {
301			HeapAllocStrategy::Dynamic { maximum_pages } =>
302				maximum_pages.map(|p| p as u64).unwrap_or(MAX_WASM_PAGES),
303			HeapAllocStrategy::Static { .. } => MAX_WASM_PAGES,
304		};
305
306		let mut pooling_config = wasmtime::PoolingAllocationConfig::default();
307		pooling_config
308			.max_unused_warm_slots(4)
309			// Pooling needs a bunch of hard limits to be set; if we go over
310			// any of these then the instantiation will fail.
311			//
312			// Current minimum values for kusama (as of 2022-04-14):
313			//   size: 32384
314			//   table_elements: 1249
315			//   memory_pages: 2070
316			.instance_size(128 * 1024)
317			.instance_table_elements(8192)
318			.instance_memory_pages(memory_pages)
319			// We can only have a single of those.
320			.instance_tables(1)
321			.instance_memories(1)
322			// This determines how many instances of the module can be
323			// instantiated in parallel from the same `Module`.
324			.instance_count(MAX_INSTANCE_COUNT);
325
326		config.allocation_strategy(wasmtime::InstanceAllocationStrategy::Pooling(pooling_config));
327	}
328
329	Ok(config)
330}
331
332/// Knobs for deterministic stack height limiting.
333///
334/// The WebAssembly standard defines a call/value stack but it doesn't say anything about its
335/// size except that it has to be finite. The implementations are free to choose their own notion
336/// of limit: some may count the number of calls or values, others would rely on the host machine
337/// stack and trap on reaching a guard page.
338///
339/// This obviously is a source of non-determinism during execution. This feature can be used
340/// to instrument the code so that it will count the depth of execution in some deterministic
341/// way (the machine stack limit should be so high that the deterministic limit always triggers
342/// first).
343///
344/// The deterministic stack height limiting feature allows to instrument the code so that it will
345/// count the number of items that may be on the stack. This counting will only act as an rough
346/// estimate of the actual stack limit in wasmtime. This is because wasmtime measures it's stack
347/// usage in bytes.
348///
349/// The actual number of bytes consumed by a function is not trivial to compute  without going
350/// through full compilation. Therefore, it's expected that `native_stack_max` is greatly
351/// overestimated and thus never reached in practice. The stack overflow check introduced by the
352/// instrumentation and that relies on the logical item count should be reached first.
353///
354/// See [here][stack_height] for more details of the instrumentation
355///
356/// [stack_height]: https://github.com/paritytech/wasm-instrument/blob/master/src/stack_limiter/mod.rs
357#[derive(Clone)]
358pub struct DeterministicStackLimit {
359	/// A number of logical "values" that can be pushed on the wasm stack. A trap will be triggered
360	/// if exceeded.
361	///
362	/// A logical value is a local, an argument or a value pushed on operand stack.
363	pub logical_max: u32,
364	/// The maximum number of bytes for stack used by wasmtime JITed code.
365	///
366	/// It's not specified how much bytes will be consumed by a stack frame for a given wasm
367	/// function after translation into machine code. It is also not quite trivial.
368	///
369	/// Therefore, this number should be chosen conservatively. It must be so large so that it can
370	/// fit the [`logical_max`](Self::logical_max) logical values on the stack, according to the
371	/// current instrumentation algorithm.
372	///
373	/// This value cannot be 0.
374	pub native_stack_max: u32,
375}
376
377/// The instantiation strategy to use for the WASM executor.
378///
379/// All of the CoW strategies (with `CopyOnWrite` suffix) are only supported when either:
380///   a) we're running on Linux,
381///   b) we're running on an Unix-like system and we're precompiling
382///      our module beforehand and instantiating from a file.
383///
384/// If the CoW variant of a strategy is unsupported the executor will
385/// fall back to the non-CoW equivalent.
386#[non_exhaustive]
387#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
388pub enum InstantiationStrategy {
389	/// Pool the instances to avoid initializing everything from scratch
390	/// on each instantiation. Use copy-on-write memory when possible.
391	///
392	/// This is the fastest instantiation strategy.
393	PoolingCopyOnWrite,
394
395	/// Recreate the instance from scratch on every instantiation.
396	/// Use copy-on-write memory when possible.
397	RecreateInstanceCopyOnWrite,
398
399	/// Pool the instances to avoid initializing everything from scratch
400	/// on each instantiation.
401	Pooling,
402
403	/// Recreate the instance from scratch on every instantiation. Very slow.
404	RecreateInstance,
405}
406
407enum InternalInstantiationStrategy {
408	Builtin,
409}
410
411#[derive(Clone)]
412pub struct Semantics {
413	/// The instantiation strategy to use.
414	pub instantiation_strategy: InstantiationStrategy,
415
416	/// Specifying `Some` will enable deterministic stack height. That is, all executor
417	/// invocations will reach stack overflow at the exactly same point across different wasmtime
418	/// versions and architectures.
419	///
420	/// This is achieved by a combination of running an instrumentation pass on input code and
421	/// configuring wasmtime accordingly.
422	///
423	/// Since this feature depends on instrumentation, it can be set only if runtime is
424	/// instantiated using the runtime blob, e.g. using [`create_runtime`].
425	// I.e. if [`CodeSupplyMode::Verbatim`] is used.
426	pub deterministic_stack_limit: Option<DeterministicStackLimit>,
427
428	/// Controls whether wasmtime should compile floating point in a way that doesn't allow for
429	/// non-determinism.
430	///
431	/// By default, the wasm spec allows some local non-determinism wrt. certain floating point
432	/// operations. Specifically, those operations that are not defined to operate on bits (e.g.
433	/// fneg) can produce NaN values. The exact bit pattern for those is not specified and may
434	/// depend on the particular machine that executes wasmtime generated JITed machine code. That
435	/// is a source of non-deterministic values.
436	///
437	/// The classical runtime environment for Substrate allowed it and punted this on the runtime
438	/// developers. For PVFs, we want to ensure that execution is deterministic though. Therefore,
439	/// for PVF execution this flag is meant to be turned on.
440	pub canonicalize_nans: bool,
441
442	/// Configures wasmtime to use multiple threads for compiling.
443	pub parallel_compilation: bool,
444
445	/// The heap allocation strategy to use.
446	pub heap_alloc_strategy: HeapAllocStrategy,
447
448	/// Enables WASM Multi-Value proposal
449	pub wasm_multi_value: bool,
450
451	/// Enables WASM Bulk Memory Operations proposal
452	pub wasm_bulk_memory: bool,
453
454	/// Enables WASM Reference Types proposal
455	pub wasm_reference_types: bool,
456
457	/// Enables WASM Fixed-Width SIMD proposal
458	pub wasm_simd: bool,
459}
460
461#[derive(Clone)]
462pub struct Config {
463	/// The WebAssembly standard requires all imports of an instantiated module to be resolved,
464	/// otherwise, the instantiation fails. If this option is set to `true`, then this behavior is
465	/// overridden and imports that are requested by the module and not provided by the host
466	/// functions will be resolved using stubs. These stubs will trap upon a call.
467	pub allow_missing_func_imports: bool,
468
469	/// A directory in which wasmtime can store its compiled artifacts cache.
470	pub cache_path: Option<PathBuf>,
471
472	/// Tuning of various semantics of the wasmtime executor.
473	pub semantics: Semantics,
474}
475
476enum CodeSupplyMode<'a> {
477	/// The runtime is instantiated using the given runtime blob.
478	Fresh(RuntimeBlob),
479
480	/// The runtime is instantiated using a precompiled module at the given path.
481	///
482	/// This assumes that the code is already prepared for execution and the same `Config` was
483	/// used.
484	///
485	/// We use a `Path` here instead of simply passing a byte slice to allow `wasmtime` to
486	/// map the runtime's linear memory on supported platforms in a copy-on-write fashion.
487	Precompiled(&'a Path),
488
489	/// The runtime is instantiated using a precompiled module with the given bytes.
490	///
491	/// This assumes that the code is already prepared for execution and the same `Config` was
492	/// used.
493	PrecompiledBytes(&'a [u8]),
494}
495
496/// Create a new `WasmtimeRuntime` given the code. This function performs translation from Wasm to
497/// machine code, which can be computationally heavy.
498///
499/// The `H` generic parameter is used to statically pass a set of host functions which are exposed
500/// to the runtime.
501pub fn create_runtime<H>(
502	blob: RuntimeBlob,
503	config: Config,
504) -> std::result::Result<WasmtimeRuntime, WasmError>
505where
506	H: HostFunctions,
507{
508	// SAFETY: this is safe because it doesn't use `CodeSupplyMode::Precompiled`.
509	unsafe { do_create_runtime::<H>(CodeSupplyMode::Fresh(blob), config) }
510}
511
512/// The same as [`create_runtime`] but takes a path to a precompiled artifact,
513/// which makes this function considerably faster than [`create_runtime`].
514///
515/// # Safety
516///
517/// The caller must ensure that the compiled artifact passed here was:
518///   1) produced by [`prepare_runtime_artifact`],
519///   2) written to the disk as a file,
520///   3) was not modified,
521///   4) will not be modified while any runtime using this artifact is alive, or is being
522///      instantiated.
523///
524/// Failure to adhere to these requirements might lead to crashes and arbitrary code execution.
525///
526/// It is ok though if the compiled artifact was created by code of another version or with
527/// different configuration flags. In such case the caller will receive an `Err` deterministically.
528pub unsafe fn create_runtime_from_artifact<H>(
529	compiled_artifact_path: &Path,
530	config: Config,
531) -> std::result::Result<WasmtimeRuntime, WasmError>
532where
533	H: HostFunctions,
534{
535	do_create_runtime::<H>(CodeSupplyMode::Precompiled(compiled_artifact_path), config)
536}
537
538/// The same as [`create_runtime`] but takes the bytes of a precompiled artifact,
539/// which makes this function considerably faster than [`create_runtime`],
540/// but slower than the more optimized [`create_runtime_from_artifact`].
541/// This is especially slow on non-Linux Unix systems. Useful in very niche cases.
542///
543/// # Safety
544///
545/// The caller must ensure that the compiled artifact passed here was:
546///   1) produced by [`prepare_runtime_artifact`],
547///   2) was not modified,
548///
549/// Failure to adhere to these requirements might lead to crashes and arbitrary code execution.
550///
551/// It is ok though if the compiled artifact was created by code of another version or with
552/// different configuration flags. In such case the caller will receive an `Err` deterministically.
553pub unsafe fn create_runtime_from_artifact_bytes<H>(
554	compiled_artifact_bytes: &[u8],
555	config: Config,
556) -> std::result::Result<WasmtimeRuntime, WasmError>
557where
558	H: HostFunctions,
559{
560	do_create_runtime::<H>(CodeSupplyMode::PrecompiledBytes(compiled_artifact_bytes), config)
561}
562
563/// # Safety
564///
565/// This is only unsafe if called with [`CodeSupplyMode::Artifact`]. See
566/// [`create_runtime_from_artifact`] to get more details.
567unsafe fn do_create_runtime<H>(
568	code_supply_mode: CodeSupplyMode<'_>,
569	mut config: Config,
570) -> std::result::Result<WasmtimeRuntime, WasmError>
571where
572	H: HostFunctions,
573{
574	replace_strategy_if_broken(&mut config.semantics.instantiation_strategy);
575
576	let mut wasmtime_config = common_config(&config.semantics)?;
577	if let Some(ref cache_path) = config.cache_path {
578		if let Err(reason) = setup_wasmtime_caching(cache_path, &mut wasmtime_config) {
579			log::warn!(
580				"failed to setup wasmtime cache. Performance may degrade significantly: {}.",
581				reason,
582			);
583		}
584	}
585
586	let engine = Engine::new(&wasmtime_config)
587		.map_err(|e| WasmError::Other(format!("cannot create the wasmtime engine: {:#}", e)))?;
588
589	let (module, instantiation_strategy) = match code_supply_mode {
590		CodeSupplyMode::Fresh(blob) => {
591			let blob = prepare_blob_for_compilation(blob, &config.semantics)?;
592			let serialized_blob = blob.clone().serialize();
593
594			let module = wasmtime::Module::new(&engine, &serialized_blob)
595				.map_err(|e| WasmError::Other(format!("cannot create module: {:#}", e)))?;
596
597			match config.semantics.instantiation_strategy {
598				InstantiationStrategy::Pooling |
599				InstantiationStrategy::PoolingCopyOnWrite |
600				InstantiationStrategy::RecreateInstance |
601				InstantiationStrategy::RecreateInstanceCopyOnWrite =>
602					(module, InternalInstantiationStrategy::Builtin),
603			}
604		},
605		CodeSupplyMode::Precompiled(compiled_artifact_path) => {
606			// SAFETY: The unsafety of `deserialize_file` is covered by this function. The
607			//         responsibilities to maintain the invariants are passed to the caller.
608			//
609			//         See [`create_runtime_from_artifact`] for more details.
610			let module = wasmtime::Module::deserialize_file(&engine, compiled_artifact_path)
611				.map_err(|e| WasmError::Other(format!("cannot deserialize module: {:#}", e)))?;
612
613			(module, InternalInstantiationStrategy::Builtin)
614		},
615		CodeSupplyMode::PrecompiledBytes(compiled_artifact_bytes) => {
616			// SAFETY: The unsafety of `deserialize` is covered by this function. The
617			//         responsibilities to maintain the invariants are passed to the caller.
618			//
619			//         See [`create_runtime_from_artifact_bytes`] for more details.
620			let module = wasmtime::Module::deserialize(&engine, compiled_artifact_bytes)
621				.map_err(|e| WasmError::Other(format!("cannot deserialize module: {:#}", e)))?;
622
623			(module, InternalInstantiationStrategy::Builtin)
624		},
625	};
626
627	let mut linker = wasmtime::Linker::new(&engine);
628	crate::imports::prepare_imports::<H>(&mut linker, &module, config.allow_missing_func_imports)?;
629
630	let instance_pre = linker
631		.instantiate_pre(&module)
632		.map_err(|e| WasmError::Other(format!("cannot preinstantiate module: {:#}", e)))?;
633
634	Ok(WasmtimeRuntime {
635		engine,
636		instance_pre: Arc::new(instance_pre),
637		instantiation_strategy,
638		instance_counter: Default::default(),
639	})
640}
641
642fn prepare_blob_for_compilation(
643	mut blob: RuntimeBlob,
644	semantics: &Semantics,
645) -> std::result::Result<RuntimeBlob, WasmError> {
646	if let Some(DeterministicStackLimit { logical_max, .. }) = semantics.deterministic_stack_limit {
647		blob = blob.inject_stack_depth_metering(logical_max)?;
648	}
649
650	// We don't actually need the memory to be imported so we can just convert any memory
651	// import into an export with impunity. This simplifies our code since `wasmtime` will
652	// now automatically take care of creating the memory for us, and it is also necessary
653	// to enable `wasmtime`'s instance pooling. (Imported memories are ineligible for pooling.)
654	blob.convert_memory_import_into_export()?;
655	blob.setup_memory_according_to_heap_alloc_strategy(semantics.heap_alloc_strategy)?;
656
657	Ok(blob)
658}
659
660/// Takes a [`RuntimeBlob`] and precompiles it returning the serialized result of compilation. It
661/// can then be used for calling [`create_runtime`] avoiding long compilation times.
662pub fn prepare_runtime_artifact(
663	blob: RuntimeBlob,
664	semantics: &Semantics,
665) -> std::result::Result<Vec<u8>, WasmError> {
666	let mut semantics = semantics.clone();
667	replace_strategy_if_broken(&mut semantics.instantiation_strategy);
668
669	let blob = prepare_blob_for_compilation(blob, &semantics)?;
670
671	let engine = Engine::new(&common_config(&semantics)?)
672		.map_err(|e| WasmError::Other(format!("cannot create the engine: {:#}", e)))?;
673
674	engine
675		.precompile_module(&blob.serialize())
676		.map_err(|e| WasmError::Other(format!("cannot precompile module: {:#}", e)))
677}
678
679fn perform_call(
680	data: &[u8],
681	instance_wrapper: &mut InstanceWrapper,
682	entrypoint: EntryPoint,
683	mut allocator: FreeingBumpHeapAllocator,
684	allocation_stats: &mut Option<AllocationStats>,
685) -> Result<Vec<u8>> {
686	let (data_ptr, data_len) = inject_input_data(instance_wrapper, &mut allocator, data)?;
687
688	let host_state = HostState::new(allocator);
689
690	// Set the host state before calling into wasm.
691	instance_wrapper.store_mut().data_mut().host_state = Some(host_state);
692
693	let ret = entrypoint
694		.call(instance_wrapper.store_mut(), data_ptr, data_len)
695		.map(unpack_ptr_and_len);
696
697	// Reset the host state
698	let host_state = instance_wrapper.store_mut().data_mut().host_state.take().expect(
699		"the host state is always set before calling into WASM so it can't be None here; qed",
700	);
701	*allocation_stats = Some(host_state.allocation_stats());
702
703	let (output_ptr, output_len) = ret?;
704	let output = extract_output_data(instance_wrapper, output_ptr, output_len)?;
705
706	Ok(output)
707}
708
709fn inject_input_data(
710	instance: &mut InstanceWrapper,
711	allocator: &mut FreeingBumpHeapAllocator,
712	data: &[u8],
713) -> Result<(Pointer<u8>, WordSize)> {
714	let mut ctx = instance.store_mut();
715	let memory = ctx.data().memory();
716	let data_len = data.len() as WordSize;
717	let data_ptr = allocator.allocate(&mut MemoryWrapper(&memory, &mut ctx), data_len)?;
718	util::write_memory_from(instance.store_mut(), data_ptr, data)?;
719	Ok((data_ptr, data_len))
720}
721
722fn extract_output_data(
723	instance: &InstanceWrapper,
724	output_ptr: u32,
725	output_len: u32,
726) -> Result<Vec<u8>> {
727	let ctx = instance.store();
728
729	// Do a length check before allocating. The returned output should not be bigger than the
730	// available WASM memory. Otherwise, a malicious parachain can trigger a large allocation,
731	// potentially causing memory exhaustion.
732	//
733	// Get the size of the WASM memory in bytes.
734	let memory_size = ctx.as_context().data().memory().data_size(ctx);
735	if checked_range(output_ptr as usize, output_len as usize, memory_size).is_none() {
736		Err(Error::OutputExceedsBounds)?
737	}
738	let mut output = vec![0; output_len as usize];
739
740	util::read_memory_into(ctx, Pointer::new(output_ptr), &mut output)?;
741	Ok(output)
742}