git.delta.rocks / unique-network / refs/commits / e8fdadb89923

difftreelog

source

pallets/contracts/src/tests.rs81.6 KiBsourcehistory
1// This file is part of Substrate.23// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.4// SPDX-License-Identifier: Apache-2.056// 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 at9//10// 	http://www.apache.org/licenses/LICENSE-2.011//12// Unless required by applicable law or agreed to in writing, software13// 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 and16// limitations under the License.1718use crate::{19	BalanceOf, ContractInfo, ContractInfoOf, Pallet, Config, Schedule, Error,20	storage::Storage,21	chain_extension::{22		Result as ExtensionResult, Environment, ChainExtension, Ext, SysConfig, RetVal,23		UncheckedFrom, InitState, ReturnFlags,24	},25	exec::{AccountIdOf, Executable},26	wasm::PrefabWasmModule,27	weights::WeightInfo,28	wasm::ReturnCode as RuntimeReturnCode,29	storage::RawAliveContractInfo,30};31use assert_matches::assert_matches;32use codec::Encode;33use sp_core::Bytes;34use sp_runtime::{35	traits::{BlakeTwo256, Hash, IdentityLookup, Convert},36	testing::{Header, H256},37	AccountId32, Perbill,38};39use sp_io::hashing::blake2_256;40use frame_support::{41	assert_ok, assert_err, assert_err_ignore_postinfo, parameter_types, assert_storage_noop,42	traits::{Currency, ReservableCurrency, OnInitialize, GenesisBuild},43	weights::{Weight, PostDispatchInfo, DispatchClass, constants::WEIGHT_PER_SECOND},44	dispatch::DispatchErrorWithPostInfo,45	storage::child,46};47use frame_system::{self as system, EventRecord, Phase};48use pretty_assertions::assert_eq;4950use crate as pallet_contracts;5152type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;53type Block = frame_system::mocking::MockBlock<Test>;5455frame_support::construct_runtime!(56	pub enum Test where57		Block = Block,58		NodeBlock = Block,59		UncheckedExtrinsic = UncheckedExtrinsic,60	{61		System: frame_system::{Pallet, Call, Config, Storage, Event<T>},62		Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},63		Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},64		Randomness: pallet_randomness_collective_flip::{Pallet, Call, Storage},65		Contracts: pallet_contracts::{Pallet, Call, Config<T>, Storage, Event<T>},66	}67);6869#[macro_use]70pub mod test_utils {71	use super::{Test, Balances};72	use crate::{73		ContractInfoOf, CodeHash,74		storage::Storage,75		exec::{StorageKey, AccountIdOf},76		Pallet as Contracts,77	};78	use frame_support::traits::Currency;7980	pub fn set_storage(addr: &AccountIdOf<Test>, key: &StorageKey, value: Option<Vec<u8>>) {81		let contract_info = <ContractInfoOf<Test>>::get(&addr)82			.unwrap()83			.get_alive()84			.unwrap();85		Storage::<Test>::write(addr, &contract_info.trie_id, key, value).unwrap();86	}87	pub fn get_storage(addr: &AccountIdOf<Test>, key: &StorageKey) -> Option<Vec<u8>> {88		let contract_info = <ContractInfoOf<Test>>::get(&addr)89			.unwrap()90			.get_alive()91			.unwrap();92		Storage::<Test>::read(&contract_info.trie_id, key)93	}94	pub fn place_contract(address: &AccountIdOf<Test>, code_hash: CodeHash<Test>) {95		let trie_id = Storage::<Test>::generate_trie_id(address);96		set_balance(address, Contracts::<Test>::subsistence_threshold() * 10);97		Storage::<Test>::place_contract(&address, trie_id, code_hash).unwrap();98	}99	pub fn set_balance(who: &AccountIdOf<Test>, amount: u64) {100		let imbalance = Balances::deposit_creating(who, amount);101		drop(imbalance);102	}103	pub fn get_balance(who: &AccountIdOf<Test>) -> u64 {104		Balances::free_balance(who)105	}106	macro_rules! assert_return_code {107		( $x:expr , $y:expr $(,)? ) => {{108			use sp_std::convert::TryInto;109			assert_eq!(110				u32::from_le_bytes($x.data[..].try_into().unwrap()),111				$y as u32112			);113		}};114	}115	macro_rules! assert_refcount {116		( $code_hash:expr , $should:expr $(,)? ) => {{117			let is = crate::CodeStorage::<Test>::get($code_hash)118				.map(|m| m.refcount())119				.unwrap_or(0);120			assert_eq!(is, $should);121		}};122	}123}124125thread_local! {126	static TEST_EXTENSION: sp_std::cell::RefCell<TestExtension> = Default::default();127}128129pub struct TestExtension {130	enabled: bool,131	last_seen_buffer: Vec<u8>,132	last_seen_inputs: (u32, u32, u32, u32),133}134135impl TestExtension {136	fn disable() {137		TEST_EXTENSION.with(|e| e.borrow_mut().enabled = false)138	}139140	fn last_seen_buffer() -> Vec<u8> {141		TEST_EXTENSION.with(|e| e.borrow().last_seen_buffer.clone())142	}143144	fn last_seen_inputs() -> (u32, u32, u32, u32) {145		TEST_EXTENSION.with(|e| e.borrow().last_seen_inputs.clone())146	}147}148149impl Default for TestExtension {150	fn default() -> Self {151		Self {152			enabled: true,153			last_seen_buffer: vec![],154			last_seen_inputs: (0, 0, 0, 0),155		}156	}157}158159impl ChainExtension<Test> for TestExtension {160	fn call<E>(func_id: u32, env: Environment<E, InitState>) -> ExtensionResult<RetVal>161	where162		E: Ext<T = Test>,163		<E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,164	{165		match func_id {166			0 => {167				let mut env = env.buf_in_buf_out();168				let input = env.read(2)?;169				env.write(&input, false, None)?;170				TEST_EXTENSION.with(|e| e.borrow_mut().last_seen_buffer = input);171				Ok(RetVal::Converging(func_id))172			}173			1 => {174				let env = env.only_in();175				TEST_EXTENSION.with(|e| {176					e.borrow_mut().last_seen_inputs =177						(env.val0(), env.val1(), env.val2(), env.val3())178				});179				Ok(RetVal::Converging(func_id))180			}181			2 => {182				let mut env = env.buf_in_buf_out();183				let weight = env.read(2)?[1].into();184				env.charge_weight(weight)?;185				Ok(RetVal::Converging(func_id))186			}187			3 => Ok(RetVal::Diverging {188				flags: ReturnFlags::REVERT,189				data: vec![42, 99],190			}),191			_ => {192				panic!(193					"Passed unknown func_id to test chain extension: {}",194					func_id195				);196			}197		}198	}199200	fn enabled() -> bool {201		TEST_EXTENSION.with(|e| e.borrow().enabled)202	}203}204205parameter_types! {206	pub const BlockHashCount: u64 = 250;207	pub BlockWeights: frame_system::limits::BlockWeights =208		frame_system::limits::BlockWeights::simple_max(2 * WEIGHT_PER_SECOND);209	pub static ExistentialDeposit: u64 = 0;210}211impl frame_system::Config for Test {212	type BaseCallFilter = ();213	type BlockWeights = BlockWeights;214	type BlockLength = ();215	type DbWeight = ();216	type Origin = Origin;217	type Index = u64;218	type BlockNumber = u64;219	type Hash = H256;220	type Call = Call;221	type Hashing = BlakeTwo256;222	type AccountId = AccountId32;223	type Lookup = IdentityLookup<Self::AccountId>;224	type Header = Header;225	type Event = Event;226	type BlockHashCount = BlockHashCount;227	type Version = ();228	type PalletInfo = PalletInfo;229	type AccountData = pallet_balances::AccountData<u64>;230	type OnNewAccount = ();231	type OnKilledAccount = ();232	type SystemWeightInfo = ();233	type SS58Prefix = ();234	type OnSetCode = ();235}236impl pallet_balances::Config for Test {237	type MaxLocks = ();238	type Balance = u64;239	type Event = Event;240	type DustRemoval = ();241	type ExistentialDeposit = ExistentialDeposit;242	type AccountStore = System;243	type WeightInfo = ();244}245parameter_types! {246	pub const MinimumPeriod: u64 = 1;247}248impl pallet_timestamp::Config for Test {249	type Moment = u64;250	type OnTimestampSet = ();251	type MinimumPeriod = MinimumPeriod;252	type WeightInfo = ();253}254parameter_types! {255	pub const SignedClaimHandicap: u64 = 2;256	pub const TombstoneDeposit: u64 = 16;257	pub const DepositPerContract: u64 = 8 * DepositPerStorageByte::get();258	pub const DepositPerStorageByte: u64 = 10_000;259	pub const DepositPerStorageItem: u64 = 10_000;260	pub RentFraction: Perbill = Perbill::from_rational(4u32, 10_000u32);261	pub const SurchargeReward: u64 = 500_000;262	pub const MaxDepth: u32 = 100;263	pub const MaxValueSize: u32 = 16_384;264	pub const DeletionQueueDepth: u32 = 1024;265	pub const DeletionWeightLimit: Weight = 500_000_000_000;266	pub const MaxCodeSize: u32 = 2 * 1024;267}268269parameter_types! {270	pub const TransactionByteFee: u64 = 0;271}272273impl Convert<Weight, BalanceOf<Self>> for Test {274	fn convert(w: Weight) -> BalanceOf<Self> {275		w276	}277}278279impl Config for Test {280	type Time = Timestamp;281	type Randomness = Randomness;282	type Currency = Balances;283	type Event = Event;284	type RentPayment = ();285	type SignedClaimHandicap = SignedClaimHandicap;286	type TombstoneDeposit = TombstoneDeposit;287	type DepositPerContract = DepositPerContract;288	type DepositPerStorageByte = DepositPerStorageByte;289	type DepositPerStorageItem = DepositPerStorageItem;290	type RentFraction = RentFraction;291	type SurchargeReward = SurchargeReward;292	type MaxDepth = MaxDepth;293	type MaxValueSize = MaxValueSize;294	type WeightPrice = Self;295	type WeightInfo = ();296	type ChainExtension = TestExtension;297	type DeletionQueueDepth = DeletionQueueDepth;298	type DeletionWeightLimit = DeletionWeightLimit;299	type MaxCodeSize = MaxCodeSize;300}301302pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]);303pub const BOB: AccountId32 = AccountId32::new([2u8; 32]);304pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]);305pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]);306307const GAS_LIMIT: Weight = 10_000_000_000;308309pub struct ExtBuilder {310	existential_deposit: u64,311}312impl Default for ExtBuilder {313	fn default() -> Self {314		Self {315			existential_deposit: 1,316		}317	}318}319impl ExtBuilder {320	pub fn existential_deposit(mut self, existential_deposit: u64) -> Self {321		self.existential_deposit = existential_deposit;322		self323	}324	pub fn set_associated_consts(&self) {325		EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit);326	}327	pub fn build(self) -> sp_io::TestExternalities {328		self.set_associated_consts();329		let mut t = frame_system::GenesisConfig::default()330			.build_storage::<Test>()331			.unwrap();332		pallet_balances::GenesisConfig::<Test> { balances: vec![] }333			.assimilate_storage(&mut t)334			.unwrap();335		pallet_contracts::GenesisConfig {336			current_schedule: Schedule::<Test> {337				enable_println: true,338				..Default::default()339			},340		}341		.assimilate_storage(&mut t)342		.unwrap();343		let mut ext = sp_io::TestExternalities::new(t);344		ext.execute_with(|| System::set_block_number(1));345		ext346	}347}348349/// Load a given wasm module represented by a .wat file and returns a wasm binary contents along350/// with it's hash.351///352/// The fixture files are located under the `fixtures/` directory.353fn compile_module<T>(fixture_name: &str) -> wat::Result<(Vec<u8>, <T::Hashing as Hash>::Output)>354where355	T: frame_system::Config,356{357	let fixture_path = ["fixtures/", fixture_name, ".wat"].concat();358	let wasm_binary = wat::parse_file(fixture_path)?;359	let code_hash = T::Hashing::hash(&wasm_binary);360	Ok((wasm_binary, code_hash))361}362363// Perform a call to a plain account.364// The actual transfer fails because we can only call contracts.365// Then we check that at least the base costs where charged (no runtime gas costs.)366#[test]367fn calling_plain_account_fails() {368	ExtBuilder::default().build().execute_with(|| {369		let _ = Balances::deposit_creating(&ALICE, 100_000_000);370		let base_cost = <<Test as Config>::WeightInfo as WeightInfo>::call(0);371372		assert_eq!(373			Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, Vec::new()),374			Err(DispatchErrorWithPostInfo {375				error: Error::<Test>::NotCallable.into(),376				post_info: PostDispatchInfo {377					actual_weight: Some(base_cost),378					pays_fee: Default::default(),379				},380			})381		);382	});383}384385#[test]386fn account_removal_does_not_remove_storage() {387	use self::test_utils::{set_storage, get_storage};388389	ExtBuilder::default()390		.existential_deposit(100)391		.build()392		.execute_with(|| {393			let trie_id1 = Storage::<Test>::generate_trie_id(&ALICE);394			let trie_id2 = Storage::<Test>::generate_trie_id(&BOB);395			let key1 = &[1; 32];396			let key2 = &[2; 32];397398			// Set up two accounts with free balance above the existential threshold.399			{400				let alice_contract_info = ContractInfo::Alive(RawAliveContractInfo {401					trie_id: trie_id1.clone(),402					storage_size: 0,403					pair_count: 0,404					deduct_block: System::block_number(),405					code_hash: H256::repeat_byte(1),406					rent_allowance: 40,407					rent_payed: 0,408					last_write: None,409					_reserved: None,410				});411				let _ = Balances::deposit_creating(&ALICE, 110);412				ContractInfoOf::<Test>::insert(ALICE, &alice_contract_info);413				set_storage(&ALICE, &key1, Some(b"1".to_vec()));414				set_storage(&ALICE, &key2, Some(b"2".to_vec()));415416				let bob_contract_info = ContractInfo::Alive(RawAliveContractInfo {417					trie_id: trie_id2.clone(),418					storage_size: 0,419					pair_count: 0,420					deduct_block: System::block_number(),421					code_hash: H256::repeat_byte(2),422					rent_allowance: 40,423					rent_payed: 0,424					last_write: None,425					_reserved: None,426				});427				let _ = Balances::deposit_creating(&BOB, 110);428				ContractInfoOf::<Test>::insert(BOB, &bob_contract_info);429				set_storage(&BOB, &key1, Some(b"3".to_vec()));430				set_storage(&BOB, &key2, Some(b"4".to_vec()));431			}432433			// Transfer funds from ALICE account of such amount that after this transfer434			// the balance of the ALICE account will be below the existential threshold.435			//436			// This does not remove the contract storage as we are not notified about a437			// account removal. This cannot happen in reality because a contract can only438			// remove itself by `seal_terminate`. There is no external event that can remove439			// the account appart from that.440			assert_ok!(Balances::transfer(Origin::signed(ALICE), BOB, 20));441442			// Verify that no entries are removed.443			{444				assert_eq!(get_storage(&ALICE, key1), Some(b"1".to_vec()));445				assert_eq!(get_storage(&ALICE, key2), Some(b"2".to_vec()));446447				assert_eq!(get_storage(&BOB, key1), Some(b"3".to_vec()));448				assert_eq!(get_storage(&BOB, key2), Some(b"4".to_vec()));449			}450		});451}452453#[test]454fn instantiate_and_call_and_deposit_event() {455	let (wasm, code_hash) = compile_module::<Test>("return_from_start_fn").unwrap();456457	ExtBuilder::default()458		.existential_deposit(100)459		.build()460		.execute_with(|| {461			let _ = Balances::deposit_creating(&ALICE, 1_000_000);462			let subsistence = Pallet::<Test>::subsistence_threshold();463464			// Check at the end to get hash on error easily465			let creation = Contracts::instantiate_with_code(466				Origin::signed(ALICE),467				subsistence * 100,468				GAS_LIMIT,469				wasm,470				vec![],471				vec![],472			);473			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);474475			assert_eq!(476				System::events(),477				vec![478					EventRecord {479						phase: Phase::Initialization,480						event: Event::frame_system(frame_system::Event::NewAccount(ALICE.clone())),481						topics: vec![],482					},483					EventRecord {484						phase: Phase::Initialization,485						event: Event::pallet_balances(pallet_balances::Event::Endowed(486							ALICE, 1_000_000487						)),488						topics: vec![],489					},490					EventRecord {491						phase: Phase::Initialization,492						event: Event::frame_system(frame_system::Event::NewAccount(addr.clone())),493						topics: vec![],494					},495					EventRecord {496						phase: Phase::Initialization,497						event: Event::pallet_balances(pallet_balances::Event::Endowed(498							addr.clone(),499							subsistence * 100500						)),501						topics: vec![],502					},503					EventRecord {504						phase: Phase::Initialization,505						event: Event::pallet_balances(pallet_balances::Event::Transfer(506							ALICE,507							addr.clone(),508							subsistence * 100509						)),510						topics: vec![],511					},512					EventRecord {513						phase: Phase::Initialization,514						event: Event::pallet_contracts(crate::Event::CodeStored(code_hash.into())),515						topics: vec![],516					},517					EventRecord {518						phase: Phase::Initialization,519						event: Event::pallet_contracts(crate::Event::ContractEmitted(520							addr.clone(),521							vec![1, 2, 3, 4]522						)),523						topics: vec![],524					},525					EventRecord {526						phase: Phase::Initialization,527						event: Event::pallet_contracts(crate::Event::Instantiated(528							ALICE,529							addr.clone()530						)),531						topics: vec![],532					},533				]534			);535536			assert_ok!(creation);537			assert!(ContractInfoOf::<Test>::contains_key(&addr));538		});539}540541#[test]542fn deposit_event_max_value_limit() {543	let (wasm, code_hash) = compile_module::<Test>("event_size").unwrap();544545	ExtBuilder::default()546		.existential_deposit(50)547		.build()548		.execute_with(|| {549			// Create550			let _ = Balances::deposit_creating(&ALICE, 1_000_000);551			assert_ok!(Contracts::instantiate_with_code(552				Origin::signed(ALICE),553				30_000,554				GAS_LIMIT,555				wasm,556				vec![],557				vec![],558			));559			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);560561			// Call contract with allowed storage value.562			assert_ok!(Contracts::call(563				Origin::signed(ALICE),564				addr.clone(),565				0,566				GAS_LIMIT * 2, // we are copying a huge buffer,567				<Test as Config>::MaxValueSize::get().encode(),568			));569570			// Call contract with too large a storage value.571			assert_err_ignore_postinfo!(572				Contracts::call(573					Origin::signed(ALICE),574					addr,575					0,576					GAS_LIMIT,577					(<Test as Config>::MaxValueSize::get() + 1).encode(),578				),579				Error::<Test>::ValueTooLarge,580			);581		});582}583584#[test]585fn run_out_of_gas() {586	let (wasm, code_hash) = compile_module::<Test>("run_out_of_gas").unwrap();587	let subsistence = Pallet::<Test>::subsistence_threshold();588589	ExtBuilder::default()590		.existential_deposit(50)591		.build()592		.execute_with(|| {593			let _ = Balances::deposit_creating(&ALICE, 1_000_000);594595			assert_ok!(Contracts::instantiate_with_code(596				Origin::signed(ALICE),597				100 * subsistence,598				GAS_LIMIT,599				wasm,600				vec![],601				vec![],602			));603			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);604605			// Call the contract with a fixed gas limit. It must run out of gas because it just606			// loops forever.607			assert_err_ignore_postinfo!(608				Contracts::call(609					Origin::signed(ALICE),610					addr, // newly created account611					0,612					67_500_000,613					vec![],614				),615				Error::<Test>::OutOfGas,616			);617		});618}619620/// Input data for each call in set_rent code621mod call {622	use super::{AccountIdOf, Test};623	pub fn set_storage_4_byte() -> Vec<u8> {624		0u32.to_le_bytes().to_vec()625	}626	pub fn remove_storage_4_byte() -> Vec<u8> {627		1u32.to_le_bytes().to_vec()628	}629	#[allow(dead_code)]630	pub fn transfer(to: &AccountIdOf<Test>) -> Vec<u8> {631		2u32.to_le_bytes()632			.iter()633			.chain(AsRef::<[u8]>::as_ref(to))634			.cloned()635			.collect()636	}637	pub fn null() -> Vec<u8> {638		3u32.to_le_bytes().to_vec()639	}640}641642#[test]643fn storage_size() {644	let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();645646	// Storage size647	ExtBuilder::default()648		.existential_deposit(50)649		.build()650		.execute_with(|| {651			// Create652			let _ = Balances::deposit_creating(&ALICE, 1_000_000);653			assert_ok!(Contracts::instantiate_with_code(654				Origin::signed(ALICE),655				30_000,656				GAS_LIMIT,657				wasm,658				// rent_allowance659				<Test as pallet_balances::Config>::Balance::from(10_000u32).encode(),660				vec![],661			));662			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);663			let bob_contract = ContractInfoOf::<Test>::get(&addr)664				.unwrap()665				.get_alive()666				.unwrap();667			assert_eq!(bob_contract.storage_size, 4);668			assert_eq!(bob_contract.pair_count, 1,);669670			assert_ok!(Contracts::call(671				Origin::signed(ALICE),672				addr.clone(),673				0,674				GAS_LIMIT,675				call::set_storage_4_byte()676			));677			let bob_contract = ContractInfoOf::<Test>::get(&addr)678				.unwrap()679				.get_alive()680				.unwrap();681			assert_eq!(bob_contract.storage_size, 4 + 4);682			assert_eq!(bob_contract.pair_count, 2,);683684			assert_ok!(Contracts::call(685				Origin::signed(ALICE),686				addr.clone(),687				0,688				GAS_LIMIT,689				call::remove_storage_4_byte()690			));691			let bob_contract = ContractInfoOf::<Test>::get(&addr)692				.unwrap()693				.get_alive()694				.unwrap();695			assert_eq!(bob_contract.storage_size, 4);696			assert_eq!(bob_contract.pair_count, 1,);697		});698}699700#[test]701fn empty_kv_pairs() {702	let (wasm, code_hash) = compile_module::<Test>("set_empty_storage").unwrap();703704	ExtBuilder::default().build().execute_with(|| {705		let _ = Balances::deposit_creating(&ALICE, 1_000_000);706		assert_ok!(Contracts::instantiate_with_code(707			Origin::signed(ALICE),708			30_000,709			GAS_LIMIT,710			wasm,711			vec![],712			vec![],713		));714		let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);715		let bob_contract = ContractInfoOf::<Test>::get(&addr)716			.unwrap()717			.get_alive()718			.unwrap();719720		assert_eq!(bob_contract.storage_size, 0,);721		assert_eq!(bob_contract.pair_count, 1,);722	});723}724725fn initialize_block(number: u64) {726	System::initialize(727		&number,728		&[0u8; 32].into(),729		&Default::default(),730		Default::default(),731	);732}733734#[test]735fn deduct_blocks() {736	let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();737	let endowment: BalanceOf<Test> = 100_000;738	let allowance: BalanceOf<Test> = 70_000;739740	ExtBuilder::default()741		.existential_deposit(50)742		.build()743		.execute_with(|| {744			// Create745			let _ = Balances::deposit_creating(&ALICE, 1_000_000);746			assert_ok!(Contracts::instantiate_with_code(747				Origin::signed(ALICE),748				endowment,749				GAS_LIMIT,750				wasm,751				allowance.encode(),752				vec![],753			));754			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);755			let contract = ContractInfoOf::<Test>::get(&addr)756				.unwrap()757				.get_alive()758				.unwrap();759			let code_len: BalanceOf<Test> =760				PrefabWasmModule::<Test>::from_storage_noinstr(contract.code_hash)761					.unwrap()762					.occupied_storage()763					.into();764765			// The instantiation deducted the rent for one block immediately766			let rent0 = <Test as Config>::RentFraction::get()767				// (base_deposit(8) + bytes in storage(4) + size of code) * byte_price768				// + 1 storage item (10_000) - free_balance769				.mul_ceil((8 + 4 + code_len) * 10_000 + 10_000 - endowment)770				// blocks to rent771				* 1;772			assert!(rent0 > 0);773			assert_eq!(contract.rent_allowance, allowance - rent0);774			assert_eq!(contract.deduct_block, 1);775			assert_eq!(Balances::free_balance(&addr), endowment - rent0);776777			// Advance 4 blocks778			initialize_block(5);779780			// Trigger rent through call781			assert_ok!(Contracts::call(782				Origin::signed(ALICE),783				addr.clone(),784				0,785				GAS_LIMIT,786				call::null()787			));788789			// Check result790			let rent = <Test as Config>::RentFraction::get()791				.mul_ceil((8 + 4 + code_len) * 10_000 + 10_000 - (endowment - rent0))792				* 4;793			let contract = ContractInfoOf::<Test>::get(&addr)794				.unwrap()795				.get_alive()796				.unwrap();797			assert_eq!(contract.rent_allowance, allowance - rent0 - rent);798			assert_eq!(contract.deduct_block, 5);799			assert_eq!(Balances::free_balance(&addr), endowment - rent0 - rent);800801			// Advance 2 blocks more802			initialize_block(7);803804			// Trigger rent through call805			assert_ok!(Contracts::call(806				Origin::signed(ALICE),807				addr.clone(),808				0,809				GAS_LIMIT,810				call::null()811			));812813			// Check result814			let rent_2 = <Test as Config>::RentFraction::get()815				.mul_ceil((8 + 4 + code_len) * 10_000 + 10_000 - (endowment - rent0 - rent))816				* 2;817			let contract = ContractInfoOf::<Test>::get(&addr)818				.unwrap()819				.get_alive()820				.unwrap();821			assert_eq!(contract.rent_allowance, allowance - rent0 - rent - rent_2);822			assert_eq!(contract.deduct_block, 7);823			assert_eq!(824				Balances::free_balance(&addr),825				endowment - rent0 - rent - rent_2826			);827828			// Second call on same block should have no effect on rent829			assert_ok!(Contracts::call(830				Origin::signed(ALICE),831				addr.clone(),832				0,833				GAS_LIMIT,834				call::null()835			));836			let contract = ContractInfoOf::<Test>::get(&addr)837				.unwrap()838				.get_alive()839				.unwrap();840			assert_eq!(contract.rent_allowance, allowance - rent0 - rent - rent_2);841			assert_eq!(contract.deduct_block, 7);842			assert_eq!(843				Balances::free_balance(&addr),844				endowment - rent0 - rent - rent_2845			)846		});847}848849#[test]850fn inherent_claim_surcharge_contract_removals() {851	removals(|addr| Contracts::claim_surcharge(Origin::none(), addr, Some(ALICE)).is_ok());852}853854#[test]855fn signed_claim_surcharge_contract_removals() {856	removals(|addr| Contracts::claim_surcharge(Origin::signed(ALICE), addr, None).is_ok());857}858859#[test]860fn claim_surcharge_malus() {861	// Test surcharge malus for inherent862	claim_surcharge(863		8,864		|addr| Contracts::claim_surcharge(Origin::none(), addr, Some(ALICE)).is_ok(),865		true,866	);867	claim_surcharge(868		7,869		|addr| Contracts::claim_surcharge(Origin::none(), addr, Some(ALICE)).is_ok(),870		true,871	);872	claim_surcharge(873		6,874		|addr| Contracts::claim_surcharge(Origin::none(), addr, Some(ALICE)).is_ok(),875		true,876	);877	claim_surcharge(878		5,879		|addr| Contracts::claim_surcharge(Origin::none(), addr, Some(ALICE)).is_ok(),880		false,881	);882883	// Test surcharge malus for signed884	claim_surcharge(885		8,886		|addr| Contracts::claim_surcharge(Origin::signed(ALICE), addr, None).is_ok(),887		true,888	);889	claim_surcharge(890		7,891		|addr| Contracts::claim_surcharge(Origin::signed(ALICE), addr, None).is_ok(),892		false,893	);894	claim_surcharge(895		6,896		|addr| Contracts::claim_surcharge(Origin::signed(ALICE), addr, None).is_ok(),897		false,898	);899	claim_surcharge(900		5,901		|addr| Contracts::claim_surcharge(Origin::signed(ALICE), addr, None).is_ok(),902		false,903	);904}905906/// Claim surcharge with the given trigger_call at the given blocks.907/// If `removes` is true then assert that the contract is a tombstone.908fn claim_surcharge(blocks: u64, trigger_call: impl Fn(AccountIdOf<Test>) -> bool, removes: bool) {909	let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();910911	ExtBuilder::default()912		.existential_deposit(50)913		.build()914		.execute_with(|| {915			// Create916			let _ = Balances::deposit_creating(&ALICE, 1_000_000);917			assert_ok!(Contracts::instantiate_with_code(918				Origin::signed(ALICE),919				100_000,920				GAS_LIMIT,921				wasm,922				<Test as pallet_balances::Config>::Balance::from(30_000u32).encode(), // rent allowance923				vec![],924			));925			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);926927			// Advance blocks928			initialize_block(blocks);929930			// Trigger rent through call931			assert_eq!(trigger_call(addr.clone()), removes);932933			if removes {934				assert!(ContractInfoOf::<Test>::get(&addr)935					.unwrap()936					.get_tombstone()937					.is_some());938			} else {939				assert!(ContractInfoOf::<Test>::get(&addr)940					.unwrap()941					.get_alive()942					.is_some());943			}944		});945}946947/// Test for all kind of removals for the given trigger:948/// * if balance is reached and balance > subsistence threshold949/// * if allowance is exceeded950/// * if balance is reached and balance < subsistence threshold951///	    * this case cannot be triggered by a contract: we check whether a tombstone is left952fn removals(trigger_call: impl Fn(AccountIdOf<Test>) -> bool) {953	let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();954955	// Balance reached and superior to subsistence threshold956	ExtBuilder::default()957		.existential_deposit(50)958		.build()959		.execute_with(|| {960			// Create961			let _ = Balances::deposit_creating(&ALICE, 1_000_000);962			assert_ok!(Contracts::instantiate_with_code(963				Origin::signed(ALICE),964				70_000,965				GAS_LIMIT,966				wasm.clone(),967				<Test as pallet_balances::Config>::Balance::from(100_000u32).encode(), // rent allowance968				vec![],969			));970			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);971			let allowance = ContractInfoOf::<Test>::get(&addr)972				.unwrap()973				.get_alive()974				.unwrap()975				.rent_allowance;976			let balance = Balances::free_balance(&addr);977978			let subsistence_threshold = Pallet::<Test>::subsistence_threshold();979980			// Trigger rent must have no effect981			assert!(!trigger_call(addr.clone()));982			assert_eq!(983				ContractInfoOf::<Test>::get(&addr)984					.unwrap()985					.get_alive()986					.unwrap()987					.rent_allowance,988				allowance,989			);990			assert_eq!(Balances::free_balance(&addr), balance);991992			// Advance blocks993			initialize_block(27);994995			// Trigger rent through call (should remove the contract)996			assert!(trigger_call(addr.clone()));997			assert!(ContractInfoOf::<Test>::get(&addr)998				.unwrap()999				.get_tombstone()1000				.is_some());1001			assert_eq!(Balances::free_balance(&addr), subsistence_threshold);10021003			// Advance blocks1004			initialize_block(30);10051006			// Trigger rent must have no effect1007			assert!(!trigger_call(addr.clone()));1008			assert!(ContractInfoOf::<Test>::get(&addr)1009				.unwrap()1010				.get_tombstone()1011				.is_some());1012			assert_eq!(Balances::free_balance(&addr), subsistence_threshold);1013		});10141015	// Allowance exceeded1016	ExtBuilder::default()1017		.existential_deposit(50)1018		.build()1019		.execute_with(|| {1020			// Create1021			let _ = Balances::deposit_creating(&ALICE, 1_000_000);1022			assert_ok!(Contracts::instantiate_with_code(1023				Origin::signed(ALICE),1024				100_000,1025				GAS_LIMIT,1026				wasm.clone(),1027				<Test as pallet_balances::Config>::Balance::from(70_000u32).encode(), // rent allowance1028				vec![],1029			));1030			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);1031			let allowance = ContractInfoOf::<Test>::get(&addr)1032				.unwrap()1033				.get_alive()1034				.unwrap()1035				.rent_allowance;1036			let balance = Balances::free_balance(&addr);10371038			// Trigger rent must have no effect1039			assert!(!trigger_call(addr.clone()));1040			assert_eq!(1041				ContractInfoOf::<Test>::get(&addr)1042					.unwrap()1043					.get_alive()1044					.unwrap()1045					.rent_allowance,1046				allowance,1047			);1048			assert_eq!(Balances::free_balance(&addr), balance);10491050			// Advance blocks1051			initialize_block(27);10521053			// Trigger rent through call1054			assert!(trigger_call(addr.clone()));1055			assert!(ContractInfoOf::<Test>::get(&addr)1056				.unwrap()1057				.get_tombstone()1058				.is_some());1059			// Balance should be initial balance - initial rent_allowance1060			assert_eq!(Balances::free_balance(&addr), 30_000);10611062			// Advance blocks1063			initialize_block(20);10641065			// Trigger rent must have no effect1066			assert!(!trigger_call(addr.clone()));1067			assert!(ContractInfoOf::<Test>::get(&addr)1068				.unwrap()1069				.get_tombstone()1070				.is_some());1071			assert_eq!(Balances::free_balance(&addr), 30_000);1072		});10731074	// Balance reached and inferior to subsistence threshold1075	ExtBuilder::default()1076		.existential_deposit(50)1077		.build()1078		.execute_with(|| {1079			// Create1080			let subsistence_threshold = Pallet::<Test>::subsistence_threshold();1081			let _ = Balances::deposit_creating(&ALICE, subsistence_threshold * 1000);1082			assert_ok!(Contracts::instantiate_with_code(1083				Origin::signed(ALICE),1084				subsistence_threshold * 100,1085				GAS_LIMIT,1086				wasm,1087				(subsistence_threshold * 100).encode(), // rent allowance1088				vec![],1089			));1090			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);1091			let allowance = ContractInfoOf::<Test>::get(&addr)1092				.unwrap()1093				.get_alive()1094				.unwrap()1095				.rent_allowance;1096			let balance = Balances::free_balance(&addr);10971098			// Trigger rent must have no effect1099			assert!(!trigger_call(addr.clone()));1100			assert_eq!(1101				ContractInfoOf::<Test>::get(&addr)1102					.unwrap()1103					.get_alive()1104					.unwrap()1105					.rent_allowance,1106				allowance,1107			);1108			assert_eq!(Balances::free_balance(&addr), balance,);11091110			// Make contract have exactly the subsistence threshold1111			Balances::make_free_balance_be(&addr, subsistence_threshold);1112			assert_eq!(Balances::free_balance(&addr), subsistence_threshold);11131114			// Advance blocks (should remove as balance is exactly subsistence)1115			initialize_block(10);11161117			// Trigger rent through call1118			assert!(trigger_call(addr.clone()));1119			assert_matches!(1120				ContractInfoOf::<Test>::get(&addr),1121				Some(ContractInfo::Tombstone(_))1122			);1123			assert_eq!(Balances::free_balance(&addr), subsistence_threshold);11241125			// Advance blocks1126			initialize_block(20);11271128			// Trigger rent must have no effect1129			assert!(!trigger_call(addr.clone()));1130			assert_matches!(1131				ContractInfoOf::<Test>::get(&addr),1132				Some(ContractInfo::Tombstone(_))1133			);1134			assert_eq!(Balances::free_balance(&addr), subsistence_threshold);1135		});1136}11371138#[test]1139fn call_removed_contract() {1140	let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();11411142	// Balance reached and superior to subsistence threshold1143	ExtBuilder::default()1144		.existential_deposit(50)1145		.build()1146		.execute_with(|| {1147			// Create1148			let _ = Balances::deposit_creating(&ALICE, 1_000_000);1149			assert_ok!(Contracts::instantiate_with_code(1150				Origin::signed(ALICE),1151				30_000,1152				GAS_LIMIT,1153				wasm,1154				// rent allowance1155				<Test as pallet_balances::Config>::Balance::from(10_000u32).encode(),1156				vec![],1157			));1158			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);11591160			// Calling contract should succeed.1161			assert_ok!(Contracts::call(1162				Origin::signed(ALICE),1163				addr.clone(),1164				0,1165				GAS_LIMIT,1166				call::null()1167			));11681169			// Advance blocks1170			initialize_block(27);11711172			// Calling contract should deny access because rent cannot be paid.1173			assert_err_ignore_postinfo!(1174				Contracts::call(1175					Origin::signed(ALICE),1176					addr.clone(),1177					0,1178					GAS_LIMIT,1179					call::null()1180				),1181				Error::<Test>::NotCallable1182			);1183			// No event is generated because the contract is not actually removed.1184			assert_eq!(System::events(), vec![]);11851186			// Subsequent contract calls should also fail.1187			assert_err_ignore_postinfo!(1188				Contracts::call(1189					Origin::signed(ALICE),1190					addr.clone(),1191					0,1192					GAS_LIMIT,1193					call::null()1194				),1195				Error::<Test>::NotCallable1196			);11971198			// A snitch can now remove the contract1199			assert_ok!(Contracts::claim_surcharge(1200				Origin::none(),1201				addr.clone(),1202				Some(ALICE)1203			));1204			assert!(ContractInfoOf::<Test>::get(&addr)1205				.unwrap()1206				.get_tombstone()1207				.is_some());1208		})1209}12101211#[test]1212fn default_rent_allowance_on_instantiate() {1213	let (wasm, code_hash) = compile_module::<Test>("check_default_rent_allowance").unwrap();12141215	ExtBuilder::default()1216		.existential_deposit(50)1217		.build()1218		.execute_with(|| {1219			// Create1220			let _ = Balances::deposit_creating(&ALICE, 1_000_000);1221			assert_ok!(Contracts::instantiate_with_code(1222				Origin::signed(ALICE),1223				30_000,1224				GAS_LIMIT,1225				wasm,1226				vec![],1227				vec![],1228			));1229			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);1230			let contract = ContractInfoOf::<Test>::get(&addr)1231				.unwrap()1232				.get_alive()1233				.unwrap();1234			let code_len: BalanceOf<Test> =1235				PrefabWasmModule::<Test>::from_storage_noinstr(contract.code_hash)1236					.unwrap()1237					.occupied_storage()1238					.into();12391240			// The instantiation deducted the rent for one block immediately1241			let first_rent = <Test as Config>::RentFraction::get()1242				// (base_deposit(8) + code_len) * byte_price - free_balance1243				.mul_ceil((8 + code_len) * 10_000 - 30_000)1244				// blocks to rent1245				* 1;1246			assert_eq!(1247				contract.rent_allowance,1248				<BalanceOf<Test>>::max_value() - first_rent1249			);12501251			// Advance blocks1252			initialize_block(5);12531254			// Trigger rent through call1255			assert_ok!(Contracts::call(1256				Origin::signed(ALICE),1257				addr.clone(),1258				0,1259				GAS_LIMIT,1260				call::null()1261			));12621263			// Check contract is still alive1264			let contract = ContractInfoOf::<Test>::get(&addr).unwrap().get_alive();1265			assert!(contract.is_some())1266		});1267}12681269#[test]1270fn restorations_dirty_storage_and_different_storage() {1271	restoration(true, true, false);1272}12731274#[test]1275fn restorations_dirty_storage() {1276	restoration(false, true, false);1277}12781279#[test]1280fn restoration_different_storage() {1281	restoration(true, false, false);1282}12831284#[test]1285fn restoration_code_evicted() {1286	restoration(false, false, true);1287}12881289#[test]1290fn restoration_success() {1291	restoration(false, false, false);1292}12931294fn restoration(1295	test_different_storage: bool,1296	test_restore_to_with_dirty_storage: bool,1297	test_code_evicted: bool,1298) {1299	let (set_rent_wasm, set_rent_code_hash) = compile_module::<Test>("set_rent").unwrap();1300	let (restoration_wasm, restoration_code_hash) = compile_module::<Test>("restoration").unwrap();1301	let allowance: <Test as pallet_balances::Config>::Balance = 10_000;13021303	ExtBuilder::default()1304		.existential_deposit(50)1305		.build()1306		.execute_with(|| {1307			let _ = Balances::deposit_creating(&ALICE, 1_000_000);13081309			// Create an account with address `BOB` with code `CODE_SET_RENT`.1310			// The input parameter sets the rent allowance to 0.1311			assert_ok!(Contracts::instantiate_with_code(1312				Origin::signed(ALICE),1313				30_000,1314				GAS_LIMIT,1315				set_rent_wasm.clone(),1316				allowance.encode(),1317				vec![],1318			));1319			let addr_bob = Contracts::contract_address(&ALICE, &set_rent_code_hash, &[]);13201321			let mut events = vec![1322				EventRecord {1323					phase: Phase::Initialization,1324					event: Event::frame_system(frame_system::Event::NewAccount(ALICE)),1325					topics: vec![],1326				},1327				EventRecord {1328					phase: Phase::Initialization,1329					event: Event::pallet_balances(pallet_balances::Event::Endowed(1330						ALICE, 1_000_000,1331					)),1332					topics: vec![],1333				},1334				EventRecord {1335					phase: Phase::Initialization,1336					event: Event::frame_system(frame_system::Event::NewAccount(addr_bob.clone())),1337					topics: vec![],1338				},1339				EventRecord {1340					phase: Phase::Initialization,1341					event: Event::pallet_balances(pallet_balances::Event::Endowed(1342						addr_bob.clone(),1343						30_000,1344					)),1345					topics: vec![],1346				},1347				EventRecord {1348					phase: Phase::Initialization,1349					event: Event::pallet_balances(pallet_balances::Event::Transfer(1350						ALICE,1351						addr_bob.clone(),1352						30_000,1353					)),1354					topics: vec![],1355				},1356				EventRecord {1357					phase: Phase::Initialization,1358					event: Event::pallet_contracts(crate::Event::CodeStored(1359						set_rent_code_hash.into(),1360					)),1361					topics: vec![],1362				},1363				EventRecord {1364					phase: Phase::Initialization,1365					event: Event::pallet_contracts(crate::Event::Instantiated(1366						ALICE,1367						addr_bob.clone(),1368					)),1369					topics: vec![],1370				},1371			];13721373			// Create another contract from the same code in order to increment the codes1374			// refcounter so that it stays on chain.1375			if !test_code_evicted {1376				assert_ok!(Contracts::instantiate_with_code(1377					Origin::signed(ALICE),1378					20_000,1379					GAS_LIMIT,1380					set_rent_wasm,1381					allowance.encode(),1382					vec![1],1383				));1384				assert_refcount!(set_rent_code_hash, 2);1385				let addr_dummy = Contracts::contract_address(&ALICE, &set_rent_code_hash, &[1]);1386				events.extend(1387					[1388						EventRecord {1389							phase: Phase::Initialization,1390							event: Event::frame_system(frame_system::Event::NewAccount(1391								addr_dummy.clone(),1392							)),1393							topics: vec![],1394						},1395						EventRecord {1396							phase: Phase::Initialization,1397							event: Event::pallet_balances(pallet_balances::Event::Endowed(1398								addr_dummy.clone(),1399								20_000,1400							)),1401							topics: vec![],1402						},1403						EventRecord {1404							phase: Phase::Initialization,1405							event: Event::pallet_balances(pallet_balances::Event::Transfer(1406								ALICE,1407								addr_dummy.clone(),1408								20_000,1409							)),1410							topics: vec![],1411						},1412						EventRecord {1413							phase: Phase::Initialization,1414							event: Event::pallet_contracts(crate::Event::Instantiated(1415								ALICE,1416								addr_dummy.clone(),1417							)),1418							topics: vec![],1419						},1420					]1421					.iter()1422					.cloned(),1423				);1424			}14251426			assert_eq!(System::events(), events);14271428			// Check if `BOB` was created successfully and that the rent allowance is below what1429			// we specified as the first rent was already collected.1430			let bob_contract = ContractInfoOf::<Test>::get(&addr_bob)1431				.unwrap()1432				.get_alive()1433				.unwrap();1434			assert!(bob_contract.rent_allowance < allowance);14351436			if test_different_storage {1437				assert_ok!(Contracts::call(1438					Origin::signed(ALICE),1439					addr_bob.clone(),1440					0,1441					GAS_LIMIT,1442					call::set_storage_4_byte()1443				));1444			}14451446			// Advance blocks in order to make the contract run out of money for rent.1447			initialize_block(27);14481449			// Call `BOB`, which makes it pay rent. Since the rent allowance is set to 20_0001450			// we expect that it is no longer callable but keeps existing until someone1451			// calls `claim_surcharge`.1452			assert_err_ignore_postinfo!(1453				Contracts::call(1454					Origin::signed(ALICE),1455					addr_bob.clone(),1456					0,1457					GAS_LIMIT,1458					call::null()1459				),1460				Error::<Test>::NotCallable1461			);1462			assert!(System::events().is_empty());1463			assert!(ContractInfoOf::<Test>::get(&addr_bob)1464				.unwrap()1465				.get_alive()1466				.is_some());1467			assert_ok!(Contracts::claim_surcharge(1468				Origin::none(),1469				addr_bob.clone(),1470				Some(ALICE)1471			));1472			assert!(ContractInfoOf::<Test>::get(&addr_bob)1473				.unwrap()1474				.get_tombstone()1475				.is_some());1476			if test_code_evicted {1477				assert_refcount!(set_rent_code_hash, 0);1478			} else {1479				assert_refcount!(set_rent_code_hash, 1);1480			}14811482			// Create another account with the address `DJANGO` with `CODE_RESTORATION`.1483			//1484			// Note that we can't use `ALICE` for creating `DJANGO` so we create yet another1485			// account `CHARLIE` and create `DJANGO` with it.1486			let _ = Balances::deposit_creating(&CHARLIE, 1_000_000);1487			assert_ok!(Contracts::instantiate_with_code(1488				Origin::signed(CHARLIE),1489				30_000,1490				GAS_LIMIT,1491				restoration_wasm,1492				vec![],1493				vec![],1494			));1495			let addr_django = Contracts::contract_address(&CHARLIE, &restoration_code_hash, &[]);14961497			// Before performing a call to `DJANGO` save its original trie id.1498			let django_trie_id = ContractInfoOf::<Test>::get(&addr_django)1499				.unwrap()1500				.get_alive()1501				.unwrap()1502				.trie_id;15031504			// The trie is regarded as 'dirty' when it was written to in the current block.1505			if !test_restore_to_with_dirty_storage {1506				// Advance 1 block.1507				initialize_block(28);1508			}15091510			// Perform a call to `DJANGO`. This should either perform restoration successfully or1511			// fail depending on the test parameters.1512			let perform_the_restoration = || {1513				Contracts::call(1514					Origin::signed(ALICE),1515					addr_django.clone(),1516					0,1517					GAS_LIMIT,1518					set_rent_code_hash1519						.as_ref()1520						.iter()1521						.chain(AsRef::<[u8]>::as_ref(&addr_bob))1522						.cloned()1523						.collect(),1524				)1525			};15261527			// The key that is used in the restorer contract but is not in the target contract.1528			// Is supplied as delta to the restoration. We need it to check whether the key1529			// is properly removed on success but still there on failure.1530			let delta_key = {1531				let mut key = [0u8; 32];1532				key[0] = 1;1533				key1534			};15351536			if test_different_storage || test_restore_to_with_dirty_storage || test_code_evicted {1537				// Parametrization of the test imply restoration failure. Check that `DJANGO` aka1538				// restoration contract is still in place and also that `BOB` doesn't exist.1539				let result = perform_the_restoration();1540				assert!(ContractInfoOf::<Test>::get(&addr_bob)1541					.unwrap()1542					.get_tombstone()1543					.is_some());1544				let django_contract = ContractInfoOf::<Test>::get(&addr_django)1545					.unwrap()1546					.get_alive()1547					.unwrap();1548				assert_eq!(django_contract.storage_size, 8);1549				assert_eq!(django_contract.trie_id, django_trie_id);1550				assert_eq!(django_contract.deduct_block, System::block_number());1551				assert_eq!(1552					Storage::<Test>::read(&django_trie_id, &delta_key),1553					Some(vec![40, 0, 0, 0]),1554				);1555				match (1556					test_different_storage,1557					test_restore_to_with_dirty_storage,1558					test_code_evicted,1559				) {1560					(true, false, false) => {1561						assert_err_ignore_postinfo!(result, Error::<Test>::InvalidTombstone,);1562						assert_eq!(System::events(), vec![]);1563					}1564					(_, true, false) => {1565						assert_err_ignore_postinfo!(result, Error::<Test>::InvalidContractOrigin,);1566						assert_eq!(1567							System::events(),1568							vec![1569								EventRecord {1570									phase: Phase::Initialization,1571									event: Event::pallet_contracts(crate::Event::Evicted(addr_bob)),1572									topics: vec![],1573								},1574								EventRecord {1575									phase: Phase::Initialization,1576									event: Event::frame_system(frame_system::Event::NewAccount(1577										CHARLIE1578									)),1579									topics: vec![],1580								},1581								EventRecord {1582									phase: Phase::Initialization,1583									event: Event::pallet_balances(pallet_balances::Event::Endowed(1584										CHARLIE, 1_000_0001585									)),1586									topics: vec![],1587								},1588								EventRecord {1589									phase: Phase::Initialization,1590									event: Event::frame_system(frame_system::Event::NewAccount(1591										addr_django.clone()1592									)),1593									topics: vec![],1594								},1595								EventRecord {1596									phase: Phase::Initialization,1597									event: Event::pallet_balances(pallet_balances::Event::Endowed(1598										addr_django.clone(),1599										30_0001600									)),1601									topics: vec![],1602								},1603								EventRecord {1604									phase: Phase::Initialization,1605									event: Event::pallet_balances(1606										pallet_balances::Event::Transfer(1607											CHARLIE,1608											addr_django.clone(),1609											30_0001610										)1611									),1612									topics: vec![],1613								},1614								EventRecord {1615									phase: Phase::Initialization,1616									event: Event::pallet_contracts(crate::Event::CodeStored(1617										restoration_code_hash1618									)),1619									topics: vec![],1620								},1621								EventRecord {1622									phase: Phase::Initialization,1623									event: Event::pallet_contracts(crate::Event::Instantiated(1624										CHARLIE,1625										addr_django.clone()1626									)),1627									topics: vec![],1628								},1629							]1630						);1631					}1632					(false, false, true) => {1633						assert_err_ignore_postinfo!(result, Error::<Test>::CodeNotFound,);1634						assert_refcount!(set_rent_code_hash, 0);1635						assert_eq!(System::events(), vec![]);1636					}1637					_ => unreachable!(),1638				}1639			} else {1640				assert_ok!(perform_the_restoration());1641				assert_refcount!(set_rent_code_hash, 2);16421643				// Here we expect that the restoration is succeeded. Check that the restoration1644				// contract `DJANGO` ceased to exist and that `BOB` returned back.1645				let bob_contract = ContractInfoOf::<Test>::get(&addr_bob)1646					.unwrap()1647					.get_alive()1648					.unwrap();1649				assert_eq!(bob_contract.rent_allowance, 50);1650				assert_eq!(bob_contract.storage_size, 4);1651				assert_eq!(bob_contract.trie_id, django_trie_id);1652				assert_eq!(bob_contract.deduct_block, System::block_number());1653				assert!(ContractInfoOf::<Test>::get(&addr_django).is_none());1654				assert_matches!(Storage::<Test>::read(&django_trie_id, &delta_key), None);1655				assert_eq!(1656					System::events(),1657					vec![1658						EventRecord {1659							phase: Phase::Initialization,1660							event: Event::pallet_contracts(crate::Event::CodeRemoved(1661								restoration_code_hash1662							)),1663							topics: vec![],1664						},1665						EventRecord {1666							phase: Phase::Initialization,1667							event: Event::frame_system(system::Event::KilledAccount(1668								addr_django.clone()1669							)),1670							topics: vec![],1671						},1672						EventRecord {1673							phase: Phase::Initialization,1674							event: Event::pallet_contracts(crate::Event::Restored(1675								addr_django,1676								addr_bob,1677								bob_contract.code_hash,1678								501679							)),1680							topics: vec![],1681						},1682					]1683				);1684			}1685		});1686}16871688#[test]1689fn storage_max_value_limit() {1690	let (wasm, code_hash) = compile_module::<Test>("storage_size").unwrap();16911692	ExtBuilder::default()1693		.existential_deposit(50)1694		.build()1695		.execute_with(|| {1696			// Create1697			let _ = Balances::deposit_creating(&ALICE, 1_000_000);1698			assert_ok!(Contracts::instantiate_with_code(1699				Origin::signed(ALICE),1700				30_000,1701				GAS_LIMIT,1702				wasm,1703				vec![],1704				vec![],1705			));1706			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);1707			ContractInfoOf::<Test>::get(&addr)1708				.unwrap()1709				.get_alive()1710				.unwrap();17111712			// Call contract with allowed storage value.1713			assert_ok!(Contracts::call(1714				Origin::signed(ALICE),1715				addr.clone(),1716				0,1717				GAS_LIMIT * 2, // we are copying a huge buffer1718				<Test as Config>::MaxValueSize::get().encode(),1719			));17201721			// Call contract with too large a storage value.1722			assert_err_ignore_postinfo!(1723				Contracts::call(1724					Origin::signed(ALICE),1725					addr,1726					0,1727					GAS_LIMIT,1728					(<Test as Config>::MaxValueSize::get() + 1).encode(),1729				),1730				Error::<Test>::ValueTooLarge,1731			);1732		});1733}17341735#[test]1736fn deploy_and_call_other_contract() {1737	let (callee_wasm, callee_code_hash) = compile_module::<Test>("return_with_data").unwrap();1738	let (caller_wasm, caller_code_hash) = compile_module::<Test>("caller_contract").unwrap();17391740	ExtBuilder::default()1741		.existential_deposit(50)1742		.build()1743		.execute_with(|| {1744			// Create1745			let _ = Balances::deposit_creating(&ALICE, 1_000_000);1746			assert_ok!(Contracts::instantiate_with_code(1747				Origin::signed(ALICE),1748				100_000,1749				GAS_LIMIT,1750				caller_wasm,1751				vec![],1752				vec![],1753			));1754			assert_ok!(Contracts::instantiate_with_code(1755				Origin::signed(ALICE),1756				100_000,1757				GAS_LIMIT,1758				callee_wasm,1759				0u32.to_le_bytes().encode(),1760				vec![42],1761			));17621763			// Call BOB contract, which attempts to instantiate and call the callee contract and1764			// makes various assertions on the results from those calls.1765			assert_ok!(Contracts::call(1766				Origin::signed(ALICE),1767				Contracts::contract_address(&ALICE, &caller_code_hash, &[]),1768				0,1769				GAS_LIMIT,1770				callee_code_hash.as_ref().to_vec(),1771			));1772		});1773}17741775#[test]1776fn cannot_self_destruct_through_draning() {1777	let (wasm, code_hash) = compile_module::<Test>("drain").unwrap();1778	ExtBuilder::default()1779		.existential_deposit(50)1780		.build()1781		.execute_with(|| {1782			let _ = Balances::deposit_creating(&ALICE, 1_000_000);17831784			// Instantiate the BOB contract.1785			assert_ok!(Contracts::instantiate_with_code(1786				Origin::signed(ALICE),1787				100_000,1788				GAS_LIMIT,1789				wasm,1790				vec![],1791				vec![],1792			));1793			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);17941795			// Check that the BOB contract has been instantiated.1796			assert_matches!(1797				ContractInfoOf::<Test>::get(&addr),1798				Some(ContractInfo::Alive(_))1799			);18001801			// Call BOB which makes it send all funds to the zero address1802			// The contract code asserts that the correct error value is returned.1803			assert_ok!(Contracts::call(1804				Origin::signed(ALICE),1805				addr,1806				0,1807				GAS_LIMIT,1808				vec![],1809			));1810		});1811}18121813#[test]1814fn cannot_self_destruct_while_live() {1815	let (wasm, code_hash) = compile_module::<Test>("self_destruct").unwrap();1816	ExtBuilder::default()1817		.existential_deposit(50)1818		.build()1819		.execute_with(|| {1820			let _ = Balances::deposit_creating(&ALICE, 1_000_000);18211822			// Instantiate the BOB contract.1823			assert_ok!(Contracts::instantiate_with_code(1824				Origin::signed(ALICE),1825				100_000,1826				GAS_LIMIT,1827				wasm,1828				vec![],1829				vec![],1830			));1831			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);18321833			// Check that the BOB contract has been instantiated.1834			assert_matches!(1835				ContractInfoOf::<Test>::get(&addr),1836				Some(ContractInfo::Alive(_))1837			);18381839			// Call BOB with input data, forcing it make a recursive call to itself to1840			// self-destruct, resulting in a trap.1841			assert_err_ignore_postinfo!(1842				Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![0],),1843				Error::<Test>::ContractTrapped,1844			);18451846			// Check that BOB is still alive.1847			assert_matches!(1848				ContractInfoOf::<Test>::get(&addr),1849				Some(ContractInfo::Alive(_))1850			);1851		});1852}18531854#[test]1855fn self_destruct_works() {1856	let (wasm, code_hash) = compile_module::<Test>("self_destruct").unwrap();1857	ExtBuilder::default()1858		.existential_deposit(50)1859		.build()1860		.execute_with(|| {1861			let _ = Balances::deposit_creating(&ALICE, 1_000_000);1862			let _ = Balances::deposit_creating(&DJANGO, 1_000_000);18631864			// Instantiate the BOB contract.1865			assert_ok!(Contracts::instantiate_with_code(1866				Origin::signed(ALICE),1867				100_000,1868				GAS_LIMIT,1869				wasm,1870				vec![],1871				vec![],1872			));1873			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);18741875			// Check that the BOB contract has been instantiated.1876			assert_matches!(1877				ContractInfoOf::<Test>::get(&addr),1878				Some(ContractInfo::Alive(_))1879			);18801881			// Drop all previous events1882			initialize_block(2);18831884			// Call BOB without input data which triggers termination.1885			assert_matches!(1886				Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![],),1887				Ok(_)1888			);18891890			pretty_assertions::assert_eq!(1891				System::events(),1892				vec![1893					EventRecord {1894						phase: Phase::Initialization,1895						event: Event::frame_system(frame_system::Event::KilledAccount(1896							addr.clone()1897						)),1898						topics: vec![],1899					},1900					EventRecord {1901						phase: Phase::Initialization,1902						event: Event::pallet_balances(pallet_balances::Event::Transfer(1903							addr.clone(),1904							DJANGO,1905							93_0861906						)),1907						topics: vec![],1908					},1909					EventRecord {1910						phase: Phase::Initialization,1911						event: Event::pallet_contracts(crate::Event::CodeRemoved(code_hash)),1912						topics: vec![],1913					},1914					EventRecord {1915						phase: Phase::Initialization,1916						event: Event::pallet_contracts(crate::Event::Terminated(1917							addr.clone(),1918							DJANGO1919						)),1920						topics: vec![],1921					},1922				]1923			);19241925			// Check that account is gone1926			assert!(ContractInfoOf::<Test>::get(&addr).is_none());19271928			// check that the beneficiary (django) got remaining balance1929			// some rent was deducted before termination1930			assert_eq!(Balances::free_balance(DJANGO), 1_093_086);1931		});1932}19331934// This tests that one contract cannot prevent another from self-destructing by sending it1935// additional funds after it has been drained.1936#[test]1937fn destroy_contract_and_transfer_funds() {1938	let (callee_wasm, callee_code_hash) = compile_module::<Test>("self_destruct").unwrap();1939	let (caller_wasm, caller_code_hash) = compile_module::<Test>("destroy_and_transfer").unwrap();19401941	ExtBuilder::default()1942		.existential_deposit(50)1943		.build()1944		.execute_with(|| {1945			// Create1946			let _ = Balances::deposit_creating(&ALICE, 1_000_000);1947			assert_ok!(Contracts::instantiate_with_code(1948				Origin::signed(ALICE),1949				200_000,1950				GAS_LIMIT,1951				callee_wasm,1952				vec![],1953				vec![42]1954			));19551956			// This deploys the BOB contract, which in turn deploys the CHARLIE contract during1957			// construction.1958			assert_ok!(Contracts::instantiate_with_code(1959				Origin::signed(ALICE),1960				200_000,1961				GAS_LIMIT,1962				caller_wasm,1963				callee_code_hash.as_ref().to_vec(),1964				vec![],1965			));1966			let addr_bob = Contracts::contract_address(&ALICE, &caller_code_hash, &[]);1967			let addr_charlie =1968				Contracts::contract_address(&addr_bob, &callee_code_hash, &[0x47, 0x11]);19691970			// Check that the CHARLIE contract has been instantiated.1971			assert_matches!(1972				ContractInfoOf::<Test>::get(&addr_charlie),1973				Some(ContractInfo::Alive(_))1974			);19751976			// Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct.1977			assert_ok!(Contracts::call(1978				Origin::signed(ALICE),1979				addr_bob,1980				0,1981				GAS_LIMIT,1982				addr_charlie.encode(),1983			));19841985			// Check that CHARLIE has moved on to the great beyond (ie. died).1986			assert!(ContractInfoOf::<Test>::get(&addr_charlie).is_none());1987		});1988}19891990#[test]1991fn cannot_self_destruct_in_constructor() {1992	let (wasm, _) = compile_module::<Test>("self_destructing_constructor").unwrap();1993	ExtBuilder::default()1994		.existential_deposit(50)1995		.build()1996		.execute_with(|| {1997			let _ = Balances::deposit_creating(&ALICE, 1_000_000);19981999			// Fail to instantiate the BOB because the contructor calls seal_terminate.2000			assert_err_ignore_postinfo!(2001				Contracts::instantiate_with_code(2002					Origin::signed(ALICE),2003					100_000,2004					GAS_LIMIT,2005					wasm,2006					vec![],2007					vec![],2008				),2009				Error::<Test>::NotCallable,2010			);2011		});2012}20132014#[test]2015fn crypto_hashes() {2016	let (wasm, code_hash) = compile_module::<Test>("crypto_hashes").unwrap();20172018	ExtBuilder::default()2019		.existential_deposit(50)2020		.build()2021		.execute_with(|| {2022			let _ = Balances::deposit_creating(&ALICE, 1_000_000);20232024			// Instantiate the CRYPTO_HASHES contract.2025			assert_ok!(Contracts::instantiate_with_code(2026				Origin::signed(ALICE),2027				100_000,2028				GAS_LIMIT,2029				wasm,2030				vec![],2031				vec![],2032			));2033			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);2034			// Perform the call.2035			let input = b"_DEAD_BEEF";2036			use sp_io::hashing::*;2037			// Wraps a hash function into a more dynamic form usable for testing.2038			macro_rules! dyn_hash_fn {2039				($name:ident) => {2040					Box::new(|input| $name(input).as_ref().to_vec().into_boxed_slice())2041				};2042			}2043			// All hash functions and their associated output byte lengths.2044			let test_cases: &[(Box<dyn Fn(&[u8]) -> Box<[u8]>>, usize)] = &[2045				(dyn_hash_fn!(sha2_256), 32),2046				(dyn_hash_fn!(keccak_256), 32),2047				(dyn_hash_fn!(blake2_256), 32),2048				(dyn_hash_fn!(blake2_128), 16),2049			];2050			// Test the given hash functions for the input: "_DEAD_BEEF"2051			for (n, (hash_fn, expected_size)) in test_cases.iter().enumerate() {2052				// We offset data in the contract tables by 1.2053				let mut params = vec![(n + 1) as u8];2054				params.extend_from_slice(input);2055				let result = <Pallet<Test>>::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, params)2056					.result2057					.unwrap();2058				assert!(result.is_success());2059				let expected = hash_fn(input.as_ref());2060				assert_eq!(&result.data[..*expected_size], &*expected);2061			}2062		})2063}20642065#[test]2066fn transfer_return_code() {2067	let (wasm, code_hash) = compile_module::<Test>("transfer_return_code").unwrap();2068	ExtBuilder::default()2069		.existential_deposit(50)2070		.build()2071		.execute_with(|| {2072			let subsistence = Pallet::<Test>::subsistence_threshold();2073			let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);20742075			assert_ok!(Contracts::instantiate_with_code(2076				Origin::signed(ALICE),2077				subsistence * 100,2078				GAS_LIMIT,2079				wasm,2080				vec![],2081				vec![],2082			),);2083			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);20842085			// Contract has only the minimal balance so any transfer will return BelowSubsistence.2086			Balances::make_free_balance_be(&addr, subsistence);2087			let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![])2088				.result2089				.unwrap();2090			assert_return_code!(result, RuntimeReturnCode::BelowSubsistenceThreshold);20912092			// Contract has enough total balance in order to not go below the subsistence2093			// threshold when transfering 100 balance but this balance is reserved so2094			// the transfer still fails but with another return code.2095			Balances::make_free_balance_be(&addr, subsistence + 100);2096			Balances::reserve(&addr, subsistence + 100).unwrap();2097			let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, vec![])2098				.result2099				.unwrap();2100			assert_return_code!(result, RuntimeReturnCode::TransferFailed);2101		});2102}21032104#[test]2105fn call_return_code() {2106	let (caller_code, caller_hash) = compile_module::<Test>("call_return_code").unwrap();2107	let (callee_code, callee_hash) = compile_module::<Test>("ok_trap_revert").unwrap();2108	ExtBuilder::default()2109		.existential_deposit(50)2110		.build()2111		.execute_with(|| {2112			let subsistence = Pallet::<Test>::subsistence_threshold();2113			let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);2114			let _ = Balances::deposit_creating(&CHARLIE, 1000 * subsistence);21152116			assert_ok!(Contracts::instantiate_with_code(2117				Origin::signed(ALICE),2118				subsistence * 100,2119				GAS_LIMIT,2120				caller_code,2121				vec![0],2122				vec![],2123			),);2124			let addr_bob = Contracts::contract_address(&ALICE, &caller_hash, &[]);2125			Balances::make_free_balance_be(&addr_bob, subsistence);21262127			// Contract calls into Django which is no valid contract2128			let result = Contracts::bare_call(2129				ALICE,2130				addr_bob.clone(),2131				0,2132				GAS_LIMIT,2133				AsRef::<[u8]>::as_ref(&DJANGO).to_vec(),2134			)2135			.result2136			.unwrap();2137			assert_return_code!(result, RuntimeReturnCode::NotCallable);21382139			assert_ok!(Contracts::instantiate_with_code(2140				Origin::signed(CHARLIE),2141				subsistence * 100,2142				GAS_LIMIT,2143				callee_code,2144				vec![0],2145				vec![],2146			),);2147			let addr_django = Contracts::contract_address(&CHARLIE, &callee_hash, &[]);2148			Balances::make_free_balance_be(&addr_django, subsistence);21492150			// Contract has only the minimal balance so any transfer will return BelowSubsistence.2151			let result = Contracts::bare_call(2152				ALICE,2153				addr_bob.clone(),2154				0,2155				GAS_LIMIT,2156				AsRef::<[u8]>::as_ref(&addr_django)2157					.iter()2158					.chain(&0u32.to_le_bytes())2159					.cloned()2160					.collect(),2161			)2162			.result2163			.unwrap();2164			assert_return_code!(result, RuntimeReturnCode::BelowSubsistenceThreshold);21652166			// Contract has enough total balance in order to not go below the subsistence2167			// threshold when transfering 100 balance but this balance is reserved so2168			// the transfer still fails but with another return code.2169			Balances::make_free_balance_be(&addr_bob, subsistence + 100);2170			Balances::reserve(&addr_bob, subsistence + 100).unwrap();2171			let result = Contracts::bare_call(2172				ALICE,2173				addr_bob.clone(),2174				0,2175				GAS_LIMIT,2176				AsRef::<[u8]>::as_ref(&addr_django)2177					.iter()2178					.chain(&0u32.to_le_bytes())2179					.cloned()2180					.collect(),2181			)2182			.result2183			.unwrap();2184			assert_return_code!(result, RuntimeReturnCode::TransferFailed);21852186			// Contract has enough balance but callee reverts because "1" is passed.2187			Balances::make_free_balance_be(&addr_bob, subsistence + 1000);2188			let result = Contracts::bare_call(2189				ALICE,2190				addr_bob.clone(),2191				0,2192				GAS_LIMIT,2193				AsRef::<[u8]>::as_ref(&addr_django)2194					.iter()2195					.chain(&1u32.to_le_bytes())2196					.cloned()2197					.collect(),2198			)2199			.result2200			.unwrap();2201			assert_return_code!(result, RuntimeReturnCode::CalleeReverted);22022203			// Contract has enough balance but callee traps because "2" is passed.2204			let result = Contracts::bare_call(2205				ALICE,2206				addr_bob,2207				0,2208				GAS_LIMIT,2209				AsRef::<[u8]>::as_ref(&addr_django)2210					.iter()2211					.chain(&2u32.to_le_bytes())2212					.cloned()2213					.collect(),2214			)2215			.result2216			.unwrap();2217			assert_return_code!(result, RuntimeReturnCode::CalleeTrapped);2218		});2219}22202221#[test]2222fn instantiate_return_code() {2223	let (caller_code, caller_hash) = compile_module::<Test>("instantiate_return_code").unwrap();2224	let (callee_code, callee_hash) = compile_module::<Test>("ok_trap_revert").unwrap();2225	ExtBuilder::default()2226		.existential_deposit(50)2227		.build()2228		.execute_with(|| {2229			let subsistence = Pallet::<Test>::subsistence_threshold();2230			let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);2231			let _ = Balances::deposit_creating(&CHARLIE, 1000 * subsistence);2232			let callee_hash = callee_hash.as_ref().to_vec();22332234			assert_ok!(Contracts::instantiate_with_code(2235				Origin::signed(ALICE),2236				subsistence * 100,2237				GAS_LIMIT,2238				callee_code,2239				vec![],2240				vec![],2241			),);22422243			assert_ok!(Contracts::instantiate_with_code(2244				Origin::signed(ALICE),2245				subsistence * 100,2246				GAS_LIMIT,2247				caller_code,2248				vec![],2249				vec![],2250			),);2251			let addr = Contracts::contract_address(&ALICE, &caller_hash, &[]);22522253			// Contract has only the minimal balance so any transfer will return BelowSubsistence.2254			Balances::make_free_balance_be(&addr, subsistence);2255			let result =2256				Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, callee_hash.clone())2257					.result2258					.unwrap();2259			assert_return_code!(result, RuntimeReturnCode::BelowSubsistenceThreshold);22602261			// Contract has enough total balance in order to not go below the subsistence2262			// threshold when transfering the balance but this balance is reserved so2263			// the transfer still fails but with another return code.2264			Balances::make_free_balance_be(&addr, subsistence + 10_000);2265			Balances::reserve(&addr, subsistence + 10_000).unwrap();2266			let result =2267				Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, callee_hash.clone())2268					.result2269					.unwrap();2270			assert_return_code!(result, RuntimeReturnCode::TransferFailed);22712272			// Contract has enough balance but the passed code hash is invalid2273			Balances::make_free_balance_be(&addr, subsistence + 10_000);2274			let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![0; 33])2275				.result2276				.unwrap();2277			assert_return_code!(result, RuntimeReturnCode::CodeNotFound);22782279			// Contract has enough balance but callee reverts because "1" is passed.2280			let result = Contracts::bare_call(2281				ALICE,2282				addr.clone(),2283				0,2284				GAS_LIMIT,2285				callee_hash2286					.iter()2287					.chain(&1u32.to_le_bytes())2288					.cloned()2289					.collect(),2290			)2291			.result2292			.unwrap();2293			assert_return_code!(result, RuntimeReturnCode::CalleeReverted);22942295			// Contract has enough balance but callee traps because "2" is passed.2296			let result = Contracts::bare_call(2297				ALICE,2298				addr,2299				0,2300				GAS_LIMIT,2301				callee_hash2302					.iter()2303					.chain(&2u32.to_le_bytes())2304					.cloned()2305					.collect(),2306			)2307			.result2308			.unwrap();2309			assert_return_code!(result, RuntimeReturnCode::CalleeTrapped);2310		});2311}23122313#[test]2314fn disabled_chain_extension_wont_deploy() {2315	let (code, _hash) = compile_module::<Test>("chain_extension").unwrap();2316	ExtBuilder::default()2317		.existential_deposit(50)2318		.build()2319		.execute_with(|| {2320			let subsistence = Pallet::<Test>::subsistence_threshold();2321			let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);2322			TestExtension::disable();2323			assert_err_ignore_postinfo!(2324				Contracts::instantiate_with_code(2325					Origin::signed(ALICE),2326					3 * subsistence,2327					GAS_LIMIT,2328					code,2329					vec![],2330					vec![],2331				),2332				"module uses chain extensions but chain extensions are disabled",2333			);2334		});2335}23362337#[test]2338fn disabled_chain_extension_errors_on_call() {2339	let (code, hash) = compile_module::<Test>("chain_extension").unwrap();2340	ExtBuilder::default()2341		.existential_deposit(50)2342		.build()2343		.execute_with(|| {2344			let subsistence = Pallet::<Test>::subsistence_threshold();2345			let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);2346			assert_ok!(Contracts::instantiate_with_code(2347				Origin::signed(ALICE),2348				subsistence * 100,2349				GAS_LIMIT,2350				code,2351				vec![],2352				vec![],2353			),);2354			let addr = Contracts::contract_address(&ALICE, &hash, &[]);2355			TestExtension::disable();2356			assert_err_ignore_postinfo!(2357				Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![],),2358				Error::<Test>::NoChainExtension,2359			);2360		});2361}23622363#[test]2364fn chain_extension_works() {2365	let (code, hash) = compile_module::<Test>("chain_extension").unwrap();2366	ExtBuilder::default()2367		.existential_deposit(50)2368		.build()2369		.execute_with(|| {2370			let subsistence = Pallet::<Test>::subsistence_threshold();2371			let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);2372			assert_ok!(Contracts::instantiate_with_code(2373				Origin::signed(ALICE),2374				subsistence * 100,2375				GAS_LIMIT,2376				code,2377				vec![],2378				vec![],2379			),);2380			let addr = Contracts::contract_address(&ALICE, &hash, &[]);23812382			// The contract takes a up to 2 byte buffer where the first byte passed is used as2383			// as func_id to the chain extension which behaves differently based on the2384			// func_id.23852386			// 0 = read input buffer and pass it through as output2387			let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![0, 99]);2388			let gas_consumed = result.gas_consumed;2389			assert_eq!(TestExtension::last_seen_buffer(), vec![0, 99]);2390			assert_eq!(result.result.unwrap().data, Bytes(vec![0, 99]));23912392			// 1 = treat inputs as integer primitives and store the supplied integers2393			Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![1])2394				.result2395				.unwrap();2396			// those values passed in the fixture2397			assert_eq!(TestExtension::last_seen_inputs(), (4, 1, 16, 12));23982399			// 2 = charge some extra weight (amount supplied in second byte)2400			let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![2, 42]);2401			assert_ok!(result.result);2402			assert_eq!(result.gas_consumed, gas_consumed + 42);24032404			// 3 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer2405			let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![3])2406				.result2407				.unwrap();2408			assert_eq!(result.flags, ReturnFlags::REVERT);2409			assert_eq!(result.data, Bytes(vec![42, 99]));2410		});2411}24122413#[test]2414fn lazy_removal_works() {2415	let (code, hash) = compile_module::<Test>("self_destruct").unwrap();2416	ExtBuilder::default()2417		.existential_deposit(50)2418		.build()2419		.execute_with(|| {2420			let subsistence = Pallet::<Test>::subsistence_threshold();2421			let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);24222423			assert_ok!(Contracts::instantiate_with_code(2424				Origin::signed(ALICE),2425				subsistence * 100,2426				GAS_LIMIT,2427				code,2428				vec![],2429				vec![],2430			),);24312432			let addr = Contracts::contract_address(&ALICE, &hash, &[]);2433			let info = <ContractInfoOf<Test>>::get(&addr)2434				.unwrap()2435				.get_alive()2436				.unwrap();2437			let trie = &info.child_trie_info();24382439			// Put value into the contracts child trie2440			child::put(trie, &[99], &42);24412442			// Terminate the contract2443			assert_ok!(Contracts::call(2444				Origin::signed(ALICE),2445				addr.clone(),2446				0,2447				GAS_LIMIT,2448				vec![],2449			));24502451			// Contract info should be gone2452			assert!(!<ContractInfoOf::<Test>>::contains_key(&addr));24532454			// But value should be still there as the lazy removal did not run, yet.2455			assert_matches!(child::get(trie, &[99]), Some(42));24562457			// Run the lazy removal2458			Contracts::on_initialize(Weight::max_value());24592460			// Value should be gone now2461			assert_matches!(child::get::<i32>(trie, &[99]), None);2462		});2463}24642465#[test]2466fn lazy_removal_partial_remove_works() {2467	let (code, hash) = compile_module::<Test>("self_destruct").unwrap();24682469	// We create a contract with some extra keys above the weight limit2470	let extra_keys = 7u32;2471	let weight_limit = 5_000_000_000;2472	let (_, max_keys) = Storage::<Test>::deletion_budget(1, weight_limit);2473	let vals: Vec<_> = (0..max_keys + extra_keys)2474		.map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode()))2475		.collect();24762477	let mut ext = ExtBuilder::default().existential_deposit(50).build();24782479	let trie = ext.execute_with(|| {2480		let subsistence = Pallet::<Test>::subsistence_threshold();2481		let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);24822483		assert_ok!(Contracts::instantiate_with_code(2484			Origin::signed(ALICE),2485			subsistence * 100,2486			GAS_LIMIT,2487			code,2488			vec![],2489			vec![],2490		),);24912492		let addr = Contracts::contract_address(&ALICE, &hash, &[]);2493		let info = <ContractInfoOf<Test>>::get(&addr)2494			.unwrap()2495			.get_alive()2496			.unwrap();2497		let trie = &info.child_trie_info();24982499		// Put value into the contracts child trie2500		for val in &vals {2501			Storage::<Test>::write(&addr, &info.trie_id, &val.0, Some(val.2.clone())).unwrap();2502		}25032504		// Terminate the contract2505		assert_ok!(Contracts::call(2506			Origin::signed(ALICE),2507			addr.clone(),2508			0,2509			GAS_LIMIT,2510			vec![],2511		));25122513		// Contract info should be gone2514		assert!(!<ContractInfoOf::<Test>>::contains_key(&addr));25152516		// But value should be still there as the lazy removal did not run, yet.2517		for val in &vals {2518			assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), Some(val.1));2519		}25202521		trie.clone()2522	});25232524	// The lazy removal limit only applies to the backend but not to the overlay.2525	// This commits all keys from the overlay to the backend.2526	ext.commit_all().unwrap();25272528	ext.execute_with(|| {2529		// Run the lazy removal2530		let weight_used = Storage::<Test>::process_deletion_queue_batch(weight_limit);25312532		// Weight should be exhausted because we could not even delete all keys2533		assert_eq!(weight_used, weight_limit);25342535		let mut num_deleted = 0u32;2536		let mut num_remaining = 0u32;25372538		for val in &vals {2539			match child::get::<u32>(&trie, &blake2_256(&val.0)) {2540				None => num_deleted += 1,2541				Some(x) if x == val.1 => num_remaining += 1,2542				Some(_) => panic!("Unexpected value in contract storage"),2543			}2544		}25452546		// All but one key is removed2547		assert_eq!(num_deleted + num_remaining, vals.len() as u32);2548		assert_eq!(num_deleted, max_keys);2549		assert_eq!(num_remaining, extra_keys);2550	});2551}25522553#[test]2554fn lazy_removal_does_no_run_on_full_block() {2555	let (code, hash) = compile_module::<Test>("self_destruct").unwrap();2556	ExtBuilder::default()2557		.existential_deposit(50)2558		.build()2559		.execute_with(|| {2560			let subsistence = Pallet::<Test>::subsistence_threshold();2561			let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);25622563			assert_ok!(Contracts::instantiate_with_code(2564				Origin::signed(ALICE),2565				subsistence * 100,2566				GAS_LIMIT,2567				code,2568				vec![],2569				vec![],2570			),);25712572			let addr = Contracts::contract_address(&ALICE, &hash, &[]);2573			let info = <ContractInfoOf<Test>>::get(&addr)2574				.unwrap()2575				.get_alive()2576				.unwrap();2577			let trie = &info.child_trie_info();2578			let max_keys = 30;25792580			// Create some storage items for the contract.2581			let vals: Vec<_> = (0..max_keys)2582				.map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode()))2583				.collect();25842585			// Put value into the contracts child trie2586			for val in &vals {2587				Storage::<Test>::write(&addr, &info.trie_id, &val.0, Some(val.2.clone())).unwrap();2588			}25892590			// Terminate the contract2591			assert_ok!(Contracts::call(2592				Origin::signed(ALICE),2593				addr.clone(),2594				0,2595				GAS_LIMIT,2596				vec![],2597			));25982599			// Contract info should be gone2600			assert!(!<ContractInfoOf::<Test>>::contains_key(&addr));26012602			// But value should be still there as the lazy removal did not run, yet.2603			for val in &vals {2604				assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), Some(val.1));2605			}26062607			// Fill up the block which should prevent the lazy storage removal from running.2608			System::register_extra_weight_unchecked(2609				<Test as system::Config>::BlockWeights::get().max_block,2610				DispatchClass::Mandatory,2611			);26122613			// Run the lazy removal without any limit so that all keys would be removed if there2614			// had been some weight left in the block.2615			let weight_used = Contracts::on_initialize(Weight::max_value());2616			let base = <<Test as Config>::WeightInfo as WeightInfo>::on_initialize();2617			assert_eq!(weight_used, base);26182619			// All the keys are still in place2620			for val in &vals {2621				assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), Some(val.1));2622			}26232624			// Run the lazy removal directly which disregards the block limits2625			Storage::<Test>::process_deletion_queue_batch(Weight::max_value());26262627			// Now the keys should be gone2628			for val in &vals {2629				assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), None);2630			}2631		});2632}26332634#[test]2635fn lazy_removal_does_not_use_all_weight() {2636	let (code, hash) = compile_module::<Test>("self_destruct").unwrap();2637	ExtBuilder::default()2638		.existential_deposit(50)2639		.build()2640		.execute_with(|| {2641			let subsistence = Pallet::<Test>::subsistence_threshold();2642			let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);26432644			assert_ok!(Contracts::instantiate_with_code(2645				Origin::signed(ALICE),2646				subsistence * 100,2647				GAS_LIMIT,2648				code,2649				vec![],2650				vec![],2651			),);26522653			let addr = Contracts::contract_address(&ALICE, &hash, &[]);2654			let info = <ContractInfoOf<Test>>::get(&addr)2655				.unwrap()2656				.get_alive()2657				.unwrap();2658			let trie = &info.child_trie_info();2659			let weight_limit = 5_000_000_000;2660			let (weight_per_key, max_keys) = Storage::<Test>::deletion_budget(1, weight_limit);26612662			// We create a contract with one less storage item than we can remove within the limit2663			let vals: Vec<_> = (0..max_keys - 1)2664				.map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode()))2665				.collect();26662667			// Put value into the contracts child trie2668			for val in &vals {2669				Storage::<Test>::write(&addr, &info.trie_id, &val.0, Some(val.2.clone())).unwrap();2670			}26712672			// Terminate the contract2673			assert_ok!(Contracts::call(2674				Origin::signed(ALICE),2675				addr.clone(),2676				0,2677				GAS_LIMIT,2678				vec![],2679			));26802681			// Contract info should be gone2682			assert!(!<ContractInfoOf::<Test>>::contains_key(&addr));26832684			// But value should be still there as the lazy removal did not run, yet.2685			for val in &vals {2686				assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), Some(val.1));2687			}26882689			// Run the lazy removal2690			let weight_used = Storage::<Test>::process_deletion_queue_batch(weight_limit);26912692			// We have one less key in our trie than our weight limit suffices for2693			assert_eq!(weight_used, weight_limit - weight_per_key);26942695			// All the keys are removed2696			for val in vals {2697				assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), None);2698			}2699		});2700}27012702#[test]2703fn deletion_queue_full() {2704	let (code, hash) = compile_module::<Test>("self_destruct").unwrap();2705	ExtBuilder::default()2706		.existential_deposit(50)2707		.build()2708		.execute_with(|| {2709			let subsistence = Pallet::<Test>::subsistence_threshold();2710			let _ = Balances::deposit_creating(&ALICE, 1000 * subsistence);27112712			assert_ok!(Contracts::instantiate_with_code(2713				Origin::signed(ALICE),2714				subsistence * 100,2715				GAS_LIMIT,2716				code,2717				vec![],2718				vec![],2719			),);27202721			let addr = Contracts::contract_address(&ALICE, &hash, &[]);27222723			// fill the deletion queue up until its limit2724			Storage::<Test>::fill_queue_with_dummies();27252726			// Terminate the contract should fail2727			assert_err_ignore_postinfo!(2728				Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![],),2729				Error::<Test>::DeletionQueueFull,2730			);27312732			// Contract should be alive because removal failed2733			<ContractInfoOf<Test>>::get(&addr)2734				.unwrap()2735				.get_alive()2736				.unwrap();27372738			// make the contract ripe for eviction2739			initialize_block(5);27402741			// eviction should fail for the same reason as termination2742			assert_err!(2743				Contracts::claim_surcharge(Origin::none(), addr.clone(), Some(ALICE)),2744				Error::<Test>::DeletionQueueFull,2745			);27462747			// Contract should be alive because removal failed2748			<ContractInfoOf<Test>>::get(&addr)2749				.unwrap()2750				.get_alive()2751				.unwrap();2752		});2753}27542755#[test]2756fn not_deployed_if_endowment_too_low_for_first_rent() {2757	let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();27582759	// The instantiation deducted the rent for one block immediately2760	let first_rent = <Test as Config>::RentFraction::get()2761		// base_deposit + deploy_set_storage (4 bytes in 1 item) - free_balance2762		.mul_ceil(80_000u32 + 40_000 + 10_000 - 30_000)2763		// blocks to rent2764		* 1;27652766	ExtBuilder::default()2767		.existential_deposit(50)2768		.build()2769		.execute_with(|| {2770			// Create2771			let _ = Balances::deposit_creating(&ALICE, 1_000_000);2772			assert_storage_noop!(assert_err_ignore_postinfo!(2773				Contracts::instantiate_with_code(2774					Origin::signed(ALICE),2775					30_000,2776					GAS_LIMIT,2777					wasm,2778					(BalanceOf::<Test>::from(first_rent) - BalanceOf::<Test>::from(1u32)).encode(), // rent allowance2779					vec![],2780				),2781				Error::<Test>::NewContractNotFunded,2782			));2783			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);2784			assert_matches!(ContractInfoOf::<Test>::get(&addr), None);2785		});2786}27872788#[test]2789fn surcharge_reward_is_capped() {2790	let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();2791	ExtBuilder::default()2792		.existential_deposit(50)2793		.build()2794		.execute_with(|| {2795			let _ = Balances::deposit_creating(&ALICE, 1_000_000);2796			assert_ok!(Contracts::instantiate_with_code(2797				Origin::signed(ALICE),2798				30_000,2799				GAS_LIMIT,2800				wasm,2801				<BalanceOf<Test>>::from(10_000u32).encode(), // rent allowance2802				vec![],2803			));2804			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);2805			let contract = <ContractInfoOf<Test>>::get(&addr)2806				.unwrap()2807				.get_alive()2808				.unwrap();2809			let balance = Balances::free_balance(&ALICE);2810			let reward = <Test as Config>::SurchargeReward::get();28112812			// some rent should have payed due to instantiation2813			assert_ne!(contract.rent_payed, 0);28142815			// the reward should be parameterized sufficiently high to make this test useful2816			assert!(reward > contract.rent_payed);28172818			// make contract eligible for eviction2819			initialize_block(40);28202821			// this should have removed the contract2822			assert_ok!(Contracts::claim_surcharge(2823				Origin::none(),2824				addr.clone(),2825				Some(ALICE)2826			));28272828			// this reward does not take into account the last rent payment collected during eviction2829			let capped_reward = reward.min(contract.rent_payed);28302831			// this is smaller than the actual reward because it does not take into account the2832			// rent collected during eviction2833			assert!(Balances::free_balance(&ALICE) > balance + capped_reward);28342835			// the full reward is not payed out because of the cap introduced by rent_payed2836			assert!(Balances::free_balance(&ALICE) < balance + reward);2837		});2838}28392840#[test]2841fn refcounter() {2842	let (wasm, code_hash) = compile_module::<Test>("self_destruct").unwrap();2843	ExtBuilder::default()2844		.existential_deposit(50)2845		.build()2846		.execute_with(|| {2847			let _ = Balances::deposit_creating(&ALICE, 1_000_000);2848			let subsistence = Pallet::<Test>::subsistence_threshold();28492850			// Create two contracts with the same code and check that they do in fact share it.2851			assert_ok!(Contracts::instantiate_with_code(2852				Origin::signed(ALICE),2853				subsistence * 100,2854				GAS_LIMIT,2855				wasm.clone(),2856				vec![],2857				vec![0],2858			));2859			assert_ok!(Contracts::instantiate_with_code(2860				Origin::signed(ALICE),2861				subsistence * 100,2862				GAS_LIMIT,2863				wasm.clone(),2864				vec![],2865				vec![1],2866			));2867			assert_refcount!(code_hash, 2);28682869			// Sharing should also work with the usual instantiate call2870			assert_ok!(Contracts::instantiate(2871				Origin::signed(ALICE),2872				subsistence * 100,2873				GAS_LIMIT,2874				code_hash,2875				vec![],2876				vec![2],2877			));2878			assert_refcount!(code_hash, 3);28792880			// addresses of all three existing contracts2881			let addr0 = Contracts::contract_address(&ALICE, &code_hash, &[0]);2882			let addr1 = Contracts::contract_address(&ALICE, &code_hash, &[1]);2883			let addr2 = Contracts::contract_address(&ALICE, &code_hash, &[2]);28842885			// Terminating one contract should decrement the refcount2886			assert_ok!(Contracts::call(2887				Origin::signed(ALICE),2888				addr0,2889				0,2890				GAS_LIMIT,2891				vec![],2892			));2893			assert_refcount!(code_hash, 2);28942895			// make remaining contracts eligible for eviction2896			initialize_block(40);28972898			// remove one of them2899			assert_ok!(Contracts::claim_surcharge(2900				Origin::none(),2901				addr1,2902				Some(ALICE)2903			));2904			assert_refcount!(code_hash, 1);29052906			// Pristine code should still be there2907			crate::PristineCode::<Test>::get(code_hash).unwrap();29082909			// remove the last contract2910			assert_ok!(Contracts::claim_surcharge(2911				Origin::none(),2912				addr2,2913				Some(ALICE)2914			));2915			assert_refcount!(code_hash, 0);29162917			// all code should be gone2918			assert_matches!(crate::PristineCode::<Test>::get(code_hash), None);2919			assert_matches!(crate::CodeStorage::<Test>::get(code_hash), None);2920		});2921}29222923#[test]2924fn reinstrument_does_charge() {2925	let (wasm, code_hash) = compile_module::<Test>("return_with_data").unwrap();2926	ExtBuilder::default()2927		.existential_deposit(50)2928		.build()2929		.execute_with(|| {2930			let _ = Balances::deposit_creating(&ALICE, 1_000_000);2931			let subsistence = Pallet::<Test>::subsistence_threshold();2932			let zero = 0u32.to_le_bytes().encode();2933			let code_len = wasm.len() as u32;29342935			assert_ok!(Contracts::instantiate_with_code(2936				Origin::signed(ALICE),2937				subsistence * 100,2938				GAS_LIMIT,2939				wasm,2940				zero.clone(),2941				vec![],2942			));29432944			let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);29452946			// Call the contract two times without reinstrument29472948			let result0 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, zero.clone());2949			assert!(result0.result.unwrap().is_success());29502951			let result1 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, zero.clone());2952			assert!(result1.result.unwrap().is_success());29532954			// They should match because both where called with the same schedule.2955			assert_eq!(result0.gas_consumed, result1.gas_consumed);29562957			// Update the schedule version but keep the rest the same2958			crate::CurrentSchedule::mutate(|old: &mut Schedule<Test>| {2959				old.version += 1;2960			});29612962			// This call should trigger reinstrumentation2963			let result2 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, zero.clone());2964			assert!(result2.result.unwrap().is_success());2965			assert!(result2.gas_consumed > result1.gas_consumed);2966			assert_eq!(2967				result2.gas_consumed,2968				result1.gas_consumed + <Test as Config>::WeightInfo::instrument(code_len / 1024),2969			);2970		});2971}