mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 14:37:57 +00:00
contracts: Don't rely on reserved balances keeping an account alive (#13369)
* Move storage deposits to their own account * Take ed for contract's account from origin * Apply suggestions from code review Co-authored-by: Cyrill Leutwiler <bigcyrill@hotmail.com> Co-authored-by: Sasha Gryaznov <hi@agryaznov.com> * Update stale docs * Use 16 bytes prefix for address derivation * Update frame/contracts/src/address.rs Co-authored-by: Cyrill Leutwiler <bigcyrill@hotmail.com> * Fix merge * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * Update frame/contracts/primitives/src/lib.rs Co-authored-by: Sasha Gryaznov <hi@agryaznov.com> --------- Co-authored-by: Cyrill Leutwiler <bigcyrill@hotmail.com> Co-authored-by: Sasha Gryaznov <hi@agryaznov.com> Co-authored-by: command-bot <>
This commit is contained in:
committed by
GitHub
parent
292e5ee4e7
commit
330484bb19
@@ -32,7 +32,6 @@ use self::{
|
||||
use crate::{
|
||||
exec::{AccountIdOf, FixSizedKey, VarSizedKey},
|
||||
schedule::{API_BENCHMARK_BATCH_SIZE, INSTR_BENCHMARK_BATCH_SIZE},
|
||||
storage::Storage,
|
||||
wasm::CallFlags,
|
||||
Pallet as Contracts, *,
|
||||
};
|
||||
@@ -133,14 +132,8 @@ where
|
||||
fn store(&self, items: &Vec<(FixSizedKey, Vec<u8>)>) -> Result<(), &'static str> {
|
||||
let info = self.info()?;
|
||||
for item in items {
|
||||
Storage::<T>::write(
|
||||
&info.trie_id,
|
||||
&item.0 as &FixSizedKey,
|
||||
Some(item.1.clone()),
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.map_err(|_| "Failed to write storage to restoration dest")?;
|
||||
info.write(&item.0 as &FixSizedKey, Some(item.1.clone()), None, false)
|
||||
.map_err(|_| "Failed to write storage to restoration dest")?;
|
||||
}
|
||||
<ContractInfoOf<T>>::insert(&self.account_id, info);
|
||||
Ok(())
|
||||
@@ -207,7 +200,7 @@ benchmarks! {
|
||||
// The base weight consumed on processing contracts deletion queue.
|
||||
#[pov_mode = Measured]
|
||||
on_process_deletion_queue_batch {}: {
|
||||
Storage::<T>::process_deletion_queue_batch(Weight::MAX)
|
||||
ContractInfo::<T>::process_deletion_queue_batch(Weight::MAX)
|
||||
}
|
||||
|
||||
#[skip_meta]
|
||||
@@ -215,9 +208,9 @@ benchmarks! {
|
||||
on_initialize_per_trie_key {
|
||||
let k in 0..1024;
|
||||
let instance = Contract::<T>::with_storage(WasmModule::dummy(), k, T::Schedule::get().limits.payload_len)?;
|
||||
Storage::<T>::queue_trie_for_deletion(&instance.info()?)?;
|
||||
instance.info()?.queue_trie_for_deletion()?;
|
||||
}: {
|
||||
Storage::<T>::process_deletion_queue_batch(Weight::MAX)
|
||||
ContractInfo::<T>::process_deletion_queue_batch(Weight::MAX)
|
||||
}
|
||||
|
||||
#[pov_mode = Measured]
|
||||
@@ -225,11 +218,11 @@ benchmarks! {
|
||||
let q in 0..1024.min(T::DeletionQueueDepth::get());
|
||||
for i in 0 .. q {
|
||||
let instance = Contract::<T>::with_index(i, WasmModule::dummy(), vec![])?;
|
||||
Storage::<T>::queue_trie_for_deletion(&instance.info()?)?;
|
||||
instance.info()?.queue_trie_for_deletion()?;
|
||||
ContractInfoOf::<T>::remove(instance.account_id);
|
||||
}
|
||||
}: {
|
||||
Storage::<T>::process_deletion_queue_batch(Weight::MAX)
|
||||
ContractInfo::<T>::process_deletion_queue_batch(Weight::MAX)
|
||||
}
|
||||
|
||||
// This benchmarks the additional weight that is charged when a contract is executed the
|
||||
@@ -293,18 +286,16 @@ benchmarks! {
|
||||
let addr = Contracts::<T>::contract_address(&caller, &hash, &input, &salt);
|
||||
}: _(origin, value, Weight::MAX, None, code, input, salt)
|
||||
verify {
|
||||
// the contract itself does not trigger any reserves
|
||||
let deposit = T::Currency::reserved_balance(&addr);
|
||||
let deposit_account = Contract::<T>::address_info(&addr)?.deposit_account().clone();
|
||||
let deposit = T::Currency::free_balance(&deposit_account);
|
||||
// uploading the code reserves some balance in the callers account
|
||||
let code_deposit = T::Currency::reserved_balance(&caller);
|
||||
assert_eq!(
|
||||
T::Currency::free_balance(&caller),
|
||||
caller_funding::<T>() - value - deposit - code_deposit,
|
||||
caller_funding::<T>() - value - deposit - code_deposit - Pallet::<T>::min_balance(),
|
||||
);
|
||||
// contract has the full value
|
||||
assert_eq!(T::Currency::free_balance(&addr), value);
|
||||
// instantiate should leave a contract
|
||||
Contract::<T>::address_info(&addr)?;
|
||||
assert_eq!(T::Currency::free_balance(&addr), value + Pallet::<T>::min_balance());
|
||||
}
|
||||
|
||||
// Instantiate uses a dummy contract constructor to measure the overhead of the instantiate.
|
||||
@@ -325,14 +316,15 @@ benchmarks! {
|
||||
Contracts::<T>::store_code_raw(code, caller.clone())?;
|
||||
}: _(origin, value, Weight::MAX, None, hash, input, salt)
|
||||
verify {
|
||||
// the contract itself does not trigger any reserves
|
||||
let deposit = T::Currency::reserved_balance(&addr);
|
||||
let deposit_account = Contract::<T>::address_info(&addr)?.deposit_account().clone();
|
||||
let deposit = T::Currency::free_balance(&deposit_account);
|
||||
// value was removed from the caller
|
||||
assert_eq!(T::Currency::free_balance(&caller), caller_funding::<T>() - value - deposit);
|
||||
assert_eq!(
|
||||
T::Currency::free_balance(&caller),
|
||||
caller_funding::<T>() - value - deposit - Pallet::<T>::min_balance(),
|
||||
);
|
||||
// contract has the full value
|
||||
assert_eq!(T::Currency::free_balance(&addr), value);
|
||||
// instantiate should leave a contract
|
||||
Contract::<T>::address_info(&addr)?;
|
||||
assert_eq!(T::Currency::free_balance(&addr), value + Pallet::<T>::min_balance());
|
||||
}
|
||||
|
||||
// We just call a dummy contract to measure the overhead of the call extrinsic.
|
||||
@@ -348,18 +340,19 @@ benchmarks! {
|
||||
let instance = Contract::<T>::with_caller(
|
||||
whitelisted_caller(), WasmModule::dummy(), vec![],
|
||||
)?;
|
||||
let deposit_account = instance.info()?.deposit_account().clone();
|
||||
let value = Pallet::<T>::min_balance();
|
||||
let origin = RawOrigin::Signed(instance.caller.clone());
|
||||
let callee = instance.addr.clone();
|
||||
let before = T::Currency::free_balance(&instance.account_id);
|
||||
let before_deposit = T::Currency::free_balance(&deposit_account);
|
||||
}: _(origin, callee, value, Weight::MAX, None, data)
|
||||
verify {
|
||||
// the contract itself does not trigger any reserves
|
||||
let deposit = T::Currency::reserved_balance(&instance.account_id);
|
||||
let deposit = T::Currency::free_balance(&deposit_account);
|
||||
// value and value transfered via call should be removed from the caller
|
||||
assert_eq!(
|
||||
T::Currency::free_balance(&instance.caller),
|
||||
caller_funding::<T>() - instance.value - value - deposit,
|
||||
caller_funding::<T>() - instance.value - value - deposit - Pallet::<T>::min_balance(),
|
||||
);
|
||||
// contract should have received the value
|
||||
assert_eq!(T::Currency::free_balance(&instance.account_id), before + value);
|
||||
@@ -798,14 +791,16 @@ benchmarks! {
|
||||
});
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let origin = RawOrigin::Signed(instance.caller.clone());
|
||||
let deposit_account = instance.info()?.deposit_account().clone();
|
||||
assert_eq!(T::Currency::total_balance(&beneficiary), 0u32.into());
|
||||
assert_eq!(T::Currency::free_balance(&instance.account_id), Pallet::<T>::min_balance());
|
||||
assert_ne!(T::Currency::reserved_balance(&instance.account_id), 0u32.into());
|
||||
assert_eq!(T::Currency::free_balance(&instance.account_id), Pallet::<T>::min_balance() * 2u32.into());
|
||||
assert_ne!(T::Currency::free_balance(&deposit_account), 0u32.into());
|
||||
}: call(origin, instance.addr.clone(), 0u32.into(), Weight::MAX, None, vec![])
|
||||
verify {
|
||||
if r > 0 {
|
||||
assert_eq!(T::Currency::total_balance(&instance.account_id), 0u32.into());
|
||||
assert_eq!(T::Currency::total_balance(&beneficiary), Pallet::<T>::min_balance());
|
||||
assert_eq!(T::Currency::total_balance(&deposit_account), 0u32.into());
|
||||
assert_eq!(T::Currency::total_balance(&beneficiary), Pallet::<T>::min_balance() * 2u32.into());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1039,8 +1034,7 @@ benchmarks! {
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let info = instance.info()?;
|
||||
for key in keys {
|
||||
Storage::<T>::write(
|
||||
&info.trie_id,
|
||||
info.write(
|
||||
&VarSizedKey::<T>::try_from(key).map_err(|e| "Key has wrong length")?,
|
||||
Some(vec![]),
|
||||
None,
|
||||
@@ -1088,8 +1082,7 @@ benchmarks! {
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let info = instance.info()?;
|
||||
for key in keys {
|
||||
Storage::<T>::write(
|
||||
&info.trie_id,
|
||||
info.write(
|
||||
&VarSizedKey::<T>::try_from(key).map_err(|e| "Key has wrong length")?,
|
||||
Some(vec![]),
|
||||
None,
|
||||
@@ -1137,8 +1130,7 @@ benchmarks! {
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let info = instance.info()?;
|
||||
for key in keys {
|
||||
Storage::<T>::write(
|
||||
&info.trie_id,
|
||||
info.write(
|
||||
&VarSizedKey::<T>::try_from(key).map_err(|e| "Key has wrong length")?,
|
||||
Some(vec![42u8; (n * 2048) as usize]), // value_len increments by 2kb up to max payload_len
|
||||
None,
|
||||
@@ -1188,8 +1180,7 @@ benchmarks! {
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let info = instance.info()?;
|
||||
for key in keys {
|
||||
Storage::<T>::write(
|
||||
&info.trie_id,
|
||||
info.write(
|
||||
&VarSizedKey::<T>::try_from(key).map_err(|e| "Key has wrong length")?,
|
||||
Some(vec![]),
|
||||
None,
|
||||
@@ -1236,8 +1227,7 @@ benchmarks! {
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let info = instance.info()?;
|
||||
for key in keys {
|
||||
Storage::<T>::write(
|
||||
&info.trie_id,
|
||||
info.write(
|
||||
&VarSizedKey::<T>::try_from(key).map_err(|e| "Key has wrong length")?,
|
||||
Some(vec![42u8; (n * 2048) as usize]), // value_len increments by 2kb up to max payload_len
|
||||
None,
|
||||
@@ -1291,8 +1281,7 @@ benchmarks! {
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let info = instance.info()?;
|
||||
for key in keys {
|
||||
Storage::<T>::write(
|
||||
&info.trie_id,
|
||||
info.write(
|
||||
&VarSizedKey::<T>::try_from(key).map_err(|e| "Key has wrong length")?,
|
||||
Some(vec![]),
|
||||
None,
|
||||
@@ -1346,8 +1335,7 @@ benchmarks! {
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let info = instance.info()?;
|
||||
for key in keys {
|
||||
Storage::<T>::write(
|
||||
&info.trie_id,
|
||||
info.write(
|
||||
&VarSizedKey::<T>::try_from(key).map_err(|e| "Key has wrong length")?,
|
||||
Some(vec![42u8; (n * 2048) as usize]), // value_len increments by 2kb up to max payload_len
|
||||
None,
|
||||
@@ -1396,8 +1384,7 @@ benchmarks! {
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let info = instance.info()?;
|
||||
for key in keys {
|
||||
Storage::<T>::write(
|
||||
&info.trie_id,
|
||||
info.write(
|
||||
&VarSizedKey::<T>::try_from(key).map_err(|e| "Key has wrong length")?,
|
||||
Some(vec![]),
|
||||
None,
|
||||
@@ -1444,8 +1431,7 @@ benchmarks! {
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let info = instance.info()?;
|
||||
for key in keys {
|
||||
Storage::<T>::write(
|
||||
&info.trie_id,
|
||||
info.write(
|
||||
&VarSizedKey::<T>::try_from(key).map_err(|e| "Key has wrong length")?,
|
||||
Some(vec![42u8; (n * 2048) as usize]), // value_len increments by 2kb up to max payload_len
|
||||
None,
|
||||
@@ -1499,8 +1485,7 @@ benchmarks! {
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let info = instance.info()?;
|
||||
for key in keys {
|
||||
Storage::<T>::write(
|
||||
&info.trie_id,
|
||||
info.write(
|
||||
&VarSizedKey::<T>::try_from(key).map_err(|e| "Key has wrong length")?,
|
||||
Some(vec![]),
|
||||
None,
|
||||
@@ -1554,8 +1539,7 @@ benchmarks! {
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let info = instance.info()?;
|
||||
for key in keys {
|
||||
Storage::<T>::write(
|
||||
&info.trie_id,
|
||||
info.write(
|
||||
&VarSizedKey::<T>::try_from(key).map_err(|e| "Key has wrong length")?,
|
||||
Some(vec![42u8; (n * 2048) as usize]), // value_len increments by 2kb up to max payload_len
|
||||
None,
|
||||
@@ -1884,7 +1868,7 @@ benchmarks! {
|
||||
.. Default::default()
|
||||
});
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
instance.set_balance(value * (r * API_BENCHMARK_BATCH_SIZE + 1).into());
|
||||
instance.set_balance((value + Pallet::<T>::min_balance()) * (r * API_BENCHMARK_BATCH_SIZE + 1).into());
|
||||
let origin = RawOrigin::Signed(instance.caller.clone());
|
||||
let callee = instance.addr.clone();
|
||||
let addresses = hashes
|
||||
@@ -1997,7 +1981,7 @@ benchmarks! {
|
||||
.. Default::default()
|
||||
});
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
instance.set_balance(value * (API_BENCHMARK_BATCH_SIZE + 1).into());
|
||||
instance.set_balance((value + Pallet::<T>::min_balance()) * (API_BENCHMARK_BATCH_SIZE + 1).into());
|
||||
let origin = RawOrigin::Signed(instance.caller.clone());
|
||||
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
|
||||
|
||||
@@ -3113,8 +3097,8 @@ benchmarks! {
|
||||
{
|
||||
let weight_limit = T::DeletionWeightLimit::get();
|
||||
let max_queue_depth = T::DeletionQueueDepth::get() as usize;
|
||||
let empty_queue_throughput = Storage::<T>::deletion_budget(0, weight_limit);
|
||||
let full_queue_throughput = Storage::<T>::deletion_budget(max_queue_depth, weight_limit);
|
||||
let empty_queue_throughput = ContractInfo::<T>::deletion_budget(0, weight_limit);
|
||||
let full_queue_throughput = ContractInfo::<T>::deletion_budget(max_queue_depth, weight_limit);
|
||||
println!("{:#?}", Schedule::<T>::default());
|
||||
println!("###############################################");
|
||||
println!("Lazy deletion weight per key: {}", empty_queue_throughput.0);
|
||||
|
||||
Reference in New Issue
Block a user