Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
contracts: Use proof_size from benchmarks (#13268)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

* 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 <[email protected]>
  • Loading branch information
2 people authored and Ross Bulat committed Feb 19, 2023
1 parent 53be987 commit fd458d6
Show file tree
Hide file tree
Showing 8 changed files with 2,173 additions and 2,021 deletions.
148 changes: 73 additions & 75 deletions frame/contracts/src/benchmarking/mod.rs

Large diffs are not rendered by default.

173 changes: 71 additions & 102 deletions frame/contracts/src/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ),+)))
}
}

Expand All @@ -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
};
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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,
}
}
Expand Down
17 changes: 6 additions & 11 deletions frame/contracts/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,23 +245,21 @@ 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
// benchmark properly. We opt for not removing any keys at all in this case.
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)
}
Expand Down Expand Up @@ -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)`.
Expand Down
8 changes: 4 additions & 4 deletions frame/contracts/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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(|| {
Expand Down Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit fd458d6

Please sign in to comment.