contracts: Use proof_size from benchmarks (#13268)

* Avoid reading contract code when it is supplied in the extrinsic

* Remove custom proof size injection from schedule

* Set benchmarks pov_mode to Measure

* Reduce overestimation of code size on re-instrument

* ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts

* Do not override proof size from benchmark

* Do not charge proof size for basic block

* Incrase gas limit for tests

* Fix deletion queue to also use `proof_size`

* Fix tests

* Update frame/contracts/src/schedule.rs

Co-authored-by: Cyrill Leutwiler <bigcyrill@hotmail.com>

* Fix wrong schedule macro invocations

* Remove stale docs

* ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts

* Handle zero components

* ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts

* Fix instruction weight

---------

Co-authored-by: command-bot <>
Co-authored-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
This commit is contained in:
Alexander Theißen
2023-02-15 22:56:50 +01:00
committed by GitHub
parent 3c0d8fe149
commit 1c04ab0f6f
8 changed files with 2173 additions and 2021 deletions
@@ -205,13 +205,13 @@ benchmarks! {
}
// The base weight consumed on processing contracts deletion queue.
#[pov_mode = Ignored]
#[pov_mode = Measured]
on_process_deletion_queue_batch {}: {
Storage::<T>::process_deletion_queue_batch(Weight::MAX)
}
#[skip_meta]
#[pov_mode = Ignored]
#[pov_mode = Measured]
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)?;
@@ -220,7 +220,7 @@ benchmarks! {
Storage::<T>::process_deletion_queue_batch(Weight::MAX)
}
#[pov_mode = Ignored]
#[pov_mode = Measured]
on_initialize_per_queue_item {
let q in 0..1024.min(T::DeletionQueueDepth::get());
for i in 0 .. q {
@@ -235,7 +235,7 @@ benchmarks! {
// This benchmarks the additional weight that is charged when a contract is executed the
// first time after a new schedule was deployed: For every new schedule a contract needs
// to re-run the instrumentation once.
#[pov_mode = Ignored]
#[pov_mode = Measured]
reinstrument {
let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get());
let WasmModule { code, hash, .. } = WasmModule::<T>::sized(c, Location::Call);
@@ -252,7 +252,7 @@ benchmarks! {
// is responsible. This is achieved by generating all code to the `deploy` function
// which is in the wasm module but not executed on `call`.
// The results are supposed to be used as `call_with_code_kb(c) - call_with_code_kb(0)`.
#[pov_mode = Ignored]
#[pov_mode = Measured]
call_with_code_per_byte {
let c in 0 .. T::MaxCodeLen::get();
let instance = Contract::<T>::with_caller(
@@ -278,7 +278,7 @@ benchmarks! {
//
// We cannot let `c` grow to the maximum code size because the code is not allowed
// to be larger than the maximum size **after instrumentation**.
#[pov_mode = Ignored]
#[pov_mode = Measured]
instantiate_with_code {
let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get());
let i in 0 .. code::max_pages::<T>() * 64 * 1024;
@@ -310,7 +310,7 @@ benchmarks! {
// Instantiate uses a dummy contract constructor to measure the overhead of the instantiate.
// `i`: Size of the input in kilobytes.
// `s`: Size of the salt in kilobytes.
#[pov_mode = Ignored]
#[pov_mode = Measured]
instantiate {
let i in 0 .. code::max_pages::<T>() * 64 * 1024;
let s in 0 .. code::max_pages::<T>() * 64 * 1024;
@@ -342,7 +342,7 @@ benchmarks! {
// part of `seal_input`. The costs for invoking a contract of a specific size are not part
// of this benchmark because we cannot know the size of the contract when issuing a call
// transaction. See `invoke_per_code_kb` for this.
#[pov_mode = Ignored]
#[pov_mode = Measured]
call {
let data = vec![42u8; 1024];
let instance = Contract::<T>::with_caller(
@@ -375,7 +375,7 @@ benchmarks! {
//
// We cannot let `c` grow to the maximum code size because the code is not allowed
// to be larger than the maximum size **after instrumentation**.
#[pov_mode = Ignored]
#[pov_mode = Measured]
upload_code {
let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get());
let caller = whitelisted_caller();
@@ -392,7 +392,7 @@ benchmarks! {
// Removing code does not depend on the size of the contract because all the information
// needed to verify the removal claim (refcount, owner) is stored in a separate storage
// item (`OwnerInfoOf`).
#[pov_mode = Ignored]
#[pov_mode = Measured]
remove_code {
let caller = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, caller_funding::<T>());
@@ -409,7 +409,7 @@ benchmarks! {
assert!(<Contract<T>>::code_removed(&hash));
}
#[pov_mode = Ignored]
#[pov_mode = Measured]
set_code {
let instance = <Contract<T>>::with_caller(
whitelisted_caller(), WasmModule::dummy(), vec![],
@@ -424,7 +424,7 @@ benchmarks! {
assert_eq!(instance.info()?.code_hash, hash);
}
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_caller {
let r in 0 .. API_BENCHMARK_BATCHES;
let instance = Contract::<T>::new(WasmModule::getter(
@@ -433,7 +433,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_is_contract {
let r in 0 .. API_BENCHMARK_BATCHES;
let accounts = (0 .. r * API_BENCHMARK_BATCH_SIZE)
@@ -471,7 +471,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_code_hash {
let r in 0 .. API_BENCHMARK_BATCHES;
let accounts = (0 .. r * API_BENCHMARK_BATCH_SIZE)
@@ -517,7 +517,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_own_code_hash {
let r in 0 .. API_BENCHMARK_BATCHES;
let instance = Contract::<T>::new(WasmModule::getter(
@@ -526,7 +526,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_caller_is_origin {
let r in 0 .. API_BENCHMARK_BATCHES;
let code = WasmModule::<T>::from(ModuleDefinition {
@@ -547,7 +547,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_address {
let r in 0 .. API_BENCHMARK_BATCHES;
let instance = Contract::<T>::new(WasmModule::getter(
@@ -556,7 +556,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_gas_left {
let r in 0 .. API_BENCHMARK_BATCHES;
let instance = Contract::<T>::new(WasmModule::getter(
@@ -565,7 +565,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_balance {
let r in 0 .. API_BENCHMARK_BATCHES;
let instance = Contract::<T>::new(WasmModule::getter(
@@ -574,7 +574,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_value_transferred {
let r in 0 .. API_BENCHMARK_BATCHES;
let instance = Contract::<T>::new(WasmModule::getter(
@@ -583,7 +583,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_minimum_balance {
let r in 0 .. API_BENCHMARK_BATCHES;
let instance = Contract::<T>::new(WasmModule::getter(
@@ -592,7 +592,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_block_number {
let r in 0 .. API_BENCHMARK_BATCHES;
let instance = Contract::<T>::new(WasmModule::getter(
@@ -601,7 +601,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_now {
let r in 0 .. API_BENCHMARK_BATCHES;
let instance = Contract::<T>::new(WasmModule::getter(
@@ -610,7 +610,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_weight_to_fee {
let r in 0 .. API_BENCHMARK_BATCHES;
let pages = code::max_pages::<T>();
@@ -638,7 +638,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_gas {
let r in 0 .. API_BENCHMARK_BATCHES;
let code = WasmModule::<T>::from(ModuleDefinition {
@@ -659,7 +659,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_input {
let r in 0 .. API_BENCHMARK_BATCHES;
let code = WasmModule::<T>::from(ModuleDefinition {
@@ -687,7 +687,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_input_per_kb {
let n in 0 .. code::max_pages::<T>() * 64;
let pages = code::max_pages::<T>();
@@ -721,7 +721,7 @@ benchmarks! {
// We cannot call `seal_return` multiple times. Therefore our weight determination is not
// as precise as with other APIs. Because this function can only be called once per
// contract it cannot be used as an attack vector.
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_return {
let r in 0 .. 1;
let code = WasmModule::<T>::from(ModuleDefinition {
@@ -744,7 +744,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_return_per_kb {
let n in 0 .. code::max_pages::<T>() * 64;
let code = WasmModule::<T>::from(ModuleDefinition {
@@ -769,7 +769,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
// The same argument as for `seal_return` is true here.
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_terminate {
let r in 0 .. 1;
let beneficiary = account::<T::AccountId>("beneficiary", 0, 0);
@@ -812,7 +812,7 @@ benchmarks! {
// We benchmark only for the maximum subject length. We assume that this is some lowish
// number (< 1 KB). Therefore we are not overcharging too much in case a smaller subject is
// used.
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_random {
let r in 0 .. API_BENCHMARK_BATCHES;
let pages = code::max_pages::<T>();
@@ -847,7 +847,7 @@ benchmarks! {
// Overhead of calling the function without any topic.
// We benchmark for the worst case (largest event).
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_deposit_event {
let r in 0 .. API_BENCHMARK_BATCHES;
let code = WasmModule::<T>::from(ModuleDefinition {
@@ -874,7 +874,7 @@ benchmarks! {
// Benchmark the overhead that topics generate.
// `t`: Number of topics
// `n`: Size of event payload in kb
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_deposit_event_per_topic_and_kb {
let t in 0 .. T::Schedule::get().limits.event_topics;
let n in 0 .. T::Schedule::get().limits.payload_len / 1024;
@@ -913,7 +913,7 @@ benchmarks! {
// Benchmark debug_message call with zero input data.
// Whereas this function is used in RPC mode only, it still should be secured
// against an excessive use.
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_debug_message {
let r in 0 .. API_BENCHMARK_BATCHES;
let code = WasmModule::<T>::from(ModuleDefinition {
@@ -1003,7 +1003,7 @@ benchmarks! {
// because re-writing at an existing key is always more expensive than writing
// it at a virgin key.
#[skip_meta]
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_set_storage {
let r in 0 .. API_BENCHMARK_BATCHES/2;
let max_key_len = T::MaxStorageKeyLen::get();
@@ -1052,7 +1052,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[skip_meta]
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_set_storage_per_new_kb {
let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb
let max_key_len = T::MaxStorageKeyLen::get();
@@ -1101,7 +1101,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[skip_meta]
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_set_storage_per_old_kb {
let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb
let max_key_len = T::MaxStorageKeyLen::get();
@@ -1154,7 +1154,7 @@ benchmarks! {
// deleting a non existing key. We generate keys of a maximum length, and have to
// reduce batch size in order to make resulting contract code size less than MaxCodeLen.
#[skip_meta]
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_clear_storage {
let r in 0 .. API_BENCHMARK_BATCHES/2;
let max_key_len = T::MaxStorageKeyLen::get();
@@ -1202,7 +1202,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[skip_meta]
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_clear_storage_per_kb {
let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb
let max_key_len = T::MaxStorageKeyLen::get();
@@ -1250,7 +1250,7 @@ benchmarks! {
// We make sure that all storage accesses are to unique keys.
#[skip_meta]
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_get_storage {
let r in 0 .. API_BENCHMARK_BATCHES/2;
let max_key_len = T::MaxStorageKeyLen::get();
@@ -1305,7 +1305,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[skip_meta]
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_get_storage_per_kb {
let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb
let max_key_len = T::MaxStorageKeyLen::get();
@@ -1361,7 +1361,7 @@ benchmarks! {
// We make sure that all storage accesses are to unique keys.
#[skip_meta]
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_contains_storage {
let r in 0 .. API_BENCHMARK_BATCHES/2;
let max_key_len = T::MaxStorageKeyLen::get();
@@ -1410,7 +1410,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[skip_meta]
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_contains_storage_per_kb {
let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb
let max_key_len = T::MaxStorageKeyLen::get();
@@ -1458,7 +1458,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[skip_meta]
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_take_storage {
let r in 0 .. API_BENCHMARK_BATCHES/2;
let max_key_len = T::MaxStorageKeyLen::get();
@@ -1513,7 +1513,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[skip_meta]
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_take_storage_per_kb {
let n in 0 .. T::Schedule::get().limits.payload_len / 2048; // half of the max payload_len in kb
let max_key_len = T::MaxStorageKeyLen::get();
@@ -1568,7 +1568,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
// We transfer to unique accounts.
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_transfer {
let r in 0 .. API_BENCHMARK_BATCHES;
let accounts = (0..r * API_BENCHMARK_BATCH_SIZE)
@@ -1622,7 +1622,7 @@ benchmarks! {
}
// We call unique accounts.
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_call {
let r in 0 .. API_BENCHMARK_BATCHES;
let dummy_code = WasmModule::<T>::dummy_with_bytes(0);
@@ -1681,7 +1681,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_delegate_call {
let r in 0 .. API_BENCHMARK_BATCHES;
let hashes = (0..r * API_BENCHMARK_BATCH_SIZE)
@@ -1734,7 +1734,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller);
}: call(origin, callee, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_call_per_transfer_clone_kb {
let t in 0 .. 1;
let c in 0 .. code::max_pages::<T>() * 64;
@@ -1793,7 +1793,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, bytes)
// We assume that every instantiate sends at least the minimum balance.
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_instantiate {
let r in 0 .. API_BENCHMARK_BATCHES;
let hashes = (0..r * API_BENCHMARK_BATCH_SIZE)
@@ -1907,7 +1907,7 @@ benchmarks! {
}
}
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_instantiate_per_transfer_input_salt_kb {
let t in 0 .. 1;
let i in 0 .. (code::max_pages::<T>() - 1) * 64;
@@ -2002,7 +2002,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
// Only the overhead of calling the function itself with minimal arguments.
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_hash_sha2_256 {
let r in 0 .. 1;
let instance = Contract::<T>::new(WasmModule::hasher(
@@ -2012,7 +2012,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
// `n`: Input to hash in kilobytes
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_hash_sha2_256_per_kb {
let n in 0 .. code::max_pages::<T>() * 64;
let instance = Contract::<T>::new(WasmModule::hasher(
@@ -2022,7 +2022,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
// Only the overhead of calling the function itself with minimal arguments.
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_hash_keccak_256 {
let r in 0 .. 1;
let instance = Contract::<T>::new(WasmModule::hasher(
@@ -2032,7 +2032,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
// `n`: Input to hash in kilobytes
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_hash_keccak_256_per_kb {
let n in 0 .. code::max_pages::<T>() * 64;
let instance = Contract::<T>::new(WasmModule::hasher(
@@ -2042,7 +2042,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
// Only the overhead of calling the function itself with minimal arguments.
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_hash_blake2_256 {
let r in 0 .. 1;
let instance = Contract::<T>::new(WasmModule::hasher(
@@ -2052,7 +2052,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
// `n`: Input to hash in kilobytes
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_hash_blake2_256_per_kb {
let n in 0 .. code::max_pages::<T>() * 64;
let instance = Contract::<T>::new(WasmModule::hasher(
@@ -2062,7 +2062,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
// Only the overhead of calling the function itself with minimal arguments.
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_hash_blake2_128 {
let r in 0 .. 1;
let instance = Contract::<T>::new(WasmModule::hasher(
@@ -2072,7 +2072,7 @@ benchmarks! {
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
// `n`: Input to hash in kilobytes
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_hash_blake2_128_per_kb {
let n in 0 .. code::max_pages::<T>() * 64;
let instance = Contract::<T>::new(WasmModule::hasher(
@@ -2083,7 +2083,7 @@ benchmarks! {
// Only calling the function itself with valid arguments.
// It generates different private keys and signatures for the message "Hello world".
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_ecdsa_recover {
let r in 0 .. 1;
@@ -2132,7 +2132,7 @@ benchmarks! {
// Only calling the function itself for the list of
// generated different ECDSA keys.
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_ecdsa_to_eth_address {
let r in 0 .. 1;
let key_type = sp_core::crypto::KeyTypeId(*b"code");
@@ -2168,7 +2168,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_set_code_hash {
let r in 0 .. API_BENCHMARK_BATCHES;
let code_hashes = (0..r * API_BENCHMARK_BATCH_SIZE)
@@ -2209,7 +2209,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_reentrance_count {
let r in 0 .. API_BENCHMARK_BATCHES;
let code = WasmModule::<T>::from(ModuleDefinition {
@@ -2230,7 +2230,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_account_reentrance_count {
let r in 0 .. API_BENCHMARK_BATCHES;
let dummy_code = WasmModule::<T>::dummy_with_bytes(0);
@@ -2264,7 +2264,7 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
#[pov_mode = Ignored]
#[pov_mode = Measured]
seal_instantiation_nonce {
let r in 0 .. API_BENCHMARK_BATCHES;
let code = WasmModule::<T>::from(ModuleDefinition {
@@ -3103,7 +3103,7 @@ benchmarks! {
// This is no benchmark. It merely exist to have an easy way to pretty print the curently
// configured `Schedule` during benchmark development.
// It can be outputed using the following command:
// cargo run --manifest-path=bin/node/cli/Cargo.toml --release \
// cargo run --manifest-path=bin/node/cli/Cargo.toml \
// --features runtime-benchmarks -- benchmark pallet --extra --dev --execution=native \
// -p pallet_contracts -e print_schedule --no-median-slopes --no-min-squares
#[extra]
@@ -3111,17 +3111,15 @@ benchmarks! {
print_schedule {
#[cfg(feature = "std")]
{
let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) -
T::WeightInfo::on_initialize_per_trie_key(0);
let weight_per_queue_item = T::WeightInfo::on_initialize_per_queue_item(1) -
T::WeightInfo::on_initialize_per_queue_item(0);
let weight_limit = T::DeletionWeightLimit::get();
let queue_depth: u64 = T::DeletionQueueDepth::get().into();
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);
println!("{:#?}", Schedule::<T>::default());
println!("###############################################");
println!("Lazy deletion weight per key: {}", empty_queue_throughput.0);
println!("Lazy deletion throughput per block (empty queue, full queue): {}, {}",
weight_limit / weight_per_key.ref_time(),
(weight_limit - weight_per_queue_item * queue_depth) / weight_per_key.ref_time(),
empty_queue_throughput.1, full_queue_throughput.1,
);
}
#[cfg(not(feature = "std"))]
@@ -3133,7 +3131,7 @@ benchmarks! {
// `g` is used to enable gas instrumentation to compare the performance impact of
// that instrumentation at runtime.
#[extra]
#[pov_mode = Ignored]
#[pov_mode = Measured]
ink_erc20_transfer {
let g in 0 .. 1;
let gas_metering = g != 0;
@@ -3172,7 +3170,7 @@ benchmarks! {
// `g` is used to enable gas instrumentation to compare the performance impact of
// that instrumentation at runtime.
#[extra]
#[pov_mode = Ignored]
#[pov_mode = Measured]
solang_erc20_transfer {
let g in 0 .. 1;
let gas_metering = g != 0;
+71 -102
View File
@@ -447,7 +447,7 @@ macro_rules! call_zero {
macro_rules! cost_args {
($name:ident, $( $arg: expr ),+) => {
(T::WeightInfo::$name($( $arg ),+).saturating_sub(call_zero!($name, $( $arg ),+))).ref_time()
(T::WeightInfo::$name($( $arg ),+).saturating_sub(call_zero!($name, $( $arg ),+)))
}
}
@@ -459,7 +459,7 @@ macro_rules! cost_batched_args {
macro_rules! cost_instr_no_params_with_batch_size {
($name:ident, $batch_size:expr) => {
(cost_args!($name, 1) / u64::from($batch_size)) as u32
(cost_args!($name, 1).ref_time() / u64::from($batch_size)) as u32
};
}
@@ -514,12 +514,6 @@ macro_rules! cost_byte_batched {
};
}
macro_rules! to_weight {
($ref_time:expr $(, $proof_size:expr )?) => {
Weight::from_ref_time($ref_time)$(.set_proof_size($proof_size))?
};
}
impl Default for Limits {
fn default() -> Self {
Self {
@@ -554,8 +548,8 @@ impl<T: Config> Default for InstructionWeights<T> {
br_table_per_entry: cost_instr!(instr_br_table_per_entry, 0),
call: cost_instr!(instr_call, 2),
call_indirect: cost_instr!(instr_call_indirect, 3),
call_indirect_per_param: cost_instr!(instr_call_indirect_per_param, 1),
call_per_local: cost_instr!(instr_call_per_local, 1),
call_indirect_per_param: cost_instr!(instr_call_indirect_per_param, 0),
call_per_local: cost_instr!(instr_call_per_local, 0),
local_get: cost_instr!(instr_local_get, 1),
local_set: cost_instr!(instr_local_set, 1),
local_tee: cost_instr!(instr_local_tee, 2),
@@ -601,116 +595,91 @@ impl<T: Config> Default for InstructionWeights<T> {
}
impl<T: Config> Default for HostFnWeights<T> {
/// PoV should contain all trie nodes that are read during state transition (i.e. block
/// production). Hence we need to charge the `proof_size` weight for every host function which
/// reads storage, namely:
/// - get_storage,
/// - take_storage,
/// - contains_storage,
/// - clear_storage,
/// - set_storage.
///
/// The last two functions write to storage, but they also do read storage in order to return
/// the size of the pre-existed value. Till we have PoV benchmarks implemented, we approximate
/// `proof_size` as being equal to the size of storage read.
fn default() -> Self {
Self {
caller: to_weight!(cost_batched!(seal_caller)),
is_contract: to_weight!(cost_batched!(seal_is_contract)),
code_hash: to_weight!(cost_batched!(seal_code_hash)),
own_code_hash: to_weight!(cost_batched!(seal_own_code_hash)),
caller_is_origin: to_weight!(cost_batched!(seal_caller_is_origin)),
address: to_weight!(cost_batched!(seal_address)),
gas_left: to_weight!(cost_batched!(seal_gas_left)),
balance: to_weight!(cost_batched!(seal_balance)),
value_transferred: to_weight!(cost_batched!(seal_value_transferred)),
minimum_balance: to_weight!(cost_batched!(seal_minimum_balance)),
block_number: to_weight!(cost_batched!(seal_block_number)),
now: to_weight!(cost_batched!(seal_now)),
weight_to_fee: to_weight!(cost_batched!(seal_weight_to_fee)),
gas: to_weight!(cost_batched!(seal_gas)),
input: to_weight!(cost_batched!(seal_input)),
input_per_byte: to_weight!(cost_byte_batched!(seal_input_per_kb)),
r#return: to_weight!(cost!(seal_return)),
return_per_byte: to_weight!(cost_byte!(seal_return_per_kb)),
terminate: to_weight!(cost!(seal_terminate)),
random: to_weight!(cost_batched!(seal_random)),
deposit_event: to_weight!(cost_batched!(seal_deposit_event)),
deposit_event_per_topic: to_weight!(cost_batched_args!(
seal_deposit_event_per_topic_and_kb,
1,
0
)),
deposit_event_per_byte: to_weight!(cost_byte_batched_args!(
caller: cost_batched!(seal_caller),
is_contract: cost_batched!(seal_is_contract),
code_hash: cost_batched!(seal_code_hash),
own_code_hash: cost_batched!(seal_own_code_hash),
caller_is_origin: cost_batched!(seal_caller_is_origin),
address: cost_batched!(seal_address),
gas_left: cost_batched!(seal_gas_left),
balance: cost_batched!(seal_balance),
value_transferred: cost_batched!(seal_value_transferred),
minimum_balance: cost_batched!(seal_minimum_balance),
block_number: cost_batched!(seal_block_number),
now: cost_batched!(seal_now),
weight_to_fee: cost_batched!(seal_weight_to_fee),
// Manually remove proof size from basic block cost.
//
// Due to imperfect benchmarking some host functions incur a small
// amount of proof size. Usually this is ok. However, charging a basic block is such
// a frequent operation that this would be a vast overestimation.
gas: cost_batched!(seal_gas).set_proof_size(0),
input: cost_batched!(seal_input),
input_per_byte: cost_byte_batched!(seal_input_per_kb),
r#return: cost!(seal_return),
return_per_byte: cost_byte!(seal_return_per_kb),
terminate: cost!(seal_terminate),
random: cost_batched!(seal_random),
deposit_event: cost_batched!(seal_deposit_event),
deposit_event_per_topic: cost_batched_args!(seal_deposit_event_per_topic_and_kb, 1, 0),
deposit_event_per_byte: cost_byte_batched_args!(
seal_deposit_event_per_topic_and_kb,
0,
1
)),
debug_message: to_weight!(cost_batched!(seal_debug_message)),
debug_message_per_byte: to_weight!(cost_byte!(seal_debug_message_per_kb)),
set_storage: to_weight!(cost_batched!(seal_set_storage), 1024u64),
set_code_hash: to_weight!(cost_batched!(seal_set_code_hash)),
set_storage_per_new_byte: to_weight!(cost_byte_batched!(seal_set_storage_per_new_kb)),
set_storage_per_old_byte: to_weight!(
cost_byte_batched!(seal_set_storage_per_old_kb),
1u64
),
clear_storage: to_weight!(cost_batched!(seal_clear_storage), 1024u64),
clear_storage_per_byte: to_weight!(cost_byte_batched!(seal_clear_storage_per_kb), 1u64),
contains_storage: to_weight!(cost_batched!(seal_contains_storage), 1024u64),
contains_storage_per_byte: to_weight!(
cost_byte_batched!(seal_contains_storage_per_kb),
1u64
),
get_storage: to_weight!(cost_batched!(seal_get_storage), 1024u64),
get_storage_per_byte: to_weight!(cost_byte_batched!(seal_get_storage_per_kb), 1u64),
take_storage: to_weight!(cost_batched!(seal_take_storage), 1024u64),
take_storage_per_byte: to_weight!(cost_byte_batched!(seal_take_storage_per_kb), 1u64),
transfer: to_weight!(cost_batched!(seal_transfer)),
call: to_weight!(cost_batched!(seal_call)),
delegate_call: to_weight!(cost_batched!(seal_delegate_call)),
call_transfer_surcharge: to_weight!(cost_batched_args!(
seal_call_per_transfer_clone_kb,
1,
0
)),
call_per_cloned_byte: to_weight!(cost_batched_args!(
seal_call_per_transfer_clone_kb,
0,
1
)),
instantiate: to_weight!(cost_batched!(seal_instantiate)),
instantiate_transfer_surcharge: to_weight!(cost_byte_batched_args!(
debug_message: cost_batched!(seal_debug_message),
debug_message_per_byte: cost_byte!(seal_debug_message_per_kb),
set_storage: cost_batched!(seal_set_storage),
set_code_hash: cost_batched!(seal_set_code_hash),
set_storage_per_new_byte: cost_byte_batched!(seal_set_storage_per_new_kb),
set_storage_per_old_byte: cost_byte_batched!(seal_set_storage_per_old_kb),
clear_storage: cost_batched!(seal_clear_storage),
clear_storage_per_byte: cost_byte_batched!(seal_clear_storage_per_kb),
contains_storage: cost_batched!(seal_contains_storage),
contains_storage_per_byte: cost_byte_batched!(seal_contains_storage_per_kb),
get_storage: cost_batched!(seal_get_storage),
get_storage_per_byte: cost_byte_batched!(seal_get_storage_per_kb),
take_storage: cost_batched!(seal_take_storage),
take_storage_per_byte: cost_byte_batched!(seal_take_storage_per_kb),
transfer: cost_batched!(seal_transfer),
call: cost_batched!(seal_call),
delegate_call: cost_batched!(seal_delegate_call),
call_transfer_surcharge: cost_batched_args!(seal_call_per_transfer_clone_kb, 1, 0),
call_per_cloned_byte: cost_byte_batched_args!(seal_call_per_transfer_clone_kb, 0, 1),
instantiate: cost_batched!(seal_instantiate),
instantiate_transfer_surcharge: cost_batched_args!(
seal_instantiate_per_transfer_input_salt_kb,
1,
0,
0
)),
instantiate_per_input_byte: to_weight!(cost_byte_batched_args!(
),
instantiate_per_input_byte: cost_byte_batched_args!(
seal_instantiate_per_transfer_input_salt_kb,
0,
1,
0
)),
instantiate_per_salt_byte: to_weight!(cost_byte_batched_args!(
),
instantiate_per_salt_byte: cost_byte_batched_args!(
seal_instantiate_per_transfer_input_salt_kb,
0,
0,
1
)),
hash_sha2_256: to_weight!(cost_batched!(seal_hash_sha2_256)),
hash_sha2_256_per_byte: to_weight!(cost_byte_batched!(seal_hash_sha2_256_per_kb)),
hash_keccak_256: to_weight!(cost_batched!(seal_hash_keccak_256)),
hash_keccak_256_per_byte: to_weight!(cost_byte_batched!(seal_hash_keccak_256_per_kb)),
hash_blake2_256: to_weight!(cost_batched!(seal_hash_blake2_256)),
hash_blake2_256_per_byte: to_weight!(cost_byte_batched!(seal_hash_blake2_256_per_kb)),
hash_blake2_128: to_weight!(cost_batched!(seal_hash_blake2_128)),
hash_blake2_128_per_byte: to_weight!(cost_byte_batched!(seal_hash_blake2_128_per_kb)),
ecdsa_recover: to_weight!(cost_batched!(seal_ecdsa_recover)),
ecdsa_to_eth_address: to_weight!(cost_batched!(seal_ecdsa_to_eth_address)),
reentrance_count: to_weight!(cost_batched!(seal_reentrance_count)),
account_reentrance_count: to_weight!(cost_batched!(seal_account_reentrance_count)),
instantiation_nonce: to_weight!(cost_batched!(seal_instantiation_nonce)),
),
hash_sha2_256: cost_batched!(seal_hash_sha2_256),
hash_sha2_256_per_byte: cost_byte_batched!(seal_hash_sha2_256_per_kb),
hash_keccak_256: cost_batched!(seal_hash_keccak_256),
hash_keccak_256_per_byte: cost_byte_batched!(seal_hash_keccak_256_per_kb),
hash_blake2_256: cost_batched!(seal_hash_blake2_256),
hash_blake2_256_per_byte: cost_byte_batched!(seal_hash_blake2_256_per_kb),
hash_blake2_128: cost_batched!(seal_hash_blake2_128),
hash_blake2_128_per_byte: cost_byte_batched!(seal_hash_blake2_128_per_kb),
ecdsa_recover: cost_batched!(seal_ecdsa_recover),
ecdsa_to_eth_address: cost_batched!(seal_ecdsa_to_eth_address),
reentrance_count: cost_batched!(seal_reentrance_count),
account_reentrance_count: cost_batched!(seal_account_reentrance_count),
instantiation_nonce: cost_batched!(seal_instantiation_nonce),
_phantom: PhantomData,
}
}
+6 -11
View File
@@ -245,13 +245,12 @@ impl<T: Config> Storage<T> {
/// Calculates the weight that is necessary to remove one key from the trie and how many
/// of those keys can be deleted from the deletion queue given the supplied queue length
/// and weight limit.
pub fn deletion_budget(queue_len: usize, weight_limit: Weight) -> (u64, u32) {
pub fn deletion_budget(queue_len: usize, weight_limit: Weight) -> (Weight, u32) {
let base_weight = T::WeightInfo::on_process_deletion_queue_batch();
let weight_per_queue_item = T::WeightInfo::on_initialize_per_queue_item(1) -
T::WeightInfo::on_initialize_per_queue_item(0);
let weight_per_key = (T::WeightInfo::on_initialize_per_trie_key(1) -
T::WeightInfo::on_initialize_per_trie_key(0))
.ref_time();
let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) -
T::WeightInfo::on_initialize_per_trie_key(0);
let decoding_weight = weight_per_queue_item.saturating_mul(queue_len as u64);
// `weight_per_key` being zero makes no sense and would constitute a failure to
@@ -259,9 +258,8 @@ impl<T: Config> Storage<T> {
let key_budget = weight_limit
.saturating_sub(base_weight)
.saturating_sub(decoding_weight)
.checked_div(weight_per_key)
.unwrap_or(Weight::zero())
.ref_time() as u32;
.checked_div_per_component(&weight_per_key)
.unwrap_or(0) as u32;
(weight_per_key, key_budget)
}
@@ -306,10 +304,7 @@ impl<T: Config> Storage<T> {
}
<DeletionQueue<T>>::put(queue);
let ref_time_weight = weight_limit
.ref_time()
.saturating_sub(weight_per_key.saturating_mul(u64::from(remaining_key_budget)));
Weight::from_ref_time(ref_time_weight)
weight_limit.saturating_sub(weight_per_key.saturating_mul(u64::from(remaining_key_budget)))
}
/// Generates a unique trie id by returning `hash(account_id ++ nonce)`.
+4 -4
View File
@@ -383,7 +383,7 @@ impl Contains<RuntimeCall> for TestFilter {
}
parameter_types! {
pub const DeletionWeightLimit: Weight = Weight::from_ref_time(500_000_000_000);
pub const DeletionWeightLimit: Weight = GAS_LIMIT;
pub static UnstableInterface: bool = true;
}
@@ -416,7 +416,7 @@ pub const BOB: AccountId32 = AccountId32::new([2u8; 32]);
pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]);
pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]);
pub const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000, 512 * 1024);
pub const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000, 3 * 1024 * 1024);
pub struct ExtBuilder {
existential_deposit: u64,
@@ -2322,7 +2322,7 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() {
fn lazy_removal_does_not_use_all_weight() {
let (code, _hash) = compile_module::<Test>("self_destruct").unwrap();
let weight_limit = Weight::from_ref_time(5_000_000_000);
let weight_limit = Weight::from_parts(5_000_000_000, 100 * 1024);
let mut ext = ExtBuilder::default().existential_deposit(50).build();
let (trie, vals, weight_per_key) = ext.execute_with(|| {
@@ -2396,7 +2396,7 @@ fn lazy_removal_does_not_use_all_weight() {
let weight_used = Storage::<Test>::process_deletion_queue_batch(weight_limit);
// We have one less key in our trie than our weight limit suffices for
assert_eq!(weight_used, weight_limit - Weight::from_ref_time(weight_per_key));
assert_eq!(weight_used, weight_limit - weight_per_key);
// All the keys are removed
for val in vals {
@@ -50,53 +50,61 @@ use sp_std::vec;
/// under the specified `code_hash`.
pub fn store<T: Config>(mut module: PrefabWasmModule<T>, instantiated: bool) -> DispatchResult {
let code_hash = sp_std::mem::take(&mut module.code_hash);
<CodeStorage<T>>::mutate(&code_hash, |existing| match existing {
Some(existing) => {
// We instrument any uploaded contract anyways. We might as well store it to save
// a potential re-instrumentation later.
existing.code = module.code;
existing.instruction_weights_version = module.instruction_weights_version;
// When the code was merely uploaded but not instantiated we can skip this.
if instantiated {
<OwnerInfoOf<T>>::mutate(&code_hash, |owner_info| {
if let Some(owner_info) = owner_info {
owner_info.refcount = owner_info.refcount.checked_add(1).expect(
"
refcount is 64bit. Generating this overflow would require to store
_at least_ 18 exabyte of data assuming that a contract consumes only
one byte of data. Any node would run out of storage space before hitting
this overflow.
qed
",
);
}
})
}
Ok(())
},
None => {
let orig_code = module.original_code.take().expect(
"
<OwnerInfoOf<T>>::mutate(&code_hash, |owner_info| {
match owner_info {
// Instantiate existing contract.
//
// No need to update the `CodeStorage` as any re-instrumentation eagerly saves
// the re-instrumented code.
Some(owner_info) if instantiated => {
owner_info.refcount = owner_info.refcount.checked_add(1).expect(
"
refcount is 64bit. Generating this overflow would require to store
_at least_ 18 exabyte of data assuming that a contract consumes only
one byte of data. Any node would run out of storage space before hitting
this overflow.
qed
",
);
Ok(())
},
// Re-upload existing contract without executing it.
//
// We are careful here to just overwrite the code to not include it into the PoV.
// We do this because the uploaded code was instrumented with the latest schedule
// and hence we persist those changes. Otherwise the next execution will pay again
// for the instrumentation.
Some(_) => {
<CodeStorage<T>>::insert(&code_hash, module);
Ok(())
},
// Upload a new contract.
//
// We need to write all data structures and collect the deposit.
None => {
let orig_code = module.original_code.take().expect(
"
If an executable isn't in storage it was uploaded.
If it was uploaded the original code must exist. qed
",
);
let mut owner_info = module.owner_info.take().expect(
"If an executable isn't in storage it was uploaded.
);
let mut new_owner_info = module.owner_info.take().expect(
"If an executable isn't in storage it was uploaded.
If it was uploaded the owner info was generated and attached. qed
",
);
// This `None` case happens only in freshly uploaded modules. This means that
// the `owner` is always the origin of the current transaction.
T::Currency::reserve(&owner_info.owner, owner_info.deposit)
.map_err(|_| <Error<T>>::StorageDepositNotEnoughFunds)?;
owner_info.refcount = if instantiated { 1 } else { 0 };
<PristineCode<T>>::insert(&code_hash, orig_code);
<OwnerInfoOf<T>>::insert(&code_hash, owner_info);
*existing = Some(module);
<Pallet<T>>::deposit_event(vec![code_hash], Event::CodeStored { code_hash });
Ok(())
},
);
// This `None` case happens only in freshly uploaded modules. This means that
// the `owner` is always the origin of the current transaction.
T::Currency::reserve(&new_owner_info.owner, new_owner_info.deposit)
.map_err(|_| <Error<T>>::StorageDepositNotEnoughFunds)?;
new_owner_info.refcount = if instantiated { 1 } else { 0 };
<PristineCode<T>>::insert(&code_hash, orig_code);
<CodeStorage<T>>::insert(&code_hash, module);
*owner_info = Some(new_owner_info);
<Pallet<T>>::deposit_event(vec![code_hash], Event::CodeStored { code_hash });
Ok(())
},
}
})
}
@@ -162,15 +170,16 @@ pub fn load<T: Config>(
let charged = gas_meter.charge(CodeToken::Load(max_code_len))?;
let mut prefab_module = <CodeStorage<T>>::get(code_hash).ok_or(Error::<T>::CodeNotFound)?;
gas_meter.adjust_gas(charged, CodeToken::Load(prefab_module.code.len() as u32));
let instrumented_code_len = prefab_module.code.len() as u32;
gas_meter.adjust_gas(charged, CodeToken::Load(instrumented_code_len));
prefab_module.code_hash = code_hash;
if prefab_module.instruction_weights_version < schedule.instruction_weights.version {
// The instruction weights have changed.
// We need to re-instrument the code with the new instruction weights.
let charged = gas_meter.charge(CodeToken::Reinstrument(max_code_len))?;
let code_size = reinstrument(&mut prefab_module, schedule)?;
gas_meter.adjust_gas(charged, CodeToken::Reinstrument(code_size));
let charged = gas_meter.charge(CodeToken::Reinstrument(instrumented_code_len))?;
let orig_code_len = reinstrument(&mut prefab_module, schedule)?;
gas_meter.adjust_gas(charged, CodeToken::Reinstrument(orig_code_len));
}
Ok(prefab_module)
@@ -224,8 +233,7 @@ impl<T: Config> Token<T> for CodeToken {
match *self {
Reinstrument(len) => T::WeightInfo::reinstrument(len),
Load(len) => T::WeightInfo::call_with_code_per_byte(len)
.saturating_sub(T::WeightInfo::call_with_code_per_byte(0))
.set_proof_size(len.into()),
.saturating_sub(T::WeightInfo::call_with_code_per_byte(0)),
}
}
}
+2 -2
View File
@@ -42,7 +42,7 @@ pub use crate::wasm::{
use crate::{
exec::{ExecResult, Executable, ExportedFunction, Ext},
gas::GasMeter,
AccountIdOf, BalanceOf, CodeHash, CodeStorage, CodeVec, Config, Error, RelaxedCodeVec,
AccountIdOf, BalanceOf, CodeHash, CodeVec, Config, Error, OwnerInfoOf, RelaxedCodeVec,
Schedule,
};
use codec::{Decode, Encode, MaxEncodedLen};
@@ -191,7 +191,7 @@ impl<T: Config> PrefabWasmModule<T> {
/// Returns `0` if the module is already in storage and hence no deposit will
/// be charged when storing it.
pub fn open_deposit(&self) -> BalanceOf<T> {
if <CodeStorage<T>>::contains_key(&self.code_hash) {
if <OwnerInfoOf<T>>::contains_key(&self.code_hash) {
0u32.into()
} else {
// Only already in-storage contracts have their `owner_info` set to `None`.
File diff suppressed because it is too large Load Diff
@@ -232,6 +232,38 @@ impl Weight {
Some(Self { ref_time, proof_size })
}
/// Calculates how many `other` fit into `self`.
///
/// Divides each component of `self` against the same component of `other`. Returns the minimum
/// of all those divisions. Returns `None` in case **all** components of `other` are zero.
///
/// This returns `Some` even if some components of `other` are zero as long as there is at least
/// one non-zero component in `other`. The devision for this particular component will then
/// yield the maximum value (e.g u64::MAX). This is because we assume not every operation and
/// hence each `Weight` will necessarily use each resource.
pub const fn checked_div_per_component(self, other: &Self) -> Option<u64> {
let mut all_zero = true;
let ref_time = match self.ref_time.checked_div(other.ref_time) {
Some(ref_time) => {
all_zero = false;
ref_time
},
None => u64::MAX,
};
let proof_size = match self.proof_size.checked_div(other.proof_size) {
Some(proof_size) => {
all_zero = false;
proof_size
},
None => u64::MAX,
};
if all_zero {
None
} else {
Some(if ref_time < proof_size { ref_time } else { proof_size })
}
}
/// Try to increase `self` by `amount` via checked addition.
pub fn checked_accrue(&mut self, amount: Self) -> Option<()> {
self.checked_add(&amount).map(|new_self| *self = new_self)
@@ -582,4 +614,48 @@ mod tests {
assert!(weight.checked_reduce(Weight::from_parts(0, 18)).is_some());
assert!(weight.is_zero());
}
#[test]
fn checked_div_per_component_works() {
assert_eq!(
Weight::from_parts(10, 20).checked_div_per_component(&Weight::from_parts(2, 10)),
Some(2)
);
assert_eq!(
Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(2, 10)),
Some(5)
);
assert_eq!(
Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(1, 10)),
Some(10)
);
assert_eq!(
Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(2, 1)),
Some(5)
);
assert_eq!(
Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(0, 10)),
Some(20)
);
assert_eq!(
Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(1, 0)),
Some(10)
);
assert_eq!(
Weight::from_parts(0, 200).checked_div_per_component(&Weight::from_parts(2, 3)),
Some(0)
);
assert_eq!(
Weight::from_parts(10, 0).checked_div_per_component(&Weight::from_parts(2, 3)),
Some(0)
);
assert_eq!(
Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(0, 0)),
None,
);
assert_eq!(
Weight::from_parts(0, 0).checked_div_per_component(&Weight::from_parts(0, 0)),
None,
);
}
}