referrerpolicy=no-referrer-when-downgrade

pallet_contracts/wasm/
mod.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 provides a means for executing contracts
19//! represented in wasm.
20
21mod prepare;
22mod runtime;
23
24#[cfg(doc)]
25pub use crate::wasm::runtime::api_doc;
26
27#[cfg(test)]
28pub use {
29	crate::wasm::{prepare::tracker, runtime::ReturnErrorCode},
30	runtime::STABLE_API_COUNT,
31	tests::MockExt,
32};
33
34#[cfg(feature = "runtime-benchmarks")]
35pub use crate::wasm::runtime::{BenchEnv, ReturnData, TrapReason};
36
37pub use crate::wasm::{
38	prepare::{LoadedModule, LoadingMode},
39	runtime::{
40		AllowDeprecatedInterface, AllowUnstableInterface, Environment, Runtime, RuntimeCosts,
41	},
42};
43
44use crate::{
45	exec::{ExecResult, Executable, ExportedFunction, Ext},
46	gas::{GasMeter, Token},
47	weights::WeightInfo,
48	AccountIdOf, BadOrigin, BalanceOf, CodeHash, CodeInfoOf, CodeVec, Config, Error, Event,
49	HoldReason, Pallet, PristineCode, Schedule, Weight, LOG_TARGET,
50};
51use alloc::vec::Vec;
52use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
53use frame_support::{
54	dispatch::DispatchResult,
55	ensure,
56	traits::{fungible::MutateHold, tokens::Precision::BestEffort},
57};
58use sp_core::Get;
59use sp_runtime::{DispatchError, RuntimeDebug};
60use wasmi::{CompilationMode, InstancePre, Linker, Memory, MemoryType, StackLimits, Store};
61
62const BYTES_PER_PAGE: usize = 64 * 1024;
63
64/// Validated Wasm module ready for execution.
65/// This data structure is immutable once created and stored.
66#[derive(Encode, Decode, scale_info::TypeInfo)]
67#[codec(mel_bound())]
68#[scale_info(skip_type_params(T))]
69pub struct WasmBlob<T: Config> {
70	code: CodeVec<T>,
71	// This isn't needed for contract execution and is not stored alongside it.
72	#[codec(skip)]
73	code_info: CodeInfo<T>,
74	// This is for not calculating the hash every time we need it.
75	#[codec(skip)]
76	code_hash: CodeHash<T>,
77}
78
79/// Contract code related data, such as:
80///
81/// - owner of the contract, i.e. account uploaded its code,
82/// - storage deposit amount,
83/// - reference count,
84/// - determinism marker.
85///
86/// It is stored in a separate storage entry to avoid loading the code when not necessary.
87#[derive(Clone, Encode, Decode, scale_info::TypeInfo, MaxEncodedLen)]
88#[codec(mel_bound())]
89#[scale_info(skip_type_params(T))]
90pub struct CodeInfo<T: Config> {
91	/// The account that has uploaded the contract code and hence is allowed to remove it.
92	owner: AccountIdOf<T>,
93	/// The amount of balance that was deposited by the owner in order to store it on-chain.
94	#[codec(compact)]
95	deposit: BalanceOf<T>,
96	/// The number of instantiated contracts that use this as their code.
97	#[codec(compact)]
98	refcount: u64,
99	/// Marks if the code might contain non-deterministic features and is therefore never allowed
100	/// to be run on-chain. Specifically, such a code can never be instantiated into a contract
101	/// and can just be used through a delegate call.
102	determinism: Determinism,
103	/// length of the code in bytes.
104	code_len: u32,
105}
106
107/// Defines the required determinism level of a wasm blob when either running or uploading code.
108#[derive(
109	Clone,
110	Copy,
111	Encode,
112	Decode,
113	DecodeWithMemTracking,
114	scale_info::TypeInfo,
115	MaxEncodedLen,
116	RuntimeDebug,
117	PartialEq,
118	Eq,
119)]
120pub enum Determinism {
121	/// The execution should be deterministic and hence no indeterministic instructions are
122	/// allowed.
123	///
124	/// Dispatchables always use this mode in order to make on-chain execution deterministic.
125	Enforced,
126	/// Allow calling or uploading an indeterministic code.
127	///
128	/// This is only possible when calling into `pallet-contracts` directly via
129	/// [`crate::Pallet::bare_call`].
130	///
131	/// # Note
132	///
133	/// **Never** use this mode for on-chain execution.
134	Relaxed,
135}
136
137impl ExportedFunction {
138	/// The wasm export name for the function.
139	fn identifier(&self) -> &str {
140		match self {
141			Self::Constructor => "deploy",
142			Self::Call => "call",
143		}
144	}
145}
146
147/// Cost of code loading from storage.
148#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
149#[derive(Clone, Copy)]
150struct CodeLoadToken(u32);
151
152impl<T: Config> Token<T> for CodeLoadToken {
153	fn weight(&self) -> Weight {
154		T::WeightInfo::call_with_code_per_byte(self.0)
155			.saturating_sub(T::WeightInfo::call_with_code_per_byte(0))
156	}
157}
158
159impl<T: Config> WasmBlob<T> {
160	/// Create the module by checking the `code`.
161	pub fn from_code(
162		code: Vec<u8>,
163		schedule: &Schedule<T>,
164		owner: AccountIdOf<T>,
165		determinism: Determinism,
166	) -> Result<Self, (DispatchError, &'static str)> {
167		prepare::prepare::<runtime::Env, T>(
168			code.try_into().map_err(|_| (<Error<T>>::CodeTooLarge.into(), ""))?,
169			schedule,
170			owner,
171			determinism,
172		)
173	}
174
175	/// Remove the code from storage and refund the deposit to its owner.
176	///
177	/// Applies all necessary checks before removing the code.
178	pub fn remove(origin: &T::AccountId, code_hash: CodeHash<T>) -> DispatchResult {
179		<CodeInfoOf<T>>::try_mutate_exists(&code_hash, |existing| {
180			if let Some(code_info) = existing {
181				ensure!(code_info.refcount == 0, <Error<T>>::CodeInUse);
182				ensure!(&code_info.owner == origin, BadOrigin);
183				let _ = T::Currency::release(
184					&HoldReason::CodeUploadDepositReserve.into(),
185					&code_info.owner,
186					code_info.deposit,
187					BestEffort,
188				);
189				let deposit_released = code_info.deposit;
190				let remover = code_info.owner.clone();
191
192				*existing = None;
193				<PristineCode<T>>::remove(&code_hash);
194				<Pallet<T>>::deposit_event(Event::CodeRemoved {
195					code_hash,
196					deposit_released,
197					remover,
198				});
199				Ok(())
200			} else {
201				Err(<Error<T>>::CodeNotFound.into())
202			}
203		})
204	}
205
206	/// Creates and returns an instance of the supplied code.
207	///
208	/// This is either used for later executing a contract or for validation of a contract.
209	/// When validating we pass `()` as `host_state`. Please note that such a dummy instance must
210	/// **never** be called/executed, since it will panic the executor.
211	pub fn instantiate<E, H>(
212		contract: LoadedModule,
213		host_state: H,
214		schedule: &Schedule<T>,
215		allow_deprecated: AllowDeprecatedInterface,
216	) -> Result<(Store<H>, Memory, InstancePre), &'static str>
217	where
218		E: Environment<H>,
219	{
220		let mut store = Store::new(&contract.engine, host_state);
221		let mut linker = Linker::new(&contract.engine);
222		E::define(
223			&mut store,
224			&mut linker,
225			if T::UnsafeUnstableInterface::get() {
226				AllowUnstableInterface::Yes
227			} else {
228				AllowUnstableInterface::No
229			},
230			allow_deprecated,
231		)
232		.map_err(|_| "can't define host functions to Linker")?;
233
234		// Query wasmi for memory limits specified in the module's import entry.
235		let memory_limits = contract.scan_imports::<T>(schedule)?;
236		// Here we allocate this memory in the _store_. It allocates _inital_ value, but allows it
237		// to grow up to maximum number of memory pages, if necessary.
238		let qed = "We checked the limits versus our Schedule,
239					 which specifies the max amount of memory pages
240					 well below u16::MAX; qed";
241		let memory = Memory::new(
242			&mut store,
243			MemoryType::new(memory_limits.0, Some(memory_limits.1)).expect(qed),
244		)
245		.expect(qed);
246
247		linker
248			.define("env", "memory", memory)
249			.expect("We just created the Linker. It has no definitions with this name; qed");
250
251		let instance = linker.instantiate(&mut store, &contract.module).map_err(|err| {
252			log::debug!(target: LOG_TARGET, "failed to instantiate module: {:?}", err);
253			"can't instantiate module with provided definitions"
254		})?;
255
256		Ok((store, memory, instance))
257	}
258
259	/// Puts the module blob into storage, and returns the deposit collected for the storage.
260	pub fn store_code(&mut self) -> Result<BalanceOf<T>, Error<T>> {
261		let code_hash = *self.code_hash();
262		<CodeInfoOf<T>>::mutate(code_hash, |stored_code_info| {
263			match stored_code_info {
264				// Contract code is already stored in storage. Nothing to be done here.
265				Some(_) => Ok(Default::default()),
266				// Upload a new contract code.
267				// We need to store the code and its code_info, and collect the deposit.
268				// This `None` case happens only with freshly uploaded modules. This means that
269				// the `owner` is always the origin of the current transaction.
270				None => {
271					let deposit = self.code_info.deposit;
272					T::Currency::hold(
273						&HoldReason::CodeUploadDepositReserve.into(),
274						&self.code_info.owner,
275						deposit,
276					)
277					.map_err(|_| <Error<T>>::StorageDepositNotEnoughFunds)?;
278
279					self.code_info.refcount = 0;
280					<PristineCode<T>>::insert(code_hash, &self.code);
281					*stored_code_info = Some(self.code_info.clone());
282					<Pallet<T>>::deposit_event(Event::CodeStored {
283						code_hash,
284						deposit_held: deposit,
285						uploader: self.code_info.owner.clone(),
286					});
287					Ok(deposit)
288				},
289			}
290		})
291	}
292
293	/// Create the module without checking the passed code.
294	///
295	/// # Note
296	///
297	/// This is useful for benchmarking where we don't want validation of the module to skew
298	/// our results. This also does not collect any deposit from the `owner`. Also useful
299	/// during testing when we want to deploy codes that do not pass the instantiation checks.
300	#[cfg(any(test, feature = "runtime-benchmarks"))]
301	pub fn from_code_unchecked(
302		code: Vec<u8>,
303		schedule: &Schedule<T>,
304		owner: T::AccountId,
305	) -> Result<Self, DispatchError> {
306		prepare::benchmarking::prepare(code, schedule, owner)
307	}
308}
309
310impl<T: Config> CodeInfo<T> {
311	#[cfg(test)]
312	pub fn new(owner: T::AccountId) -> Self {
313		CodeInfo {
314			owner,
315			deposit: Default::default(),
316			refcount: 0,
317			code_len: 0,
318			determinism: Determinism::Enforced,
319		}
320	}
321
322	/// Returns the determinism of the module.
323	pub fn determinism(&self) -> Determinism {
324		self.determinism
325	}
326
327	/// Returns reference count of the module.
328	pub fn refcount(&self) -> u64 {
329		self.refcount
330	}
331
332	/// Return mutable reference to the refcount of the module.
333	pub fn refcount_mut(&mut self) -> &mut u64 {
334		&mut self.refcount
335	}
336
337	/// Returns the deposit of the module.
338	pub fn deposit(&self) -> BalanceOf<T> {
339		self.deposit
340	}
341}
342
343use crate::{ExecError, ExecReturnValue};
344use wasmi::Func;
345enum InstanceOrExecReturn<'a, E: Ext> {
346	Instance((Func, Store<Runtime<'a, E>>)),
347	ExecReturn(ExecReturnValue),
348}
349
350type PreExecResult<'a, E> = Result<InstanceOrExecReturn<'a, E>, ExecError>;
351
352impl<T: Config> WasmBlob<T> {
353	/// Sync the frame's gas meter with the engine's one.
354	pub fn process_result<E: Ext<T = T>>(
355		mut store: Store<Runtime<E>>,
356		result: Result<(), wasmi::Error>,
357	) -> ExecResult {
358		let engine_fuel = store.get_fuel().expect("Fuel metering is enabled; qed");
359		let gas_meter = store.data_mut().ext().gas_meter_mut();
360		let _ = gas_meter.sync_from_executor(engine_fuel)?;
361		store.into_data().to_execution_result(result)
362	}
363
364	#[cfg(feature = "runtime-benchmarks")]
365	pub fn bench_prepare_call<E: Ext<T = T>>(
366		self,
367		ext: &mut E,
368		input_data: Vec<u8>,
369	) -> (Func, Store<Runtime<E>>) {
370		use InstanceOrExecReturn::*;
371		match Self::prepare_execute(
372			self,
373			Runtime::new(ext, input_data),
374			&ExportedFunction::Call,
375			CompilationMode::Eager,
376		)
377		.expect("Benchmark should provide valid module")
378		{
379			Instance((func, store)) => (func, store),
380			ExecReturn(_) => panic!("Expected Instance"),
381		}
382	}
383
384	fn prepare_execute<'a, E: Ext<T = T>>(
385		self,
386		runtime: Runtime<'a, E>,
387		function: &'a ExportedFunction,
388		compilation_mode: CompilationMode,
389	) -> PreExecResult<'a, E> {
390		let code = self.code.as_slice();
391		// Instantiate the Wasm module to the engine.
392		let schedule = <T>::Schedule::get();
393
394		let contract = LoadedModule::new::<T>(
395			&code,
396			self.code_info.determinism,
397			Some(StackLimits::default()),
398			LoadingMode::Unchecked,
399			compilation_mode,
400		)
401		.map_err(|err| {
402			log::debug!(target: LOG_TARGET, "failed to create wasmi module: {err:?}");
403			Error::<T>::CodeRejected
404		})?;
405
406		let (mut store, memory, instance) = Self::instantiate::<crate::wasm::runtime::Env, _>(
407			contract,
408			runtime,
409			&schedule,
410			match function {
411				ExportedFunction::Call => AllowDeprecatedInterface::Yes,
412				ExportedFunction::Constructor => AllowDeprecatedInterface::No,
413			},
414		)
415		.map_err(|msg| {
416			log::debug!(target: LOG_TARGET, "failed to instantiate code to wasmi: {}", msg);
417			Error::<T>::CodeRejected
418		})?;
419		store.data_mut().set_memory(memory);
420
421		// Set fuel limit for the wasmi execution.
422		// We normalize it by the base instruction weight, as its cost in wasmi engine is `1`.
423		let fuel_limit = store
424			.data_mut()
425			.ext()
426			.gas_meter_mut()
427			.gas_left()
428			.ref_time()
429			.checked_div(T::Schedule::get().ref_time_by_fuel())
430			.ok_or(Error::<T>::InvalidSchedule)?;
431		store
432			.set_fuel(fuel_limit)
433			.expect("We've set up engine to fuel consuming mode; qed");
434
435		// Start function should already see the correct refcount in case it will be ever inspected.
436		if let &ExportedFunction::Constructor = function {
437			E::increment_refcount(self.code_hash)?;
438		}
439
440		// Any abort in start function (includes `return` + `terminate`) will make us skip the
441		// call into the subsequent exported function. This means that calling `return` returns data
442		// from the whole contract execution.
443		match instance.start(&mut store) {
444			Ok(instance) => {
445				let exported_func = instance
446					.get_export(&store, function.identifier())
447					.and_then(|export| export.into_func())
448					.ok_or_else(|| {
449						log::error!(target: LOG_TARGET, "failed to find entry point");
450						Error::<T>::CodeRejected
451					})?;
452
453				Ok(InstanceOrExecReturn::Instance((exported_func, store)))
454			},
455			Err(err) => Self::process_result(store, Err(err)).map(InstanceOrExecReturn::ExecReturn),
456		}
457	}
458}
459
460impl<T: Config> Executable<T> for WasmBlob<T> {
461	fn from_storage(
462		code_hash: CodeHash<T>,
463		gas_meter: &mut GasMeter<T>,
464	) -> Result<Self, DispatchError> {
465		let code_info = <CodeInfoOf<T>>::get(code_hash).ok_or(Error::<T>::CodeNotFound)?;
466		gas_meter.charge(CodeLoadToken(code_info.code_len))?;
467		let code = <PristineCode<T>>::get(code_hash).ok_or(Error::<T>::CodeNotFound)?;
468		Ok(Self { code, code_info, code_hash })
469	}
470
471	fn execute<E: Ext<T = T>>(
472		self,
473		ext: &mut E,
474		function: &ExportedFunction,
475		input_data: Vec<u8>,
476	) -> ExecResult {
477		use InstanceOrExecReturn::*;
478		match Self::prepare_execute(
479			self,
480			Runtime::new(ext, input_data),
481			function,
482			CompilationMode::Lazy,
483		)? {
484			Instance((func, mut store)) => {
485				let result = func.call(&mut store, &[], &mut []);
486				Self::process_result(store, result)
487			},
488			ExecReturn(exec_return) => Ok(exec_return),
489		}
490	}
491
492	fn code_hash(&self) -> &CodeHash<T> {
493		&self.code_hash
494	}
495
496	fn code_info(&self) -> &CodeInfo<T> {
497		&self.code_info
498	}
499
500	fn is_deterministic(&self) -> bool {
501		matches!(self.code_info.determinism, Determinism::Enforced)
502	}
503}
504
505#[cfg(test)]
506mod tests {
507	use super::*;
508	use crate::{
509		exec::{AccountIdOf, ErrorOrigin, ExecError, Executable, Ext, Key, SeedOf},
510		gas::GasMeter,
511		primitives::ExecReturnValue,
512		storage::WriteOutcome,
513		tests::{RuntimeCall, Test, ALICE, BOB},
514		transient_storage::TransientStorage,
515		BalanceOf, CodeHash, Error, Origin, Pallet as Contracts,
516	};
517	use assert_matches::assert_matches;
518	use frame_support::{
519		assert_err, assert_ok, dispatch::DispatchResultWithPostInfo, weights::Weight,
520	};
521	use frame_system::pallet_prelude::BlockNumberFor;
522	use pallet_contracts_uapi::ReturnFlags;
523	use pretty_assertions::assert_eq;
524	use sp_core::H256;
525	use sp_runtime::DispatchError;
526	use std::{
527		borrow::BorrowMut,
528		cell::RefCell,
529		collections::{
530			hash_map::{Entry, HashMap},
531			HashSet,
532		},
533	};
534
535	#[derive(Debug, PartialEq, Eq)]
536	struct InstantiateEntry {
537		code_hash: H256,
538		value: u64,
539		data: Vec<u8>,
540		gas_left: u64,
541		salt: Vec<u8>,
542	}
543
544	#[derive(Debug, PartialEq, Eq)]
545	struct TerminationEntry {
546		beneficiary: AccountIdOf<Test>,
547	}
548
549	#[derive(Debug, PartialEq, Eq)]
550	struct TransferEntry {
551		to: AccountIdOf<Test>,
552		value: u64,
553	}
554
555	#[derive(Debug, PartialEq, Eq)]
556	struct CallEntry {
557		to: AccountIdOf<Test>,
558		value: u64,
559		data: Vec<u8>,
560		allows_reentry: bool,
561		read_only: bool,
562	}
563
564	#[derive(Debug, PartialEq, Eq)]
565	struct CallCodeEntry {
566		code_hash: H256,
567		data: Vec<u8>,
568	}
569
570	pub struct MockExt {
571		storage: HashMap<Vec<u8>, Vec<u8>>,
572		transient_storage: TransientStorage<Test>,
573		instantiates: Vec<InstantiateEntry>,
574		terminations: Vec<TerminationEntry>,
575		calls: Vec<CallEntry>,
576		code_calls: Vec<CallCodeEntry>,
577		transfers: Vec<TransferEntry>,
578		// (topics, data)
579		events: Vec<(Vec<H256>, Vec<u8>)>,
580		runtime_calls: RefCell<Vec<RuntimeCall>>,
581		schedule: Schedule<Test>,
582		gas_meter: GasMeter<Test>,
583		debug_buffer: Vec<u8>,
584		ecdsa_recover: RefCell<Vec<([u8; 65], [u8; 32])>>,
585		sr25519_verify: RefCell<Vec<([u8; 64], Vec<u8>, [u8; 32])>>,
586		code_hashes: Vec<CodeHash<Test>>,
587		caller: Origin<Test>,
588		delegate_dependencies: RefCell<HashSet<CodeHash<Test>>>,
589	}
590
591	/// The call is mocked and just returns this hardcoded value.
592	fn call_return_data() -> Vec<u8> {
593		vec![0xDE, 0xAD, 0xBE, 0xEF]
594	}
595
596	impl Default for MockExt {
597		fn default() -> Self {
598			Self {
599				code_hashes: Default::default(),
600				storage: Default::default(),
601				transient_storage: TransientStorage::new(1024 * 1024),
602				instantiates: Default::default(),
603				terminations: Default::default(),
604				calls: Default::default(),
605				code_calls: Default::default(),
606				transfers: Default::default(),
607				events: Default::default(),
608				runtime_calls: Default::default(),
609				schedule: Default::default(),
610				gas_meter: GasMeter::new(Weight::from_parts(10_000_000_000, 10 * 1024 * 1024)),
611				debug_buffer: Default::default(),
612				ecdsa_recover: Default::default(),
613				caller: Default::default(),
614				sr25519_verify: Default::default(),
615				delegate_dependencies: Default::default(),
616			}
617		}
618	}
619
620	impl Ext for MockExt {
621		type T = Test;
622
623		fn call(
624			&mut self,
625			_gas_limit: Weight,
626			_deposit_limit: BalanceOf<Self::T>,
627			to: AccountIdOf<Self::T>,
628			value: u64,
629			data: Vec<u8>,
630			allows_reentry: bool,
631			read_only: bool,
632		) -> Result<ExecReturnValue, ExecError> {
633			self.calls.push(CallEntry { to, value, data, allows_reentry, read_only });
634			Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: call_return_data() })
635		}
636		fn delegate_call(
637			&mut self,
638			code_hash: CodeHash<Self::T>,
639			data: Vec<u8>,
640		) -> Result<ExecReturnValue, ExecError> {
641			self.code_calls.push(CallCodeEntry { code_hash, data });
642			Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: call_return_data() })
643		}
644		fn instantiate(
645			&mut self,
646			gas_limit: Weight,
647			_deposit_limit: BalanceOf<Self::T>,
648			code_hash: CodeHash<Test>,
649			value: u64,
650			data: Vec<u8>,
651			salt: &[u8],
652		) -> Result<(AccountIdOf<Self::T>, ExecReturnValue), ExecError> {
653			self.instantiates.push(InstantiateEntry {
654				code_hash,
655				value,
656				data: data.to_vec(),
657				gas_left: gas_limit.ref_time(),
658				salt: salt.to_vec(),
659			});
660			Ok((
661				Contracts::<Test>::contract_address(&ALICE, &code_hash, &data, salt),
662				ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() },
663			))
664		}
665		fn set_code_hash(&mut self, hash: CodeHash<Self::T>) -> DispatchResult {
666			self.code_hashes.push(hash);
667			Ok(())
668		}
669		fn transfer(&mut self, to: &AccountIdOf<Self::T>, value: u64) -> DispatchResult {
670			self.transfers.push(TransferEntry { to: to.clone(), value });
671			Ok(())
672		}
673		fn terminate(&mut self, beneficiary: &AccountIdOf<Self::T>) -> DispatchResult {
674			self.terminations.push(TerminationEntry { beneficiary: beneficiary.clone() });
675			Ok(())
676		}
677		fn get_storage(&mut self, key: &Key<Self::T>) -> Option<Vec<u8>> {
678			self.storage.get(&key.to_vec()).cloned()
679		}
680		fn get_storage_size(&mut self, key: &Key<Self::T>) -> Option<u32> {
681			self.storage.get(&key.to_vec()).map(|val| val.len() as u32)
682		}
683		fn set_storage(
684			&mut self,
685			key: &Key<Self::T>,
686			value: Option<Vec<u8>>,
687			take_old: bool,
688		) -> Result<WriteOutcome, DispatchError> {
689			let key = key.to_vec();
690			let entry = self.storage.entry(key.clone());
691			let result = match (entry, take_old) {
692				(Entry::Vacant(_), _) => WriteOutcome::New,
693				(Entry::Occupied(entry), false) =>
694					WriteOutcome::Overwritten(entry.remove().len() as u32),
695				(Entry::Occupied(entry), true) => WriteOutcome::Taken(entry.remove()),
696			};
697			if let Some(value) = value {
698				self.storage.insert(key, value);
699			}
700			Ok(result)
701		}
702		fn get_transient_storage(&self, key: &Key<Self::T>) -> Option<Vec<u8>> {
703			self.transient_storage.read(self.address(), key)
704		}
705		fn get_transient_storage_size(&self, key: &Key<Self::T>) -> Option<u32> {
706			self.transient_storage.read(self.address(), key).map(|value| value.len() as _)
707		}
708		fn set_transient_storage(
709			&mut self,
710			key: &Key<Self::T>,
711			value: Option<Vec<u8>>,
712			take_old: bool,
713		) -> Result<WriteOutcome, DispatchError> {
714			let account_id = self.address().clone();
715			self.transient_storage.write(&account_id, key, value, take_old)
716		}
717		fn caller(&self) -> Origin<Self::T> {
718			self.caller.clone()
719		}
720		fn is_contract(&self, _address: &AccountIdOf<Self::T>) -> bool {
721			true
722		}
723		fn code_hash(&self, _address: &AccountIdOf<Self::T>) -> Option<CodeHash<Self::T>> {
724			Some(H256::from_slice(&[0x11; 32]))
725		}
726		fn own_code_hash(&mut self) -> &CodeHash<Self::T> {
727			const HASH: H256 = H256::repeat_byte(0x10);
728			&HASH
729		}
730		fn caller_is_origin(&self) -> bool {
731			false
732		}
733		fn caller_is_root(&self) -> bool {
734			&self.caller == &Origin::Root
735		}
736		fn address(&self) -> &AccountIdOf<Self::T> {
737			&BOB
738		}
739		fn balance(&self) -> u64 {
740			228
741		}
742		fn value_transferred(&self) -> u64 {
743			1337
744		}
745		fn now(&self) -> &u64 {
746			&1111
747		}
748		fn minimum_balance(&self) -> u64 {
749			666
750		}
751		fn random(&self, subject: &[u8]) -> (SeedOf<Self::T>, BlockNumberFor<Self::T>) {
752			(H256::from_slice(subject), 42)
753		}
754		fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>) {
755			self.events.push((topics, data))
756		}
757		fn block_number(&self) -> u64 {
758			121
759		}
760		fn max_value_size(&self) -> u32 {
761			16_384
762		}
763		fn get_weight_price(&self, weight: Weight) -> BalanceOf<Self::T> {
764			BalanceOf::<Self::T>::from(1312_u32)
765				.saturating_mul(weight.ref_time().into())
766				.saturating_add(
767					BalanceOf::<Self::T>::from(103_u32).saturating_mul(weight.proof_size()),
768				)
769		}
770		fn schedule(&self) -> &Schedule<Self::T> {
771			&self.schedule
772		}
773		fn gas_meter(&self) -> &GasMeter<Self::T> {
774			&self.gas_meter
775		}
776		fn gas_meter_mut(&mut self) -> &mut GasMeter<Self::T> {
777			&mut self.gas_meter
778		}
779		fn charge_storage(&mut self, _diff: &crate::storage::meter::Diff) {}
780
781		fn debug_buffer_enabled(&self) -> bool {
782			true
783		}
784		fn append_debug_buffer(&mut self, msg: &str) -> bool {
785			self.debug_buffer.extend(msg.as_bytes());
786			true
787		}
788		fn call_runtime(
789			&self,
790			call: <Self::T as Config>::RuntimeCall,
791		) -> DispatchResultWithPostInfo {
792			self.runtime_calls.borrow_mut().push(call);
793			Ok(Default::default())
794		}
795		fn ecdsa_recover(
796			&self,
797			signature: &[u8; 65],
798			message_hash: &[u8; 32],
799		) -> Result<[u8; 33], ()> {
800			self.ecdsa_recover.borrow_mut().push((*signature, *message_hash));
801			Ok([3; 33])
802		}
803		fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool {
804			self.sr25519_verify.borrow_mut().push((*signature, message.to_vec(), *pub_key));
805			true
806		}
807		fn contract_info(&mut self) -> &mut crate::ContractInfo<Self::T> {
808			unimplemented!()
809		}
810		#[cfg(feature = "runtime-benchmarks")]
811		fn transient_storage(&mut self) -> &mut TransientStorage<Self::T> {
812			unimplemented!()
813		}
814		fn ecdsa_to_eth_address(&self, _pk: &[u8; 33]) -> Result<[u8; 20], ()> {
815			Ok([2u8; 20])
816		}
817		fn reentrance_count(&self) -> u32 {
818			12
819		}
820		fn account_reentrance_count(&self, _account_id: &AccountIdOf<Self::T>) -> u32 {
821			12
822		}
823		fn nonce(&mut self) -> u64 {
824			995
825		}
826		fn increment_refcount(_code_hash: CodeHash<Self::T>) -> DispatchResult {
827			Ok(())
828		}
829		fn decrement_refcount(_code_hash: CodeHash<Self::T>) {}
830		fn lock_delegate_dependency(&mut self, code: CodeHash<Self::T>) -> DispatchResult {
831			self.delegate_dependencies.borrow_mut().insert(code);
832			Ok(())
833		}
834		fn unlock_delegate_dependency(&mut self, code: &CodeHash<Self::T>) -> DispatchResult {
835			self.delegate_dependencies.borrow_mut().remove(code);
836			Ok(())
837		}
838
839		fn locked_delegate_dependencies_count(&mut self) -> usize {
840			self.delegate_dependencies.borrow().len()
841		}
842
843		fn is_read_only(&self) -> bool {
844			false
845		}
846	}
847
848	/// Execute the supplied code.
849	///
850	/// Not used directly but through the wrapper functions defined below.
851	fn execute_internal<E: BorrowMut<MockExt>>(
852		wat: &str,
853		input_data: Vec<u8>,
854		mut ext: E,
855		entry_point: &ExportedFunction,
856		unstable_interface: bool,
857		skip_checks: bool,
858	) -> ExecResult {
859		type RuntimeConfig = <MockExt as Ext>::T;
860		RuntimeConfig::set_unstable_interface(unstable_interface);
861		let wasm = wat::parse_str(wat).unwrap();
862		let executable = if skip_checks {
863			WasmBlob::<RuntimeConfig>::from_code_unchecked(
864				wasm,
865				ext.borrow_mut().schedule(),
866				ALICE,
867			)?
868		} else {
869			WasmBlob::<RuntimeConfig>::from_code(
870				wasm,
871				ext.borrow_mut().schedule(),
872				ALICE,
873				Determinism::Enforced,
874			)
875			.map_err(|err| err.0)?
876		};
877		executable.execute(ext.borrow_mut(), entry_point, input_data)
878	}
879
880	/// Execute the `call` function within the supplied code.
881	fn execute<E: BorrowMut<MockExt>>(wat: &str, input_data: Vec<u8>, ext: E) -> ExecResult {
882		execute_internal(wat, input_data, ext, &ExportedFunction::Call, true, false)
883	}
884
885	/// Execute the `deploy` function within the supplied code.
886	fn execute_instantiate<E: BorrowMut<MockExt>>(
887		wat: &str,
888		input_data: Vec<u8>,
889		ext: E,
890	) -> ExecResult {
891		execute_internal(wat, input_data, ext, &ExportedFunction::Constructor, true, false)
892	}
893
894	/// Execute the supplied code with disabled unstable functions.
895	///
896	/// In our test config unstable functions are disabled so that we can test them.
897	/// In order to test that code using them is properly rejected we temporarily disable
898	/// them when this test is run.
899	#[cfg(not(feature = "runtime-benchmarks"))]
900	fn execute_no_unstable<E: BorrowMut<MockExt>>(
901		wat: &str,
902		input_data: Vec<u8>,
903		ext: E,
904	) -> ExecResult {
905		execute_internal(wat, input_data, ext, &ExportedFunction::Call, false, false)
906	}
907
908	/// Execute code without validating it first.
909	///
910	/// This is mainly useful in order to test code which uses deprecated functions. Those
911	/// would fail when validating the code.
912	fn execute_unvalidated<E: BorrowMut<MockExt>>(
913		wat: &str,
914		input_data: Vec<u8>,
915		ext: E,
916	) -> ExecResult {
917		execute_internal(wat, input_data, ext, &ExportedFunction::Call, false, true)
918	}
919
920	/// Execute instantiation entry point of code without validating it first.
921	///
922	/// Same as `execute_unvalidated` except that the `deploy` entry point is ran.
923	#[cfg(not(feature = "runtime-benchmarks"))]
924	fn execute_instantiate_unvalidated<E: BorrowMut<MockExt>>(
925		wat: &str,
926		input_data: Vec<u8>,
927		ext: E,
928	) -> ExecResult {
929		execute_internal(wat, input_data, ext, &ExportedFunction::Constructor, false, true)
930	}
931
932	const CODE_TRANSFER: &str = r#"
933(module
934	;; seal_transfer(
935	;;    account_ptr: u32,
936	;;    account_len: u32,
937	;;    value_ptr: u32,
938	;;    value_len: u32,
939	;;) -> u32
940	(import "seal0" "seal_transfer" (func $seal_transfer (param i32 i32 i32 i32) (result i32)))
941	(import "env" "memory" (memory 1 1))
942	(func (export "call")
943		(drop
944			(call $seal_transfer
945				(i32.const 4)  ;; Pointer to "account" address.
946				(i32.const 32)  ;; Length of "account" address.
947				(i32.const 36) ;; Pointer to the buffer with value to transfer
948				(i32.const 8)  ;; Length of the buffer with value to transfer.
949			)
950		)
951	)
952	(func (export "deploy"))
953
954	;; Destination AccountId (ALICE)
955	(data (i32.const 4)
956		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
957		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
958	)
959
960	;; Amount of value to transfer.
961	;; Represented by u64 (8 bytes long) in little endian.
962	(data (i32.const 36) "\99\00\00\00\00\00\00\00")
963)
964"#;
965
966	#[test]
967	fn contract_transfer() {
968		let mut mock_ext = MockExt::default();
969		assert_ok!(execute(CODE_TRANSFER, vec![], &mut mock_ext));
970
971		assert_eq!(&mock_ext.transfers, &[TransferEntry { to: ALICE, value: 153 }]);
972	}
973
974	const CODE_CALL: &str = r#"
975(module
976	;; seal_call(
977	;;    callee_ptr: u32,
978	;;    callee_len: u32,
979	;;    gas: u64,
980	;;    value_ptr: u32,
981	;;    value_len: u32,
982	;;    input_data_ptr: u32,
983	;;    input_data_len: u32,
984	;;    output_ptr: u32,
985	;;    output_len_ptr: u32
986	;;) -> u32
987	(import "seal0" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32 i32) (result i32)))
988	(import "env" "memory" (memory 1 1))
989	(func (export "call")
990		(drop
991			(call $seal_call
992				(i32.const 4)  ;; Pointer to "callee" address.
993				(i32.const 32)  ;; Length of "callee" address.
994				(i64.const 0)  ;; How much gas to devote for the execution. 0 = all.
995				(i32.const 36) ;; Pointer to the buffer with value to transfer
996				(i32.const 8)  ;; Length of the buffer with value to transfer.
997				(i32.const 44) ;; Pointer to input data buffer address
998				(i32.const 4)  ;; Length of input data buffer
999				(i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output
1000				(i32.const 0) ;; Length is ignored in this case
1001			)
1002		)
1003	)
1004	(func (export "deploy"))
1005
1006	;; Destination AccountId (ALICE)
1007	(data (i32.const 4)
1008		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1009		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1010	)
1011
1012	;; Amount of value to transfer.
1013	;; Represented by u64 (8 bytes long) in little endian.
1014	(data (i32.const 36) "\06\00\00\00\00\00\00\00")
1015
1016	(data (i32.const 44) "\01\02\03\04")
1017)
1018"#;
1019
1020	#[test]
1021	fn contract_call() {
1022		let mut mock_ext = MockExt::default();
1023		assert_ok!(execute(CODE_CALL, vec![], &mut mock_ext));
1024
1025		assert_eq!(
1026			&mock_ext.calls,
1027			&[CallEntry {
1028				to: ALICE,
1029				value: 6,
1030				data: vec![1, 2, 3, 4],
1031				allows_reentry: true,
1032				read_only: false
1033			}]
1034		);
1035	}
1036
1037	#[test]
1038	fn contract_delegate_call() {
1039		const CODE: &str = r#"
1040(module
1041	;; seal_delegate_call(
1042	;;    flags: u32,
1043	;;    code_hash_ptr: u32,
1044	;;    input_data_ptr: u32,
1045	;;    input_data_len: u32,
1046	;;    output_ptr: u32,
1047	;;    output_len_ptr: u32
1048	;;) -> u32
1049	(import "seal0" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32)))
1050	(import "env" "memory" (memory 1 1))
1051	(func (export "call")
1052		(drop
1053			(call $seal_delegate_call
1054				(i32.const 0) ;; No flags are set
1055				(i32.const 4)  ;; Pointer to "callee" code_hash.
1056				(i32.const 36) ;; Pointer to input data buffer address
1057				(i32.const 4)  ;; Length of input data buffer
1058				(i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output
1059				(i32.const 0) ;; Length is ignored in this case
1060			)
1061		)
1062	)
1063	(func (export "deploy"))
1064
1065	;; Callee code_hash
1066	(data (i32.const 4)
1067		"\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11"
1068		"\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11"
1069	)
1070
1071	(data (i32.const 36) "\01\02\03\04")
1072)
1073"#;
1074		let mut mock_ext = MockExt::default();
1075		assert_ok!(execute(CODE, vec![], &mut mock_ext));
1076
1077		assert_eq!(
1078			&mock_ext.code_calls,
1079			&[CallCodeEntry { code_hash: [0x11; 32].into(), data: vec![1, 2, 3, 4] }]
1080		);
1081	}
1082
1083	#[test]
1084	fn contract_call_forward_input() {
1085		const CODE: &str = r#"
1086(module
1087	(import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32)))
1088	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
1089	(import "env" "memory" (memory 1 1))
1090	(func (export "call")
1091		(drop
1092			(call $seal_call
1093				(i32.const 1) ;; Set FORWARD_INPUT bit
1094				(i32.const 4)  ;; Pointer to "callee" address.
1095				(i64.const 0)  ;; How much gas to devote for the execution. 0 = all.
1096				(i32.const 36) ;; Pointer to the buffer with value to transfer
1097				(i32.const 44) ;; Pointer to input data buffer address
1098				(i32.const 4)  ;; Length of input data buffer
1099				(i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output
1100				(i32.const 0) ;; Length is ignored in this case
1101			)
1102		)
1103
1104		;; triggers a trap because we already forwarded the input
1105		(call $seal_input (i32.const 1) (i32.const 44))
1106	)
1107
1108	(func (export "deploy"))
1109
1110	;; Destination AccountId (ALICE)
1111	(data (i32.const 4)
1112		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1113		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1114	)
1115
1116	;; Amount of value to transfer.
1117	;; Represented by u64 (8 bytes long) in little endian.
1118	(data (i32.const 36) "\2A\00\00\00\00\00\00\00")
1119
1120	;; The input is ignored because we forward our own input
1121	(data (i32.const 44) "\01\02\03\04")
1122)
1123"#;
1124		let mut mock_ext = MockExt::default();
1125		let input = vec![0xff, 0x2a, 0x99, 0x88];
1126		assert_err!(execute(CODE, input.clone(), &mut mock_ext), <Error<Test>>::InputForwarded,);
1127
1128		assert_eq!(
1129			&mock_ext.calls,
1130			&[CallEntry {
1131				to: ALICE,
1132				value: 0x2a,
1133				data: input,
1134				allows_reentry: false,
1135				read_only: false
1136			}]
1137		);
1138	}
1139
1140	#[test]
1141	fn contract_call_clone_input() {
1142		const CODE: &str = r#"
1143(module
1144	(import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32)))
1145	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
1146	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
1147	(import "env" "memory" (memory 1 1))
1148	(func (export "call")
1149		(drop
1150			(call $seal_call
1151				(i32.const 11) ;; Set FORWARD_INPUT | CLONE_INPUT | ALLOW_REENTRY bits
1152				(i32.const 4)  ;; Pointer to "callee" address.
1153				(i64.const 0)  ;; How much gas to devote for the execution. 0 = all.
1154				(i32.const 36) ;; Pointer to the buffer with value to transfer
1155				(i32.const 44) ;; Pointer to input data buffer address
1156				(i32.const 4)  ;; Length of input data buffer
1157				(i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output
1158				(i32.const 0) ;; Length is ignored in this case
1159			)
1160		)
1161
1162		;; works because the input was cloned
1163		(call $seal_input (i32.const 0) (i32.const 44))
1164
1165		;; return the input to caller for inspection
1166		(call $seal_return (i32.const 0) (i32.const 0) (i32.load (i32.const 44)))
1167	)
1168
1169	(func (export "deploy"))
1170
1171	;; Destination AccountId (ALICE)
1172	(data (i32.const 4)
1173		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1174		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1175	)
1176
1177	;; Amount of value to transfer.
1178	;; Represented by u64 (8 bytes long) in little endian.
1179	(data (i32.const 36) "\2A\00\00\00\00\00\00\00")
1180
1181	;; The input is ignored because we forward our own input
1182	(data (i32.const 44) "\01\02\03\04")
1183)
1184"#;
1185		let mut mock_ext = MockExt::default();
1186		let input = vec![0xff, 0x2a, 0x99, 0x88];
1187		let result = execute(CODE, input.clone(), &mut mock_ext).unwrap();
1188		assert_eq!(result.data, input);
1189		assert_eq!(
1190			&mock_ext.calls,
1191			&[CallEntry {
1192				to: ALICE,
1193				value: 0x2a,
1194				data: input,
1195				allows_reentry: true,
1196				read_only: false
1197			}]
1198		);
1199	}
1200
1201	#[test]
1202	fn contract_call_tail_call() {
1203		const CODE: &str = r#"
1204(module
1205	(import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32)))
1206	(import "env" "memory" (memory 1 1))
1207	(func (export "call")
1208		(drop
1209			(call $seal_call
1210				(i32.const 5) ;; Set FORWARD_INPUT | TAIL_CALL bit
1211				(i32.const 4)  ;; Pointer to "callee" address.
1212				(i64.const 0)  ;; How much gas to devote for the execution. 0 = all.
1213				(i32.const 36) ;; Pointer to the buffer with value to transfer
1214				(i32.const 0) ;; Pointer to input data buffer address
1215				(i32.const 0)  ;; Length of input data buffer
1216				(i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output
1217				(i32.const 0) ;; Length is ignored in this case
1218			)
1219		)
1220
1221		;; a tail call never returns
1222		(unreachable)
1223	)
1224
1225	(func (export "deploy"))
1226
1227	;; Destination AccountId (ALICE)
1228	(data (i32.const 4)
1229		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1230		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1231	)
1232
1233	;; Amount of value to transfer.
1234	;; Represented by u64 (8 bytes long) in little endian.
1235	(data (i32.const 36) "\2A\00\00\00\00\00\00\00")
1236)
1237"#;
1238		let mut mock_ext = MockExt::default();
1239		let input = vec![0xff, 0x2a, 0x99, 0x88];
1240		let result = execute(CODE, input.clone(), &mut mock_ext).unwrap();
1241		assert_eq!(result.data, call_return_data());
1242		assert_eq!(
1243			&mock_ext.calls,
1244			&[CallEntry {
1245				to: ALICE,
1246				value: 0x2a,
1247				data: input,
1248				allows_reentry: false,
1249				read_only: false
1250			}]
1251		);
1252	}
1253
1254	#[test]
1255	fn contains_storage_works() {
1256		const CODE: &str = r#"
1257(module
1258	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
1259	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
1260	(import "seal1" "contains_storage" (func $contains_storage (param i32 i32) (result i32)))
1261	(import "env" "memory" (memory 1 1))
1262
1263
1264	;; size of input buffer
1265	;; [0, 4) size of input buffer (128+32 = 160 bytes = 0xA0)
1266	(data (i32.const 0) "\A0")
1267
1268	;; [4, 164) input buffer
1269
1270	(func (export "call")
1271		;; Receive key
1272		(call $seal_input
1273			(i32.const 4)	;; Where we take input and store it
1274			(i32.const 0)	;; Where we take and store the length of the data
1275		)
1276		;; Call seal_clear_storage and save what it returns at 0
1277		(i32.store (i32.const 0)
1278			(call $contains_storage
1279				(i32.const 8)			;; key_ptr
1280				(i32.load (i32.const 4))	;; key_len
1281			)
1282		)
1283		(call $seal_return
1284			(i32.const 0)	;; flags
1285			(i32.const 0)	;; returned value
1286			(i32.const 4)	;; length of returned value
1287		)
1288	)
1289
1290	(func (export "deploy"))
1291)
1292"#;
1293
1294		let mut ext = MockExt::default();
1295		ext.set_storage(
1296			&Key::<Test>::try_from_var([1u8; 64].to_vec()).unwrap(),
1297			Some(vec![42u8]),
1298			false,
1299		)
1300		.unwrap();
1301		ext.set_storage(
1302			&Key::<Test>::try_from_var([2u8; 19].to_vec()).unwrap(),
1303			Some(vec![]),
1304			false,
1305		)
1306		.unwrap();
1307
1308		//value does not exist (wrong key length)
1309		let input = (63, [1u8; 64]).encode();
1310		let result = execute(CODE, input, &mut ext).unwrap();
1311		// sentinel returned
1312		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL);
1313
1314		// value exists
1315		let input = (64, [1u8; 64]).encode();
1316		let result = execute(CODE, input, &mut ext).unwrap();
1317		// true as u32 returned
1318		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1);
1319		// getter does not remove the value from storage
1320		assert_eq!(ext.storage.get(&[1u8; 64].to_vec()).unwrap(), &[42u8]);
1321
1322		// value exists (test for 0 sized)
1323		let input = (19, [2u8; 19]).encode();
1324		let result = execute(CODE, input, &mut ext).unwrap();
1325		// true as u32 returned
1326		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0);
1327		// getter does not remove the value from storage
1328		assert_eq!(ext.storage.get(&[2u8; 19].to_vec()).unwrap(), &([] as [u8; 0]));
1329	}
1330
1331	const CODE_INSTANTIATE: &str = r#"
1332(module
1333	;; seal_instantiate(
1334	;;     code_ptr: u32,
1335	;;     code_len: u32,
1336	;;     gas: u64,
1337	;;     value_ptr: u32,
1338	;;     value_len: u32,
1339	;;     input_data_ptr: u32,
1340	;;     input_data_len: u32,
1341	;;     input_data_len: u32,
1342	;;     address_ptr: u32,
1343	;;     address_len_ptr: u32,
1344	;;     output_ptr: u32,
1345	;;     output_len_ptr: u32
1346	;; ) -> u32
1347	(import "seal0" "seal_instantiate" (func $seal_instantiate
1348		(param i32 i32 i64 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32)
1349	))
1350	(import "env" "memory" (memory 1 1))
1351	(func (export "call")
1352		(drop
1353			(call $seal_instantiate
1354				(i32.const 16)   ;; Pointer to `code_hash`
1355				(i32.const 32)   ;; Length of `code_hash`
1356				(i64.const 0)    ;; How much gas to devote for the execution. 0 = all.
1357				(i32.const 4)    ;; Pointer to the buffer with value to transfer
1358				(i32.const 8)    ;; Length of the buffer with value to transfer
1359				(i32.const 12)   ;; Pointer to input data buffer address
1360				(i32.const 4)    ;; Length of input data buffer
1361				(i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy address
1362				(i32.const 0) ;; Length is ignored in this case
1363				(i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output
1364				(i32.const 0) ;; Length is ignored in this case
1365				(i32.const 0) ;; salt_ptr
1366				(i32.const 4) ;; salt_len
1367			)
1368		)
1369	)
1370	(func (export "deploy"))
1371
1372	;; Salt
1373	(data (i32.const 0) "\42\43\44\45")
1374	;; Amount of value to transfer.
1375	;; Represented by u64 (8 bytes long) in little endian.
1376	(data (i32.const 4) "\03\00\00\00\00\00\00\00")
1377	;; Input data to pass to the contract being instantiated.
1378	(data (i32.const 12) "\01\02\03\04")
1379	;; Hash of code.
1380	(data (i32.const 16)
1381		"\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11"
1382		"\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11"
1383	)
1384)
1385"#;
1386
1387	#[test]
1388	fn contract_instantiate() {
1389		let mut mock_ext = MockExt::default();
1390		assert_ok!(execute(CODE_INSTANTIATE, vec![], &mut mock_ext));
1391
1392		assert_matches!(
1393			&mock_ext.instantiates[..],
1394			[InstantiateEntry {
1395				code_hash,
1396				value: 3,
1397				data,
1398				gas_left: _,
1399				salt,
1400			}] if
1401				code_hash == &[0x11; 32].into() &&
1402				data == &vec![1, 2, 3, 4] &&
1403				salt == &vec![0x42, 0x43, 0x44, 0x45]
1404		);
1405	}
1406
1407	const CODE_TERMINATE: &str = r#"
1408(module
1409	;; seal_terminate(
1410	;;     beneficiary_ptr: u32,
1411	;;     beneficiary_len: u32,
1412	;; )
1413	(import "seal0" "seal_terminate" (func $seal_terminate (param i32 i32)))
1414	(import "env" "memory" (memory 1 1))
1415	(func (export "call")
1416		(call $seal_terminate
1417			(i32.const 4)  ;; Pointer to "beneficiary" address.
1418			(i32.const 32)  ;; Length of "beneficiary" address.
1419		)
1420	)
1421	(func (export "deploy"))
1422
1423	;; Beneficiary AccountId to transfer the funds.
1424	(data (i32.const 4)
1425		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1426		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1427	)
1428)
1429"#;
1430
1431	#[test]
1432	fn contract_terminate() {
1433		let mut mock_ext = MockExt::default();
1434		execute(CODE_TERMINATE, vec![], &mut mock_ext).unwrap();
1435
1436		assert_eq!(&mock_ext.terminations, &[TerminationEntry { beneficiary: ALICE }]);
1437	}
1438
1439	const CODE_TRANSFER_LIMITED_GAS: &str = r#"
1440(module
1441	;; seal_call(
1442	;;    callee_ptr: u32,
1443	;;    callee_len: u32,
1444	;;    gas: u64,
1445	;;    value_ptr: u32,
1446	;;    value_len: u32,
1447	;;    input_data_ptr: u32,
1448	;;    input_data_len: u32,
1449	;;    output_ptr: u32,
1450	;;    output_len_ptr: u32
1451	;;) -> u32
1452	(import "seal0" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32 i32) (result i32)))
1453	(import "env" "memory" (memory 1 1))
1454	(func (export "call")
1455		(drop
1456			(call $seal_call
1457				(i32.const 4)  ;; Pointer to "callee" address.
1458				(i32.const 32)  ;; Length of "callee" address.
1459				(i64.const 228)  ;; How much gas to devote for the execution.
1460				(i32.const 36)  ;; Pointer to the buffer with value to transfer
1461				(i32.const 8)   ;; Length of the buffer with value to transfer.
1462				(i32.const 44)   ;; Pointer to input data buffer address
1463				(i32.const 4)   ;; Length of input data buffer
1464				(i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output
1465				(i32.const 0) ;; Length is ignored in this cas
1466			)
1467		)
1468	)
1469	(func (export "deploy"))
1470
1471	;; Destination AccountId to transfer the funds.
1472	(data (i32.const 4)
1473		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1474		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1475	)
1476	;; Amount of value to transfer.
1477	;; Represented by u64 (8 bytes long) in little endian.
1478	(data (i32.const 36) "\06\00\00\00\00\00\00\00")
1479
1480	(data (i32.const 44) "\01\02\03\04")
1481)
1482"#;
1483
1484	#[test]
1485	fn contract_call_limited_gas() {
1486		let mut mock_ext = MockExt::default();
1487		assert_ok!(execute(&CODE_TRANSFER_LIMITED_GAS, vec![], &mut mock_ext));
1488
1489		assert_eq!(
1490			&mock_ext.calls,
1491			&[CallEntry {
1492				to: ALICE,
1493				value: 6,
1494				data: vec![1, 2, 3, 4],
1495				allows_reentry: true,
1496				read_only: false
1497			}]
1498		);
1499	}
1500
1501	const CODE_ECDSA_RECOVER: &str = r#"
1502(module
1503	;; seal_ecdsa_recover(
1504	;;    signature_ptr: u32,
1505	;;    message_hash_ptr: u32,
1506	;;    output_ptr: u32
1507	;; ) -> u32
1508	(import "seal0" "seal_ecdsa_recover" (func $seal_ecdsa_recover (param i32 i32 i32) (result i32)))
1509	(import "env" "memory" (memory 1 1))
1510	(func (export "call")
1511		(drop
1512			(call $seal_ecdsa_recover
1513				(i32.const 36) ;; Pointer to signature.
1514				(i32.const 4)  ;; Pointer to message hash.
1515				(i32.const 36) ;; Pointer for output - public key.
1516			)
1517		)
1518	)
1519	(func (export "deploy"))
1520
1521	;; Hash of message.
1522	(data (i32.const 4)
1523		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1524		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1525	)
1526	;; Signature
1527	(data (i32.const 36)
1528		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1529		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1530		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1531		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1532		"\01"
1533	)
1534)
1535"#;
1536
1537	#[test]
1538	fn contract_ecdsa_recover() {
1539		let mut mock_ext = MockExt::default();
1540		assert_ok!(execute(&CODE_ECDSA_RECOVER, vec![], &mut mock_ext));
1541		assert_eq!(mock_ext.ecdsa_recover.into_inner(), [([1; 65], [1; 32])]);
1542	}
1543
1544	#[test]
1545	fn contract_ecdsa_to_eth_address() {
1546		/// calls `seal_ecdsa_to_eth_address` for the constant and ensures the result equals the
1547		/// expected one.
1548		const CODE_ECDSA_TO_ETH_ADDRESS: &str = r#"
1549(module
1550	(import "seal0" "seal_ecdsa_to_eth_address" (func $seal_ecdsa_to_eth_address (param i32 i32) (result i32)))
1551	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
1552	(import "env" "memory" (memory 1 1))
1553
1554	(func (export "call")
1555		;; fill the buffer with the eth address.
1556		(call $seal_ecdsa_to_eth_address (i32.const 0) (i32.const 0))
1557
1558		;; Return the contents of the buffer
1559		(call $seal_return
1560			(i32.const 0)
1561			(i32.const 0)
1562			(i32.const 20)
1563		)
1564
1565		;; seal_return doesn't return, so this is effectively unreachable.
1566		(unreachable)
1567	)
1568	(func (export "deploy"))
1569)
1570"#;
1571
1572		let output = execute(CODE_ECDSA_TO_ETH_ADDRESS, vec![], MockExt::default()).unwrap();
1573		assert_eq!(
1574			output,
1575			ExecReturnValue { flags: ReturnFlags::empty(), data: [0x02; 20].to_vec() }
1576		);
1577	}
1578
1579	#[test]
1580	fn contract_sr25519() {
1581		const CODE_SR25519: &str = r#"
1582(module
1583	(import "seal0" "sr25519_verify" (func $sr25519_verify (param i32 i32 i32 i32) (result i32)))
1584	(import "env" "memory" (memory 1 1))
1585	(func (export "call")
1586		(drop
1587			(call $sr25519_verify
1588				(i32.const 0) ;; Pointer to signature.
1589				(i32.const 64) ;; Pointer to public key.
1590				(i32.const 16) ;; message length.
1591				(i32.const 96) ;; Pointer to message.
1592			)
1593		)
1594	)
1595	(func (export "deploy"))
1596
1597	;; Signature (64 bytes)
1598	(data (i32.const 0)
1599		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1600		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1601		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1602		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1603	)
1604
1605	;;  public key (32 bytes)
1606	(data (i32.const 64)
1607		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1608		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1609	)
1610
1611	;;  message. (16 bytes)
1612	(data (i32.const 96)
1613		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
1614	)
1615)
1616"#;
1617		let mut mock_ext = MockExt::default();
1618		assert_ok!(execute(&CODE_SR25519, vec![], &mut mock_ext));
1619		assert_eq!(mock_ext.sr25519_verify.into_inner(), [([1; 64], [1; 16].to_vec(), [1; 32])]);
1620	}
1621
1622	const CODE_GET_STORAGE: &str = r#"
1623(module
1624	(import "seal0" "seal_get_storage" (func $seal_get_storage (param i32 i32 i32) (result i32)))
1625	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
1626	(import "env" "memory" (memory 1 1))
1627
1628	;; [0, 32) key for get storage
1629	(data (i32.const 0)
1630		"\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11"
1631		"\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11"
1632	)
1633
1634	;; [32, 36) buffer size = 4k in little endian
1635	(data (i32.const 32) "\00\10")
1636
1637	;; [36; inf) buffer where the result is copied
1638
1639	(func $assert (param i32)
1640		(block $ok
1641			(br_if $ok
1642				(local.get 0)
1643			)
1644			(unreachable)
1645		)
1646	)
1647
1648	(func (export "call")
1649		(local $buf_size i32)
1650
1651		;; Load a storage value into contract memory.
1652		(call $assert
1653			(i32.eq
1654				(call $seal_get_storage
1655					(i32.const 0)		;; The pointer to the storage key to fetch
1656					(i32.const 36)		;; Pointer to the output buffer
1657					(i32.const 32)		;; Pointer to the size of the buffer
1658				)
1659
1660				;; Return value 0 means that the value is found and there were
1661				;; no errors.
1662				(i32.const 0)
1663			)
1664		)
1665
1666		;; Find out the size of the buffer
1667		(local.set $buf_size
1668			(i32.load (i32.const 32))
1669		)
1670
1671		;; Return the contents of the buffer
1672		(call $seal_return
1673			(i32.const 0)
1674			(i32.const 36)
1675			(local.get $buf_size)
1676		)
1677
1678		;; env:seal_return doesn't return, so this is effectively unreachable.
1679		(unreachable)
1680	)
1681
1682	(func (export "deploy"))
1683)
1684"#;
1685
1686	#[test]
1687	fn get_storage_puts_data_into_buf() {
1688		let mut mock_ext = MockExt::default();
1689		mock_ext.storage.insert([0x11; 32].to_vec(), [0x22; 32].to_vec());
1690
1691		let output = execute(CODE_GET_STORAGE, vec![], mock_ext).unwrap();
1692
1693		assert_eq!(
1694			output,
1695			ExecReturnValue { flags: ReturnFlags::empty(), data: [0x22; 32].to_vec() }
1696		);
1697	}
1698
1699	/// calls `seal_caller` and compares the result with the constant (ALICE's address part).
1700	const CODE_CALLER: &str = r#"
1701(module
1702	(import "seal0" "seal_caller" (func $seal_caller (param i32 i32)))
1703	(import "env" "memory" (memory 1 1))
1704
1705	;; size of our buffer is 32 bytes
1706	(data (i32.const 32) "\20")
1707
1708	(func $assert (param i32)
1709		(block $ok
1710			(br_if $ok
1711				(local.get 0)
1712			)
1713			(unreachable)
1714		)
1715	)
1716
1717	(func (export "call")
1718		;; fill the buffer with the caller.
1719		(call $seal_caller (i32.const 0) (i32.const 32))
1720
1721		;; assert len == 32
1722		(call $assert
1723			(i32.eq
1724				(i32.load (i32.const 32))
1725				(i32.const 32)
1726			)
1727		)
1728
1729		;; assert that the first 8 bytes are the beginning of "ALICE"
1730		(call $assert
1731			(i64.eq
1732				(i64.load (i32.const 0))
1733				(i64.const 0x0101010101010101)
1734			)
1735		)
1736	)
1737
1738	(func (export "deploy"))
1739)
1740"#;
1741
1742	#[test]
1743	fn caller() {
1744		assert_ok!(execute(CODE_CALLER, vec![], MockExt::default()));
1745	}
1746
1747	#[test]
1748	fn caller_traps_when_no_account_id() {
1749		let mut ext = MockExt::default();
1750		ext.caller = Origin::Root;
1751		assert_eq!(
1752			execute(CODE_CALLER, vec![], ext),
1753			Err(ExecError { error: DispatchError::RootNotAllowed, origin: ErrorOrigin::Caller })
1754		);
1755	}
1756
1757	/// calls `seal_address` and compares the result with the constant (BOB's address part).
1758	const CODE_ADDRESS: &str = r#"
1759(module
1760	(import "seal0" "seal_address" (func $seal_address (param i32 i32)))
1761	(import "env" "memory" (memory 1 1))
1762
1763	;; size of our buffer is 32 bytes
1764	(data (i32.const 32) "\20")
1765
1766	(func $assert (param i32)
1767		(block $ok
1768			(br_if $ok
1769				(local.get 0)
1770			)
1771			(unreachable)
1772		)
1773	)
1774
1775	(func (export "call")
1776		;; fill the buffer with the self address.
1777		(call $seal_address (i32.const 0) (i32.const 32))
1778
1779		;; assert size == 32
1780		(call $assert
1781			(i32.eq
1782				(i32.load (i32.const 32))
1783				(i32.const 32)
1784			)
1785		)
1786
1787		;; assert that the first 8 bytes are the beginning of "BOB"
1788		(call $assert
1789			(i64.eq
1790				(i64.load (i32.const 0))
1791				(i64.const 0x0202020202020202)
1792			)
1793		)
1794	)
1795
1796	(func (export "deploy"))
1797)
1798"#;
1799
1800	#[test]
1801	fn address() {
1802		assert_ok!(execute(CODE_ADDRESS, vec![], MockExt::default()));
1803	}
1804
1805	const CODE_BALANCE: &str = r#"
1806(module
1807	(import "seal0" "seal_balance" (func $seal_balance (param i32 i32)))
1808	(import "env" "memory" (memory 1 1))
1809
1810	;; size of our buffer is 32 bytes
1811	(data (i32.const 32) "\20")
1812
1813	(func $assert (param i32)
1814		(block $ok
1815			(br_if $ok
1816				(local.get 0)
1817			)
1818			(unreachable)
1819		)
1820	)
1821
1822	(func (export "call")
1823		;; This stores the balance in the buffer
1824		(call $seal_balance (i32.const 0) (i32.const 32))
1825
1826		;; assert len == 8
1827		(call $assert
1828			(i32.eq
1829				(i32.load (i32.const 32))
1830				(i32.const 8)
1831			)
1832		)
1833
1834		;; assert that contents of the buffer is equal to the i64 value of 228.
1835		(call $assert
1836			(i64.eq
1837				(i64.load (i32.const 0))
1838				(i64.const 228)
1839			)
1840		)
1841	)
1842	(func (export "deploy"))
1843)
1844"#;
1845
1846	#[test]
1847	fn balance() {
1848		assert_ok!(execute(CODE_BALANCE, vec![], MockExt::default()));
1849	}
1850
1851	const CODE_GAS_PRICE: &str = r#"
1852(module
1853	(import "seal1" "weight_to_fee" (func $seal_weight_to_fee (param i64 i64 i32 i32)))
1854	(import "env" "memory" (memory 1 1))
1855
1856	;; size of our buffer is 32 bytes
1857	(data (i32.const 32) "\20")
1858
1859	(func $assert (param i32)
1860		(block $ok
1861			(br_if $ok
1862				(local.get 0)
1863			)
1864			(unreachable)
1865		)
1866	)
1867
1868	(func (export "call")
1869		;; This stores the gas price in the buffer
1870		(call $seal_weight_to_fee (i64.const 2) (i64.const 1) (i32.const 0) (i32.const 32))
1871
1872		;; assert len == 8
1873		(call $assert
1874			(i32.eq
1875				(i32.load (i32.const 32))
1876				(i32.const 8)
1877			)
1878		)
1879
1880		;; assert that contents of the buffer is equal to the i64 value of 2 * 1312 + 103 = 2727.
1881		(call $assert
1882			(i64.eq
1883				(i64.load (i32.const 0))
1884				(i64.const 2727)
1885			)
1886		)
1887	)
1888	(func (export "deploy"))
1889)
1890"#;
1891
1892	#[test]
1893	fn gas_price() {
1894		assert_ok!(execute(CODE_GAS_PRICE, vec![], MockExt::default()));
1895	}
1896
1897	const CODE_GAS_LEFT: &str = r#"
1898(module
1899	(import "seal1" "gas_left" (func $seal_gas_left (param i32 i32)))
1900	(import "seal0" "clear_storage" (func $clear_storage (param i32)))
1901	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
1902	(import "env" "memory" (memory 1 1))
1903
1904	;; Make output buffer size 20 bytes
1905	(data (i32.const 20) "\14")
1906
1907	(func $assert (param i32)
1908		(block $ok
1909			(br_if $ok
1910				(local.get 0)
1911			)
1912			(unreachable)
1913		)
1914	)
1915
1916	(func (export "call")
1917		;; Burn some PoV, clear_storage consumes some PoV as in order to clear the storage we need to we need to read its size first.
1918		(call $clear_storage (i32.const 0))
1919
1920		;; This stores the weight left to the buffer
1921		(call $seal_gas_left (i32.const 0) (i32.const 20))
1922
1923		;; Assert len <= 16 (max encoded Weight len)
1924		(call $assert
1925			(i32.le_u
1926				(i32.load (i32.const 20))
1927				(i32.const 16)
1928			)
1929		)
1930
1931		;; Burn some PoV, clear_storage consumes some PoV as in order to clear the storage we need to we need to read its size first.
1932		(call $clear_storage (i32.const 0))
1933
1934		;; Return weight left and its encoded value len
1935		(call $seal_return (i32.const 0) (i32.const 0) (i32.load (i32.const 20)))
1936
1937		(unreachable)
1938	)
1939	(func (export "deploy"))
1940)
1941"#;
1942
1943	#[test]
1944	fn gas_left() {
1945		let mut ext = MockExt::default();
1946		let gas_limit = ext.gas_meter.gas_left();
1947
1948		let output = execute(CODE_GAS_LEFT, vec![], &mut ext).unwrap();
1949
1950		let weight_left = Weight::decode(&mut &*output.data).unwrap();
1951		let actual_left = ext.gas_meter.gas_left();
1952
1953		assert!(weight_left.all_lt(gas_limit), "gas_left must be less than initial");
1954		assert!(weight_left.all_gt(actual_left), "gas_left must be greater than final");
1955	}
1956
1957	const CODE_VALUE_TRANSFERRED: &str = r#"
1958(module
1959	(import "seal0" "seal_value_transferred" (func $seal_value_transferred (param i32 i32)))
1960	(import "env" "memory" (memory 1 1))
1961
1962	;; size of our buffer is 32 bytes
1963	(data (i32.const 32) "\20")
1964
1965	(func $assert (param i32)
1966		(block $ok
1967			(br_if $ok
1968				(local.get 0)
1969			)
1970			(unreachable)
1971		)
1972	)
1973
1974	(func (export "call")
1975		;; This stores the value transferred in the buffer
1976		(call $seal_value_transferred (i32.const 0) (i32.const 32))
1977
1978		;; assert len == 8
1979		(call $assert
1980			(i32.eq
1981				(i32.load (i32.const 32))
1982				(i32.const 8)
1983			)
1984		)
1985
1986		;; assert that contents of the buffer is equal to the i64 value of 1337.
1987		(call $assert
1988			(i64.eq
1989				(i64.load (i32.const 0))
1990				(i64.const 1337)
1991			)
1992		)
1993	)
1994	(func (export "deploy"))
1995)
1996"#;
1997
1998	#[test]
1999	fn value_transferred() {
2000		assert_ok!(execute(CODE_VALUE_TRANSFERRED, vec![], MockExt::default()));
2001	}
2002
2003	const START_FN_DOES_RUN: &str = r#"
2004(module
2005	(import "seal0" "seal_deposit_event" (func $seal_deposit_event (param i32 i32 i32 i32)))
2006	(import "env" "memory" (memory 1 1))
2007
2008	(start $start)
2009	(func $start
2010		(call $seal_deposit_event
2011			(i32.const 0) ;; Pointer to the start of topics buffer
2012			(i32.const 0) ;; The length of the topics buffer.
2013			(i32.const 0) ;; Pointer to the start of the data buffer
2014			(i32.const 13) ;; Length of the buffer
2015		)
2016	)
2017
2018	(func (export "call"))
2019
2020	(func (export "deploy"))
2021
2022	(data (i32.const 0) "\00\01\2A\00\00\00\00\00\00\00\E5\14\00")
2023)
2024"#;
2025
2026	#[test]
2027	fn start_fn_does_run_on_call() {
2028		let mut ext = MockExt::default();
2029		execute(START_FN_DOES_RUN, vec![], &mut ext).unwrap();
2030		assert_eq!(
2031			ext.events[0].1,
2032			[0x00_u8, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00]
2033		);
2034	}
2035
2036	#[test]
2037	fn start_fn_does_run_on_deploy() {
2038		let mut ext = MockExt::default();
2039		execute_instantiate(START_FN_DOES_RUN, vec![], &mut ext).unwrap();
2040		assert_eq!(
2041			ext.events[0].1,
2042			[0x00_u8, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00]
2043		);
2044	}
2045
2046	const CODE_TIMESTAMP_NOW: &str = r#"
2047(module
2048	(import "seal0" "seal_now" (func $seal_now (param i32 i32)))
2049	(import "env" "memory" (memory 1 1))
2050
2051	;; size of our buffer is 32 bytes
2052	(data (i32.const 32) "\20")
2053
2054	(func $assert (param i32)
2055		(block $ok
2056			(br_if $ok
2057				(local.get 0)
2058			)
2059			(unreachable)
2060		)
2061	)
2062
2063	(func (export "call")
2064		;; This stores the block timestamp in the buffer
2065		(call $seal_now (i32.const 0) (i32.const 32))
2066
2067		;; assert len == 8
2068		(call $assert
2069			(i32.eq
2070				(i32.load (i32.const 32))
2071				(i32.const 8)
2072			)
2073		)
2074
2075		;; assert that contents of the buffer is equal to the i64 value of 1111.
2076		(call $assert
2077			(i64.eq
2078				(i64.load (i32.const 0))
2079				(i64.const 1111)
2080			)
2081		)
2082	)
2083	(func (export "deploy"))
2084)
2085"#;
2086
2087	const CODE_TIMESTAMP_NOW_UNPREFIXED: &str = r#"
2088(module
2089	(import "seal0" "now" (func $now (param i32 i32)))
2090	(import "env" "memory" (memory 1 1))
2091
2092	;; size of our buffer is 32 bytes
2093	(data (i32.const 32) "\20")
2094
2095	(func $assert (param i32)
2096		(block $ok
2097			(br_if $ok
2098				(local.get 0)
2099			)
2100			(unreachable)
2101		)
2102	)
2103
2104	(func (export "call")
2105		;; This stores the block timestamp in the buffer
2106		(call $now (i32.const 0) (i32.const 32))
2107
2108		;; assert len == 8
2109		(call $assert
2110			(i32.eq
2111				(i32.load (i32.const 32))
2112				(i32.const 8)
2113			)
2114		)
2115
2116		;; assert that contents of the buffer is equal to the i64 value of 1111.
2117		(call $assert
2118			(i64.eq
2119				(i64.load (i32.const 0))
2120				(i64.const 1111)
2121			)
2122		)
2123	)
2124	(func (export "deploy"))
2125)
2126"#;
2127
2128	#[test]
2129	fn now() {
2130		assert_ok!(execute(CODE_TIMESTAMP_NOW, vec![], MockExt::default()));
2131		assert_ok!(execute(CODE_TIMESTAMP_NOW_UNPREFIXED, vec![], MockExt::default()));
2132	}
2133
2134	const CODE_MINIMUM_BALANCE: &str = r#"
2135(module
2136	(import "seal0" "seal_minimum_balance" (func $seal_minimum_balance (param i32 i32)))
2137	(import "env" "memory" (memory 1 1))
2138
2139	;; size of our buffer is 32 bytes
2140	(data (i32.const 32) "\20")
2141
2142	(func $assert (param i32)
2143		(block $ok
2144			(br_if $ok
2145				(local.get 0)
2146			)
2147			(unreachable)
2148		)
2149	)
2150
2151	(func (export "call")
2152		(call $seal_minimum_balance (i32.const 0) (i32.const 32))
2153
2154		;; assert len == 8
2155		(call $assert
2156			(i32.eq
2157				(i32.load (i32.const 32))
2158				(i32.const 8)
2159			)
2160		)
2161
2162		;; assert that contents of the buffer is equal to the i64 value of 666.
2163		(call $assert
2164			(i64.eq
2165				(i64.load (i32.const 0))
2166				(i64.const 666)
2167			)
2168		)
2169	)
2170	(func (export "deploy"))
2171)
2172"#;
2173
2174	#[test]
2175	fn minimum_balance() {
2176		assert_ok!(execute(CODE_MINIMUM_BALANCE, vec![], MockExt::default()));
2177	}
2178
2179	const CODE_RANDOM: &str = r#"
2180(module
2181	(import "seal0" "seal_random" (func $seal_random (param i32 i32 i32 i32)))
2182	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
2183	(import "env" "memory" (memory 1 1))
2184
2185	;; [0,128) is reserved for the result of PRNG.
2186
2187	;; the subject used for the PRNG. [128,160)
2188	(data (i32.const 128)
2189		"\00\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F"
2190		"\00\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F"
2191	)
2192
2193	;; size of our buffer is 128 bytes
2194	(data (i32.const 160) "\80")
2195
2196	(func $assert (param i32)
2197		(block $ok
2198			(br_if $ok
2199				(local.get 0)
2200			)
2201			(unreachable)
2202		)
2203	)
2204
2205	(func (export "call")
2206		;; This stores the block random seed in the buffer
2207		(call $seal_random
2208			(i32.const 128) ;; Pointer in memory to the start of the subject buffer
2209			(i32.const 32) ;; The subject buffer's length
2210			(i32.const 0) ;; Pointer to the output buffer
2211			(i32.const 160) ;; Pointer to the output buffer length
2212		)
2213
2214		;; assert len == 32
2215		(call $assert
2216			(i32.eq
2217				(i32.load (i32.const 160))
2218				(i32.const 32)
2219			)
2220		)
2221
2222		;; return the random data
2223		(call $seal_return
2224			(i32.const 0)
2225			(i32.const 0)
2226			(i32.const 32)
2227		)
2228	)
2229	(func (export "deploy"))
2230)
2231"#;
2232
2233	#[test]
2234	fn random() {
2235		let output = execute_unvalidated(CODE_RANDOM, vec![], MockExt::default()).unwrap();
2236
2237		// The mock ext just returns the same data that was passed as the subject.
2238		assert_eq!(
2239			output,
2240			ExecReturnValue {
2241				flags: ReturnFlags::empty(),
2242				data: array_bytes::hex_into_unchecked(
2243					"000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
2244				)
2245			},
2246		);
2247	}
2248
2249	const CODE_RANDOM_V1: &str = r#"
2250(module
2251	(import "seal1" "seal_random" (func $seal_random (param i32 i32 i32 i32)))
2252	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
2253	(import "env" "memory" (memory 1 1))
2254
2255	;; [0,128) is reserved for the result of PRNG.
2256
2257	;; the subject used for the PRNG. [128,160)
2258	(data (i32.const 128)
2259		"\00\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F"
2260		"\00\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F"
2261	)
2262
2263	;; size of our buffer is 128 bytes
2264	(data (i32.const 160) "\80")
2265
2266	(func $assert (param i32)
2267		(block $ok
2268			(br_if $ok
2269				(local.get 0)
2270			)
2271			(unreachable)
2272		)
2273	)
2274
2275	(func (export "call")
2276		;; This stores the block random seed in the buffer
2277		(call $seal_random
2278			(i32.const 128) ;; Pointer in memory to the start of the subject buffer
2279			(i32.const 32) ;; The subject buffer's length
2280			(i32.const 0) ;; Pointer to the output buffer
2281			(i32.const 160) ;; Pointer to the output buffer length
2282		)
2283
2284		;; assert len == 32
2285		(call $assert
2286			(i32.eq
2287				(i32.load (i32.const 160))
2288				(i32.const 40)
2289			)
2290		)
2291
2292		;; return the random data
2293		(call $seal_return
2294			(i32.const 0)
2295			(i32.const 0)
2296			(i32.const 40)
2297		)
2298	)
2299	(func (export "deploy"))
2300)
2301"#;
2302
2303	#[test]
2304	fn random_v1() {
2305		let output = execute_unvalidated(CODE_RANDOM_V1, vec![], MockExt::default()).unwrap();
2306
2307		// The mock ext just returns the same data that was passed as the subject.
2308		assert_eq!(
2309			output,
2310			ExecReturnValue {
2311				flags: ReturnFlags::empty(),
2312				data: (
2313					array_bytes::hex2array_unchecked::<_, 32>(
2314						"000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
2315					),
2316					42u64,
2317				)
2318					.encode()
2319			},
2320		);
2321	}
2322
2323	const CODE_DEPOSIT_EVENT: &str = r#"
2324(module
2325	(import "seal0" "seal_deposit_event" (func $seal_deposit_event (param i32 i32 i32 i32)))
2326	(import "env" "memory" (memory 1 1))
2327
2328	(func (export "call")
2329		(call $seal_deposit_event
2330			(i32.const 32) ;; Pointer to the start of topics buffer
2331			(i32.const 33) ;; The length of the topics buffer.
2332			(i32.const 8) ;; Pointer to the start of the data buffer
2333			(i32.const 13) ;; Length of the buffer
2334		)
2335	)
2336	(func (export "deploy"))
2337
2338	(data (i32.const 8) "\00\01\2A\00\00\00\00\00\00\00\E5\14\00")
2339
2340	;; Encoded Vec<TopicOf<T>>, the buffer has length of 33 bytes.
2341	(data (i32.const 32) "\04\33\33\33\33\33\33\33\33\33\33\33\33\33\33\33\33\33\33\33\33\33\33\33"
2342	"\33\33\33\33\33\33\33\33\33")
2343)
2344"#;
2345
2346	#[test]
2347	fn deposit_event() {
2348		let mut mock_ext = MockExt::default();
2349		assert_ok!(execute(CODE_DEPOSIT_EVENT, vec![], &mut mock_ext));
2350
2351		assert_eq!(
2352			mock_ext.events,
2353			vec![(
2354				vec![H256::repeat_byte(0x33)],
2355				vec![0x00, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00]
2356			)]
2357		);
2358
2359		assert!(mock_ext.gas_meter.gas_left().ref_time() > 0);
2360	}
2361
2362	const CODE_DEPOSIT_EVENT_DUPLICATES: &str = r#"
2363(module
2364	(import "seal0" "seal_deposit_event" (func $seal_deposit_event (param i32 i32 i32 i32)))
2365	(import "env" "memory" (memory 1 1))
2366
2367	(func (export "call")
2368		(call $seal_deposit_event
2369			(i32.const 32) ;; Pointer to the start of topics buffer
2370			(i32.const 129) ;; The length of the topics buffer.
2371			(i32.const 8) ;; Pointer to the start of the data buffer
2372			(i32.const 13) ;; Length of the buffer
2373		)
2374	)
2375	(func (export "deploy"))
2376
2377	(data (i32.const 8) "\00\01\2A\00\00\00\00\00\00\00\E5\14\00")
2378
2379	;; Encoded Vec<TopicOf<T>>, the buffer has length of 129 bytes.
2380	(data (i32.const 32) "\10"
2381"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
2382"\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02"
2383"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
2384"\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04")
2385)
2386"#;
2387
2388	/// Checks that the runtime allows duplicate topics.
2389	#[test]
2390	fn deposit_event_duplicates_allowed() {
2391		let mut mock_ext = MockExt::default();
2392		assert_ok!(execute(CODE_DEPOSIT_EVENT_DUPLICATES, vec![], &mut mock_ext,));
2393
2394		assert_eq!(
2395			mock_ext.events,
2396			vec![(
2397				vec![
2398					H256::repeat_byte(0x01),
2399					H256::repeat_byte(0x02),
2400					H256::repeat_byte(0x01),
2401					H256::repeat_byte(0x04)
2402				],
2403				vec![0x00, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00]
2404			)]
2405		);
2406	}
2407
2408	const CODE_DEPOSIT_EVENT_MAX_TOPICS: &str = r#"
2409(module
2410	(import "seal0" "seal_deposit_event" (func $seal_deposit_event (param i32 i32 i32 i32)))
2411	(import "env" "memory" (memory 1 1))
2412
2413	(func (export "call")
2414		(call $seal_deposit_event
2415			(i32.const 32) ;; Pointer to the start of topics buffer
2416			(i32.const 161) ;; The length of the topics buffer.
2417			(i32.const 8) ;; Pointer to the start of the data buffer
2418			(i32.const 13) ;; Length of the buffer
2419		)
2420	)
2421	(func (export "deploy"))
2422
2423	(data (i32.const 8) "\00\01\2A\00\00\00\00\00\00\00\E5\14\00")
2424
2425	;; Encoded Vec<TopicOf<T>>, the buffer has length of 161 bytes.
2426	(data (i32.const 32) "\14"
2427"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
2428"\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02"
2429"\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03"
2430"\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04\04"
2431"\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05\05")
2432)
2433"#;
2434
2435	/// Checks that the runtime traps if there are more than `max_topic_events` topics.
2436	#[test]
2437	fn deposit_event_max_topics() {
2438		assert_eq!(
2439			execute(CODE_DEPOSIT_EVENT_MAX_TOPICS, vec![], MockExt::default(),),
2440			Err(ExecError {
2441				error: Error::<Test>::TooManyTopics.into(),
2442				origin: ErrorOrigin::Caller,
2443			})
2444		);
2445	}
2446
2447	/// calls `seal_block_number` compares the result with the constant 121.
2448	const CODE_BLOCK_NUMBER: &str = r#"
2449(module
2450	(import "seal0" "seal_block_number" (func $seal_block_number (param i32 i32)))
2451	(import "env" "memory" (memory 1 1))
2452
2453	;; size of our buffer is 32 bytes
2454	(data (i32.const 32) "\20")
2455
2456	(func $assert (param i32)
2457		(block $ok
2458			(br_if $ok
2459				(local.get 0)
2460			)
2461			(unreachable)
2462		)
2463	)
2464
2465	(func (export "call")
2466		;; This stores the block height in the buffer
2467		(call $seal_block_number (i32.const 0) (i32.const 32))
2468
2469		;; assert len == 8
2470		(call $assert
2471			(i32.eq
2472				(i32.load (i32.const 32))
2473				(i32.const 8)
2474			)
2475		)
2476
2477		;; assert that contents of the buffer is equal to the i64 value of 121.
2478		(call $assert
2479			(i64.eq
2480				(i64.load (i32.const 0))
2481				(i64.const 121)
2482			)
2483		)
2484	)
2485
2486	(func (export "deploy"))
2487)
2488"#;
2489
2490	#[test]
2491	fn block_number() {
2492		let _ = execute(CODE_BLOCK_NUMBER, vec![], MockExt::default()).unwrap();
2493	}
2494
2495	const CODE_RETURN_WITH_DATA: &str = r#"
2496(module
2497	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
2498	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
2499	(import "env" "memory" (memory 1 1))
2500
2501	(data (i32.const 32) "\20")
2502
2503	;; Deploy routine is the same as call.
2504	(func (export "deploy")
2505		(call $call)
2506	)
2507
2508	;; Call reads the first 4 bytes (LE) as the exit status and returns the rest as output data.
2509	(func $call (export "call")
2510		;; Copy input data this contract memory.
2511		(call $seal_input
2512			(i32.const 0)	;; Pointer where to store input
2513			(i32.const 32)	;; Pointer to the length of the buffer
2514		)
2515
2516		;; Copy all but the first 4 bytes of the input data as the output data.
2517		(call $seal_return
2518			(i32.load (i32.const 0))
2519			(i32.const 4)
2520			(i32.sub (i32.load (i32.const 32)) (i32.const 4))
2521		)
2522		(unreachable)
2523	)
2524)
2525"#;
2526
2527	#[test]
2528	fn seal_return_with_success_status() {
2529		let output = execute(
2530			CODE_RETURN_WITH_DATA,
2531			array_bytes::hex2bytes_unchecked("00000000445566778899"),
2532			MockExt::default(),
2533		)
2534		.unwrap();
2535
2536		assert_eq!(
2537			output,
2538			ExecReturnValue {
2539				flags: ReturnFlags::empty(),
2540				data: array_bytes::hex2bytes_unchecked("445566778899"),
2541			}
2542		);
2543		assert!(!output.did_revert());
2544	}
2545
2546	#[test]
2547	fn return_with_revert_status() {
2548		let output = execute(
2549			CODE_RETURN_WITH_DATA,
2550			array_bytes::hex2bytes_unchecked("010000005566778899"),
2551			MockExt::default(),
2552		)
2553		.unwrap();
2554
2555		assert_eq!(
2556			output,
2557			ExecReturnValue {
2558				flags: ReturnFlags::REVERT,
2559				data: array_bytes::hex2bytes_unchecked("5566778899"),
2560			}
2561		);
2562		assert!(output.did_revert());
2563	}
2564
2565	const CODE_OUT_OF_BOUNDS_ACCESS: &str = r#"
2566(module
2567	(import "seal0" "seal_terminate" (func $seal_terminate (param i32 i32)))
2568	(import "env" "memory" (memory 1 1))
2569
2570	(func (export "deploy"))
2571
2572	(func (export "call")
2573		(call $seal_terminate
2574			(i32.const 65536)  ;; Pointer to "account" address (out of bound).
2575			(i32.const 8)  ;; Length of "account" address.
2576		)
2577	)
2578)
2579"#;
2580
2581	#[test]
2582	fn contract_out_of_bounds_access() {
2583		let mut mock_ext = MockExt::default();
2584		let result = execute(CODE_OUT_OF_BOUNDS_ACCESS, vec![], &mut mock_ext);
2585
2586		assert_eq!(
2587			result,
2588			Err(ExecError {
2589				error: Error::<Test>::DecodingFailed.into(),
2590				origin: ErrorOrigin::Caller,
2591			})
2592		);
2593	}
2594
2595	const CODE_DECODE_FAILURE: &str = r#"
2596(module
2597	(import "seal0" "seal_terminate" (func $seal_terminate (param i32 i32)))
2598	(import "env" "memory" (memory 1 1))
2599
2600	(func (export "deploy"))
2601
2602	(func (export "call")
2603		(call $seal_terminate
2604			(i32.const 0)  ;; Pointer to "account" address.
2605			(i32.const 4)  ;; Length of "account" address (too small -> decode fail).
2606		)
2607	)
2608)
2609"#;
2610
2611	#[test]
2612	fn contract_decode_length_ignored() {
2613		let mut mock_ext = MockExt::default();
2614		let result = execute(CODE_DECODE_FAILURE, vec![], &mut mock_ext);
2615		// AccountID implements `MaxEncodeLen` and therefore the supplied length is
2616		// no longer needed nor used to determine how much is read from contract memory.
2617		assert_ok!(result);
2618	}
2619
2620	#[test]
2621	fn debug_message_works() {
2622		const CODE_DEBUG_MESSAGE: &str = r#"
2623(module
2624	(import "seal0" "seal_debug_message" (func $seal_debug_message (param i32 i32) (result i32)))
2625	(import "env" "memory" (memory 1 1))
2626
2627	(data (i32.const 0) "Hello World!")
2628
2629	(func (export "call")
2630		(call $seal_debug_message
2631			(i32.const 0)	;; Pointer to the text buffer
2632			(i32.const 12)	;; The size of the buffer
2633		)
2634		drop
2635	)
2636
2637	(func (export "deploy"))
2638)
2639"#;
2640		let mut ext = MockExt::default();
2641		execute(CODE_DEBUG_MESSAGE, vec![], &mut ext).unwrap();
2642
2643		assert_eq!(std::str::from_utf8(&ext.debug_buffer).unwrap(), "Hello World!");
2644	}
2645
2646	#[test]
2647	fn debug_message_invalid_utf8_fails() {
2648		const CODE_DEBUG_MESSAGE_FAIL: &str = r#"
2649(module
2650	(import "seal0" "seal_debug_message" (func $seal_debug_message (param i32 i32) (result i32)))
2651	(import "env" "memory" (memory 1 1))
2652
2653	(data (i32.const 0) "\fc")
2654
2655	(func (export "call")
2656		(call $seal_debug_message
2657			(i32.const 0)	;; Pointer to the text buffer
2658			(i32.const 1)	;; The size of the buffer
2659		)
2660		drop
2661	)
2662
2663	(func (export "deploy"))
2664)
2665"#;
2666		let mut ext = MockExt::default();
2667		let result = execute(CODE_DEBUG_MESSAGE_FAIL, vec![], &mut ext);
2668		assert_ok!(result);
2669		assert!(ext.debug_buffer.is_empty());
2670	}
2671
2672	const CODE_CALL_RUNTIME: &str = r#"
2673(module
2674	(import "seal0" "call_runtime" (func $call_runtime (param i32 i32) (result i32)))
2675	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
2676	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
2677	(import "env" "memory" (memory 1 1))
2678
2679	;; 0x1000 = 4k in little endian
2680	;; size of input buffer
2681	(data (i32.const 0) "\00\10")
2682
2683	(func (export "call")
2684		;; Receive the encoded call
2685		(call $seal_input
2686			(i32.const 4)	;; Pointer to the input buffer
2687			(i32.const 0)	;; Size of the length buffer
2688		)
2689		;; Just use the call passed as input and store result to memory
2690		(i32.store (i32.const 0)
2691			(call $call_runtime
2692				(i32.const 4)				;; Pointer where the call is stored
2693				(i32.load (i32.const 0))	;; Size of the call
2694			)
2695		)
2696		(call $seal_return
2697			(i32.const 0)	;; flags
2698			(i32.const 0)	;; returned value
2699			(i32.const 4)	;; length of returned value
2700		)
2701	)
2702
2703	(func (export "deploy"))
2704)
2705"#;
2706
2707	#[test]
2708	fn call_runtime_works() {
2709		let call =
2710			RuntimeCall::System(frame_system::Call::remark { remark: b"Hello World".to_vec() });
2711		let mut ext = MockExt::default();
2712		let result = execute(CODE_CALL_RUNTIME, call.encode(), &mut ext).unwrap();
2713		assert_eq!(*ext.runtime_calls.borrow(), vec![call]);
2714		// 0 = ReturnCode::Success
2715		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0);
2716	}
2717
2718	#[test]
2719	fn call_runtime_panics_on_invalid_call() {
2720		let mut ext = MockExt::default();
2721		let result = execute(CODE_CALL_RUNTIME, vec![0x42], &mut ext);
2722		assert_eq!(
2723			result,
2724			Err(ExecError {
2725				error: Error::<Test>::DecodingFailed.into(),
2726				origin: ErrorOrigin::Caller,
2727			})
2728		);
2729		assert_eq!(*ext.runtime_calls.borrow(), vec![]);
2730	}
2731
2732	#[test]
2733	fn set_storage_works() {
2734		const CODE: &str = r#"
2735(module
2736	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
2737	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
2738	(import "seal2" "set_storage" (func $set_storage (param i32 i32 i32 i32) (result i32)))
2739	(import "env" "memory" (memory 1 1))
2740
2741	;; [0, 4) size of input buffer
2742	;; 4k in little endian
2743	(data (i32.const 0) "\00\10")
2744
2745	;; [4, 4100) input buffer
2746
2747	(func (export "call")
2748		;; Receive (key ++ value_to_write)
2749		(call $seal_input
2750			(i32.const 4)	;; Pointer to the input buffer
2751			(i32.const 0)	;; Size of the input buffer
2752		)
2753		;; Store the passed value to the passed key and store result to memory
2754		(i32.store (i32.const 168)
2755			(call $set_storage
2756				(i32.const 8)				;; key_ptr
2757				(i32.load (i32.const 4))		;; key_len
2758				(i32.add				;; value_ptr = 8 + key_len
2759					(i32.const 8)
2760					(i32.load (i32.const 4)))
2761				(i32.sub				;; value_len (input_size - (key_len + key_len_len))
2762					(i32.load (i32.const 0))
2763					(i32.add
2764						(i32.load (i32.const 4))
2765						(i32.const 4)
2766					)
2767				)
2768			)
2769		)
2770		(call $seal_return
2771			(i32.const 0)	;; flags
2772			(i32.const 168)	;; ptr to returned value
2773			(i32.const 4)	;; length of returned value
2774		)
2775	)
2776
2777	(func (export "deploy"))
2778)
2779"#;
2780
2781		let mut ext = MockExt::default();
2782
2783		// value did not exist before -> sentinel returned
2784		let input = (32, [1u8; 32], [42u8, 48]).encode();
2785		let result = execute(CODE, input, &mut ext).unwrap();
2786		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL);
2787		assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[42u8, 48]);
2788
2789		// value do exist -> length of old value returned
2790		let input = (32, [1u8; 32], [0u8; 0]).encode();
2791		let result = execute(CODE, input, &mut ext).unwrap();
2792		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 2);
2793		assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[0u8; 0]);
2794
2795		// value do exist -> length of old value returned (test for zero sized val)
2796		let input = (32, [1u8; 32], [99u8]).encode();
2797		let result = execute(CODE, input, &mut ext).unwrap();
2798		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0);
2799		assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[99u8]);
2800	}
2801
2802	#[test]
2803	fn get_storage_works() {
2804		const CODE: &str = r#"
2805(module
2806	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
2807	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
2808	(import "seal1" "get_storage" (func $get_storage (param i32 i32 i32 i32) (result i32)))
2809	(import "env" "memory" (memory 1 1))
2810
2811	;; [0, 4) size of input buffer (160 bytes as we copy the key+len here)
2812	(data (i32.const 0) "\A0")
2813
2814	;; [4, 8) size of output buffer
2815	;; 4k in little endian
2816	(data (i32.const 4) "\00\10")
2817
2818	;; [8, 168) input buffer
2819	;; [168, 4264) output buffer
2820
2821	(func (export "call")
2822		;; Receive (key ++ value_to_write)
2823		(call $seal_input
2824			(i32.const 8)	;; Pointer to the input buffer
2825			(i32.const 0)	;; Size of the input buffer
2826		)
2827		;; Load a storage value and result of this call into the output buffer
2828		(i32.store (i32.const 168)
2829			(call $get_storage
2830				(i32.const 12)			;; key_ptr
2831				(i32.load (i32.const 8))	;; key_len
2832				(i32.const 172)			;; Pointer to the output buffer
2833				(i32.const 4)			;; Pointer to the size of the buffer
2834			)
2835		)
2836		(call $seal_return
2837			(i32.const 0)				;; flags
2838			(i32.const 168)				;; output buffer ptr
2839			(i32.add				;; length: output size + 4 (retval)
2840				(i32.load (i32.const 4))
2841				(i32.const 4)
2842			)
2843		)
2844	)
2845
2846	(func (export "deploy"))
2847)
2848"#;
2849
2850		let mut ext = MockExt::default();
2851
2852		ext.set_storage(
2853			&Key::<Test>::try_from_var([1u8; 64].to_vec()).unwrap(),
2854			Some(vec![42u8]),
2855			false,
2856		)
2857		.unwrap();
2858
2859		ext.set_storage(
2860			&Key::<Test>::try_from_var([2u8; 19].to_vec()).unwrap(),
2861			Some(vec![]),
2862			false,
2863		)
2864		.unwrap();
2865
2866		// value does not exist
2867		let input = (63, [1u8; 64]).encode();
2868		let result = execute(CODE, input, &mut ext).unwrap();
2869		assert_eq!(
2870			u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
2871			ReturnErrorCode::KeyNotFound as u32
2872		);
2873
2874		// value exists
2875		let input = (64, [1u8; 64]).encode();
2876		let result = execute(CODE, input, &mut ext).unwrap();
2877		assert_eq!(
2878			u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
2879			ReturnErrorCode::Success as u32
2880		);
2881		assert_eq!(ext.storage.get(&[1u8; 64].to_vec()).unwrap(), &[42u8]);
2882		assert_eq!(&result.data[4..], &[42u8]);
2883
2884		// value exists (test for 0 sized)
2885		let input = (19, [2u8; 19]).encode();
2886		let result = execute(CODE, input, &mut ext).unwrap();
2887		assert_eq!(
2888			u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
2889			ReturnErrorCode::Success as u32
2890		);
2891		assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), Some(&vec![]));
2892		assert_eq!(&result.data[4..], &([] as [u8; 0]));
2893	}
2894
2895	#[test]
2896	fn clear_storage_works() {
2897		const CODE: &str = r#"
2898(module
2899	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
2900	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
2901	(import "seal1" "clear_storage" (func $clear_storage (param i32 i32) (result i32)))
2902	(import "env" "memory" (memory 1 1))
2903
2904	;; size of input buffer
2905	;; [0, 4) size of input buffer (128+32 = 160 bytes = 0xA0)
2906	(data (i32.const 0) "\A0")
2907
2908	;; [4, 164) input buffer
2909
2910	(func (export "call")
2911		;; Receive key
2912		(call $seal_input
2913			(i32.const 4)	;; Where we take input and store it
2914			(i32.const 0)	;; Where we take and store the length of thedata
2915		)
2916		;; Call seal_clear_storage and save what it returns at 0
2917		(i32.store (i32.const 0)
2918			(call $clear_storage
2919				(i32.const 8)			;; key_ptr
2920				(i32.load (i32.const 4))	;; key_len
2921			)
2922		)
2923		(call $seal_return
2924			(i32.const 0)	;; flags
2925			(i32.const 0)	;; returned value
2926			(i32.const 4)	;; length of returned value
2927		)
2928	)
2929
2930	(func (export "deploy"))
2931)
2932"#;
2933
2934		let mut ext = MockExt::default();
2935
2936		ext.set_storage(
2937			&Key::<Test>::try_from_var([1u8; 64].to_vec()).unwrap(),
2938			Some(vec![42u8]),
2939			false,
2940		)
2941		.unwrap();
2942		ext.set_storage(
2943			&Key::<Test>::try_from_var([2u8; 19].to_vec()).unwrap(),
2944			Some(vec![]),
2945			false,
2946		)
2947		.unwrap();
2948
2949		// value did not exist
2950		let input = (32, [3u8; 32]).encode();
2951		let result = execute(CODE, input, &mut ext).unwrap();
2952		// sentinel returned
2953		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL);
2954		assert_eq!(ext.storage.get(&[3u8; 32].to_vec()), None);
2955
2956		// value did exist
2957		let input = (64, [1u8; 64]).encode();
2958		let result = execute(CODE, input, &mut ext).unwrap();
2959		// length returned
2960		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1);
2961		// value cleared
2962		assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None);
2963
2964		//value did not exist (wrong key length)
2965		let input = (63, [1u8; 64]).encode();
2966		let result = execute(CODE, input, &mut ext).unwrap();
2967		// sentinel returned
2968		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL);
2969		assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None);
2970
2971		// value exists
2972		let input = (19, [2u8; 19]).encode();
2973		let result = execute(CODE, input, &mut ext).unwrap();
2974		// length returned (test for 0 sized)
2975		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0);
2976		// value cleared
2977		assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), None);
2978	}
2979
2980	#[test]
2981	fn take_storage_works() {
2982		const CODE: &str = r#"
2983(module
2984	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
2985	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
2986	(import "seal0" "take_storage" (func $take_storage (param i32 i32 i32 i32) (result i32)))
2987	(import "env" "memory" (memory 1 1))
2988
2989	;; [0, 4) size of input buffer (160 bytes as we copy the key+len here)
2990	(data (i32.const 0) "\A0")
2991
2992	;; [4, 8) size of output buffer
2993	;; 4k in little endian
2994	(data (i32.const 4) "\00\10")
2995
2996	;; [8, 168) input buffer
2997	;; [168, 4264) output buffer
2998
2999	(func (export "call")
3000		;; Receive key
3001		(call $seal_input
3002			(i32.const 8)	;; Pointer to the input buffer
3003			(i32.const 0)	;; Size of the length buffer
3004		)
3005
3006		;; Load a storage value and result of this call into the output buffer
3007		(i32.store (i32.const 168)
3008			(call $take_storage
3009				(i32.const 12)			;; key_ptr
3010				(i32.load (i32.const 8))	;; key_len
3011				(i32.const 172)			;; Pointer to the output buffer
3012				(i32.const 4)			;; Pointer to the size of the buffer
3013			)
3014		)
3015
3016		;; Return the contents of the buffer
3017		(call $seal_return
3018			(i32.const 0)				;; flags
3019			(i32.const 168)				;; output buffer ptr
3020			(i32.add				;; length: storage size + 4 (retval)
3021				(i32.load (i32.const 4))
3022				(i32.const 4)
3023			)
3024		)
3025	)
3026
3027	(func (export "deploy"))
3028)
3029"#;
3030
3031		let mut ext = MockExt::default();
3032
3033		ext.set_storage(
3034			&Key::<Test>::try_from_var([1u8; 64].to_vec()).unwrap(),
3035			Some(vec![42u8]),
3036			false,
3037		)
3038		.unwrap();
3039
3040		ext.set_storage(
3041			&Key::<Test>::try_from_var([2u8; 19].to_vec()).unwrap(),
3042			Some(vec![]),
3043			false,
3044		)
3045		.unwrap();
3046
3047		// value does not exist -> error returned
3048		let input = (63, [1u8; 64]).encode();
3049		let result = execute(CODE, input, &mut ext).unwrap();
3050		assert_eq!(
3051			u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
3052			ReturnErrorCode::KeyNotFound as u32
3053		);
3054
3055		// value did exist -> value returned
3056		let input = (64, [1u8; 64]).encode();
3057		let result = execute(CODE, input, &mut ext).unwrap();
3058		assert_eq!(
3059			u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
3060			ReturnErrorCode::Success as u32
3061		);
3062		assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None);
3063		assert_eq!(&result.data[4..], &[42u8]);
3064
3065		// value did exist -> length returned (test for 0 sized)
3066		let input = (19, [2u8; 19]).encode();
3067		let result = execute(CODE, input, &mut ext).unwrap();
3068		assert_eq!(
3069			u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
3070			ReturnErrorCode::Success as u32
3071		);
3072		assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), None);
3073		assert_eq!(&result.data[4..], &[0u8; 0]);
3074	}
3075
3076	#[test]
3077	fn set_transient_storage_works() {
3078		const CODE: &str = r#"
3079(module
3080	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
3081	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
3082	(import "seal0" "set_transient_storage" (func $set_transient_storage (param i32 i32 i32 i32) (result i32)))
3083	(import "env" "memory" (memory 1 1))
3084
3085	;; [0, 4) size of input buffer
3086	;; 4k in little endian
3087	(data (i32.const 0) "\00\10")
3088
3089	;; [4, 4100) input buffer
3090
3091	(func (export "call")
3092		;; Receive (key ++ value_to_write)
3093		(call $seal_input
3094			(i32.const 4)	;; Pointer to the input buffer
3095			(i32.const 0)	;; Size of the input buffer
3096		)
3097		;; Store the passed value to the passed key and store result to memory
3098		(i32.store (i32.const 168)
3099			(call $set_transient_storage
3100				(i32.const 8)				;; key_ptr
3101				(i32.load (i32.const 4))		;; key_len
3102				(i32.add				;; value_ptr = 8 + key_len
3103					(i32.const 8)
3104					(i32.load (i32.const 4)))
3105				(i32.sub				;; value_len (input_size - (key_len + key_len_len))
3106					(i32.load (i32.const 0))
3107					(i32.add
3108						(i32.load (i32.const 4))
3109						(i32.const 4)
3110					)
3111				)
3112			)
3113		)
3114		(call $seal_return
3115			(i32.const 0)	;; flags
3116			(i32.const 168)	;; ptr to returned value
3117			(i32.const 4)	;; length of returned value
3118		)
3119	)
3120
3121	(func (export "deploy"))
3122)
3123"#;
3124
3125		let mut ext = MockExt::default();
3126
3127		// value did not exist before -> sentinel returned
3128		let input = (32, [1u8; 32], [42u8, 48]).encode();
3129		let result = execute(CODE, input, &mut ext).unwrap();
3130		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL);
3131		assert_eq!(
3132			ext.get_transient_storage(&Key::<Test>::try_from_var([1u8; 32].to_vec()).unwrap()),
3133			Some(vec![42, 48])
3134		);
3135
3136		// value do exist -> length of old value returned
3137		let input = (32, [1u8; 32], [0u8; 0]).encode();
3138		let result = execute(CODE, input, &mut ext).unwrap();
3139		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 2);
3140		assert_eq!(
3141			ext.get_transient_storage(&Key::<Test>::try_from_var([1u8; 32].to_vec()).unwrap()),
3142			Some(vec![])
3143		);
3144
3145		// value do exist -> length of old value returned (test for zero sized val)
3146		let input = (32, [1u8; 32], [99u8]).encode();
3147		let result = execute(CODE, input, &mut ext).unwrap();
3148		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0);
3149		assert_eq!(
3150			ext.get_transient_storage(&Key::<Test>::try_from_var([1u8; 32].to_vec()).unwrap()),
3151			Some(vec![99])
3152		);
3153	}
3154
3155	#[test]
3156	fn get_transient_storage_works() {
3157		const CODE: &str = r#"
3158(module
3159	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
3160	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
3161	(import "seal0" "get_transient_storage" (func $get_transient_storage (param i32 i32 i32 i32) (result i32)))
3162	(import "env" "memory" (memory 1 1))
3163
3164	;; [0, 4) size of input buffer (160 bytes as we copy the key+len here)
3165	(data (i32.const 0) "\A0")
3166
3167	;; [4, 8) size of output buffer
3168	;; 4k in little endian
3169	(data (i32.const 4) "\00\10")
3170
3171	;; [8, 168) input buffer
3172	;; [168, 4264) output buffer
3173
3174	(func (export "call")
3175		;; Receive (key ++ value_to_write)
3176		(call $seal_input
3177			(i32.const 8)	;; Pointer to the input buffer
3178			(i32.const 0)	;; Size of the input buffer
3179		)
3180		;; Load a storage value and result of this call into the output buffer
3181		(i32.store (i32.const 168)
3182			(call $get_transient_storage
3183				(i32.const 12)			;; key_ptr
3184				(i32.load (i32.const 8))	;; key_len
3185				(i32.const 172)			;; Pointer to the output buffer
3186				(i32.const 4)			;; Pointer to the size of the buffer
3187			)
3188		)
3189		(call $seal_return
3190			(i32.const 0)				;; flags
3191			(i32.const 168)				;; output buffer ptr
3192			(i32.add				;; length: output size + 4 (retval)
3193				(i32.load (i32.const 4))
3194				(i32.const 4)
3195			)
3196		)
3197	)
3198
3199	(func (export "deploy"))
3200)
3201"#;
3202
3203		let mut ext = MockExt::default();
3204
3205		assert_ok!(ext.set_transient_storage(
3206			&Key::<Test>::try_from_var([1u8; 64].to_vec()).unwrap(),
3207			Some(vec![42u8]),
3208			false
3209		));
3210		assert_ok!(ext.set_transient_storage(
3211			&Key::<Test>::try_from_var([2u8; 19].to_vec()).unwrap(),
3212			Some(vec![]),
3213			false
3214		));
3215
3216		// value does not exist
3217		let input = (63, [1u8; 64]).encode();
3218		let result = execute(CODE, input, &mut ext).unwrap();
3219		assert_eq!(
3220			u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
3221			ReturnErrorCode::KeyNotFound as u32
3222		);
3223
3224		// value exists
3225		let input = (64, [1u8; 64]).encode();
3226		let result = execute(CODE, input, &mut ext).unwrap();
3227		assert_eq!(
3228			u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
3229			ReturnErrorCode::Success as u32
3230		);
3231		assert_eq!(&result.data[4..], &[42u8]);
3232
3233		// value exists (test for 0 sized)
3234		let input = (19, [2u8; 19]).encode();
3235		let result = execute(CODE, input, &mut ext).unwrap();
3236		assert_eq!(
3237			u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
3238			ReturnErrorCode::Success as u32
3239		);
3240		assert_eq!(&result.data[4..], &([] as [u8; 0]));
3241	}
3242
3243	#[test]
3244	fn clear_transient_storage_works() {
3245		const CODE: &str = r#"
3246(module
3247	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
3248	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
3249	(import "seal0" "clear_transient_storage" (func $clear_transient_storage (param i32 i32) (result i32)))
3250	(import "env" "memory" (memory 1 1))
3251
3252	;; size of input buffer
3253	;; [0, 4) size of input buffer (128+32 = 160 bytes = 0xA0)
3254	(data (i32.const 0) "\A0")
3255
3256	;; [4, 164) input buffer
3257
3258	(func (export "call")
3259		;; Receive key
3260		(call $seal_input
3261			(i32.const 4)	;; Where we take input and store it
3262			(i32.const 0)	;; Where we take and store the length of thedata
3263		)
3264		;; Call seal_clear_storage and save what it returns at 0
3265		(i32.store (i32.const 0)
3266			(call $clear_transient_storage
3267				(i32.const 8)			;; key_ptr
3268				(i32.load (i32.const 4))	;; key_len
3269			)
3270		)
3271		(call $seal_return
3272			(i32.const 0)	;; flags
3273			(i32.const 0)	;; returned value
3274			(i32.const 4)	;; length of returned value
3275		)
3276	)
3277
3278	(func (export "deploy"))
3279)
3280"#;
3281
3282		let mut ext = MockExt::default();
3283
3284		assert_ok!(ext.set_transient_storage(
3285			&Key::<Test>::try_from_var([1u8; 64].to_vec()).unwrap(),
3286			Some(vec![42u8]),
3287			false
3288		));
3289
3290		// value did not exist
3291		let input = (32, [3u8; 32]).encode();
3292		let result = execute(CODE, input, &mut ext).unwrap();
3293		// sentinel returned
3294		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL);
3295
3296		// value did exist
3297		let input = (64, [1u8; 64]).encode();
3298		let result = execute(CODE, input, &mut ext).unwrap();
3299		// length returned
3300		assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1);
3301		// value cleared
3302		assert_eq!(
3303			ext.get_transient_storage(&Key::<Test>::try_from_var([1u8; 64].to_vec()).unwrap()),
3304			None
3305		);
3306	}
3307
3308	#[test]
3309	fn take_transient_storage_works() {
3310		const CODE: &str = r#"
3311(module
3312	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
3313	(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
3314	(import "seal0" "take_transient_storage" (func $take_transient_storage (param i32 i32 i32 i32) (result i32)))
3315	(import "env" "memory" (memory 1 1))
3316
3317	;; [0, 4) size of input buffer (160 bytes as we copy the key+len here)
3318	(data (i32.const 0) "\A0")
3319
3320	;; [4, 8) size of output buffer
3321	;; 4k in little endian
3322	(data (i32.const 4) "\00\10")
3323
3324	;; [8, 168) input buffer
3325	;; [168, 4264) output buffer
3326
3327	(func (export "call")
3328		;; Receive key
3329		(call $seal_input
3330			(i32.const 8)	;; Pointer to the input buffer
3331			(i32.const 0)	;; Size of the length buffer
3332		)
3333
3334		;; Load a storage value and result of this call into the output buffer
3335		(i32.store (i32.const 168)
3336			(call $take_transient_storage
3337				(i32.const 12)			;; key_ptr
3338				(i32.load (i32.const 8))	;; key_len
3339				(i32.const 172)			;; Pointer to the output buffer
3340				(i32.const 4)			;; Pointer to the size of the buffer
3341			)
3342		)
3343
3344		;; Return the contents of the buffer
3345		(call $seal_return
3346			(i32.const 0)				;; flags
3347			(i32.const 168)				;; output buffer ptr
3348			(i32.add				;; length: storage size + 4 (retval)
3349				(i32.load (i32.const 4))
3350				(i32.const 4)
3351			)
3352		)
3353	)
3354
3355	(func (export "deploy"))
3356)
3357"#;
3358
3359		let mut ext = MockExt::default();
3360
3361		assert_ok!(ext.set_transient_storage(
3362			&Key::<Test>::try_from_var([1u8; 64].to_vec()).unwrap(),
3363			Some(vec![42u8]),
3364			false
3365		));
3366		assert_ok!(ext.set_transient_storage(
3367			&Key::<Test>::try_from_var([2u8; 19].to_vec()).unwrap(),
3368			Some(vec![]),
3369			false
3370		));
3371
3372		// value does not exist -> error returned
3373		let input = (63, [1u8; 64]).encode();
3374		let result = execute(CODE, input, &mut ext).unwrap();
3375		assert_eq!(
3376			u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
3377			ReturnErrorCode::KeyNotFound as u32
3378		);
3379
3380		// value did exist -> value returned
3381		let input = (64, [1u8; 64]).encode();
3382		let result = execute(CODE, input, &mut ext).unwrap();
3383		assert_eq!(
3384			u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
3385			ReturnErrorCode::Success as u32
3386		);
3387		assert_eq!(
3388			ext.get_transient_storage(&Key::<Test>::try_from_var([1u8; 64].to_vec()).unwrap()),
3389			None
3390		);
3391		assert_eq!(&result.data[4..], &[42u8]);
3392
3393		// value did exist -> length returned (test for 0 sized)
3394		let input = (19, [2u8; 19]).encode();
3395		let result = execute(CODE, input, &mut ext).unwrap();
3396		assert_eq!(
3397			u32::from_le_bytes(result.data[0..4].try_into().unwrap()),
3398			ReturnErrorCode::Success as u32
3399		);
3400		assert_eq!(
3401			ext.get_transient_storage(&Key::<Test>::try_from_var([2u8; 19].to_vec()).unwrap()),
3402			None
3403		);
3404		assert_eq!(&result.data[4..], &[0u8; 0]);
3405	}
3406
3407	#[test]
3408	fn is_contract_works() {
3409		const CODE_IS_CONTRACT: &str = r#"
3410;; This runs `is_contract` check on zero account address
3411(module
3412	(import "seal0" "seal_is_contract" (func $seal_is_contract (param i32) (result i32)))
3413	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
3414	(import "env" "memory" (memory 1 1))
3415
3416	;; [0, 32) zero-adress
3417	(data (i32.const 0)
3418		"\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
3419		"\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
3420	)
3421
3422	;; [32, 36) here we store the return code of the `seal_is_contract`
3423
3424	(func (export "deploy"))
3425
3426	(func (export "call")
3427		(i32.store
3428			(i32.const 32)
3429			(call $seal_is_contract
3430				(i32.const 0) ;; ptr to destination address
3431			)
3432		)
3433		;; exit with success and take `seal_is_contract` return code to the output buffer
3434		(call $seal_return (i32.const 0) (i32.const 32) (i32.const 4))
3435	)
3436)
3437"#;
3438		let output = execute(CODE_IS_CONTRACT, vec![], MockExt::default()).unwrap();
3439
3440		// The mock ext just always returns 1u32 (`true`).
3441		assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: 1u32.encode() },);
3442	}
3443
3444	#[test]
3445	fn code_hash_works() {
3446		/// calls `seal_code_hash` and compares the result with the constant.
3447		const CODE_CODE_HASH: &str = r#"
3448(module
3449	(import "seal0" "seal_code_hash" (func $seal_code_hash (param i32 i32 i32) (result i32)))
3450	(import "env" "memory" (memory 1 1))
3451
3452	;; size of our buffer is 32 bytes
3453	(data (i32.const 32) "\20")
3454
3455	(func $assert (param i32)
3456		(block $ok
3457			(br_if $ok
3458				(local.get 0)
3459			)
3460			(unreachable)
3461		)
3462	)
3463
3464	(func (export "call")
3465		;; fill the buffer with the code hash.
3466		(call $seal_code_hash
3467			(i32.const 0) ;; input: address_ptr (before call)
3468			(i32.const 0) ;; output: code_hash_ptr (after call)
3469			(i32.const 32) ;; same 32 bytes length for input and output
3470		)
3471
3472		;; assert size == 32
3473		(call $assert
3474			(i32.eq
3475				(i32.load (i32.const 32))
3476				(i32.const 32)
3477			)
3478		)
3479
3480		;; assert that the first 8 bytes are "1111111111111111"
3481		(call $assert
3482			(i64.eq
3483				(i64.load (i32.const 0))
3484				(i64.const 0x1111111111111111)
3485			)
3486		)
3487		drop
3488	)
3489
3490	(func (export "deploy"))
3491)
3492"#;
3493		assert_ok!(execute(CODE_CODE_HASH, vec![], MockExt::default()));
3494	}
3495
3496	#[test]
3497	fn own_code_hash_works() {
3498		/// calls `seal_own_code_hash` and compares the result with the constant.
3499		const CODE_OWN_CODE_HASH: &str = r#"
3500(module
3501	(import "seal0" "seal_own_code_hash" (func $seal_own_code_hash (param i32 i32)))
3502	(import "env" "memory" (memory 1 1))
3503
3504	;; size of our buffer is 32 bytes
3505	(data (i32.const 32) "\20")
3506
3507	(func $assert (param i32)
3508		(block $ok
3509			(br_if $ok
3510				(local.get 0)
3511			)
3512			(unreachable)
3513		)
3514	)
3515
3516	(func (export "call")
3517		;; fill the buffer with the code hash
3518		(call $seal_own_code_hash
3519			(i32.const 0)  ;; output: code_hash_ptr
3520			(i32.const 32) ;; 32 bytes length of code_hash output
3521		)
3522
3523		;; assert size == 32
3524		(call $assert
3525			(i32.eq
3526				(i32.load (i32.const 32))
3527				(i32.const 32)
3528			)
3529		)
3530
3531		;; assert that the first 8 bytes are "1010101010101010"
3532		(call $assert
3533			(i64.eq
3534				(i64.load (i32.const 0))
3535				(i64.const 0x1010101010101010)
3536			)
3537		)
3538	)
3539
3540	(func (export "deploy"))
3541)
3542"#;
3543		assert_ok!(execute(CODE_OWN_CODE_HASH, vec![], MockExt::default()));
3544	}
3545
3546	#[test]
3547	fn caller_is_origin_works() {
3548		const CODE_CALLER_IS_ORIGIN: &str = r#"
3549;; This runs `caller_is_origin` check on zero account address
3550(module
3551	(import "seal0" "seal_caller_is_origin" (func $seal_caller_is_origin (result i32)))
3552	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
3553	(import "env" "memory" (memory 1 1))
3554
3555	;; [0, 4) here the return code of the `seal_caller_is_origin` will be stored
3556	;; we initialize it with non-zero value to be sure that it's being overwritten below
3557	(data (i32.const 0) "\10\10\10\10")
3558
3559	(func (export "deploy"))
3560
3561	(func (export "call")
3562		(i32.store
3563			(i32.const 0)
3564			(call $seal_caller_is_origin)
3565		)
3566		;; exit with success and take `seal_caller_is_origin` return code to the output buffer
3567		(call $seal_return (i32.const 0) (i32.const 0) (i32.const 4))
3568	)
3569)
3570"#;
3571		let output = execute(CODE_CALLER_IS_ORIGIN, vec![], MockExt::default()).unwrap();
3572
3573		// The mock ext just always returns 0u32 (`false`)
3574		assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: 0u32.encode() },);
3575	}
3576
3577	#[test]
3578	fn caller_is_root_works() {
3579		const CODE_CALLER_IS_ROOT: &str = r#"
3580;; This runs `caller_is_root` check on zero account address
3581(module
3582	(import "seal0" "caller_is_root" (func $caller_is_root (result i32)))
3583	(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
3584	(import "env" "memory" (memory 1 1))
3585
3586	;; [0, 4) here the return code of the `caller_is_root` will be stored
3587	;; we initialize it with non-zero value to be sure that it's being overwritten below
3588	(data (i32.const 0) "\10\10\10\10")
3589
3590	(func (export "deploy"))
3591
3592	(func (export "call")
3593		(i32.store
3594			(i32.const 0)
3595			(call $caller_is_root)
3596		)
3597		;; exit with success and take `caller_is_root` return code to the output buffer
3598		(call $seal_return (i32.const 0) (i32.const 0) (i32.const 4))
3599	)
3600)
3601"#;
3602		// The default `caller` is ALICE. Therefore not root.
3603		let output = execute(CODE_CALLER_IS_ROOT, vec![], MockExt::default()).unwrap();
3604		assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: 0u32.encode() },);
3605
3606		// The caller is forced to be root instead of using the default ALICE.
3607		let output = execute(
3608			CODE_CALLER_IS_ROOT,
3609			vec![],
3610			MockExt { caller: Origin::Root, ..MockExt::default() },
3611		)
3612		.unwrap();
3613		assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: 1u32.encode() },);
3614	}
3615
3616	#[test]
3617	fn set_code_hash() {
3618		const CODE: &str = r#"
3619(module
3620	(import "seal0" "seal_set_code_hash" (func $seal_set_code_hash (param i32) (result i32)))
3621	(import "env" "memory" (memory 1 1))
3622	(func $assert (param i32)
3623		(block $ok
3624			(br_if $ok
3625				(local.get 0)
3626			)
3627			(unreachable)
3628		)
3629	)
3630	(func (export "call")
3631		(local $exit_code i32)
3632		(local.set $exit_code
3633			(call $seal_set_code_hash (i32.const 0))
3634		)
3635		(call $assert
3636			(i32.eq (local.get $exit_code) (i32.const 0)) ;; ReturnCode::Success
3637		)
3638	)
3639
3640	(func (export "deploy"))
3641
3642	;; Hash of code.
3643	(data (i32.const 0)
3644		"\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11"
3645		"\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11"
3646	)
3647)
3648"#;
3649
3650		let mut mock_ext = MockExt::default();
3651		execute(CODE, [0u8; 32].encode(), &mut mock_ext).unwrap();
3652
3653		assert_eq!(mock_ext.code_hashes.pop().unwrap(), H256::from_slice(&[17u8; 32]));
3654	}
3655
3656	#[test]
3657	fn reentrance_count_works() {
3658		const CODE: &str = r#"
3659(module
3660	(import "seal0" "reentrance_count" (func $reentrance_count (result i32)))
3661	(import "env" "memory" (memory 1 1))
3662	(func $assert (param i32)
3663		(block $ok
3664			(br_if $ok
3665				(local.get 0)
3666			)
3667			(unreachable)
3668		)
3669	)
3670	(func (export "call")
3671		(local $return_val i32)
3672		(local.set $return_val
3673			(call $reentrance_count)
3674		)
3675		(call $assert
3676			(i32.eq (local.get $return_val) (i32.const 12))
3677		)
3678	)
3679
3680	(func (export "deploy"))
3681)
3682"#;
3683
3684		let mut mock_ext = MockExt::default();
3685		execute(CODE, vec![], &mut mock_ext).unwrap();
3686	}
3687
3688	#[test]
3689	fn account_reentrance_count_works() {
3690		const CODE: &str = r#"
3691(module
3692	(import "seal0" "account_reentrance_count" (func $account_reentrance_count (param i32) (result i32)))
3693	(import "env" "memory" (memory 1 1))
3694	(func $assert (param i32)
3695		(block $ok
3696			(br_if $ok
3697				(local.get 0)
3698			)
3699			(unreachable)
3700		)
3701	)
3702	(func (export "call")
3703		(local $return_val i32)
3704		(local.set $return_val
3705			(call $account_reentrance_count (i32.const 0))
3706		)
3707		(call $assert
3708			(i32.eq (local.get $return_val) (i32.const 12))
3709		)
3710	)
3711
3712	(func (export "deploy"))
3713)
3714"#;
3715
3716		let mut mock_ext = MockExt::default();
3717		execute(CODE, vec![], &mut mock_ext).unwrap();
3718	}
3719
3720	#[test]
3721	fn instantiation_nonce_works() {
3722		const CODE: &str = r#"
3723(module
3724	(import "seal0" "instantiation_nonce" (func $nonce (result i64)))
3725	(import "env" "memory" (memory 1 1))
3726
3727	(func $assert (param i32)
3728		(block $ok
3729			(br_if $ok
3730				(local.get 0)
3731			)
3732			(unreachable)
3733		)
3734	)
3735	(func (export "call")
3736		(call $assert
3737			(i64.eq (call $nonce) (i64.const 995))
3738		)
3739	)
3740	(func (export "deploy"))
3741)
3742"#;
3743
3744		let mut mock_ext = MockExt::default();
3745		execute(CODE, vec![], &mut mock_ext).unwrap();
3746	}
3747
3748	/// This test check that an unstable interface cannot be deployed. In case of runtime
3749	/// benchmarks we always allow unstable interfaces. This is why this test does not
3750	/// work when this feature is enabled.
3751	#[cfg(not(feature = "runtime-benchmarks"))]
3752	#[test]
3753	fn cannot_deploy_unstable() {
3754		const CANNOT_DEPLOY_UNSTABLE: &str = r#"
3755(module
3756	(import "seal0" "reentrance_count" (func $reentrance_count (result i32)))
3757	(import "env" "memory" (memory 1 1))
3758
3759	(func (export "call"))
3760	(func (export "deploy"))
3761)
3762"#;
3763		assert_err!(
3764			execute_no_unstable(CANNOT_DEPLOY_UNSTABLE, vec![], MockExt::default()),
3765			<Error<Test>>::CodeRejected,
3766		);
3767		assert_ok!(execute(CANNOT_DEPLOY_UNSTABLE, vec![], MockExt::default()));
3768	}
3769
3770	/// The random interface is deprecated and hence new contracts using it should not be deployed.
3771	/// In case of runtime benchmarks we always allow deprecated interfaces. This is why this
3772	/// test doesn't work if this feature is enabled.
3773	#[cfg(not(feature = "runtime-benchmarks"))]
3774	#[test]
3775	fn cannot_deploy_deprecated() {
3776		const CODE_RANDOM_0: &str = r#"
3777(module
3778	(import "seal0" "seal_random" (func $seal_random (param i32 i32 i32 i32)))
3779	(import "env" "memory" (memory 1 1))
3780
3781	(func (export "call"))
3782	(func (export "deploy"))
3783)
3784	"#;
3785		const CODE_RANDOM_1: &str = r#"
3786(module
3787	(import "seal1" "seal_random" (func $seal_random (param i32 i32 i32 i32)))
3788	(import "env" "memory" (memory 1 1))
3789
3790	(func (export "call"))
3791	(func (export "deploy"))
3792)
3793	"#;
3794		const CODE_RANDOM_2: &str = r#"
3795(module
3796	(import "seal0" "random" (func $seal_random (param i32 i32 i32 i32)))
3797	(import "env" "memory" (memory 1 1))
3798
3799	(func (export "call"))
3800	(func (export "deploy"))
3801)
3802	"#;
3803		const CODE_RANDOM_3: &str = r#"
3804(module
3805	(import "seal1" "random" (func $seal_random (param i32 i32 i32 i32)))
3806	(import "env" "memory" (memory 1 1))
3807
3808	(func (export "call"))
3809	(func (export "deploy"))
3810)
3811	"#;
3812
3813		assert_ok!(execute_unvalidated(CODE_RANDOM_0, vec![], MockExt::default()));
3814		assert_err!(
3815			execute_instantiate_unvalidated(CODE_RANDOM_0, vec![], MockExt::default()),
3816			<Error<Test>>::CodeRejected,
3817		);
3818		assert_err!(
3819			execute(CODE_RANDOM_0, vec![], MockExt::default()),
3820			<Error<Test>>::CodeRejected,
3821		);
3822
3823		assert_ok!(execute_unvalidated(CODE_RANDOM_1, vec![], MockExt::default()));
3824		assert_err!(
3825			execute_instantiate_unvalidated(CODE_RANDOM_1, vec![], MockExt::default()),
3826			<Error<Test>>::CodeRejected,
3827		);
3828		assert_err!(
3829			execute(CODE_RANDOM_1, vec![], MockExt::default()),
3830			<Error<Test>>::CodeRejected,
3831		);
3832
3833		assert_ok!(execute_unvalidated(CODE_RANDOM_2, vec![], MockExt::default()));
3834		assert_err!(
3835			execute_instantiate_unvalidated(CODE_RANDOM_2, vec![], MockExt::default()),
3836			<Error<Test>>::CodeRejected,
3837		);
3838		assert_err!(
3839			execute(CODE_RANDOM_2, vec![], MockExt::default()),
3840			<Error<Test>>::CodeRejected,
3841		);
3842
3843		assert_ok!(execute_unvalidated(CODE_RANDOM_3, vec![], MockExt::default()));
3844		assert_err!(
3845			execute_instantiate_unvalidated(CODE_RANDOM_3, vec![], MockExt::default()),
3846			<Error<Test>>::CodeRejected,
3847		);
3848		assert_err!(
3849			execute(CODE_RANDOM_3, vec![], MockExt::default()),
3850			<Error<Test>>::CodeRejected,
3851		);
3852	}
3853
3854	#[test]
3855	fn lock_unlock_delegate_dependency() {
3856		const CODE_LOCK_UNLOCK_DELEGATE_DEPENDENCY: &str = r#"
3857(module
3858	(import "seal0" "lock_delegate_dependency" (func $lock_delegate_dependency (param i32)))
3859	(import "seal0" "unlock_delegate_dependency" (func $unlock_delegate_dependency (param i32)))
3860	(import "env" "memory" (memory 1 1))
3861	(func (export "call")
3862		(call $lock_delegate_dependency (i32.const 0))
3863		(call $lock_delegate_dependency (i32.const 32))
3864		(call $unlock_delegate_dependency (i32.const 32))
3865	)
3866	(func (export "deploy"))
3867
3868	;;  hash1 (32 bytes)
3869	(data (i32.const 0)
3870		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
3871		"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
3872	)
3873
3874	;;  hash2 (32 bytes)
3875	(data (i32.const 32)
3876		"\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02"
3877		"\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02"
3878	)
3879)
3880"#;
3881		let mut mock_ext = MockExt::default();
3882		assert_ok!(execute(&CODE_LOCK_UNLOCK_DELEGATE_DEPENDENCY, vec![], &mut mock_ext));
3883		let delegate_dependencies: Vec<_> =
3884			mock_ext.delegate_dependencies.into_inner().into_iter().collect();
3885		assert_eq!(delegate_dependencies.len(), 1);
3886		assert_eq!(delegate_dependencies[0].as_bytes(), [1; 32]);
3887	}
3888
3889	// This test checks that [`Runtime::read_sandbox_memory_as`] works, when the decoded type has a
3890	// max_len greater than the memory size, but the decoded data fits into the memory.
3891	#[test]
3892	fn read_sandbox_memory_as_works_with_max_len_out_of_bounds_but_fitting_actual_data() {
3893		use frame_support::BoundedVec;
3894		use sp_core::ConstU32;
3895
3896		let mut ext = MockExt::default();
3897		let runtime = Runtime::new(&mut ext, vec![]);
3898		let data = vec![1u8, 2, 3];
3899		let memory = data.encode();
3900		let decoded: BoundedVec<u8, ConstU32<128>> =
3901			runtime.read_sandbox_memory_as(&memory, 0u32).unwrap();
3902		assert_eq!(decoded.into_inner(), data);
3903	}
3904
3905	#[test]
3906	fn run_out_of_gas_in_start_fn() {
3907		const CODE: &str = r#"
3908(module
3909	(import "env" "memory" (memory 1 1))
3910	(start $start)
3911	(func $start
3912		(loop $inf (br $inf)) ;; just run out of gas
3913		(unreachable)
3914	)
3915	(func (export "call"))
3916	(func (export "deploy"))
3917)
3918"#;
3919		let mut mock_ext = MockExt::default();
3920		assert_err!(execute(&CODE, vec![], &mut mock_ext), <Error<Test>>::OutOfGas);
3921	}
3922}