diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 3dbcbbb69da4c..6c1be178d70fd 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -1641,6 +1641,10 @@ mod tests { } impl MockLoader { + fn code_hashes() -> Vec> { + Loader::get().map.keys().copied().collect() + } + fn insert( func_type: ExportedFunction, f: impl Fn(MockCtx, &MockExecutable) -> ExecResult + 'static, @@ -2042,29 +2046,33 @@ mod tests { }); // This one tests passing the input data into a contract via instantiate. - ExtBuilder::default().build().execute_with(|| { - let schedule = ::Schedule::get(); - let min_balance = ::Currency::minimum_balance(); - let mut gas_meter = GasMeter::::new(GAS_LIMIT); - let executable = MockExecutable::from_storage(input_data_ch, &mut gas_meter).unwrap(); - set_balance(&ALICE, min_balance * 10_000); - let contract_origin = Origin::from_account_id(ALICE); - let mut storage_meter = - storage::meter::Meter::new(&contract_origin, None, min_balance).unwrap(); - - let result = MockStack::run_instantiate( - ALICE, - executable, - &mut gas_meter, - &mut storage_meter, - &schedule, - min_balance, - vec![1, 2, 3, 4], - &[], - None, - ); - assert_matches!(result, Ok(_)); - }); + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .build() + .execute_with(|| { + let schedule = ::Schedule::get(); + let min_balance = ::Currency::minimum_balance(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + let executable = + MockExecutable::from_storage(input_data_ch, &mut gas_meter).unwrap(); + set_balance(&ALICE, min_balance * 10_000); + let contract_origin = Origin::from_account_id(ALICE); + let mut storage_meter = + storage::meter::Meter::new(&contract_origin, None, min_balance).unwrap(); + + let result = MockStack::run_instantiate( + ALICE, + executable, + &mut gas_meter, + &mut storage_meter, + &schedule, + min_balance, + vec![1, 2, 3, 4], + &[], + None, + ); + assert_matches!(result, Ok(_)); + }); } #[test] @@ -2487,43 +2495,53 @@ mod tests { Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: vec![80, 65, 83, 83] }) }); - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let schedule = ::Schedule::get(); - let min_balance = ::Currency::minimum_balance(); - let mut gas_meter = GasMeter::::new(GAS_LIMIT); - let executable = MockExecutable::from_storage(dummy_ch, &mut gas_meter).unwrap(); - set_balance(&ALICE, min_balance * 1000); - let contract_origin = Origin::from_account_id(ALICE); - let mut storage_meter = - storage::meter::Meter::new(&contract_origin, Some(min_balance * 100), min_balance) - .unwrap(); - - let instantiated_contract_address = assert_matches!( - MockStack::run_instantiate( - ALICE, - executable, - &mut gas_meter, - &mut storage_meter, - &schedule, + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .existential_deposit(15) + .build() + .execute_with(|| { + let schedule = ::Schedule::get(); + let min_balance = ::Currency::minimum_balance(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + let executable = MockExecutable::from_storage(dummy_ch, &mut gas_meter).unwrap(); + set_balance(&ALICE, min_balance * 1000); + let contract_origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new( + &contract_origin, + Some(min_balance * 100), min_balance, - vec![], - &[], - None, - ), - Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address - ); + ) + .unwrap(); - // Check that the newly created account has the expected code hash and - // there are instantiation event. - assert_eq!( - ContractInfo::::load_code_hash(&instantiated_contract_address).unwrap(), - dummy_ch - ); - assert_eq!( - &events(), - &[Event::Instantiated { deployer: ALICE, contract: instantiated_contract_address }] - ); - }); + let instantiated_contract_address = assert_matches!( + MockStack::run_instantiate( + ALICE, + executable, + &mut gas_meter, + &mut storage_meter, + &schedule, + min_balance, + vec![], + &[], + None, + ), + Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address + ); + + // Check that the newly created account has the expected code hash and + // there are instantiation event. + assert_eq!( + ContractInfo::::load_code_hash(&instantiated_contract_address).unwrap(), + dummy_ch + ); + assert_eq!( + &events(), + &[Event::Instantiated { + deployer: ALICE, + contract: instantiated_contract_address + }] + ); + }); } #[test] @@ -2532,36 +2550,45 @@ mod tests { Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![70, 65, 73, 76] }) }); - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let schedule = ::Schedule::get(); - let min_balance = ::Currency::minimum_balance(); - let mut gas_meter = GasMeter::::new(GAS_LIMIT); - let executable = MockExecutable::from_storage(dummy_ch, &mut gas_meter).unwrap(); - set_balance(&ALICE, min_balance * 1000); - let contract_origin = Origin::from_account_id(ALICE); - let mut storage_meter = - storage::meter::Meter::new(&contract_origin, Some(min_balance * 100), min_balance) - .unwrap(); - - let instantiated_contract_address = assert_matches!( - MockStack::run_instantiate( - ALICE, - executable, - &mut gas_meter, - &mut storage_meter, - &schedule, + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .existential_deposit(15) + .build() + .execute_with(|| { + let schedule = ::Schedule::get(); + let min_balance = ::Currency::minimum_balance(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + let executable = MockExecutable::from_storage(dummy_ch, &mut gas_meter).unwrap(); + set_balance(&ALICE, min_balance * 1000); + let contract_origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new( + &contract_origin, + Some(min_balance * 100), min_balance, - vec![], - &[], - None, - ), - Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address - ); + ) + .unwrap(); - // Check that the account has not been created. - assert!(ContractInfo::::load_code_hash(&instantiated_contract_address).is_none()); - assert!(events().is_empty()); - }); + let instantiated_contract_address = assert_matches!( + MockStack::run_instantiate( + ALICE, + executable, + &mut gas_meter, + &mut storage_meter, + &schedule, + min_balance, + vec![], + &[], + None, + ), + Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address + ); + + // Check that the account has not been created. + assert!( + ContractInfo::::load_code_hash(&instantiated_contract_address).is_none() + ); + assert!(events().is_empty()); + }); } #[test] @@ -2589,51 +2616,58 @@ mod tests { } }); - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let schedule = ::Schedule::get(); - let min_balance = ::Currency::minimum_balance(); - set_balance(&ALICE, min_balance * 100); - place_contract(&BOB, instantiator_ch); - let contract_origin = Origin::from_account_id(ALICE); - let mut storage_meter = storage::meter::Meter::new( - &contract_origin, - Some(min_balance * 10), - min_balance * 10, - ) - .unwrap(); - - assert_matches!( - MockStack::run_call( - contract_origin, - BOB, - &mut GasMeter::::new(GAS_LIMIT), - &mut storage_meter, - &schedule, + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .existential_deposit(15) + .build() + .execute_with(|| { + let schedule = ::Schedule::get(); + let min_balance = ::Currency::minimum_balance(); + set_balance(&ALICE, min_balance * 100); + place_contract(&BOB, instantiator_ch); + let contract_origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new( + &contract_origin, + Some(min_balance * 10), min_balance * 10, - vec![], - None, - Determinism::Enforced, - ), - Ok(_) - ); + ) + .unwrap(); - let instantiated_contract_address = - instantiated_contract_address.borrow().as_ref().unwrap().clone(); + assert_matches!( + MockStack::run_call( + contract_origin, + BOB, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + &schedule, + min_balance * 10, + vec![], + None, + Determinism::Enforced, + ), + Ok(_) + ); - // Check that the newly created account has the expected code hash and - // there are instantiation event. - assert_eq!( - ContractInfo::::load_code_hash(&instantiated_contract_address).unwrap(), - dummy_ch - ); - assert_eq!( - &events(), - &[ - Event::Instantiated { deployer: BOB, contract: instantiated_contract_address }, - Event::Called { caller: Origin::from_account_id(ALICE), contract: BOB }, - ] - ); - }); + let instantiated_contract_address = + instantiated_contract_address.borrow().as_ref().unwrap().clone(); + + // Check that the newly created account has the expected code hash and + // there are instantiation event. + assert_eq!( + ContractInfo::::load_code_hash(&instantiated_contract_address).unwrap(), + dummy_ch + ); + assert_eq!( + &events(), + &[ + Event::Instantiated { + deployer: BOB, + contract: instantiated_contract_address + }, + Event::Called { caller: Origin::from_account_id(ALICE), contract: BOB }, + ] + ); + }); } #[test] @@ -2661,37 +2695,41 @@ mod tests { } }); - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let schedule = ::Schedule::get(); - set_balance(&ALICE, 1000); - set_balance(&BOB, 100); - place_contract(&BOB, instantiator_ch); - let contract_origin = Origin::from_account_id(ALICE); - let mut storage_meter = - storage::meter::Meter::new(&contract_origin, Some(200), 0).unwrap(); + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .existential_deposit(15) + .build() + .execute_with(|| { + let schedule = ::Schedule::get(); + set_balance(&ALICE, 1000); + set_balance(&BOB, 100); + place_contract(&BOB, instantiator_ch); + let contract_origin = Origin::from_account_id(ALICE); + let mut storage_meter = + storage::meter::Meter::new(&contract_origin, Some(200), 0).unwrap(); - assert_matches!( - MockStack::run_call( - contract_origin, - BOB, - &mut GasMeter::::new(GAS_LIMIT), - &mut storage_meter, - &schedule, - 0, - vec![], - None, - Determinism::Enforced, - ), - Ok(_) - ); + assert_matches!( + MockStack::run_call( + contract_origin, + BOB, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + &schedule, + 0, + vec![], + None, + Determinism::Enforced, + ), + Ok(_) + ); - // The contract wasn't instantiated so we don't expect to see an instantiation - // event here. - assert_eq!( - &events(), - &[Event::Called { caller: Origin::from_account_id(ALICE), contract: BOB },] - ); - }); + // The contract wasn't instantiated so we don't expect to see an instantiation + // event here. + assert_eq!( + &events(), + &[Event::Called { caller: Origin::from_account_id(ALICE), contract: BOB },] + ); + }); } #[test] @@ -2701,32 +2739,37 @@ mod tests { exec_success() }); - ExtBuilder::default().existential_deposit(15).build().execute_with(|| { - let schedule = ::Schedule::get(); - let mut gas_meter = GasMeter::::new(GAS_LIMIT); - let executable = MockExecutable::from_storage(terminate_ch, &mut gas_meter).unwrap(); - set_balance(&ALICE, 10_000); - let contract_origin = Origin::from_account_id(ALICE); - let mut storage_meter = - storage::meter::Meter::new(&contract_origin, None, 100).unwrap(); + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .existential_deposit(15) + .build() + .execute_with(|| { + let schedule = ::Schedule::get(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + let executable = + MockExecutable::from_storage(terminate_ch, &mut gas_meter).unwrap(); + set_balance(&ALICE, 10_000); + let contract_origin = Origin::from_account_id(ALICE); + let mut storage_meter = + storage::meter::Meter::new(&contract_origin, None, 100).unwrap(); - assert_eq!( - MockStack::run_instantiate( - ALICE, - executable, - &mut gas_meter, - &mut storage_meter, - &schedule, - 100, - vec![], - &[], - None, - ), - Err(Error::::TerminatedInConstructor.into()) - ); + assert_eq!( + MockStack::run_instantiate( + ALICE, + executable, + &mut gas_meter, + &mut storage_meter, + &schedule, + 100, + vec![], + &[], + None, + ), + Err(Error::::TerminatedInConstructor.into()) + ); - assert_eq!(&events(), &[]); - }); + assert_eq!(&events(), &[]); + }); } #[test] @@ -2802,29 +2845,32 @@ mod tests { }); // This one tests passing the input data into a contract via instantiate. - ExtBuilder::default().build().execute_with(|| { - let schedule = ::Schedule::get(); - let min_balance = ::Currency::minimum_balance(); - let mut gas_meter = GasMeter::::new(GAS_LIMIT); - let executable = MockExecutable::from_storage(code, &mut gas_meter).unwrap(); - set_balance(&ALICE, min_balance * 10_000); - let contract_origin = Origin::from_account_id(ALICE); - let mut storage_meter = - storage::meter::Meter::new(&contract_origin, None, min_balance).unwrap(); - - let result = MockStack::run_instantiate( - ALICE, - executable, - &mut gas_meter, - &mut storage_meter, - &schedule, - min_balance, - vec![], - &[], - None, - ); - assert_matches!(result, Ok(_)); - }); + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .build() + .execute_with(|| { + let schedule = ::Schedule::get(); + let min_balance = ::Currency::minimum_balance(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + let executable = MockExecutable::from_storage(code, &mut gas_meter).unwrap(); + set_balance(&ALICE, min_balance * 10_000); + let contract_origin = Origin::from_account_id(ALICE); + let mut storage_meter = + storage::meter::Meter::new(&contract_origin, None, min_balance).unwrap(); + + let result = MockStack::run_instantiate( + ALICE, + executable, + &mut gas_meter, + &mut storage_meter, + &schedule, + min_balance, + vec![], + &[], + None, + ); + assert_matches!(result, Ok(_)); + }); } #[test] @@ -3226,75 +3272,79 @@ mod tests { exec_success() }); - ExtBuilder::default().build().execute_with(|| { - let schedule = ::Schedule::get(); - let min_balance = ::Currency::minimum_balance(); - let mut gas_meter = GasMeter::::new(GAS_LIMIT); - let fail_executable = MockExecutable::from_storage(fail_code, &mut gas_meter).unwrap(); - let success_executable = - MockExecutable::from_storage(success_code, &mut gas_meter).unwrap(); - let succ_fail_executable = - MockExecutable::from_storage(succ_fail_code, &mut gas_meter).unwrap(); - let succ_succ_executable = - MockExecutable::from_storage(succ_succ_code, &mut gas_meter).unwrap(); - set_balance(&ALICE, min_balance * 10_000); - let contract_origin = Origin::from_account_id(ALICE); - let mut storage_meter = - storage::meter::Meter::new(&contract_origin, None, min_balance * 100).unwrap(); + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .build() + .execute_with(|| { + let schedule = ::Schedule::get(); + let min_balance = ::Currency::minimum_balance(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + let fail_executable = + MockExecutable::from_storage(fail_code, &mut gas_meter).unwrap(); + let success_executable = + MockExecutable::from_storage(success_code, &mut gas_meter).unwrap(); + let succ_fail_executable = + MockExecutable::from_storage(succ_fail_code, &mut gas_meter).unwrap(); + let succ_succ_executable = + MockExecutable::from_storage(succ_succ_code, &mut gas_meter).unwrap(); + set_balance(&ALICE, min_balance * 10_000); + let contract_origin = Origin::from_account_id(ALICE); + let mut storage_meter = + storage::meter::Meter::new(&contract_origin, None, min_balance * 100).unwrap(); - MockStack::run_instantiate( - ALICE, - fail_executable, - &mut gas_meter, - &mut storage_meter, - &schedule, - min_balance * 100, - vec![], - &[], - None, - ) - .ok(); - assert_eq!(>::get(), 0); + MockStack::run_instantiate( + ALICE, + fail_executable, + &mut gas_meter, + &mut storage_meter, + &schedule, + min_balance * 100, + vec![], + &[], + None, + ) + .ok(); + assert_eq!(>::get(), 0); - assert_ok!(MockStack::run_instantiate( - ALICE, - success_executable, - &mut gas_meter, - &mut storage_meter, - &schedule, - min_balance * 100, - vec![], - &[], - None, - )); - assert_eq!(>::get(), 1); + assert_ok!(MockStack::run_instantiate( + ALICE, + success_executable, + &mut gas_meter, + &mut storage_meter, + &schedule, + min_balance * 100, + vec![], + &[], + None, + )); + assert_eq!(>::get(), 1); - assert_ok!(MockStack::run_instantiate( - ALICE, - succ_fail_executable, - &mut gas_meter, - &mut storage_meter, - &schedule, - min_balance * 200, - vec![], - &[], - None, - )); - assert_eq!(>::get(), 2); + assert_ok!(MockStack::run_instantiate( + ALICE, + succ_fail_executable, + &mut gas_meter, + &mut storage_meter, + &schedule, + min_balance * 200, + vec![], + &[], + None, + )); + assert_eq!(>::get(), 2); - assert_ok!(MockStack::run_instantiate( - ALICE, - succ_succ_executable, - &mut gas_meter, - &mut storage_meter, - &schedule, - min_balance * 200, - vec![], - &[], - None, - )); - assert_eq!(>::get(), 4); - }); + assert_ok!(MockStack::run_instantiate( + ALICE, + succ_succ_executable, + &mut gas_meter, + &mut storage_meter, + &schedule, + min_balance * 200, + vec![], + &[], + None, + )); + assert_eq!(>::get(), 4); + }); } #[test] @@ -3762,26 +3812,30 @@ mod tests { exec_success() }); - ExtBuilder::default().build().execute_with(|| { - let min_balance = ::Currency::minimum_balance(); - let schedule = ::Schedule::get(); - let mut gas_meter = GasMeter::::new(GAS_LIMIT); - set_balance(&ALICE, min_balance * 1000); - place_contract(&BOB, code_hash); - let contract_origin = Origin::from_account_id(ALICE); - let mut storage_meter = storage::meter::Meter::new(&contract_origin, None, 0).unwrap(); - assert_ok!(MockStack::run_call( - contract_origin, - BOB, - &mut gas_meter, - &mut storage_meter, - &schedule, - 0, - vec![], - None, - Determinism::Enforced - )); - }); + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .build() + .execute_with(|| { + let min_balance = ::Currency::minimum_balance(); + let schedule = ::Schedule::get(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + set_balance(&ALICE, min_balance * 1000); + place_contract(&BOB, code_hash); + let contract_origin = Origin::from_account_id(ALICE); + let mut storage_meter = + storage::meter::Meter::new(&contract_origin, None, 0).unwrap(); + assert_ok!(MockStack::run_call( + contract_origin, + BOB, + &mut gas_meter, + &mut storage_meter, + &schedule, + 0, + vec![], + None, + Determinism::Enforced + )); + }); } /// This works even though random interface is deprecated, as the check to ban deprecated diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 5e46dc44938b5..34498a976231d 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -27,9 +27,9 @@ use crate::{ tests::test_utils::{get_contract, get_contract_checked}, wasm::{Determinism, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, - BalanceOf, Code, CollectEvents, Config, ContractInfo, ContractInfoOf, DebugInfo, - DefaultAddressGenerator, DeletionQueueCounter, Error, MigrationInProgress, NoopMigration, - Origin, Pallet, PristineCode, Schedule, + BalanceOf, Code, CodeHash, CodeInfoOf, CollectEvents, Config, ContractInfo, ContractInfoOf, + DebugInfo, DefaultAddressGenerator, DeletionQueueCounter, Error, MigrationInProgress, + NoopMigration, Origin, Pallet, PristineCode, Schedule, }; use assert_matches::assert_matches; use codec::Encode; @@ -104,6 +104,7 @@ pub mod test_utils { *counter }); set_balance(address, ::Currency::minimum_balance() * 10); + >::insert(code_hash, CodeInfo::new(address.clone())); let contract = >::new(&address, nonce, code_hash).unwrap(); >::insert(address, contract); } @@ -472,17 +473,28 @@ pub const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000, 3 * 1024 * 102 pub struct ExtBuilder { existential_deposit: u64, storage_version: Option, + code_hashes: Vec>, } + impl Default for ExtBuilder { fn default() -> Self { - Self { existential_deposit: ExistentialDeposit::get(), storage_version: None } + Self { + existential_deposit: ExistentialDeposit::get(), + storage_version: None, + code_hashes: vec![], + } } } + impl ExtBuilder { pub fn existential_deposit(mut self, existential_deposit: u64) -> Self { self.existential_deposit = existential_deposit; self } + pub fn with_code_hashes(mut self, code_hashes: Vec>) -> Self { + self.code_hashes = code_hashes; + self + } pub fn set_associated_consts(&self) { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); } @@ -510,6 +522,11 @@ impl ExtBuilder { } System::set_block_number(1) }); + ext.execute_with(|| { + for code_hash in self.code_hashes { + CodeInfoOf::::insert(code_hash, crate::CodeInfo::new(ALICE)); + } + }); ext } } @@ -5491,7 +5508,7 @@ fn native_dependency_deposit_works() { ) .unwrap(); - // Upload set_code_hash contracts if using Code::Existing. + // Upload `set_code_hash` contracts if using Code::Existing. let add_upload_deposit = match code { Code::Existing(_) => { Contracts::upload_code( diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index b677bdd131242..07050aabbe93a 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -415,6 +415,16 @@ impl CodeInfo { self.refcount } + #[cfg(test)] + pub fn new(owner: T::AccountId) -> Self { + CodeInfo { + owner, + deposit: Default::default(), + refcount: 0, + determinism: Determinism::Enforced, + } + } + /// Returns the deposit of the module. pub fn deposit(&self) -> BalanceOf { self.deposit