referrerpolicy=no-referrer-when-downgrade

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