123456789101112131415161718use 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}348349350351352353fn 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}362363364365366#[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 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 434 435 436 437 438 439 440 assert_ok!(Balances::transfer(Origin::signed(ALICE), BOB, 20));441442 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 465 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 550 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 562 assert_ok!(Contracts::call(563 Origin::signed(ALICE),564 addr.clone(),565 0,566 GAS_LIMIT * 2, 567 <Test as Config>::MaxValueSize::get().encode(),568 ));569570 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 606 607 assert_err_ignore_postinfo!(608 Contracts::call(609 Origin::signed(ALICE),610 addr, 611 0,612 67_500_000,613 vec![],614 ),615 Error::<Test>::OutOfGas,616 );617 });618}619620621mod 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 647 ExtBuilder::default()648 .existential_deposit(50)649 .build()650 .execute_with(|| {651 652 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 659 <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 745 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 766 let rent0 = <Test as Config>::RentFraction::get()767 768 769 .mul_ceil((8 + 4 + code_len) * 10_000 + 10_000 - endowment)770 771 * 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 778 initialize_block(5);779780 781 assert_ok!(Contracts::call(782 Origin::signed(ALICE),783 addr.clone(),784 0,785 GAS_LIMIT,786 call::null()787 ));788789 790 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 802 initialize_block(7);803804 805 assert_ok!(Contracts::call(806 Origin::signed(ALICE),807 addr.clone(),808 0,809 GAS_LIMIT,810 call::null()811 ));812813 814 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 829 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 862 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 884 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}905906907908fn 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 916 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(), 923 vec![],924 ));925 let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);926927 928 initialize_block(blocks);929930 931 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}946947948949950951952fn removals(trigger_call: impl Fn(AccountIdOf<Test>) -> bool) {953 let (wasm, code_hash) = compile_module::<Test>("set_rent").unwrap();954955 956 ExtBuilder::default()957 .existential_deposit(50)958 .build()959 .execute_with(|| {960 961 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(), 968 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 981 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 993 initialize_block(27);994995 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 1004 initialize_block(30);10051006 1007 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 1016 ExtBuilder::default()1017 .existential_deposit(50)1018 .build()1019 .execute_with(|| {1020 1021 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(), 1028 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 1039 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 1051 initialize_block(27);10521053 1054 assert!(trigger_call(addr.clone()));1055 assert!(ContractInfoOf::<Test>::get(&addr)1056 .unwrap()1057 .get_tombstone()1058 .is_some());1059 1060 assert_eq!(Balances::free_balance(&addr), 30_000);10611062 1063 initialize_block(20);10641065 1066 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 1075 ExtBuilder::default()1076 .existential_deposit(50)1077 .build()1078 .execute_with(|| {1079 1080 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(), 1088 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 1099 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 1111 Balances::make_free_balance_be(&addr, subsistence_threshold);1112 assert_eq!(Balances::free_balance(&addr), subsistence_threshold);11131114 1115 initialize_block(10);11161117 1118 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 1126 initialize_block(20);11271128 1129 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 1143 ExtBuilder::default()1144 .existential_deposit(50)1145 .build()1146 .execute_with(|| {1147 1148 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 1155 <Test as pallet_balances::Config>::Balance::from(10_000u32).encode(),1156 vec![],1157 ));1158 let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);11591160 1161 assert_ok!(Contracts::call(1162 Origin::signed(ALICE),1163 addr.clone(),1164 0,1165 GAS_LIMIT,1166 call::null()1167 ));11681169 1170 initialize_block(27);11711172 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 1184 assert_eq!(System::events(), vec![]);11851186 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 1199 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 1220 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 1241 let first_rent = <Test as Config>::RentFraction::get()1242 1243 .mul_ceil((8 + code_len) * 10_000 - 30_000)1244 1245 * 1;1246 assert_eq!(1247 contract.rent_allowance,1248 <BalanceOf<Test>>::max_value() - first_rent1249 );12501251 1252 initialize_block(5);12531254 1255 assert_ok!(Contracts::call(1256 Origin::signed(ALICE),1257 addr.clone(),1258 0,1259 GAS_LIMIT,1260 call::null()1261 ));12621263 1264 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 1310 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 1374 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 1429 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 1447 initialize_block(27);14481449 1450 1451 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 1483 1484 1485 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 1498 let django_trie_id = ContractInfoOf::<Test>::get(&addr_django)1499 .unwrap()1500 .get_alive()1501 .unwrap()1502 .trie_id;15031504 1505 if !test_restore_to_with_dirty_storage {1506 1507 initialize_block(28);1508 }15091510 1511 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 1528 1529 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 1538 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 1644 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 1697 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 1713 assert_ok!(Contracts::call(1714 Origin::signed(ALICE),1715 addr.clone(),1716 0,1717 GAS_LIMIT * 2, 1718 <Test as Config>::MaxValueSize::get().encode(),1719 ));17201721 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 1745 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 1764 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 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 1796 assert_matches!(1797 ContractInfoOf::<Test>::get(&addr),1798 Some(ContractInfo::Alive(_))1799 );18001801 1802 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 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 1834 assert_matches!(1835 ContractInfoOf::<Test>::get(&addr),1836 Some(ContractInfo::Alive(_))1837 );18381839 1840 1841 assert_err_ignore_postinfo!(1842 Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![0],),1843 Error::<Test>::ContractTrapped,1844 );18451846 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 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 1876 assert_matches!(1877 ContractInfoOf::<Test>::get(&addr),1878 Some(ContractInfo::Alive(_))1879 );18801881 1882 initialize_block(2);18831884 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 1926 assert!(ContractInfoOf::<Test>::get(&addr).is_none());19271928 1929 1930 assert_eq!(Balances::free_balance(DJANGO), 1_093_086);1931 });1932}1933193419351936#[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 1946 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 1957 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 1971 assert_matches!(1972 ContractInfoOf::<Test>::get(&addr_charlie),1973 Some(ContractInfo::Alive(_))1974 );19751976 1977 assert_ok!(Contracts::call(1978 Origin::signed(ALICE),1979 addr_bob,1980 0,1981 GAS_LIMIT,1982 addr_charlie.encode(),1983 ));19841985 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 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 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 2035 let input = b"_DEAD_BEEF";2036 use sp_io::hashing::*;2037 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 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 2051 for (n, (hash_fn, expected_size)) in test_cases.iter().enumerate() {2052 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 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 2093 2094 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 2128 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 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 2167 2168 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 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 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 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 2262 2263 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 2273 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 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 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 2383 2384 23852386 2387 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 2393 Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, vec![1])2394 .result2395 .unwrap();2396 2397 assert_eq!(TestExtension::last_seen_inputs(), (4, 1, 16, 12));23982399 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 2405 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 2440 child::put(trie, &[99], &42);24412442 2443 assert_ok!(Contracts::call(2444 Origin::signed(ALICE),2445 addr.clone(),2446 0,2447 GAS_LIMIT,2448 vec![],2449 ));24502451 2452 assert!(!<ContractInfoOf::<Test>>::contains_key(&addr));24532454 2455 assert_matches!(child::get(trie, &[99]), Some(42));24562457 2458 Contracts::on_initialize(Weight::max_value());24592460 2461 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 2470 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 2500 for val in &vals {2501 Storage::<Test>::write(&addr, &info.trie_id, &val.0, Some(val.2.clone())).unwrap();2502 }25032504 2505 assert_ok!(Contracts::call(2506 Origin::signed(ALICE),2507 addr.clone(),2508 0,2509 GAS_LIMIT,2510 vec![],2511 ));25122513 2514 assert!(!<ContractInfoOf::<Test>>::contains_key(&addr));25152516 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 2525 2526 ext.commit_all().unwrap();25272528 ext.execute_with(|| {2529 2530 let weight_used = Storage::<Test>::process_deletion_queue_batch(weight_limit);25312532 2533 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 2547 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 2581 let vals: Vec<_> = (0..max_keys)2582 .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode()))2583 .collect();25842585 2586 for val in &vals {2587 Storage::<Test>::write(&addr, &info.trie_id, &val.0, Some(val.2.clone())).unwrap();2588 }25892590 2591 assert_ok!(Contracts::call(2592 Origin::signed(ALICE),2593 addr.clone(),2594 0,2595 GAS_LIMIT,2596 vec![],2597 ));25982599 2600 assert!(!<ContractInfoOf::<Test>>::contains_key(&addr));26012602 2603 for val in &vals {2604 assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), Some(val.1));2605 }26062607 2608 System::register_extra_weight_unchecked(2609 <Test as system::Config>::BlockWeights::get().max_block,2610 DispatchClass::Mandatory,2611 );26122613 2614 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 2620 for val in &vals {2621 assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), Some(val.1));2622 }26232624 2625 Storage::<Test>::process_deletion_queue_batch(Weight::max_value());26262627 2628 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 2663 let vals: Vec<_> = (0..max_keys - 1)2664 .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode()))2665 .collect();26662667 2668 for val in &vals {2669 Storage::<Test>::write(&addr, &info.trie_id, &val.0, Some(val.2.clone())).unwrap();2670 }26712672 2673 assert_ok!(Contracts::call(2674 Origin::signed(ALICE),2675 addr.clone(),2676 0,2677 GAS_LIMIT,2678 vec![],2679 ));26802681 2682 assert!(!<ContractInfoOf::<Test>>::contains_key(&addr));26832684 2685 for val in &vals {2686 assert_eq!(child::get::<u32>(trie, &blake2_256(&val.0)), Some(val.1));2687 }26882689 2690 let weight_used = Storage::<Test>::process_deletion_queue_batch(weight_limit);26912692 2693 assert_eq!(weight_used, weight_limit - weight_per_key);26942695 2696 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 2724 Storage::<Test>::fill_queue_with_dummies();27252726 2727 assert_err_ignore_postinfo!(2728 Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, vec![],),2729 Error::<Test>::DeletionQueueFull,2730 );27312732 2733 <ContractInfoOf<Test>>::get(&addr)2734 .unwrap()2735 .get_alive()2736 .unwrap();27372738 2739 initialize_block(5);27402741 2742 assert_err!(2743 Contracts::claim_surcharge(Origin::none(), addr.clone(), Some(ALICE)),2744 Error::<Test>::DeletionQueueFull,2745 );27462747 2748 <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 2760 let first_rent = <Test as Config>::RentFraction::get()2761 2762 .mul_ceil(80_000u32 + 40_000 + 10_000 - 30_000)2763 2764 * 1;27652766 ExtBuilder::default()2767 .existential_deposit(50)2768 .build()2769 .execute_with(|| {2770 2771 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(), 2779 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(), 2802 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 2813 assert_ne!(contract.rent_payed, 0);28142815 2816 assert!(reward > contract.rent_payed);28172818 2819 initialize_block(40);28202821 2822 assert_ok!(Contracts::claim_surcharge(2823 Origin::none(),2824 addr.clone(),2825 Some(ALICE)2826 ));28272828 2829 let capped_reward = reward.min(contract.rent_payed);28302831 2832 2833 assert!(Balances::free_balance(&ALICE) > balance + capped_reward);28342835 2836 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 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 2870 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 2881 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 2886 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 2896 initialize_block(40);28972898 2899 assert_ok!(Contracts::claim_surcharge(2900 Origin::none(),2901 addr1,2902 Some(ALICE)2903 ));2904 assert_refcount!(code_hash, 1);29052906 2907 crate::PristineCode::<Test>::get(code_hash).unwrap();29082909 2910 assert_ok!(Contracts::claim_surcharge(2911 Origin::none(),2912 addr2,2913 Some(ALICE)2914 ));2915 assert_refcount!(code_hash, 0);29162917 2918 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 29472948 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 2955 assert_eq!(result0.gas_consumed, result1.gas_consumed);29562957 2958 crate::CurrentSchedule::mutate(|old: &mut Schedule<Test>| {2959 old.version += 1;2960 });29612962 2963 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}