referrerpolicy=no-referrer-when-downgrade

pallet_contracts/wasm/
prepare.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! This module takes care of loading, checking and preprocessing of a
19//! wasm module before execution. It also extracts some essential information
20//! from a module.
21
22use crate::{
23	chain_extension::ChainExtension,
24	storage::meter::Diff,
25	wasm::{
26		runtime::AllowDeprecatedInterface, CodeInfo, Determinism, Environment, WasmBlob,
27		BYTES_PER_PAGE,
28	},
29	AccountIdOf, CodeVec, Config, Error, Schedule, LOG_TARGET,
30};
31#[cfg(any(test, feature = "runtime-benchmarks"))]
32use alloc::vec::Vec;
33use codec::MaxEncodedLen;
34use sp_runtime::{traits::Hash, DispatchError};
35use wasmi::{
36	core::ValType as WasmiValueType, CompilationMode, Config as WasmiConfig, Engine, ExternType,
37	Module, StackLimits,
38};
39
40/// Imported memory must be located inside this module. The reason for hardcoding is that current
41/// compiler toolchains might not support specifying other modules than "env" for memory imports.
42pub const IMPORT_MODULE_MEMORY: &str = "env";
43
44/// The inner deserialized module is valid and contains only allowed WebAssembly features.
45/// This is checked by loading it into wasmi interpreter `engine`.
46pub struct LoadedModule {
47	pub module: Module,
48	pub engine: Engine,
49}
50
51#[derive(PartialEq, Debug, Clone)]
52pub enum LoadingMode {
53	Checked,
54	Unchecked,
55}
56
57#[cfg(test)]
58pub mod tracker {
59	use core::cell::RefCell;
60	thread_local! {
61		pub static LOADED_MODULE: RefCell<Vec<super::LoadingMode>> = RefCell::new(Vec::new());
62	}
63}
64
65impl LoadedModule {
66	/// Creates a new instance of `LoadedModule`.
67	///
68	/// The inner Wasm module is checked not to have restricted WebAssembly proposals.
69	/// Returns `Err` if the `code` cannot be deserialized or if it contains an invalid module.
70	pub fn new<T>(
71		code: &[u8],
72		determinism: Determinism,
73		stack_limits: Option<StackLimits>,
74		loading_mode: LoadingMode,
75		compilation_mode: CompilationMode,
76	) -> Result<Self, &'static str> {
77		// NOTE: wasmi does not support unstable WebAssembly features. The module is implicitly
78		// checked for not having those ones when creating `wasmi::Module` below.
79		let mut config = WasmiConfig::default();
80		config
81			.wasm_multi_value(false)
82			.wasm_mutable_global(false)
83			.wasm_sign_extension(true)
84			.wasm_bulk_memory(false)
85			.wasm_reference_types(false)
86			.wasm_tail_call(false)
87			.wasm_extended_const(false)
88			.wasm_saturating_float_to_int(false)
89			.floats(matches!(determinism, Determinism::Relaxed))
90			.compilation_mode(compilation_mode)
91			.consume_fuel(true);
92
93		if let Some(stack_limits) = stack_limits {
94			config.set_stack_limits(stack_limits);
95		}
96
97		let engine = Engine::new(&config);
98
99		let module = match loading_mode {
100			LoadingMode::Checked => Module::new(&engine, code),
101			// Safety: The code has been validated, Therefore we know that it's a valid binary.
102			LoadingMode::Unchecked => unsafe { Module::new_unchecked(&engine, code) },
103		}
104		.map_err(|err| {
105			log::debug!(target: LOG_TARGET, "Module creation failed: {:?}", err);
106			"Can't load the module into wasmi!"
107		})?;
108
109		#[cfg(test)]
110		tracker::LOADED_MODULE.with(|t| t.borrow_mut().push(loading_mode));
111
112		// Return a `LoadedModule` instance with
113		// __valid__ module.
114		Ok(LoadedModule { module, engine })
115	}
116
117	/// Check that the module has required exported functions. For now
118	/// these are just entrypoints:
119	///
120	/// - 'call'
121	/// - 'deploy'
122	///
123	/// Any other exports are not allowed.
124	fn scan_exports(&self) -> Result<(), &'static str> {
125		let mut deploy_found = false;
126		let mut call_found = false;
127		let module = &self.module;
128		let exports = module.exports();
129
130		for export in exports {
131			match export.ty() {
132				ExternType::Func(ft) => {
133					match export.name() {
134						"call" => call_found = true,
135						"deploy" => deploy_found = true,
136						_ =>
137							return Err(
138								"unknown function export: expecting only deploy and call functions",
139							),
140					}
141					// Check the signature.
142					// Both "call" and "deploy" have the () -> () function type.
143					// We still support () -> (i32) for backwards compatibility.
144					if !(ft.params().is_empty() &&
145						(ft.results().is_empty() || ft.results() == [WasmiValueType::I32]))
146					{
147						return Err("entry point has wrong signature")
148					}
149				},
150				ExternType::Memory(_) => return Err("memory export is forbidden"),
151				ExternType::Global(_) => return Err("global export is forbidden"),
152				ExternType::Table(_) => return Err("table export is forbidden"),
153			}
154		}
155
156		if !deploy_found {
157			return Err("deploy function isn't exported")
158		}
159		if !call_found {
160			return Err("call function isn't exported")
161		}
162
163		Ok(())
164	}
165
166	/// Scan an import section if any.
167	///
168	/// This makes sure that:
169	/// - The import section looks as we expect it from a contract.
170	/// - The limits of the memory type declared by the contract comply with the Schedule.
171	///
172	/// Returns the checked memory limits back to caller.
173	///
174	/// This method fails if:
175	///
176	/// - Memory import not found in the module.
177	/// - Tables or globals found among imports.
178	/// - `call_chain_extension` host function is imported, while chain extensions are disabled.
179	///
180	/// NOTE that only single memory instance is allowed for contract modules, which is enforced by
181	/// this check combined with multi_memory proposal gets disabled in the engine.
182	pub fn scan_imports<T: Config>(
183		&self,
184		schedule: &Schedule<T>,
185	) -> Result<(u32, u32), &'static str> {
186		let module = &self.module;
187		let imports = module.imports();
188		let mut memory_limits = None;
189
190		for import in imports {
191			match *import.ty() {
192				ExternType::Table(_) => return Err("Cannot import tables"),
193				ExternType::Global(_) => return Err("Cannot import globals"),
194				ExternType::Func(_) => {
195					import.ty().func().ok_or("expected a function")?;
196
197					if !<T as Config>::ChainExtension::enabled() &&
198						(import.name().as_bytes() == b"seal_call_chain_extension" ||
199							import.name().as_bytes() == b"call_chain_extension")
200					{
201						return Err("Module uses chain extensions but chain extensions are disabled")
202					}
203				},
204				ExternType::Memory(mt) => {
205					if import.module().as_bytes() != IMPORT_MODULE_MEMORY.as_bytes() {
206						return Err("Invalid module for imported memory")
207					}
208					if import.name().as_bytes() != b"memory" {
209						return Err("Memory import must have the field name 'memory'")
210					}
211					if memory_limits.is_some() {
212						return Err("Multiple memory imports defined")
213					}
214					// Parse memory limits defaulting it to (0,0).
215					// Any access to it will then lead to out of bounds trap.
216					let (initial, maximum) = (
217						mt.initial_pages().to_bytes().unwrap_or(0).saturating_div(BYTES_PER_PAGE)
218							as u32,
219						mt.maximum_pages().map_or(schedule.limits.memory_pages, |p| {
220							p.to_bytes().unwrap_or(0).saturating_div(BYTES_PER_PAGE) as u32
221						}),
222					);
223					if initial > maximum {
224						return Err(
225						"Requested initial number of memory pages should not exceed the requested maximum",
226					)
227					}
228					if maximum > schedule.limits.memory_pages {
229						return Err("Maximum number of memory pages should not exceed the maximum configured in the Schedule")
230					}
231
232					memory_limits = Some((initial, maximum));
233					continue
234				},
235			}
236		}
237
238		memory_limits.ok_or("No memory import found in the module")
239	}
240}
241
242/// Check that given `code` satisfies constraints required for the contract Wasm module.
243/// This includes two groups of checks:
244///
245/// 1. General engine-side validation makes sure the module is consistent and does not contain
246///    forbidden WebAssembly features.
247/// 2. Additional checks which are specific to smart contracts eligible for this pallet.
248fn validate<E, T>(
249	code: &[u8],
250	schedule: &Schedule<T>,
251	determinism: &mut Determinism,
252) -> Result<(), (DispatchError, &'static str)>
253where
254	E: Environment<()>,
255	T: Config,
256{
257	let module = (|| {
258		// We don't actually ever execute this instance so we can get away with a minimal stack
259		// which reduces the amount of memory that needs to be zeroed.
260		let stack_limits = Some(StackLimits::new(1, 1, 0).expect("initial <= max; qed"));
261
262		// We check that the module is generally valid,
263		// and does not have restricted WebAssembly features, here.
264		let contract_module = match *determinism {
265			Determinism::Relaxed =>
266				if let Ok(module) = LoadedModule::new::<T>(
267					code,
268					Determinism::Enforced,
269					stack_limits,
270					LoadingMode::Checked,
271					CompilationMode::Eager,
272				) {
273					*determinism = Determinism::Enforced;
274					module
275				} else {
276					LoadedModule::new::<T>(
277						code,
278						Determinism::Relaxed,
279						None,
280						LoadingMode::Checked,
281						CompilationMode::Eager,
282					)?
283				},
284			Determinism::Enforced => LoadedModule::new::<T>(
285				code,
286				Determinism::Enforced,
287				stack_limits,
288				LoadingMode::Checked,
289				CompilationMode::Eager,
290			)?,
291		};
292
293		// The we check that module satisfies constraints the pallet puts on contracts.
294		contract_module.scan_exports()?;
295		contract_module.scan_imports::<T>(schedule)?;
296		Ok(contract_module)
297	})()
298	.map_err(|msg: &str| {
299		log::debug!(target: LOG_TARGET, "New code rejected on validation: {}", msg);
300		(Error::<T>::CodeRejected.into(), msg)
301	})?;
302
303	// This will make sure that the module can be actually run within wasmi:
304	//
305	// - It doesn't use any unknown imports.
306	// - It doesn't explode the wasmi bytecode generation.
307	WasmBlob::<T>::instantiate::<E, _>(module, (), schedule, AllowDeprecatedInterface::No)
308		.map_err(|err| {
309			log::debug!(target: LOG_TARGET, "{err}");
310			(Error::<T>::CodeRejected.into(), "New code rejected on wasmi instantiation!")
311		})?;
312
313	Ok(())
314}
315
316/// Validates the given binary `code` is a valid Wasm module satisfying following constraints:
317///
318/// - The module doesn't export any memory.
319/// - The module does imports memory, which limits lay within the limits permitted by the
320///   `schedule`.
321/// - All imported functions from the external environment match defined by `env` module.
322///
323/// Also constructs contract `code_info` by calculating the storage deposit.
324pub fn prepare<E, T>(
325	code: CodeVec<T>,
326	schedule: &Schedule<T>,
327	owner: AccountIdOf<T>,
328	mut determinism: Determinism,
329) -> Result<WasmBlob<T>, (DispatchError, &'static str)>
330where
331	E: Environment<()>,
332	T: Config,
333{
334	validate::<E, T>(code.as_ref(), schedule, &mut determinism)?;
335
336	// Calculate deposit for storing contract code and `code_info` in two different storage items.
337	let code_len = code.len() as u32;
338	let bytes_added = code_len.saturating_add(<CodeInfo<T>>::max_encoded_len() as u32);
339	let deposit = Diff { bytes_added, items_added: 2, ..Default::default() }
340		.update_contract::<T>(None)
341		.charge_or_zero();
342	let code_info = CodeInfo { owner, deposit, determinism, refcount: 0, code_len };
343	let code_hash = T::Hashing::hash(&code);
344
345	Ok(WasmBlob { code, code_info, code_hash })
346}
347
348/// Alternate (possibly unsafe) preparation functions used only for benchmarking and testing.
349///
350/// For benchmarking we need to construct special contracts that might not pass our
351/// sanity checks. We hide functions allowing this behind a feature that is only set during
352/// benchmarking or testing to prevent usage in production code.
353#[cfg(any(test, feature = "runtime-benchmarks"))]
354pub mod benchmarking {
355	use super::*;
356
357	/// Prepare function that does not perform export section checks on the passed in code.
358	pub fn prepare<T: Config>(
359		code: Vec<u8>,
360		schedule: &Schedule<T>,
361		owner: AccountIdOf<T>,
362	) -> Result<WasmBlob<T>, DispatchError> {
363		let determinism = Determinism::Enforced;
364		let contract_module = LoadedModule::new::<T>(
365			&code,
366			determinism,
367			None,
368			LoadingMode::Checked,
369			CompilationMode::Eager,
370		)?;
371		contract_module.scan_imports::<T>(schedule)?;
372		let code: CodeVec<T> = code.try_into().map_err(|_| <Error<T>>::CodeTooLarge)?;
373		let code_info = CodeInfo {
374			owner,
375			// this is a helper function for benchmarking which skips deposit collection
376			deposit: Default::default(),
377			refcount: 0,
378			code_len: code.len() as u32,
379			determinism,
380		};
381		let code_hash = T::Hashing::hash(&code);
382
383		Ok(WasmBlob { code, code_info, code_hash })
384	}
385}
386
387#[cfg(test)]
388mod tests {
389	use super::*;
390	use crate::{
391		exec::Ext,
392		schedule::Limits,
393		tests::{Test, ALICE},
394	};
395	use pallet_contracts_proc_macro::define_env;
396	use std::fmt;
397
398	impl fmt::Debug for WasmBlob<Test> {
399		fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400			write!(f, "ContractCode {{ .. }}")
401		}
402	}
403
404	/// Using unreachable statements triggers unreachable warnings in the generated code
405	#[allow(unreachable_code)]
406	mod env {
407		use super::*;
408		use crate::wasm::runtime::{AllowDeprecatedInterface, AllowUnstableInterface, TrapReason};
409
410		// Define test environment for tests. We need ImportSatisfyCheck
411		// implementation from it. So actual implementations doesn't matter.
412		#[define_env]
413		pub mod test_env {
414			fn panic(_ctx: _, _memory: _) -> Result<(), TrapReason> {
415				Ok(())
416			}
417
418			// gas is an implementation defined function and a contract can't import it.
419			fn gas(_ctx: _, _memory: _, _amount: u64) -> Result<(), TrapReason> {
420				Ok(())
421			}
422
423			fn nop(_ctx: _, _memory: _, _unused: u64) -> Result<(), TrapReason> {
424				Ok(())
425			}
426
427			// new version of nop with other data type for argument
428			#[version(1)]
429			fn nop(_ctx: _, _memory: _, _unused: i32) -> Result<(), TrapReason> {
430				Ok(())
431			}
432		}
433	}
434
435	macro_rules! prepare_test {
436		($name:ident, $wat:expr, $($expected:tt)*) => {
437			#[test]
438			fn $name() {
439				let wasm = wat::parse_str($wat).unwrap().try_into().unwrap();
440				let schedule = Schedule {
441					limits: Limits {
442						memory_pages: 16,
443						.. Default::default()
444					},
445					.. Default::default()
446				};
447				let r = prepare::<env::Env, Test>(
448					wasm,
449					&schedule,
450					ALICE,
451					Determinism::Enforced,
452				);
453				assert_matches::assert_matches!(r.map_err(|(_, msg)| msg), $($expected)*);
454			}
455		};
456	}
457
458	prepare_test!(
459		no_floats,
460		r#"
461		(module
462			(func (export "call")
463				(drop
464					(f32.add
465						(f32.const 0)
466						(f32.const 1)
467					)
468				)
469			)
470			(func (export "deploy"))
471		)"#,
472		Err("Can't load the module into wasmi!")
473	);
474
475	mod memories {
476		use super::*;
477
478		prepare_test!(
479			memory_with_one_page,
480			r#"
481			(module
482				(import "env" "memory" (memory 1 1))
483
484				(func (export "call"))
485				(func (export "deploy"))
486			)
487			"#,
488			Ok(_)
489		);
490
491		prepare_test!(
492			internal_memory_declaration,
493			r#"
494			(module
495				(memory 1 1)
496
497				(func (export "call"))
498				(func (export "deploy"))
499			)
500			"#,
501			Err("No memory import found in the module")
502		);
503
504		prepare_test!(
505			no_memory_import,
506			r#"
507			(module
508				;; no memory imported
509
510				(func (export "call"))
511				(func (export "deploy"))
512			)"#,
513			Err("No memory import found in the module")
514		);
515
516		prepare_test!(
517			initial_exceeds_maximum,
518			r#"
519			(module
520				(import "env" "memory" (memory 16 1))
521
522				(func (export "call"))
523				(func (export "deploy"))
524			)
525			"#,
526			Err("Can't load the module into wasmi!")
527		);
528
529		prepare_test!(
530			requested_maximum_valid,
531			r#"
532			(module
533				(import "env" "memory" (memory 1 16))
534
535				(func (export "call"))
536				(func (export "deploy"))
537			)
538			"#,
539			Ok(_)
540		);
541
542		prepare_test!(
543			requested_maximum_exceeds_configured_maximum,
544			r#"
545			(module
546				(import "env" "memory" (memory 1 17))
547
548				(func (export "call"))
549				(func (export "deploy"))
550			)
551			"#,
552			Err("Maximum number of memory pages should not exceed the maximum configured in the Schedule")
553		);
554
555		prepare_test!(
556			field_name_not_memory,
557			r#"
558			(module
559				(import "env" "forgetit" (memory 1 1))
560
561				(func (export "call"))
562				(func (export "deploy"))
563			)
564			"#,
565			Err("Memory import must have the field name 'memory'")
566		);
567
568		prepare_test!(
569			multiple_memory_imports,
570			r#"
571			(module
572				(import "env" "memory" (memory 1 1))
573				(import "env" "memory" (memory 1 1))
574
575				(func (export "call"))
576				(func (export "deploy"))
577			)
578			"#,
579			Err("Can't load the module into wasmi!")
580		);
581
582		prepare_test!(
583			table_import,
584			r#"
585			(module
586				(import "seal0" "table" (table 1 anyfunc))
587
588				(func (export "call"))
589				(func (export "deploy"))
590			)
591			"#,
592			Err("Cannot import tables")
593		);
594
595		prepare_test!(
596			global_import,
597			r#"
598			(module
599				(global $g (import "seal0" "global") i32)
600				(func (export "call"))
601				(func (export "deploy"))
602			)
603			"#,
604			Err("Cannot import globals")
605		);
606	}
607
608	mod imports {
609		use super::*;
610
611		prepare_test!(
612			can_import_legit_function,
613			r#"
614			(module
615				(import "seal0" "nop" (func (param i64)))
616				(import "env" "memory" (memory 1 1))
617
618				(func (export "call"))
619				(func (export "deploy"))
620			)
621			"#,
622			Ok(_)
623		);
624
625		// memory is in "env" and not in "seal0"
626		prepare_test!(
627			memory_not_in_seal0,
628			r#"
629			(module
630				(import "seal0" "memory" (memory 1 1))
631
632				(func (export "call"))
633				(func (export "deploy"))
634			)
635			"#,
636			Err("Invalid module for imported memory")
637		);
638
639		// Memory is in "env" and not in some arbitrary module
640		prepare_test!(
641			memory_not_in_arbitrary_module,
642			r#"
643			(module
644				(import "any_module" "memory" (memory 1 1))
645
646				(func (export "call"))
647				(func (export "deploy"))
648			)
649			"#,
650			Err("Invalid module for imported memory")
651		);
652
653		prepare_test!(
654			function_in_other_module_works,
655			r#"
656			(module
657				(import "seal1" "nop" (func (param i32)))
658				(import "env" "memory" (memory 1 1))
659
660
661				(func (export "call"))
662				(func (export "deploy"))
663			)
664			"#,
665			Ok(_)
666		);
667
668		prepare_test!(
669			wrong_signature,
670			r#"
671			(module
672				(import "seal0" "input" (func (param i64)))
673				(import "env" "memory" (memory 1 1))
674
675				(func (export "call"))
676				(func (export "deploy"))
677			)
678			"#,
679			Err("New code rejected on wasmi instantiation!")
680		);
681
682		prepare_test!(
683			unknown_func_name,
684			r#"
685			(module
686				(import "seal0" "unknown_func" (func))
687
688				(func (export "call"))
689				(func (export "deploy"))
690			)
691			"#,
692			Err("No memory import found in the module")
693		);
694
695		// Try to import function from not a "seal*" module.
696		prepare_test!(
697			try_import_from_wrong_module,
698			r#"
699			(module
700				(import "env" "panic" (func))
701				(import "env" "memory" (memory 1 1))
702
703				(func (export "call"))
704				(func (export "deploy"))
705			)
706			"#,
707			Err("New code rejected on wasmi instantiation!")
708		);
709	}
710
711	mod entrypoints {
712		use super::*;
713
714		prepare_test!(
715			it_works,
716			r#"
717			(module
718				(import "env" "memory" (memory 1 1))
719				(func (export "call"))
720				(func (export "deploy"))
721			)
722			"#,
723			Ok(_)
724		);
725
726		prepare_test!(
727			signed_extension_works,
728			r#"
729			(module
730				(import "env" "memory" (memory 1 1))
731				(func (export "deploy"))
732				(func (export "call"))
733				(func (param i32) (result i32)
734					local.get 0
735					i32.extend8_s
736				)
737			)
738			"#,
739			Ok(_)
740		);
741
742		prepare_test!(
743			omit_memory,
744			r#"
745			(module
746				(func (export "call"))
747				(func (export "deploy"))
748			)
749			"#,
750			Err("No memory import found in the module")
751		);
752
753		prepare_test!(
754			omit_deploy,
755			r#"
756			(module
757				(func (export "call"))
758			)
759			"#,
760			Err("deploy function isn't exported")
761		);
762
763		prepare_test!(
764			omit_call,
765			r#"
766			(module
767				(func (export "deploy"))
768			)
769			"#,
770			Err("call function isn't exported")
771		);
772
773		// Try to use imported function as an entry point.
774		// This is allowed.
775		prepare_test!(
776			try_sneak_export_as_entrypoint,
777			r#"
778			(module
779				(import "seal0" "panic" (func))
780				(import "env" "memory" (memory 1 1))
781
782				(func (export "deploy"))
783
784				(export "call" (func 0))
785			)
786			"#,
787			Ok(_)
788		);
789
790		// Try to use global as an entry point.
791		prepare_test!(
792			try_sneak_export_as_global,
793			r#"
794			(module
795				(func (export "deploy"))
796				(global (export "call") i32 (i32.const 0))
797			)
798			"#,
799			Err("global export is forbidden")
800		);
801
802		prepare_test!(
803			wrong_signature,
804			r#"
805			(module
806				(func (export "deploy"))
807				(func (export "call") (param i32))
808			)
809			"#,
810			Err("entry point has wrong signature")
811		);
812
813		prepare_test!(
814			unknown_exports,
815			r#"
816			(module
817				(func (export "call"))
818				(func (export "deploy"))
819				(func (export "whatevs"))
820			)
821			"#,
822			Err("unknown function export: expecting only deploy and call functions")
823		);
824
825		prepare_test!(
826			global_float,
827			r#"
828			(module
829				(global $x f32 (f32.const 0))
830				(func (export "call"))
831				(func (export "deploy"))
832			)
833			"#,
834			Err("Can't load the module into wasmi!")
835		);
836
837		prepare_test!(
838			local_float,
839			r#"
840			(module
841				(func $foo (local f32))
842				(func (export "call"))
843				(func (export "deploy"))
844			)
845			"#,
846			Err("Can't load the module into wasmi!")
847		);
848
849		prepare_test!(
850			param_float,
851			r#"
852			(module
853				(func $foo (param f32))
854				(func (export "call"))
855				(func (export "deploy"))
856			)
857			"#,
858			Err("Can't load the module into wasmi!")
859		);
860
861		prepare_test!(
862			result_float,
863			r#"
864			(module
865				(func $foo (result f32) (f32.const 0))
866				(func (export "call"))
867				(func (export "deploy"))
868			)
869			"#,
870			Err("Can't load the module into wasmi!")
871		);
872	}
873}