mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 16:17:59 +00:00
Contracts Add deposit for dependencies (#14079)
* wip * fixes * rm comment * join fns * clippy * Fix limits * reduce diff * fix * fix * fix typo * refactor store to use self * refactor run to take self by value * pass tests * rm comment * fixes * fix typo * rm * fix fmt * clippy * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * Update frame/contracts/src/lib.rs Co-authored-by: Sasha Gryaznov <hi@agryaznov.com> * Update frame/contracts/src/wasm/mod.rs Co-authored-by: Sasha Gryaznov <hi@agryaznov.com> * Update frame/contracts/src/wasm/mod.rs Co-authored-by: Sasha Gryaznov <hi@agryaznov.com> * PR review, rm duplicate increment_refcount * PR review * Update frame/contracts/src/wasm/prepare.rs Co-authored-by: Sasha Gryaznov <hi@agryaznov.com> * Add test for failing storage_deposit * fix lint * wip * Delegate update take 2 * update * fix migration * fix migration * doc * fix lint * update migration * fix warning * reformat comment * regenerate weightInfo trait * fix merge * PR review https://github.com/paritytech/substrate/pull/14079#discussion_r1255904563 * PR review https://github.com/paritytech/substrate/pull/14079/files#r1257521373 * PR review remove optimisation https://github.com/paritytech/substrate/pull/14079/files#r1263312237 * PR review fix return type https://github.com/paritytech/substrate/pull/14079/files#r1263315804 * Apply suggestions from code review Co-authored-by: Alexander Theißen <alex.theissen@me.com> * PR review pass CodeInfo and update docstring https://github.com/paritytech/substrate/pull/14079/files#r1257522327 * PR review add code_info to the executable https://github.com/paritytech/substrate/pull/14079/files#r1263309049 * rename info -> contract_info * Update frame/contracts/src/exec.rs Co-authored-by: Alexander Theißen <alex.theissen@me.com> * Update frame/contracts/fixtures/add_remove_delegate_dependency.wat Co-authored-by: Alexander Theißen <alex.theissen@me.com> * Update frame/contracts/src/migration/v13.rs * fix tests * Fmt & fix tests * Test Result<(), _> return type * Update frame/contracts/src/migration.rs Co-authored-by: Alexander Theißen <alex.theissen@me.com> * Revert "Test Result<(), _> return type" This reverts commit a876168f2054edf84d720c666387583ccbe78dcd. * add / update doc comments * fix backticks * Revert "Revert "Test Result<(), _> return type"" This reverts commit 3cbb6161d1abd9520cd9f8519b4dfbf4f29a2998. * fix bench * fix bench * fix * Update frame/contracts/src/storage/meter.rs Co-authored-by: Alexander Theißen <alex.theissen@me.com> * rm stale comments * Apply suggestions from code review Co-authored-by: Sasha Gryaznov <hi@agryaznov.com> * PR suggestion * Add missing doc * fx lint * ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --pallet=pallet_contracts * Update frame/contracts/src/lib.rs Co-authored-by: Juan <juangirini@gmail.com> --------- Co-authored-by: command-bot <> Co-authored-by: Sasha Gryaznov <hi@agryaznov.com> Co-authored-by: Alexander Theißen <alex.theissen@me.com> Co-authored-by: Juan <juangirini@gmail.com>
This commit is contained in:
@@ -18,14 +18,16 @@
|
||||
use crate::{
|
||||
gas::GasMeter,
|
||||
storage::{self, DepositAccount, WriteOutcome},
|
||||
BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, DebugBufferVec, Determinism, Error,
|
||||
Event, Nonce, Origin, Pallet as Contracts, Schedule, System, LOG_TARGET,
|
||||
BalanceOf, CodeHash, CodeInfo, CodeInfoOf, Config, ContractInfo, ContractInfoOf,
|
||||
DebugBufferVec, Determinism, Error, Event, Nonce, Origin, Pallet as Contracts, Schedule,
|
||||
System, WasmBlob, LOG_TARGET,
|
||||
};
|
||||
use frame_support::{
|
||||
crypto::ecdsa::ECDSAExt,
|
||||
dispatch::{
|
||||
fmt::Debug, DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable,
|
||||
},
|
||||
ensure,
|
||||
storage::{with_transaction, TransactionOutcome},
|
||||
traits::{
|
||||
tokens::{Fortitude::Polite, Preservation::Expendable},
|
||||
@@ -35,11 +37,12 @@ use frame_support::{
|
||||
Blake2_128Concat, BoundedVec, StorageHasher,
|
||||
};
|
||||
use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
|
||||
use pallet_contracts_primitives::ExecReturnValue;
|
||||
use pallet_contracts_primitives::{ExecReturnValue, StorageDeposit};
|
||||
use smallvec::{Array, SmallVec};
|
||||
use sp_core::{
|
||||
ecdsa::Public as ECDSAPublic,
|
||||
sr25519::{Public as SR25519Public, Signature as SR25519Signature},
|
||||
Get,
|
||||
};
|
||||
use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256};
|
||||
use sp_runtime::traits::{Convert, Hash, Zero};
|
||||
@@ -308,6 +311,35 @@ pub trait Ext: sealing::Sealed {
|
||||
|
||||
/// Returns a nonce that is incremented for every instantiated contract.
|
||||
fn nonce(&mut self) -> u64;
|
||||
|
||||
/// Adds a delegate dependency to [`ContractInfo`]'s `delegate_dependencies` field.
|
||||
///
|
||||
/// This ensures that the delegated contract is not removed while it is still in use. It
|
||||
/// increases the reference count of the code hash and charges a fraction (see
|
||||
/// [`Config::CodeHashLockupDepositPercent`]) of the code deposit.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// - [`Error::<T>::MaxDelegateDependenciesReached`]
|
||||
/// - [`Error::<T>::CannotAddSelfAsDelegateDependency`]
|
||||
/// - [`Error::<T>::DelegateDependencyAlreadyExists`]
|
||||
fn add_delegate_dependency(
|
||||
&mut self,
|
||||
code_hash: CodeHash<Self::T>,
|
||||
) -> Result<(), DispatchError>;
|
||||
|
||||
/// Removes a delegate dependency from [`ContractInfo`]'s `delegate_dependencies` field.
|
||||
///
|
||||
/// This is the counterpart of [`Self::add_delegate_dependency`]. It decreases the reference
|
||||
/// count and refunds the deposit that was charged by [`Self::add_delegate_dependency`].
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// - [`Error::<T>::DelegateDependencyNotFound`]
|
||||
fn remove_delegate_dependency(
|
||||
&mut self,
|
||||
code_hash: &CodeHash<Self::T>,
|
||||
) -> Result<(), DispatchError>;
|
||||
}
|
||||
|
||||
/// Describes the different functions that can be exported by an [`Executable`].
|
||||
@@ -365,6 +397,9 @@ pub trait Executable<T: Config>: Sized {
|
||||
input_data: Vec<u8>,
|
||||
) -> ExecResult;
|
||||
|
||||
/// The code info of the executable.
|
||||
fn code_info(&self) -> &CodeInfo<T>;
|
||||
|
||||
/// The code hash of the executable.
|
||||
fn code_hash(&self) -> &CodeHash<T>;
|
||||
|
||||
@@ -861,6 +896,7 @@ where
|
||||
origin,
|
||||
&frame.account_id,
|
||||
frame.contract_info.get(&frame.account_id),
|
||||
executable.code_info(),
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -1259,6 +1295,14 @@ where
|
||||
info.queue_trie_for_deletion();
|
||||
ContractInfoOf::<T>::remove(&frame.account_id);
|
||||
E::decrement_refcount(info.code_hash);
|
||||
|
||||
for (code_hash, deposit) in info.delegate_dependencies() {
|
||||
E::decrement_refcount(*code_hash);
|
||||
frame
|
||||
.nested_storage
|
||||
.charge_deposit(info.deposit_account().clone(), StorageDeposit::Refund(*deposit));
|
||||
}
|
||||
|
||||
Contracts::<T>::deposit_event(
|
||||
vec![T::Hashing::hash_of(&frame.account_id), T::Hashing::hash_of(&beneficiary)],
|
||||
Event::Terminated {
|
||||
@@ -1433,10 +1477,24 @@ where
|
||||
if !E::from_storage(hash, &mut frame.nested_gas)?.is_deterministic() {
|
||||
return Err(<Error<T>>::Indeterministic.into())
|
||||
}
|
||||
|
||||
let info = frame.contract_info();
|
||||
|
||||
let prev_hash = info.code_hash;
|
||||
info.code_hash = hash;
|
||||
|
||||
let code_info = CodeInfoOf::<T>::get(hash).ok_or(Error::<T>::CodeNotFound)?;
|
||||
|
||||
let old_base_deposit = info.storage_base_deposit();
|
||||
let new_base_deposit = info.update_base_deposit(&code_info);
|
||||
let deposit = StorageDeposit::Charge(new_base_deposit)
|
||||
.saturating_sub(&StorageDeposit::Charge(old_base_deposit));
|
||||
|
||||
let deposit_account = info.deposit_account().clone();
|
||||
frame.nested_storage.charge_deposit(deposit_account, deposit);
|
||||
|
||||
E::increment_refcount(hash)?;
|
||||
let prev_hash = frame.contract_info().code_hash;
|
||||
E::decrement_refcount(prev_hash);
|
||||
frame.contract_info().code_hash = hash;
|
||||
Contracts::<Self::T>::deposit_event(
|
||||
vec![T::Hashing::hash_of(&frame.account_id), hash, prev_hash],
|
||||
Event::ContractCodeUpdated {
|
||||
@@ -1468,6 +1526,41 @@ where
|
||||
current
|
||||
}
|
||||
}
|
||||
|
||||
fn add_delegate_dependency(
|
||||
&mut self,
|
||||
code_hash: CodeHash<Self::T>,
|
||||
) -> Result<(), DispatchError> {
|
||||
let frame = self.top_frame_mut();
|
||||
let info = frame.contract_info.get(&frame.account_id);
|
||||
ensure!(code_hash != info.code_hash, Error::<T>::CannotAddSelfAsDelegateDependency);
|
||||
|
||||
let code_info = CodeInfoOf::<T>::get(code_hash).ok_or(Error::<T>::CodeNotFound)?;
|
||||
let deposit = T::CodeHashLockupDepositPercent::get().mul_ceil(code_info.deposit());
|
||||
|
||||
info.add_delegate_dependency(code_hash, deposit)?;
|
||||
<WasmBlob<T>>::increment_refcount(code_hash)?;
|
||||
frame
|
||||
.nested_storage
|
||||
.charge_deposit(info.deposit_account().clone(), StorageDeposit::Charge(deposit));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_delegate_dependency(
|
||||
&mut self,
|
||||
code_hash: &CodeHash<Self::T>,
|
||||
) -> Result<(), DispatchError> {
|
||||
let frame = self.top_frame_mut();
|
||||
let info = frame.contract_info.get(&frame.account_id);
|
||||
|
||||
let deposit = info.remove_delegate_dependency(code_hash)?;
|
||||
<WasmBlob<T>>::decrement_refcount(*code_hash);
|
||||
|
||||
frame
|
||||
.nested_storage
|
||||
.charge_deposit(info.deposit_account().clone(), StorageDeposit::Refund(deposit));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
mod sealing {
|
||||
@@ -1543,6 +1636,7 @@ mod tests {
|
||||
func: Rc<dyn Fn(MockCtx, &Self) -> ExecResult + 'static>,
|
||||
func_type: ExportedFunction,
|
||||
code_hash: CodeHash<Test>,
|
||||
code_info: CodeInfo<Test>,
|
||||
refcount: u64,
|
||||
}
|
||||
|
||||
@@ -1553,6 +1647,10 @@ mod tests {
|
||||
}
|
||||
|
||||
impl MockLoader {
|
||||
fn code_hashes() -> Vec<CodeHash<Test>> {
|
||||
Loader::get().map.keys().copied().collect()
|
||||
}
|
||||
|
||||
fn insert(
|
||||
func_type: ExportedFunction,
|
||||
f: impl Fn(MockCtx, &MockExecutable) -> ExecResult + 'static,
|
||||
@@ -1563,7 +1661,13 @@ mod tests {
|
||||
loader.counter += 1;
|
||||
loader.map.insert(
|
||||
hash,
|
||||
MockExecutable { func: Rc::new(f), func_type, code_hash: hash, refcount: 1 },
|
||||
MockExecutable {
|
||||
func: Rc::new(f),
|
||||
func_type,
|
||||
code_hash: hash,
|
||||
code_info: CodeInfo::<Test>::new(ALICE),
|
||||
refcount: 1,
|
||||
},
|
||||
);
|
||||
hash
|
||||
})
|
||||
@@ -1633,6 +1737,10 @@ mod tests {
|
||||
&self.code_hash
|
||||
}
|
||||
|
||||
fn code_info(&self) -> &CodeInfo<Test> {
|
||||
&self.code_info
|
||||
}
|
||||
|
||||
fn code_len(&self) -> u32 {
|
||||
0
|
||||
}
|
||||
@@ -1954,29 +2062,33 @@ mod tests {
|
||||
});
|
||||
|
||||
// This one tests passing the input data into a contract via instantiate.
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let mut gas_meter = GasMeter::<Test>::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();
|
||||
ExtBuilder::default()
|
||||
.with_code_hashes(MockLoader::code_hashes())
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let mut gas_meter = GasMeter::<Test>::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(_));
|
||||
});
|
||||
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]
|
||||
@@ -2399,43 +2511,53 @@ mod tests {
|
||||
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: vec![80, 65, 83, 83] })
|
||||
});
|
||||
|
||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let mut gas_meter = GasMeter::<Test>::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 = <Test as Config>::Schedule::get();
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let mut gas_meter = GasMeter::<Test>::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::<Test>::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::<Test>::load_code_hash(&instantiated_contract_address).unwrap(),
|
||||
dummy_ch
|
||||
);
|
||||
assert_eq!(
|
||||
&events(),
|
||||
&[Event::Instantiated {
|
||||
deployer: ALICE,
|
||||
contract: instantiated_contract_address
|
||||
}]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2444,36 +2566,45 @@ mod tests {
|
||||
Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![70, 65, 73, 76] })
|
||||
});
|
||||
|
||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let mut gas_meter = GasMeter::<Test>::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 = <Test as Config>::Schedule::get();
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let mut gas_meter = GasMeter::<Test>::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::<Test>::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::<Test>::load_code_hash(&instantiated_contract_address).is_none()
|
||||
);
|
||||
assert!(events().is_empty());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2501,51 +2632,58 @@ mod tests {
|
||||
}
|
||||
});
|
||||
|
||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let min_balance = <Test as Config>::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::<Test>::new(GAS_LIMIT),
|
||||
&mut storage_meter,
|
||||
&schedule,
|
||||
ExtBuilder::default()
|
||||
.with_code_hashes(MockLoader::code_hashes())
|
||||
.existential_deposit(15)
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let min_balance = <Test as Config>::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::<Test>::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::<Test>::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::<Test>::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]
|
||||
@@ -2573,37 +2711,41 @@ mod tests {
|
||||
}
|
||||
});
|
||||
|
||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
||||
let schedule = <Test as Config>::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 = <Test as Config>::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::<Test>::new(GAS_LIMIT),
|
||||
&mut storage_meter,
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Enforced,
|
||||
),
|
||||
Ok(_)
|
||||
);
|
||||
assert_matches!(
|
||||
MockStack::run_call(
|
||||
contract_origin,
|
||||
BOB,
|
||||
&mut GasMeter::<Test>::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]
|
||||
@@ -2613,32 +2755,37 @@ mod tests {
|
||||
exec_success()
|
||||
});
|
||||
|
||||
ExtBuilder::default().existential_deposit(15).build().execute_with(|| {
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::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 = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::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::<Test>::TerminatedInConstructor.into())
|
||||
);
|
||||
assert_eq!(
|
||||
MockStack::run_instantiate(
|
||||
ALICE,
|
||||
executable,
|
||||
&mut gas_meter,
|
||||
&mut storage_meter,
|
||||
&schedule,
|
||||
100,
|
||||
vec![],
|
||||
&[],
|
||||
None,
|
||||
),
|
||||
Err(Error::<Test>::TerminatedInConstructor.into())
|
||||
);
|
||||
|
||||
assert_eq!(&events(), &[]);
|
||||
});
|
||||
assert_eq!(&events(), &[]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2714,29 +2861,32 @@ mod tests {
|
||||
});
|
||||
|
||||
// This one tests passing the input data into a contract via instantiate.
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let mut gas_meter = GasMeter::<Test>::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();
|
||||
ExtBuilder::default()
|
||||
.with_code_hashes(MockLoader::code_hashes())
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let mut gas_meter = GasMeter::<Test>::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(_));
|
||||
});
|
||||
let result = MockStack::run_instantiate(
|
||||
ALICE,
|
||||
executable,
|
||||
&mut gas_meter,
|
||||
&mut storage_meter,
|
||||
&schedule,
|
||||
min_balance,
|
||||
vec![],
|
||||
&[],
|
||||
None,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -3138,75 +3288,79 @@ mod tests {
|
||||
exec_success()
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let mut gas_meter = GasMeter::<Test>::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 = <Test as Config>::Schedule::get();
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let mut gas_meter = GasMeter::<Test>::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!(<Nonce<Test>>::get(), 0);
|
||||
MockStack::run_instantiate(
|
||||
ALICE,
|
||||
fail_executable,
|
||||
&mut gas_meter,
|
||||
&mut storage_meter,
|
||||
&schedule,
|
||||
min_balance * 100,
|
||||
vec![],
|
||||
&[],
|
||||
None,
|
||||
)
|
||||
.ok();
|
||||
assert_eq!(<Nonce<Test>>::get(), 0);
|
||||
|
||||
assert_ok!(MockStack::run_instantiate(
|
||||
ALICE,
|
||||
success_executable,
|
||||
&mut gas_meter,
|
||||
&mut storage_meter,
|
||||
&schedule,
|
||||
min_balance * 100,
|
||||
vec![],
|
||||
&[],
|
||||
None,
|
||||
));
|
||||
assert_eq!(<Nonce<Test>>::get(), 1);
|
||||
assert_ok!(MockStack::run_instantiate(
|
||||
ALICE,
|
||||
success_executable,
|
||||
&mut gas_meter,
|
||||
&mut storage_meter,
|
||||
&schedule,
|
||||
min_balance * 100,
|
||||
vec![],
|
||||
&[],
|
||||
None,
|
||||
));
|
||||
assert_eq!(<Nonce<Test>>::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!(<Nonce<Test>>::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!(<Nonce<Test>>::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!(<Nonce<Test>>::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!(<Nonce<Test>>::get(), 4);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -3676,26 +3830,30 @@ mod tests {
|
||||
exec_success()
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let min_balance = <Test as Config>::Currency::minimum_balance();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::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 = <Test as Config>::Currency::minimum_balance();
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
let mut gas_meter = GasMeter::<Test>::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
|
||||
|
||||
Reference in New Issue
Block a user