From bfbd24c7499fec31ebb2b849877ac444375e6975 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Wed, 25 Sep 2024 19:09:57 +0200 Subject: [PATCH 01/35] introduce contract immutables to stack Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/exec.rs | 31 +++++++++++++-- substrate/frame/revive/src/lib.rs | 20 +++++++--- substrate/frame/revive/src/limits.rs | 5 +++ substrate/frame/revive/src/storage.rs | 25 ++++++++---- substrate/frame/revive/src/storage/meter.rs | 42 +++++++++++++-------- substrate/frame/revive/src/wasm/runtime.rs | 33 +++++++++++++--- 6 files changed, 117 insertions(+), 39 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 233658696c8f..1fdcef897e17 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -25,7 +25,7 @@ use crate::{ storage::{self, meter::Diff, WriteOutcome}, transient_storage::TransientStorage, BalanceOf, CodeInfo, CodeInfoOf, Config, ContractInfo, ContractInfoOf, DebugBuffer, Error, - Event, Pallet as Contracts, LOG_TARGET, + Event, ImmutableData, ImmutableDataOf, Pallet as Contracts, LOG_TARGET, }; use alloc::vec::Vec; use core::{fmt::Debug, marker::PhantomData, mem}; @@ -56,6 +56,7 @@ use sp_runtime::{ traits::{BadOrigin, Convert, Dispatchable, Zero}, DispatchError, SaturatedConversion, }; +use sp_std::collections::btree_map::BTreeMap; pub type AccountIdOf = ::AccountId; pub type MomentOf = <::Time as Time>::Moment; @@ -300,6 +301,11 @@ pub trait Ext: sealing::Sealed { ::AddressMapper::to_address(self.account_id()) } + /// Returns the immutable data of the current contract. + /// + /// Returns `Err(InvalidImmutableAccess)` if called from a constructor. + fn get_immutable_data(&mut self) -> Result<&mut ImmutableData, DispatchError>; + /// Returns the balance of the current contract. /// /// The `value_transferred` is already added. @@ -520,6 +526,8 @@ pub struct Stack<'a, T: Config, E> { debug_message: Option<&'a mut DebugBuffer>, /// Transient storage used to store data, which is kept for the duration of a transaction. transient_storage: TransientStorage, + /// Contract immutable data is kept for the duration of a transaction. + immutable_data: BTreeMap, /// No executable is held by the struct but influences its behaviour. _phantom: PhantomData, } @@ -835,6 +843,7 @@ where frames: Default::default(), debug_message, transient_storage: TransientStorage::new(limits::TRANSIENT_STORAGE_BYTES), + immutable_data: Default::default(), _phantom: Default::default(), }; @@ -865,7 +874,7 @@ where { contract } else { - return Ok(None) + return Ok(None); } }; @@ -1088,8 +1097,9 @@ where with_transaction(|| -> TransactionOutcome> { let output = do_transaction(); match &output { - Ok(result) if !result.did_revert() => - TransactionOutcome::Commit(Ok((true, output))), + Ok(result) if !result.did_revert() => { + TransactionOutcome::Commit(Ok((true, output))) + }, _ => TransactionOutcome::Rollback(Ok((false, output))), } }); @@ -1503,6 +1513,19 @@ where self.caller_is_origin() && self.origin == Origin::Root } + fn get_immutable_data(&mut self) -> Result<&mut ImmutableData, DispatchError> { + if self.top_frame().entry_point == ExportedFunction::Constructor { + return Err(Error::::InvalidImmutableAccess.into()); + } + + let account_id = self.account_id().clone(); + let address = T::AddressMapper::to_address(&account_id); + Ok(self + .immutable_data + .entry(account_id) + .or_insert_with(move || >::get(address).unwrap_or_default())) + } + fn balance(&self) -> U256 { self.account_balance(&self.top_frame().account_id) } diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 114d51c89695..2cb962f3c97a 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -94,6 +94,7 @@ type CodeVec = BoundedVec>; type EventRecordOf = EventRecord<::RuntimeEvent, ::Hash>; type DebugBuffer = BoundedVec>; +pub(crate) type ImmutableData = BoundedVec>; /// Used as a sentinel value when reading and writing contract memory. /// @@ -550,6 +551,8 @@ pub mod pallet { ExecutionFailed, /// Failed to convert a U256 to a Balance. BalanceConversionFailed, + /// Immutable data can only be during deploys and only be read during calls. + InvalidImmutableAccess, } /// A reason for the pallet contracts placing a hold on funds. @@ -573,6 +576,10 @@ pub mod pallet { #[pallet::storage] pub(crate) type ContractInfoOf = StorageMap<_, Identity, H160, ContractInfo>; + /// The immutable data associated with a given account. + #[pallet::storage] + pub(crate) type ImmutableDataOf = StorageMap<_, Identity, H160, ImmutableData>; + /// Evicted contracts that await child trie deletion. /// /// Child trie deletion is a heavy operation depending on the amount of storage items @@ -667,8 +674,8 @@ pub mod pallet { // We can use storage to store items using the available block ref_time with the // `set_storage` host function. - let max_storage_size: u32 = ((max_block_ref_time / - (>::weight(&RuntimeCosts::SetStorage { + let max_storage_size: u32 = ((max_block_ref_time + / (>::weight(&RuntimeCosts::SetStorage { new_bytes: max_payload_size, old_bytes: 0, }) @@ -690,8 +697,8 @@ pub mod pallet { // We can use storage to store events using the available block ref_time with the // `deposit_event` host function. The overhead of stored events, which is around 100B, // is not taken into account to simplify calculations, as it does not change much. - let max_events_size: u32 = ((max_block_ref_time / - (>::weight(&RuntimeCosts::DepositEvent { + let max_events_size: u32 = ((max_block_ref_time + / (>::weight(&RuntimeCosts::DepositEvent { num_topic: 0, len: max_payload_size, }) @@ -1049,8 +1056,9 @@ where storage_deposit_limit.saturating_reduce(upload_deposit); (executable, upload_deposit) }, - Code::Existing(code_hash) => - (WasmBlob::from_storage(code_hash, &mut gas_meter)?, Default::default()), + Code::Existing(code_hash) => { + (WasmBlob::from_storage(code_hash, &mut gas_meter)?, Default::default()) + }, }; let instantiate_origin = Origin::from_account_id(instantiate_account.clone()); let mut storage_meter = diff --git a/substrate/frame/revive/src/limits.rs b/substrate/frame/revive/src/limits.rs index f712493d3bc8..a09b64eb5b5d 100644 --- a/substrate/frame/revive/src/limits.rs +++ b/substrate/frame/revive/src/limits.rs @@ -65,6 +65,11 @@ pub const DEBUG_BUFFER_BYTES: u32 = 2 * 1024 * 1024; /// The page size in which PolkaVM should allocate memory chunks. pub const PAGE_SIZE: u32 = 4 * 1024; +/// The maximum amount of immutable bytes a single contract can store. +/// +/// The current limit of 4kb allows storing up 16 U256 immutable variables. +pub const IMMUTABLE_BYTES: u32 = 4 * 1024; + /// Limits that are only enforced on code upload. /// /// # Note diff --git a/substrate/frame/revive/src/storage.rs b/substrate/frame/revive/src/storage.rs index ef7ce2db32cf..13e97e03a8c5 100644 --- a/substrate/frame/revive/src/storage.rs +++ b/substrate/frame/revive/src/storage.rs @@ -75,6 +75,8 @@ pub struct ContractInfo { /// to the map can not be removed from the chain state and can be safely used for delegate /// calls. delegate_dependencies: DelegateDependencyMap, + /// The size of the immutable data of this contract. + immutable_bytes: u32, } impl ContractInfo { @@ -88,7 +90,7 @@ impl ContractInfo { code_hash: sp_core::H256, ) -> Result { if >::contains_key(address) { - return Err(Error::::DuplicateContract.into()) + return Err(Error::::DuplicateContract.into()); } let trie_id = { @@ -108,6 +110,7 @@ impl ContractInfo { storage_item_deposit: Zero::zero(), storage_base_deposit: Zero::zero(), delegate_dependencies: Default::default(), + immutable_bytes: 0, }; Ok(contract) @@ -202,12 +205,13 @@ impl ContractInfo { if let Some(storage_meter) = storage_meter { let mut diff = meter::Diff::default(); match (old_len, new_value.as_ref().map(|v| v.len() as u32)) { - (Some(old_len), Some(new_len)) => + (Some(old_len), Some(new_len)) => { if new_len > old_len { diff.bytes_added = new_len - old_len; } else { diff.bytes_removed = old_len - new_len; - }, + } + }, (None, Some(new_len)) => { diff.bytes_added = new_len; diff.items_added = 1; @@ -299,8 +303,8 @@ impl ContractInfo { /// of those keys can be deleted from the deletion queue given the supplied weight limit. pub fn deletion_budget(meter: &WeightMeter) -> (Weight, u32) { let base_weight = T::WeightInfo::on_process_deletion_queue_batch(); - let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) - - T::WeightInfo::on_initialize_per_trie_key(0); + let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) + - T::WeightInfo::on_initialize_per_trie_key(0); // `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. @@ -316,7 +320,7 @@ impl ContractInfo { /// Delete as many items from the deletion queue possible within the supplied weight limit. pub fn process_deletion_queue_batch(meter: &mut WeightMeter) { if meter.try_consume(T::WeightInfo::on_process_deletion_queue_batch()).is_err() { - return + return; }; let mut queue = >::load(); @@ -339,7 +343,7 @@ impl ContractInfo { // This happens when our budget wasn't large enough to remove all keys. KillStorageResult::SomeRemaining(keys_removed) => { remaining_key_budget.saturating_reduce(keys_removed); - break + break; }, KillStorageResult::AllRemoved(keys_removed) => { entry.remove(); @@ -356,6 +360,11 @@ impl ContractInfo { pub fn load_code_hash(account: &AccountIdOf) -> Option { >::get(&T::AddressMapper::to_address(account)).map(|i| i.code_hash) } + + /// Returns the size in bytes of the immutable data of this contract. + pub fn immutable_data_size(&self) -> u32 { + self.immutable_bytes + } } /// Information about what happened to the pre-existing value when calling [`ContractInfo::write`]. @@ -463,7 +472,7 @@ impl DeletionQueueManager { /// the cost of an extra call to `sp_io::storage::next_key` to lookup the next entry in the map fn next(&mut self) -> Option> { if self.is_empty() { - return None + return None; } let entry = >::get(self.delete_counter); diff --git a/substrate/frame/revive/src/storage/meter.rs b/substrate/frame/revive/src/storage/meter.rs index a2ece03f9aaf..ea019bbc0c48 100644 --- a/substrate/frame/revive/src/storage/meter.rs +++ b/substrate/frame/revive/src/storage/meter.rs @@ -167,7 +167,7 @@ impl Diff { } else { debug_assert_eq!(self.bytes_removed, 0); debug_assert_eq!(self.items_removed, 0); - return bytes_deposit.saturating_add(&items_deposit) + return bytes_deposit.saturating_add(&items_deposit); }; // Refunds are calculated pro rata based on the accumulated storage within the contract @@ -190,16 +190,20 @@ impl Diff { info.storage_items = info.storage_items.saturating_add(items_added).saturating_sub(items_removed); match &bytes_deposit { - Deposit::Charge(amount) => - info.storage_byte_deposit = info.storage_byte_deposit.saturating_add(*amount), - Deposit::Refund(amount) => - info.storage_byte_deposit = info.storage_byte_deposit.saturating_sub(*amount), + Deposit::Charge(amount) => { + info.storage_byte_deposit = info.storage_byte_deposit.saturating_add(*amount) + }, + Deposit::Refund(amount) => { + info.storage_byte_deposit = info.storage_byte_deposit.saturating_sub(*amount) + }, } match &items_deposit { - Deposit::Charge(amount) => - info.storage_item_deposit = info.storage_item_deposit.saturating_add(*amount), - Deposit::Refund(amount) => - info.storage_item_deposit = info.storage_item_deposit.saturating_sub(*amount), + Deposit::Charge(amount) => { + info.storage_item_deposit = info.storage_item_deposit.saturating_add(*amount) + }, + Deposit::Refund(amount) => { + info.storage_item_deposit = info.storage_item_deposit.saturating_sub(*amount) + }, } bytes_deposit.saturating_add(&items_deposit) @@ -261,8 +265,9 @@ impl Contribution { fn update_contract(&self, info: Option<&mut ContractInfo>) -> DepositOf { match self { Self::Alive(diff) => diff.update_contract::(info), - Self::Terminated { deposit, beneficiary: _ } | Self::Checked(deposit) => - deposit.clone(), + Self::Terminated { deposit, beneficiary: _ } | Self::Checked(deposit) => { + deposit.clone() + }, } } } @@ -342,8 +347,9 @@ where /// Returns the state of the currently executed contract. fn contract_state(&self) -> ContractState { match &self.own_contribution { - Contribution::Terminated { deposit: _, beneficiary } => - ContractState::Terminated { beneficiary: beneficiary.clone() }, + Contribution::Terminated { deposit: _, beneficiary } => { + ContractState::Terminated { beneficiary: beneficiary.clone() } + }, _ => ContractState::Alive, } } @@ -370,7 +376,7 @@ where let limit = E::check_limit(o, limit, min_leftover)?; Ok(Self { limit, ..Default::default() }) }, - } + }; } /// The total amount of deposit that should change hands as result of the execution @@ -479,7 +485,7 @@ impl> RawMeter { } if let Deposit::Charge(amount) = total_deposit { if amount > self.limit { - return Err(>::StorageDepositLimitExhausted.into()) + return Err(>::StorageDepositLimitExhausted.into()); } } Ok(()) @@ -674,6 +680,7 @@ mod tests { items: u32, bytes_deposit: BalanceOf, items_deposit: BalanceOf, + immutable_bytes: u32, } fn new_info(info: StorageInfo) -> ContractInfo { @@ -686,6 +693,7 @@ mod tests { storage_item_deposit: info.items_deposit, storage_base_deposit: Default::default(), delegate_dependencies: Default::default(), + immutable_bytes: info.immutable_bytes, } } @@ -773,6 +781,7 @@ mod tests { items: 5, bytes_deposit: 100, items_deposit: 10, + immutable_bytes: 0, }); let mut nested0 = meter.nested(BalanceOf::::zero()); nested0.charge(&Diff { @@ -788,6 +797,7 @@ mod tests { items: 10, bytes_deposit: 100, items_deposit: 20, + immutable_bytes: 0, }); let mut nested1 = nested0.nested(BalanceOf::::zero()); nested1.charge(&Diff { items_removed: 5, ..Default::default() }); @@ -798,6 +808,7 @@ mod tests { items: 7, bytes_deposit: 100, items_deposit: 20, + immutable_bytes: 0, }); let mut nested2 = nested0.nested(BalanceOf::::zero()); nested2.charge(&Diff { items_removed: 7, ..Default::default() }); @@ -867,6 +878,7 @@ mod tests { items: 10, bytes_deposit: 100, items_deposit: 20, + immutable_bytes: 0, }); let mut nested1 = nested0.nested(BalanceOf::::zero()); nested1.charge(&Diff { items_removed: 5, ..Default::default() }); diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index ebc407adacd2..3e4fe972d45d 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -569,8 +569,9 @@ impl<'a, E: Ext, M: PolkaVmInstance> Runtime<'a, E, M> { log::error!(target: LOG_TARGET, "polkavm execution error: {error}"); Some(Err(Error::::ExecutionFailed.into())) }, - Ok(Finished) => - Some(Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })), + Ok(Finished) => { + Some(Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })) + }, Ok(Trap) => Some(Err(Error::::ContractTrapped.into())), Ok(Segfault(_)) => Some(Err(Error::::ExecutionFailed.into())), Ok(NotEnoughGas) => Some(Err(Error::::OutOfGas.into())), @@ -585,11 +586,12 @@ impl<'a, E: Ext, M: PolkaVmInstance> Runtime<'a, E, M> { instance.write_output(return_value); None }, - Err(TrapReason::Return(ReturnData { flags, data })) => + Err(TrapReason::Return(ReturnData { flags, data })) => { match ReturnFlags::from_bits(flags) { None => Some(Err(Error::::InvalidCallFlags.into())), Some(flags) => Some(Ok(ExecReturnValue { flags, data })), - }, + } + }, Err(TrapReason::Termination) => Some(Ok(Default::default())), Err(TrapReason::SupervisorError(error)) => Some(Err(error.into())), } @@ -1507,6 +1509,24 @@ pub mod env { )?) } + /// Stores the immutable data into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::get_immutable_data`]. + #[api_version(0)] + fn get_immutable_data( + &mut self, + memory: &mut M, + out_ptr: u32, + out_len_ptr: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::GasLeft)?; + let data = core::mem::take(self.ext.get_immutable_data()?); + let write_outcome = + self.write_sandbox_output(memory, out_ptr, out_len_ptr, &data, false, already_charged); + *self.ext.get_immutable_data().expect("bailed out earlier; qed") = data; + write_outcome?; + Ok(()) + } + /// Stores the *free* balance of the current account into the supplied buffer. /// See [`pallet_revive_uapi::HostFn::balance`]. #[api_version(0)] @@ -1738,8 +1758,9 @@ pub mod env { Environment::new(self, memory, id, input_ptr, input_len, output_ptr, output_len_ptr); let ret = match chain_extension.call(env)? { RetVal::Converging(val) => Ok(val), - RetVal::Diverging { flags, data } => - Err(TrapReason::Return(ReturnData { flags: flags.bits(), data })), + RetVal::Diverging { flags, data } => { + Err(TrapReason::Return(ReturnData { flags: flags.bits(), data })) + }, }; self.chain_extension = Some(chain_extension); ret From 589097a6867ee8a400f49de2bc702358d8e25afc Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Wed, 25 Sep 2024 19:59:55 +0200 Subject: [PATCH 02/35] setter Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/exec.rs | 17 +++++++++++++++++ substrate/frame/revive/src/wasm/runtime.rs | 14 ++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 227e5bcdd5a6..111850cfdebe 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -302,6 +302,11 @@ pub trait Ext: sealing::Sealed { /// Returns `Err(InvalidImmutableAccess)` if called from a constructor. fn get_immutable_data(&mut self) -> Result<&mut ImmutableData, DispatchError>; + /// Set the the immutable data of the current contract. + /// + /// Returns `Err(InvalidImmutableAccess)` if not called from a constructor. + fn set_immutable_data(&mut self, data: ImmutableData) -> Result<(), DispatchError>; + /// Returns the balance of the current contract. /// /// The `value_transferred` is already added. @@ -1544,6 +1549,18 @@ where .or_insert_with(move || >::get(address).unwrap_or_default())) } + fn set_immutable_data(&mut self, data: ImmutableData) -> Result<(), DispatchError> { + if self.top_frame().entry_point == ExportedFunction::Call { + return Err(Error::::InvalidImmutableAccess.into()); + } + + let account_id = self.account_id().clone(); + let address = T::AddressMapper::to_address(&account_id); + >::insert(address, &data); + self.immutable_data.insert(account_id, data); + Ok(()) + } + fn balance(&self) -> U256 { self.account_balance(&self.top_frame().account_id) } diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index 9a51a63b3a72..c0d7980a3d87 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -1533,6 +1533,20 @@ pub mod env { Ok(()) } + /// Attaches the supplied immutable data to the currently executing contract. + /// See [`pallet_revive_uapi::HostFn::get_immutable_data`]. + #[api_version(0)] + fn set_immutable_data(&mut self, memory: &mut M, ptr: u32, len: u32) -> Result<(), TrapReason> { + if len > limits::IMMUTABLE_BYTES { + return Err(Error::::OutOfBounds.into()); + } + self.charge_gas(RuntimeCosts::GasLeft)?; + let buf = memory.read(ptr, len)?; + let data = buf.try_into().expect("bailed out earlier; qed"); + self.ext.set_immutable_data(data)?; + Ok(()) + } + /// Stores the *free* balance of the current account into the supplied buffer. /// See [`pallet_revive_uapi::HostFn::balance`]. #[api_version(0)] From eb8999e27c641a0d0c523b0b10242eeffa026f5d Mon Sep 17 00:00:00 2001 From: xermicus Date: Wed, 25 Sep 2024 21:25:29 +0200 Subject: [PATCH 03/35] test the immutable data access checks Signed-off-by: xermicus --- substrate/frame/revive/src/exec.rs | 51 ++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 111850cfdebe..5d9ed9b47f11 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -4320,4 +4320,55 @@ mod tests { assert_matches!(result, Ok(_)); }); } + + #[test] + fn immutable_data_access_checks_work() { + let dummy_ch = MockLoader::insert(Constructor, move |ctx, _| { + // Calls can not store immutable data + assert_eq!( + ctx.ext.get_immutable_data(), + Err(Error::::InvalidImmutableAccess.into()) + ); + exec_success() + }); + let instantiator_ch = MockLoader::insert(Call, { + move |ctx, _| { + let value = ::Currency::minimum_balance().into(); + + assert_eq!( + ctx.ext.set_immutable_data(Default::default()), + Err(Error::::InvalidImmutableAccess.into()) + ); + + // Constructors can not access the immutable data + ctx.ext + .instantiate(Weight::zero(), U256::zero(), dummy_ch, value, vec![], None) + .unwrap(); + + exec_success() + } + }); + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .existential_deposit(15) + .build() + .execute_with(|| { + set_balance(&ALICE, 1000); + set_balance(&BOB_CONTRACT_ID, 100); + place_contract(&BOB, instantiator_ch); + let origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new(&origin, 200, 0).unwrap(); + + MockStack::run_call( + origin, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + 0, + vec![], + None, + ) + .unwrap() + }); + } } From cec4e417ccc5e9d30582851f050ddc05889346c3 Mon Sep 17 00:00:00 2001 From: xermicus Date: Wed, 25 Sep 2024 22:20:29 +0200 Subject: [PATCH 04/35] uapi Signed-off-by: xermicus --- .../fixtures/contracts/immutable_data.rs | 43 +++++++++++++++++++ substrate/frame/revive/src/tests.rs | 23 +++++++++- substrate/frame/revive/uapi/src/host.rs | 16 +++++++ .../frame/revive/uapi/src/host/riscv32.rs | 14 ++++++ 4 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 substrate/frame/revive/fixtures/contracts/immutable_data.rs diff --git a/substrate/frame/revive/fixtures/contracts/immutable_data.rs b/substrate/frame/revive/fixtures/contracts/immutable_data.rs new file mode 100644 index 000000000000..ac50e61a400b --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/immutable_data.rs @@ -0,0 +1,43 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests that the `get_immutable_data` and `set_immutable_data` APIs work. + +#![no_std] +#![no_main] + +use common::input; +use uapi::{HostFn, HostFnImpl as api}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() { + input!(data: &[u8; 8],); + + api::set_immutable_data(data); +} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + input!(data: &[u8; 8],); + + let mut buf = [0; 8]; + api::get_immutable_data(&mut &mut buf[..]); + + assert_eq!(data, &buf); +} diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 5c5d144f24a2..c58c9c51f46c 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -149,8 +149,8 @@ pub mod test_utils { let code_info_len = CodeInfo::::max_encoded_len() as u64; // Calculate deposit to be reserved. // We add 2 storage items: one for code, other for code_info - DepositPerByte::get().saturating_mul(code_len as u64 + code_info_len) + - DepositPerItem::get().saturating_mul(2) + DepositPerByte::get().saturating_mul(code_len as u64 + code_info_len) + + DepositPerItem::get().saturating_mul(2) } pub fn ensure_stored(code_hash: sp_core::H256) -> usize { // Assert that code_info is stored @@ -4354,4 +4354,23 @@ mod run_tests { .build()); }); } + + #[test] + fn immutable_data_works() { + let (code, _) = compile_module("immutable_data").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let data = [0xfe; 8]; + + // Create fixture: Constructor sets the immtuable data + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .data(data.to_vec()) + .build_and_unwrap_contract(); + + // Call the contract: Asserts the input to equal the immutable data + assert_ok!(builder::call(addr).data(data.to_vec()).build()); + }); + } } diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs index 816fdec3aaaf..6706114d198a 100644 --- a/substrate/frame/revive/uapi/src/host.rs +++ b/substrate/frame/revive/uapi/src/host.rs @@ -56,6 +56,22 @@ pub trait HostFn: private::Sealed { /// otherwise. fn lock_delegate_dependency(code_hash: &[u8; 32]); + /// Get the contract immutable data. + /// + /// Traps if called from within the deploy export. + /// + /// # Parameters + /// - `output`: A reference to the output buffer to write the immutable bytes. + fn get_immutable_data(output: &mut &mut [u8]); + + /// Set the contract immutable data. + /// + /// Traps if called from within the call export. + /// + /// # Parameters + /// - `data`: A reference to the data to be stored as immutable bytes. + fn set_immutable_data(data: &[u8]); + /// Stores the **reducible** balance of the current account into the supplied buffer. /// /// # Parameters diff --git a/substrate/frame/revive/uapi/src/host/riscv32.rs b/substrate/frame/revive/uapi/src/host/riscv32.rs index d5ea94c1a910..26d3c84a230d 100644 --- a/substrate/frame/revive/uapi/src/host/riscv32.rs +++ b/substrate/frame/revive/uapi/src/host/riscv32.rs @@ -81,6 +81,8 @@ mod sys { pub fn address(out_ptr: *mut u8); pub fn weight_to_fee(ref_time: u64, proof_size: u64, out_ptr: *mut u8); pub fn weight_left(out_ptr: *mut u8, out_len_ptr: *mut u32); + pub fn get_immutable_data(out_ptr: *mut u8, out_len_ptr: *mut u32); + pub fn set_immutable_data(ptr: *const u8, len: u32); pub fn balance(out_ptr: *mut u8); pub fn balance_of(addr_ptr: *const u8, out_ptr: *mut u8); pub fn chain_id(out_ptr: *mut u8); @@ -502,6 +504,18 @@ impl HostFn for HostFnImpl { ret_val.into_bool() } + fn get_immutable_data(output: &mut &mut [u8]) { + let mut output_len = output.len() as u32; + { + unsafe { sys::get_immutable_data(output.as_mut_ptr(), &mut output_len) }; + } + extract_from_slice(output, output_len as usize); + } + + fn set_immutable_data(data: &[u8]) { + unsafe { sys::set_immutable_data(data.as_ptr(), data.len() as u32) } + } + fn balance_of(address: &[u8; 20], output: &mut [u8; 32]) { unsafe { sys::balance_of(address.as_ptr(), output.as_mut_ptr()) }; } From 9eb9820cc5190d9298ba06f485feb8707884693e Mon Sep 17 00:00:00 2001 From: xermicus Date: Wed, 25 Sep 2024 22:43:39 +0200 Subject: [PATCH 05/35] setter updates contract info Signed-off-by: xermicus --- substrate/frame/revive/src/exec.rs | 5 +++++ substrate/frame/revive/src/storage.rs | 7 +------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 5d9ed9b47f11..7109e391409c 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -305,6 +305,8 @@ pub trait Ext: sealing::Sealed { /// Set the the immutable data of the current contract. /// /// Returns `Err(InvalidImmutableAccess)` if not called from a constructor. + /// + /// Note: Requires &mut self to access the contract info. fn set_immutable_data(&mut self, data: ImmutableData) -> Result<(), DispatchError>; /// Returns the balance of the current contract. @@ -1556,8 +1558,11 @@ where let account_id = self.account_id().clone(); let address = T::AddressMapper::to_address(&account_id); + + self.top_frame_mut().contract_info.get(&account_id).immutable_bytes = data.len() as u32; >::insert(address, &data); self.immutable_data.insert(account_id, data); + Ok(()) } diff --git a/substrate/frame/revive/src/storage.rs b/substrate/frame/revive/src/storage.rs index 13e97e03a8c5..a01923903e3e 100644 --- a/substrate/frame/revive/src/storage.rs +++ b/substrate/frame/revive/src/storage.rs @@ -76,7 +76,7 @@ pub struct ContractInfo { /// calls. delegate_dependencies: DelegateDependencyMap, /// The size of the immutable data of this contract. - immutable_bytes: u32, + pub immutable_bytes: u32, } impl ContractInfo { @@ -360,11 +360,6 @@ impl ContractInfo { pub fn load_code_hash(account: &AccountIdOf) -> Option { >::get(&T::AddressMapper::to_address(account)).map(|i| i.code_hash) } - - /// Returns the size in bytes of the immutable data of this contract. - pub fn immutable_data_size(&self) -> u32 { - self.immutable_bytes - } } /// Information about what happened to the pre-existing value when calling [`ContractInfo::write`]. From 1cdffd41afa36721967a22eaa29035d6318c98f4 Mon Sep 17 00:00:00 2001 From: xermicus Date: Thu, 26 Sep 2024 07:38:25 +0200 Subject: [PATCH 06/35] terminate can prune the immutable data Signed-off-by: xermicus --- substrate/frame/revive/src/exec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 7109e391409c..e72f011c65fa 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -1435,6 +1435,7 @@ where info.queue_trie_for_deletion(); let account_address = T::AddressMapper::to_address(&frame.account_id); ContractInfoOf::::remove(&account_address); + ImmutableDataOf::::remove(&account_address); Self::decrement_refcount(info.code_hash); for (code_hash, deposit) in info.delegate_dependencies() { From a61a7b949b6e6b5ddc0c93188432ffb6f2d619ed Mon Sep 17 00:00:00 2001 From: xermicus Date: Thu, 26 Sep 2024 09:42:15 +0200 Subject: [PATCH 07/35] charge for immutable data in constructor and set_code_hash Signed-off-by: xermicus --- substrate/frame/revive/src/exec.rs | 34 +++++++++++++++++----- substrate/frame/revive/src/storage.rs | 8 ++++- substrate/frame/revive/src/wasm/runtime.rs | 7 +++-- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index e72f011c65fa..618afe66244e 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -53,7 +53,7 @@ use sp_core::{ }; use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; use sp_runtime::{ - traits::{BadOrigin, Convert, Dispatchable, Zero}, + traits::{BadOrigin, Convert, Dispatchable, Saturating, Zero}, DispatchError, SaturatedConversion, }; use sp_std::collections::btree_map::BTreeMap; @@ -386,8 +386,8 @@ pub trait Ext: sealing::Sealed { #[cfg(feature = "runtime-benchmarks")] fn transient_storage(&mut self) -> &mut TransientStorage; - /// Sets new code hash for existing contract. - fn set_code_hash(&mut self, hash: H256) -> DispatchResult; + /// Sets new code hash and immutable data for an existing contract. + fn set_code_hash(&mut self, address: H160) -> DispatchResult; /// Returns the number of times the specified contract exists on the call stack. Delegated calls /// Increment the reference count of a of a stored code by one. @@ -1074,11 +1074,21 @@ where return Err(Error::::TerminatedInConstructor.into()); } + let frame = self.top_frame_mut(); + let contract = frame.contract_info.as_contract().inspect(|info| { + // Charge for immutable data stored during constructor execution. + if info.immutable_bytes == 0 { + return; + }; + let amount = StorageDeposit::Charge( + T::DepositPerByte::get().saturating_mul(info.immutable_bytes.into()), + ); + frame.nested_storage.charge_deposit(frame.account_id.clone(), amount); + }); + // If a special limit was set for the sub-call, we enforce it here. // This is needed because contract constructor might write to storage. // The sub-call will be rolled back in case the limit is exhausted. - let frame = self.top_frame_mut(); - let contract = frame.contract_info.as_contract(); frame.nested_storage.enforce_subcall_limit(contract)?; let caller = T::AddressMapper::to_address(self.caller().account_id()?); @@ -1673,16 +1683,26 @@ where &mut self.transient_storage } - fn set_code_hash(&mut self, hash: H256) -> DispatchResult { + fn set_code_hash(&mut self, address: H160) -> DispatchResult { let frame = top_frame_mut!(self); + let contract = T::AddressMapper::to_address(&frame.account_id); + + let Some(new_info) = ContractInfoOf::::get(&address) else { + return Err(Error::::CodeNotFound.into()); + }; let info = frame.contract_info(); + let hash = new_info.code_hash; let prev_hash = info.code_hash; info.code_hash = hash; let code_info = CodeInfoOf::::get(hash).ok_or(Error::::CodeNotFound)?; + let immutable_data = ImmutableDataOf::::get(&address); + info.immutable_bytes = immutable_data.as_ref().map(|data| data.len() as u32).unwrap_or(0); + ImmutableDataOf::::mutate(&contract, |data| *data = immutable_data); + 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) @@ -1693,7 +1713,7 @@ where Self::increment_refcount(hash)?; Self::decrement_refcount(prev_hash); Contracts::::deposit_event(Event::ContractCodeUpdated { - contract: T::AddressMapper::to_address(&frame.account_id), + contract, new_code_hash: hash, old_code_hash: prev_hash, }); diff --git a/substrate/frame/revive/src/storage.rs b/substrate/frame/revive/src/storage.rs index a01923903e3e..539036cd966e 100644 --- a/substrate/frame/revive/src/storage.rs +++ b/substrate/frame/revive/src/storage.rs @@ -252,7 +252,13 @@ impl ContractInfo { // to prevent abuse. let upload_deposit = T::CodeHashLockupDepositPercent::get().mul_ceil(code_info.deposit()); - let deposit = info_deposit.saturating_add(upload_deposit); + // Immutable data is unique per contract and part of the base deposit. + let immutable_data_deposit = + T::DepositPerByte::get().saturating_mul(self.immutable_bytes.into()); + + let deposit = info_deposit + .saturating_add(upload_deposit) + .saturating_add(immutable_data_deposit); self.storage_base_deposit = deposit; deposit } diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index c0d7980a3d87..befd238bbb30 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -1970,11 +1970,12 @@ pub mod env { fn set_code_hash( &mut self, memory: &mut M, - code_hash_ptr: u32, + address_ptr: u32, ) -> Result { self.charge_gas(RuntimeCosts::SetCodeHash)?; - let code_hash: H256 = memory.read_h256(code_hash_ptr)?; - match self.ext.set_code_hash(code_hash) { + let mut address = H160::zero(); + memory.read_into_buf(address_ptr, address.as_bytes_mut())?; + match self.ext.set_code_hash(address) { Err(err) => { let code = Self::err_into_return_code(err)?; Ok(code) From b9c348d9758a1894e5c9c00693d33571b0a8705f Mon Sep 17 00:00:00 2001 From: xermicus Date: Thu, 26 Sep 2024 14:17:43 +0200 Subject: [PATCH 08/35] disable the set_code_hash API to fix it later Signed-off-by: xermicus --- substrate/frame/revive/src/exec.rs | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 618afe66244e..dfeefabf9fa0 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -387,7 +387,7 @@ pub trait Ext: sealing::Sealed { fn transient_storage(&mut self) -> &mut TransientStorage; /// Sets new code hash and immutable data for an existing contract. - fn set_code_hash(&mut self, address: H160) -> DispatchResult; + fn set_code_hash(&mut self, hash: H256) -> DispatchResult; /// Returns the number of times the specified contract exists on the call stack. Delegated calls /// Increment the reference count of a of a stored code by one. @@ -1572,7 +1572,6 @@ where self.top_frame_mut().contract_info.get(&account_id).immutable_bytes = data.len() as u32; >::insert(address, &data); - self.immutable_data.insert(account_id, data); Ok(()) } @@ -1683,26 +1682,29 @@ where &mut self.transient_storage } - fn set_code_hash(&mut self, address: H160) -> DispatchResult { + /// TODO: This should be changed to run the constructor of the supplied `hash`. + /// + /// Because the immutable data is attached to a contract and not a code, + /// we need to update the immutable data too. + /// + /// Otherwise we open a massive footgun: + /// If the immutables changed in the new code, the contract will brick. + /// + /// A possible implementation strategy is to add a flag to `FrameArgs::Instantiate`, + /// so that `fn run()` will roll back any changes if this flag is set. + /// + /// After running the constructor, the new immutable data is already stored in + /// `self.immutable_data` at the address of the (reverted) contract instantiation. + fn set_code_hash(&mut self, hash: H256) -> DispatchResult { let frame = top_frame_mut!(self); - let contract = T::AddressMapper::to_address(&frame.account_id); - - let Some(new_info) = ContractInfoOf::::get(&address) else { - return Err(Error::::CodeNotFound.into()); - }; let info = frame.contract_info(); - let hash = new_info.code_hash; let prev_hash = info.code_hash; info.code_hash = hash; let code_info = CodeInfoOf::::get(hash).ok_or(Error::::CodeNotFound)?; - let immutable_data = ImmutableDataOf::::get(&address); - info.immutable_bytes = immutable_data.as_ref().map(|data| data.len() as u32).unwrap_or(0); - ImmutableDataOf::::mutate(&contract, |data| *data = immutable_data); - 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) @@ -1713,7 +1715,7 @@ where Self::increment_refcount(hash)?; Self::decrement_refcount(prev_hash); Contracts::::deposit_event(Event::ContractCodeUpdated { - contract, + contract: T::AddressMapper::to_address(&frame.account_id), new_code_hash: hash, old_code_hash: prev_hash, }); From 0bb6f79405f9d9f600a2db30d4d00f7749da0b7d Mon Sep 17 00:00:00 2001 From: xermicus Date: Thu, 26 Sep 2024 14:22:29 +0200 Subject: [PATCH 09/35] add Signed-off-by: xermicus --- substrate/frame/revive/src/wasm/runtime.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index befd238bbb30..0cf1d5f2b234 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -1965,17 +1965,15 @@ pub mod env { /// Replace the contract code at the specified address with new code. /// See [`pallet_revive_uapi::HostFn::set_code_hash`]. - #[api_version(0)] #[mutating] fn set_code_hash( &mut self, memory: &mut M, - address_ptr: u32, + code_hash_ptr: u32, ) -> Result { self.charge_gas(RuntimeCosts::SetCodeHash)?; - let mut address = H160::zero(); - memory.read_into_buf(address_ptr, address.as_bytes_mut())?; - match self.ext.set_code_hash(address) { + let code_hash: H256 = memory.read_h256(code_hash_ptr)?; + match self.ext.set_code_hash(code_hash) { Err(err) => { let code = Self::err_into_return_code(err)?; Ok(code) From 3c8a3578ad40dc12b5202ce2631583933413a25c Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Thu, 26 Sep 2024 16:23:46 +0200 Subject: [PATCH 10/35] delegate call test Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/exec.rs | 71 ++++++++++++++++++++++++ substrate/frame/revive/src/test_utils.rs | 1 + 2 files changed, 72 insertions(+) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index dfeefabf9fa0..a42600bb199e 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -4399,4 +4399,75 @@ mod tests { .unwrap() }); } + + #[test] + fn correct_immutable_data_in_delegate_call() { + let charlie_ch = MockLoader::insert(Call, |ctx, _| { + Ok(ExecReturnValue { + flags: ReturnFlags::empty(), + data: ctx.ext.get_immutable_data()?.to_vec(), + }) + }); + let bob_ch = MockLoader::insert(Call, move |ctx, _| { + // In a regular call, we should witness the callee immutable data + assert_eq!( + ctx.ext + .call( + Weight::zero(), + U256::zero(), + &CHARLIE_ADDR, + U256::zero(), + vec![], + true, + false, + ) + .map(|_| ctx.ext.last_frame_output().data.clone()), + Ok(vec![2]), + ); + + // In a delegate call, we should witness the caller immutable data + assert_eq!( + ctx.ext.delegate_call(charlie_ch, Vec::new()).map(|_| ctx + .ext + .last_frame_output() + .data + .clone()), + Ok(vec![1]) + ); + + exec_success() + }); + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .existential_deposit(15) + .build() + .execute_with(|| { + place_contract(&BOB, bob_ch); + place_contract(&CHARLIE, charlie_ch); + + let origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new(&origin, 200, 0).unwrap(); + + // Place unique immutable data for each contract + >::insert::<_, ImmutableData>( + BOB_ADDR, + vec![1].try_into().unwrap(), + ); + >::insert::<_, ImmutableData>( + CHARLIE_ADDR, + vec![2].try_into().unwrap(), + ); + + MockStack::run_call( + origin, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + 0, + vec![], + None, + ) + .unwrap() + }); + } } diff --git a/substrate/frame/revive/src/test_utils.rs b/substrate/frame/revive/src/test_utils.rs index 671efebdf4bd..92c21297a3ec 100644 --- a/substrate/frame/revive/src/test_utils.rs +++ b/substrate/frame/revive/src/test_utils.rs @@ -54,6 +54,7 @@ pub const BOB_CONTRACT_ID: AccountId32 = ee_suffix(BOB_ADDR); pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]); pub const CHARLIE_ADDR: H160 = H160([3u8; 20]); +pub const CHARLIE_CONTRACT_ID: AccountId32 = ee_suffix(CHARLIE_ADDR); pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]); pub const DJANGO_ADDR: H160 = H160([4u8; 20]); From 66618ffe01c464439aa9a3090d675873d040e9a5 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Fri, 27 Sep 2024 21:50:39 +0200 Subject: [PATCH 11/35] bench Signed-off-by: Cyrill Leutwiler --- .../frame/revive/src/benchmarking/mod.rs | 53 +++++++++++++++++-- substrate/frame/revive/src/exec.rs | 7 +++ substrate/frame/revive/src/tests.rs | 17 ++++++ substrate/frame/revive/src/wasm/runtime.rs | 10 +++- substrate/frame/revive/src/weights.rs | 51 ++++++++++++++++++ 5 files changed, 133 insertions(+), 5 deletions(-) diff --git a/substrate/frame/revive/src/benchmarking/mod.rs b/substrate/frame/revive/src/benchmarking/mod.rs index cbc4cc62d481..25101445a15b 100644 --- a/substrate/frame/revive/src/benchmarking/mod.rs +++ b/substrate/frame/revive/src/benchmarking/mod.rs @@ -169,7 +169,7 @@ where }; if key == &key_new { - continue + continue; } child::put_raw(&child_trie_info, &key_new, &value); } @@ -213,8 +213,8 @@ fn caller_funding() -> BalanceOf { /// The deposit limit we use for benchmarks. fn default_deposit_limit() -> BalanceOf { - (T::DepositPerByte::get() * 1024u32.into() * 1024u32.into()) + - T::DepositPerItem::get() * 1024u32.into() + (T::DepositPerByte::get() * 1024u32.into() * 1024u32.into()) + + T::DepositPerItem::get() * 1024u32.into() } #[benchmarks( @@ -628,6 +628,53 @@ mod benchmarks { assert_eq!(U256::from_little_endian(&memory[..len]), runtime.ext().balance_of(&address)); } + #[benchmark(pov_mode = Measured)] + fn seal_get_immutable_data(n: Linear<0, { limits::IMMUTABLE_BYTES }>) { + let len = n as usize; + let immutable_data = vec![1u8; len]; + + build_runtime!(runtime, contract, memory: [(len as u32).encode(), vec![0u8; len],]); + + >::insert::<_, BoundedVec<_, _>>( + contract.address(), + immutable_data.clone().try_into().unwrap(), + ); + + let result; + #[block] + { + result = runtime.bench_get_immutable_data(memory.as_mut_slice(), 4, 0 as u32); + } + + assert_ok!(result); + assert_eq!(&memory[0..4], (len as u32).encode()); + assert_eq!(&memory[4..len + 4], &immutable_data); + } + + #[benchmark(pov_mode = Measured)] + fn seal_set_immutable_data(n: Linear<0, { limits::IMMUTABLE_BYTES }>) { + let len = n as usize; + let mut memory = vec![1u8; len]; + let mut setup = CallSetup::::default(); + let input = setup.data(); + let (mut ext, _) = setup.ext(); + ext.override_export(crate::debug::ExportedFunction::Constructor); + + let mut runtime = crate::wasm::Runtime::<_, [u8]>::new(&mut ext, input); + + let result; + #[block] + { + result = runtime.bench_set_immutable_data(memory.as_mut_slice(), 0, n); + } + + assert_ok!(result); + assert_eq!( + &memory[..], + &>::get(setup.contract().address()).unwrap()[..] + ); + } + #[benchmark(pov_mode = Measured)] fn seal_value_transferred() { build_runtime!(runtime, memory: [[0u8;32], ]); diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index a42600bb199e..c17ac13eb96a 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -1313,6 +1313,13 @@ where fn account_balance(&self, who: &T::AccountId) -> U256 { T::Currency::reducible_balance(who, Preservation::Preserve, Fortitude::Polite).into() } + + /// Certain APIs, e.g. `{set,get}_immutable_data` behave differently depending + /// on the configured entry point. Thus, we allow setting the export manually. + #[cfg(feature = "runtime-benchmarks")] + pub(crate) fn override_export(&mut self, export: ExportedFunction) { + self.top_frame_mut().entry_point = export; + } } impl<'a, T, E> Ext for Stack<'a, T, E> diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index c58c9c51f46c..065e34d0dc6e 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -4373,4 +4373,21 @@ mod run_tests { assert_ok!(builder::call(addr).data(data.to_vec()).build()); }); } + + #[test] + fn immutable_data_bench() { + let (code, _) = compile_module("immutable_data_bench").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor sets the immtuable data + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .data(10u32.encode()) + .build_and_unwrap_contract(); + + // Call the contract: Asserts the input to equal the immutable data + assert_ok!(builder::call(addr).data(10u32.encode()).build()); + }); + } } diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index 0cf1d5f2b234..d4ca387b86ee 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -390,6 +390,10 @@ pub enum RuntimeCosts { LockDelegateDependency, /// Weight of calling `unlock_delegate_dependency` UnlockDelegateDependency, + /// Weight of calling `get_immutable_dependency` + GetImmutableData(u32), + /// Weight of calling `set_immutable_dependency` + SetImmutableData(u32), } /// For functions that modify storage, benchmarks are performed with one item in the @@ -507,6 +511,8 @@ impl Token for RuntimeCosts { EcdsaToEthAddress => T::WeightInfo::seal_ecdsa_to_eth_address(), LockDelegateDependency => T::WeightInfo::lock_delegate_dependency(), UnlockDelegateDependency => T::WeightInfo::unlock_delegate_dependency(), + GetImmutableData(len) => T::WeightInfo::seal_get_immutable_data(len), + SetImmutableData(len) => T::WeightInfo::seal_set_immutable_data(len), } } } @@ -1524,8 +1530,8 @@ pub mod env { out_ptr: u32, out_len_ptr: u32, ) -> Result<(), TrapReason> { - self.charge_gas(RuntimeCosts::GasLeft)?; let data = core::mem::take(self.ext.get_immutable_data()?); + self.charge_gas(RuntimeCosts::GetImmutableData(data.len() as u32))?; let write_outcome = self.write_sandbox_output(memory, out_ptr, out_len_ptr, &data, false, already_charged); *self.ext.get_immutable_data().expect("bailed out earlier; qed") = data; @@ -1540,7 +1546,7 @@ pub mod env { if len > limits::IMMUTABLE_BYTES { return Err(Error::::OutOfBounds.into()); } - self.charge_gas(RuntimeCosts::GasLeft)?; + self.charge_gas(RuntimeCosts::SetImmutableData(len))?; let buf = memory.read(ptr, len)?; let data = buf.try_into().expect("bailed out earlier; qed"); self.ext.set_immutable_data(data)?; diff --git a/substrate/frame/revive/src/weights.rs b/substrate/frame/revive/src/weights.rs index b66c28bdf7d8..08286ca7c598 100644 --- a/substrate/frame/revive/src/weights.rs +++ b/substrate/frame/revive/src/weights.rs @@ -118,6 +118,8 @@ pub trait WeightInfo { fn seal_account_reentrance_count() -> Weight; fn seal_instantiation_nonce() -> Weight; fn instr_i64_load_store(r: u32, ) -> Weight; + fn seal_get_immutable_data(n: u32,) -> Weight; + fn seal_set_immutable_data(n: u32,) -> Weight; } /// Weights for `pallet_revive` using the Substrate node and recommended hardware. @@ -420,6 +422,31 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(3_874_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) } + + /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) + /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) + /// The range of component `n` is `[0, 4096]`. + fn seal_get_immutable_data(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `201 + n * (1 ±0)` + // Estimated: `7766` + // Minimum execution time: 7_711_000 picoseconds. + Weight::from_parts(10_350_000, 0) + .saturating_add(Weight::from_parts(0, 7766)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Revive::ImmutableDataOf` (r:0 w:1) + /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) + /// The range of component `n` is `[0, 4096]`. + fn seal_set_immutable_data(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_780_000 picoseconds. + Weight::from_parts(7_790_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -1244,6 +1271,30 @@ impl WeightInfo for () { Weight::from_parts(3_874_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) } + /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) + /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) + /// The range of component `n` is `[0, 4096]`. + fn seal_get_immutable_data(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `201 + n * (1 ±0)` + // Estimated: `7766` + // Minimum execution time: 7_711_000 picoseconds. + Weight::from_parts(10_350_000, 0) + .saturating_add(Weight::from_parts(0, 7766)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Revive::ImmutableDataOf` (r:0 w:1) + /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) + /// The range of component `n` is `[0, 4096]`. + fn seal_set_immutable_data(_n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_780_000 picoseconds. + Weight::from_parts(7_790_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: // Measured: `0` From 0290c55ec4a10dc833f29797f5b9059b8806a48d Mon Sep 17 00:00:00 2001 From: xermicus Date: Fri, 27 Sep 2024 22:44:12 +0200 Subject: [PATCH 12/35] implement optimizations later Signed-off-by: xermicus --- substrate/frame/revive/src/exec.rs | 20 +++++--------------- substrate/frame/revive/src/tests.rs | 17 ----------------- substrate/frame/revive/src/wasm/runtime.rs | 7 ++----- substrate/frame/revive/src/weights.rs | 4 ++-- 4 files changed, 9 insertions(+), 39 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index c17ac13eb96a..c352fc4cbfe7 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -56,7 +56,6 @@ use sp_runtime::{ traits::{BadOrigin, Convert, Dispatchable, Saturating, Zero}, DispatchError, SaturatedConversion, }; -use sp_std::collections::btree_map::BTreeMap; pub type AccountIdOf = ::AccountId; pub type MomentOf = <::Time as Time>::Moment; @@ -300,7 +299,7 @@ pub trait Ext: sealing::Sealed { /// Returns the immutable data of the current contract. /// /// Returns `Err(InvalidImmutableAccess)` if called from a constructor. - fn get_immutable_data(&mut self) -> Result<&mut ImmutableData, DispatchError>; + fn get_immutable_data(&mut self) -> Result; /// Set the the immutable data of the current contract. /// @@ -535,8 +534,6 @@ pub struct Stack<'a, T: Config, E> { debug_message: Option<&'a mut DebugBuffer>, /// Transient storage used to store data, which is kept for the duration of a transaction. transient_storage: TransientStorage, - /// Contract immutable data is kept for the duration of a transaction. - immutable_data: BTreeMap, /// No executable is held by the struct but influences its behaviour. _phantom: PhantomData, } @@ -856,7 +853,6 @@ where frames: Default::default(), debug_message, transient_storage: TransientStorage::new(limits::TRANSIENT_STORAGE_BYTES), - immutable_data: Default::default(), _phantom: Default::default(), }; @@ -1556,17 +1552,13 @@ where self.caller_is_origin() && self.origin == Origin::Root } - fn get_immutable_data(&mut self) -> Result<&mut ImmutableData, DispatchError> { + fn get_immutable_data(&mut self) -> Result { if self.top_frame().entry_point == ExportedFunction::Constructor { return Err(Error::::InvalidImmutableAccess.into()); } - let account_id = self.account_id().clone(); - let address = T::AddressMapper::to_address(&account_id); - Ok(self - .immutable_data - .entry(account_id) - .or_insert_with(move || >::get(address).unwrap_or_default())) + let address = T::AddressMapper::to_address(self.account_id()); + Ok(>::get(address).ok_or_else(|| Error::::InvalidImmutableAccess)?) } fn set_immutable_data(&mut self, data: ImmutableData) -> Result<(), DispatchError> { @@ -1575,10 +1567,8 @@ where } let account_id = self.account_id().clone(); - let address = T::AddressMapper::to_address(&account_id); - self.top_frame_mut().contract_info.get(&account_id).immutable_bytes = data.len() as u32; - >::insert(address, &data); + >::insert(T::AddressMapper::to_address(&account_id), &data); Ok(()) } diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 065e34d0dc6e..c58c9c51f46c 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -4373,21 +4373,4 @@ mod run_tests { assert_ok!(builder::call(addr).data(data.to_vec()).build()); }); } - - #[test] - fn immutable_data_bench() { - let (code, _) = compile_module("immutable_data_bench").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create fixture: Constructor sets the immtuable data - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .data(10u32.encode()) - .build_and_unwrap_contract(); - - // Call the contract: Asserts the input to equal the immutable data - assert_ok!(builder::call(addr).data(10u32.encode()).build()); - }); - } } diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index d4ca387b86ee..4ed91d8a359b 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -1530,12 +1530,9 @@ pub mod env { out_ptr: u32, out_len_ptr: u32, ) -> Result<(), TrapReason> { - let data = core::mem::take(self.ext.get_immutable_data()?); + let data = self.ext.get_immutable_data()?; self.charge_gas(RuntimeCosts::GetImmutableData(data.len() as u32))?; - let write_outcome = - self.write_sandbox_output(memory, out_ptr, out_len_ptr, &data, false, already_charged); - *self.ext.get_immutable_data().expect("bailed out earlier; qed") = data; - write_outcome?; + self.write_sandbox_output(memory, out_ptr, out_len_ptr, &data, false, already_charged)?; Ok(()) } diff --git a/substrate/frame/revive/src/weights.rs b/substrate/frame/revive/src/weights.rs index 08286ca7c598..e3efb32672ab 100644 --- a/substrate/frame/revive/src/weights.rs +++ b/substrate/frame/revive/src/weights.rs @@ -1281,7 +1281,7 @@ impl WeightInfo for () { // Minimum execution time: 7_711_000 picoseconds. Weight::from_parts(10_350_000, 0) .saturating_add(Weight::from_parts(0, 7766)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().reads(1)) } /// Storage: `Revive::ImmutableDataOf` (r:0 w:1) /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) @@ -1293,7 +1293,7 @@ impl WeightInfo for () { // Minimum execution time: 2_780_000 picoseconds. Weight::from_parts(7_790_000, 0) .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: From 9f539e8cc7f72f5c2c4f5a19f874c1b243297a1a Mon Sep 17 00:00:00 2001 From: xermicus Date: Fri, 27 Sep 2024 23:05:53 +0200 Subject: [PATCH 13/35] storage limits Signed-off-by: xermicus --- substrate/frame/revive/src/lib.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 2cb962f3c97a..fdaddf42d0bd 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -672,6 +672,16 @@ pub mod pallet { .hash() .len() as u32; + let max_immutable_key_size = T::AccountId::max_encoded_len() as u32; + let max_immutable_size: u32 = ((max_block_ref_time + / (>::weight(&RuntimeCosts::SetImmutableData( + limits::IMMUTABLE_BYTES, + )) + .ref_time())) + .saturating_mul(limits::IMMUTABLE_BYTES.saturating_add(max_immutable_key_size) as u64)) + .try_into() + .expect("Immutable data size too big"); + // We can use storage to store items using the available block ref_time with the // `set_storage` host function. let max_storage_size: u32 = ((max_block_ref_time @@ -681,6 +691,7 @@ pub mod pallet { }) .ref_time())) .saturating_mul(max_payload_size.saturating_add(max_key_size) as u64)) + .saturating_add(max_immutable_size.into()) .try_into() .expect("Storage size too big"); From f85b18b6fe16c9a783675e9f320dd2bbde731892 Mon Sep 17 00:00:00 2001 From: xermicus Date: Fri, 27 Sep 2024 23:43:30 +0200 Subject: [PATCH 14/35] prdoc Signed-off-by: xermicus --- prdoc/pr_5861.prdoc | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 prdoc/pr_5861.prdoc diff --git a/prdoc/pr_5861.prdoc b/prdoc/pr_5861.prdoc new file mode 100644 index 000000000000..e2187dc1bdde --- /dev/null +++ b/prdoc/pr_5861.prdoc @@ -0,0 +1,37 @@ +title: "[pallet-revive] immutable data storage" + +doc: + - audience: Runtime Dev + description: | + This PR introduces the concept of immutable storage data, used for + [Solidity immutable variables](https://docs.soliditylang.org/en/latest/contracts.html#immutable). + + This is a minimal implementation. Immutable data is attached to a contract; to + `ContractInfo` fixed in size, we only store the length there, and store the immutable + data in a dedicated storage map instead. Which comes at the cost of requiring an + storage read (costly) for contracts using this feature. + + We discussed more optimal solutions not requiring any additional storage accesses + internally, but they turned out to be non-trivial to implement. Another optimization + benefiting multiple calls to the same contract in a single call stack would be to cache + the immutable data in `Stack`. However, this potential creates a DOS vulnerability (the + attack vector is to call into as many contracts in a single stack as possible, where + they all have maximum immutable data to fill the cache as efficiently as possible). So + this either has to be guaranteed to be a non-issue by limits, or, more likely, to have + some logic to bound the cache. Eventually, we should think about introducing the concept + of warm and cold storage reads (akin to EVM). Since immutable variables are commonly + used in contracts, this change is blocking our initial launch and we should only + optimize it properly in follow-ups. + + This PR also disables the `set_code_hash` API (which isn't usable for Solidity contracts + without pre-compiles anyways). With immutable storage attached to contracts, we now want + to run the constructor of the new code hash to collect the immutable data during + `set_code_hash`. This will be implemented in a follow up PR. + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: patch + - name: pallet-revive-uapi + bump: minor From 6f3aa5e64b1e602423b3ffb4a2dffe92811c08ca Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Fri, 27 Sep 2024 21:52:16 +0000 Subject: [PATCH 15/35] ".git/.scripts/commands/fmt/fmt.sh" --- .../frame/revive/src/benchmarking/mod.rs | 4 +-- substrate/frame/revive/src/exec.rs | 5 ++-- substrate/frame/revive/src/lib.rs | 17 +++++------ substrate/frame/revive/src/storage.rs | 9 +++--- substrate/frame/revive/src/storage/meter.rs | 30 ++++++++----------- substrate/frame/revive/src/tests.rs | 4 +-- substrate/frame/revive/src/wasm/runtime.rs | 15 ++++------ 7 files changed, 36 insertions(+), 48 deletions(-) diff --git a/substrate/frame/revive/src/benchmarking/mod.rs b/substrate/frame/revive/src/benchmarking/mod.rs index 25101445a15b..5404a660a906 100644 --- a/substrate/frame/revive/src/benchmarking/mod.rs +++ b/substrate/frame/revive/src/benchmarking/mod.rs @@ -213,8 +213,8 @@ fn caller_funding() -> BalanceOf { /// The deposit limit we use for benchmarks. fn default_deposit_limit() -> BalanceOf { - (T::DepositPerByte::get() * 1024u32.into() * 1024u32.into()) - + T::DepositPerItem::get() * 1024u32.into() + (T::DepositPerByte::get() * 1024u32.into() * 1024u32.into()) + + T::DepositPerItem::get() * 1024u32.into() } #[benchmarks( diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index c352fc4cbfe7..0b109abc92a9 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -1129,9 +1129,8 @@ where with_transaction(|| -> TransactionOutcome> { let output = do_transaction(); match &output { - Ok(result) if !result.did_revert() => { - TransactionOutcome::Commit(Ok((true, output))) - }, + Ok(result) if !result.did_revert() => + TransactionOutcome::Commit(Ok((true, output))), _ => TransactionOutcome::Rollback(Ok((false, output))), } }); diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index fdaddf42d0bd..38736e9e6eca 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -673,8 +673,8 @@ pub mod pallet { .len() as u32; let max_immutable_key_size = T::AccountId::max_encoded_len() as u32; - let max_immutable_size: u32 = ((max_block_ref_time - / (>::weight(&RuntimeCosts::SetImmutableData( + let max_immutable_size: u32 = ((max_block_ref_time / + (>::weight(&RuntimeCosts::SetImmutableData( limits::IMMUTABLE_BYTES, )) .ref_time())) @@ -684,8 +684,8 @@ pub mod pallet { // We can use storage to store items using the available block ref_time with the // `set_storage` host function. - let max_storage_size: u32 = ((max_block_ref_time - / (>::weight(&RuntimeCosts::SetStorage { + let max_storage_size: u32 = ((max_block_ref_time / + (>::weight(&RuntimeCosts::SetStorage { new_bytes: max_payload_size, old_bytes: 0, }) @@ -708,8 +708,8 @@ pub mod pallet { // We can use storage to store events using the available block ref_time with the // `deposit_event` host function. The overhead of stored events, which is around 100B, // is not taken into account to simplify calculations, as it does not change much. - let max_events_size: u32 = ((max_block_ref_time - / (>::weight(&RuntimeCosts::DepositEvent { + let max_events_size: u32 = ((max_block_ref_time / + (>::weight(&RuntimeCosts::DepositEvent { num_topic: 0, len: max_payload_size, }) @@ -1067,9 +1067,8 @@ where storage_deposit_limit.saturating_reduce(upload_deposit); (executable, upload_deposit) }, - Code::Existing(code_hash) => { - (WasmBlob::from_storage(code_hash, &mut gas_meter)?, Default::default()) - }, + Code::Existing(code_hash) => + (WasmBlob::from_storage(code_hash, &mut gas_meter)?, Default::default()), }; let instantiate_origin = Origin::from_account_id(instantiate_account.clone()); let mut storage_meter = diff --git a/substrate/frame/revive/src/storage.rs b/substrate/frame/revive/src/storage.rs index 539036cd966e..5cf568f7fee1 100644 --- a/substrate/frame/revive/src/storage.rs +++ b/substrate/frame/revive/src/storage.rs @@ -205,13 +205,12 @@ impl ContractInfo { if let Some(storage_meter) = storage_meter { let mut diff = meter::Diff::default(); match (old_len, new_value.as_ref().map(|v| v.len() as u32)) { - (Some(old_len), Some(new_len)) => { + (Some(old_len), Some(new_len)) => if new_len > old_len { diff.bytes_added = new_len - old_len; } else { diff.bytes_removed = old_len - new_len; - } - }, + }, (None, Some(new_len)) => { diff.bytes_added = new_len; diff.items_added = 1; @@ -309,8 +308,8 @@ impl ContractInfo { /// of those keys can be deleted from the deletion queue given the supplied weight limit. pub fn deletion_budget(meter: &WeightMeter) -> (Weight, u32) { let base_weight = T::WeightInfo::on_process_deletion_queue_batch(); - let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) - - T::WeightInfo::on_initialize_per_trie_key(0); + let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) - + T::WeightInfo::on_initialize_per_trie_key(0); // `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. diff --git a/substrate/frame/revive/src/storage/meter.rs b/substrate/frame/revive/src/storage/meter.rs index ea019bbc0c48..325db202b1a2 100644 --- a/substrate/frame/revive/src/storage/meter.rs +++ b/substrate/frame/revive/src/storage/meter.rs @@ -190,20 +190,16 @@ impl Diff { info.storage_items = info.storage_items.saturating_add(items_added).saturating_sub(items_removed); match &bytes_deposit { - Deposit::Charge(amount) => { - info.storage_byte_deposit = info.storage_byte_deposit.saturating_add(*amount) - }, - Deposit::Refund(amount) => { - info.storage_byte_deposit = info.storage_byte_deposit.saturating_sub(*amount) - }, + Deposit::Charge(amount) => + info.storage_byte_deposit = info.storage_byte_deposit.saturating_add(*amount), + Deposit::Refund(amount) => + info.storage_byte_deposit = info.storage_byte_deposit.saturating_sub(*amount), } match &items_deposit { - Deposit::Charge(amount) => { - info.storage_item_deposit = info.storage_item_deposit.saturating_add(*amount) - }, - Deposit::Refund(amount) => { - info.storage_item_deposit = info.storage_item_deposit.saturating_sub(*amount) - }, + Deposit::Charge(amount) => + info.storage_item_deposit = info.storage_item_deposit.saturating_add(*amount), + Deposit::Refund(amount) => + info.storage_item_deposit = info.storage_item_deposit.saturating_sub(*amount), } bytes_deposit.saturating_add(&items_deposit) @@ -265,9 +261,8 @@ impl Contribution { fn update_contract(&self, info: Option<&mut ContractInfo>) -> DepositOf { match self { Self::Alive(diff) => diff.update_contract::(info), - Self::Terminated { deposit, beneficiary: _ } | Self::Checked(deposit) => { - deposit.clone() - }, + Self::Terminated { deposit, beneficiary: _ } | Self::Checked(deposit) => + deposit.clone(), } } } @@ -347,9 +342,8 @@ where /// Returns the state of the currently executed contract. fn contract_state(&self) -> ContractState { match &self.own_contribution { - Contribution::Terminated { deposit: _, beneficiary } => { - ContractState::Terminated { beneficiary: beneficiary.clone() } - }, + Contribution::Terminated { deposit: _, beneficiary } => + ContractState::Terminated { beneficiary: beneficiary.clone() }, _ => ContractState::Alive, } } diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index c58c9c51f46c..71d730aedf4f 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -149,8 +149,8 @@ pub mod test_utils { let code_info_len = CodeInfo::::max_encoded_len() as u64; // Calculate deposit to be reserved. // We add 2 storage items: one for code, other for code_info - DepositPerByte::get().saturating_mul(code_len as u64 + code_info_len) - + DepositPerItem::get().saturating_mul(2) + DepositPerByte::get().saturating_mul(code_len as u64 + code_info_len) + + DepositPerItem::get().saturating_mul(2) } pub fn ensure_stored(code_hash: sp_core::H256) -> usize { // Assert that code_info is stored diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index 4ed91d8a359b..7ddc928c694c 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -575,9 +575,8 @@ impl<'a, E: Ext, M: PolkaVmInstance> Runtime<'a, E, M> { log::error!(target: LOG_TARGET, "polkavm execution error: {error}"); Some(Err(Error::::ExecutionFailed.into())) }, - Ok(Finished) => { - Some(Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })) - }, + Ok(Finished) => + Some(Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })), Ok(Trap) => Some(Err(Error::::ContractTrapped.into())), Ok(Segfault(_)) => Some(Err(Error::::ExecutionFailed.into())), Ok(NotEnoughGas) => Some(Err(Error::::OutOfGas.into())), @@ -592,12 +591,11 @@ impl<'a, E: Ext, M: PolkaVmInstance> Runtime<'a, E, M> { instance.write_output(return_value); None }, - Err(TrapReason::Return(ReturnData { flags, data })) => { + Err(TrapReason::Return(ReturnData { flags, data })) => match ReturnFlags::from_bits(flags) { None => Some(Err(Error::::InvalidCallFlags.into())), Some(flags) => Some(Ok(ExecReturnValue { flags, data })), - } - }, + }, Err(TrapReason::Termination) => Some(Ok(Default::default())), Err(TrapReason::SupervisorError(error)) => Some(Err(error.into())), } @@ -1781,9 +1779,8 @@ pub mod env { Environment::new(self, memory, id, input_ptr, input_len, output_ptr, output_len_ptr); let ret = match chain_extension.call(env)? { RetVal::Converging(val) => Ok(val), - RetVal::Diverging { flags, data } => { - Err(TrapReason::Return(ReturnData { flags: flags.bits(), data })) - }, + RetVal::Diverging { flags, data } => + Err(TrapReason::Return(ReturnData { flags: flags.bits(), data })), }; self.chain_extension = Some(chain_extension); ret From f325b72effe725188a63e0873bd6d32342e2cf40 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Thu, 3 Oct 2024 08:03:37 +0200 Subject: [PATCH 16/35] Update substrate/frame/revive/src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexander Theißen --- substrate/frame/revive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 38736e9e6eca..82b2222723c9 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -94,7 +94,7 @@ type CodeVec = BoundedVec>; type EventRecordOf = EventRecord<::RuntimeEvent, ::Hash>; type DebugBuffer = BoundedVec>; -pub(crate) type ImmutableData = BoundedVec>; +type ImmutableData = BoundedVec>; /// Used as a sentinel value when reading and writing contract memory. /// From 6fd2d013a26021a4f082a26e543d310d6729e9f0 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Thu, 3 Oct 2024 08:20:39 +0200 Subject: [PATCH 17/35] private field and comments Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/exec.rs | 8 +++++--- substrate/frame/revive/src/storage.rs | 15 ++++++++++++++- substrate/frame/revive/src/wasm/runtime.rs | 3 +++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 0b109abc92a9..f4f1dc32faa1 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -1073,11 +1073,11 @@ where let frame = self.top_frame_mut(); let contract = frame.contract_info.as_contract().inspect(|info| { // Charge for immutable data stored during constructor execution. - if info.immutable_bytes == 0 { + if info.immutable_bytes() == 0 { return; }; let amount = StorageDeposit::Charge( - T::DepositPerByte::get().saturating_mul(info.immutable_bytes.into()), + T::DepositPerByte::get().saturating_mul(info.immutable_bytes().into()), ); frame.nested_storage.charge_deposit(frame.account_id.clone(), amount); }); @@ -1566,7 +1566,7 @@ where } let account_id = self.account_id().clone(); - self.top_frame_mut().contract_info.get(&account_id).immutable_bytes = data.len() as u32; + self.top_frame_mut().contract_info.get(&account_id).set_immutable_bytes(data.len() as u32); >::insert(T::AddressMapper::to_address(&account_id), &data); Ok(()) @@ -1691,6 +1691,8 @@ where /// /// After running the constructor, the new immutable data is already stored in /// `self.immutable_data` at the address of the (reverted) contract instantiation. + /// + /// The `set_code_hash` contract API stays disabled until this change is implemented. fn set_code_hash(&mut self, hash: H256) -> DispatchResult { let frame = top_frame_mut!(self); diff --git a/substrate/frame/revive/src/storage.rs b/substrate/frame/revive/src/storage.rs index 5cf568f7fee1..c62d148786d9 100644 --- a/substrate/frame/revive/src/storage.rs +++ b/substrate/frame/revive/src/storage.rs @@ -76,7 +76,7 @@ pub struct ContractInfo { /// calls. delegate_dependencies: DelegateDependencyMap, /// The size of the immutable data of this contract. - pub immutable_bytes: u32, + immutable_bytes: u32, } impl ContractInfo { @@ -365,6 +365,19 @@ impl ContractInfo { pub fn load_code_hash(account: &AccountIdOf) -> Option { >::get(&T::AddressMapper::to_address(account)).map(|i| i.code_hash) } + + /// Returns the amount of immutable bytes of this contract. + pub fn immutable_bytes(&self) -> u32 { + self.immutable_bytes + } + + /// Set the number of immutable bytes of this contract. + /// + /// Note: Changing the immutable bytes of a contract requires updating + /// the base deposit during the same transaction! + pub fn set_immutable_bytes(&mut self, immutable_bytes: u32) { + self.immutable_bytes = immutable_bytes + } } /// Information about what happened to the pre-existing value when calling [`ContractInfo::write`]. diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index 7ddc928c694c..6b8b0a411b73 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -1965,6 +1965,9 @@ pub mod env { /// Replace the contract code at the specified address with new code. /// See [`pallet_revive_uapi::HostFn::set_code_hash`]. + /// + /// Disabled until the internal implementation takes care of collecting + /// the immutable data of the new code hash. #[mutating] fn set_code_hash( &mut self, From cafbc2f177806d14856081e7e1a4b4c227d56934 Mon Sep 17 00:00:00 2001 From: xermicus Date: Thu, 3 Oct 2024 10:08:19 +0200 Subject: [PATCH 18/35] only charge the storage item on instantiate Signed-off-by: xermicus --- substrate/frame/revive/src/storage.rs | 11 +++-------- substrate/frame/revive/src/tests.rs | 25 +++++++++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/substrate/frame/revive/src/storage.rs b/substrate/frame/revive/src/storage.rs index c62d148786d9..120bd6a3caf2 100644 --- a/substrate/frame/revive/src/storage.rs +++ b/substrate/frame/revive/src/storage.rs @@ -241,8 +241,9 @@ impl ContractInfo { /// The base deposit is updated when the `code_hash` of the contract changes, as it depends on /// the deposit paid to upload the contract's code. pub fn update_base_deposit(&mut self, code_info: &CodeInfo) -> BalanceOf { + // The 2 items added are code info and immutable data let info_deposit = - Diff { bytes_added: self.encoded_size() as u32, items_added: 1, ..Default::default() } + Diff { bytes_added: self.encoded_size() as u32, items_added: 2, ..Default::default() } .update_contract::(None) .charge_or_zero(); @@ -251,13 +252,7 @@ impl ContractInfo { // to prevent abuse. let upload_deposit = T::CodeHashLockupDepositPercent::get().mul_ceil(code_info.deposit()); - // Immutable data is unique per contract and part of the base deposit. - let immutable_data_deposit = - T::DepositPerByte::get().saturating_mul(self.immutable_bytes.into()); - - let deposit = info_deposit - .saturating_add(upload_deposit) - .saturating_add(immutable_data_deposit); + let deposit = info_deposit.saturating_add(upload_deposit); self.storage_base_deposit = deposit; deposit } diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 71d730aedf4f..51647f896590 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -140,17 +140,22 @@ pub mod test_utils { pub fn contract_info_storage_deposit(addr: &H160) -> BalanceOf { let contract_info = self::get_contract(&addr); let info_size = contract_info.encoded_size() as u64; - DepositPerByte::get() + let immutable_size = contract_info.immutable_bytes() as u64; + let info_deposit = DepositPerByte::get() .saturating_mul(info_size) - .saturating_add(DepositPerItem::get()) + .saturating_add(DepositPerItem::get()); + let immutable_deposit = DepositPerByte::get() + .saturating_mul(immutable_size) + .saturating_add(DepositPerItem::get()); + info_deposit.saturating_add(immutable_deposit) } pub fn expected_deposit(code_len: usize) -> u64 { // For code_info, the deposit for max_encoded_len is taken. let code_info_len = CodeInfo::::max_encoded_len() as u64; // Calculate deposit to be reserved. // We add 2 storage items: one for code, other for code_info - DepositPerByte::get().saturating_mul(code_len as u64 + code_info_len) + - DepositPerItem::get().saturating_mul(2) + DepositPerByte::get().saturating_mul(code_len as u64 + code_info_len) + + DepositPerItem::get().saturating_mul(2) } pub fn ensure_stored(code_hash: sp_core::H256) -> usize { // Assert that code_info is stored @@ -3530,8 +3535,11 @@ mod run_tests { // Set enough deposit limit for the child instantiate. This should succeed. let result = builder::bare_call(addr_caller) .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(callee_info_len + 2 + ED + 4) - .data((1u32, &code_hash_callee, U256::from(callee_info_len + 2 + ED + 3)).encode()) + .storage_deposit_limit(callee_info_len + 2 + ED + 4 + 2) + .data( + (1u32, &code_hash_callee, U256::from(callee_info_len + 2 + ED + 3 + 2)) + .encode(), + ) .build(); let returned = result.result.unwrap(); @@ -3548,12 +3556,13 @@ mod run_tests { // - callee instantiation deposit = (callee_info_len + 2) // - callee account ED // - for writing an item of 1 byte to storage = 3 Balance + // - Immutable data storage item deposit assert_eq!( ::Currency::free_balance(&BOB), - 1_000_000 - (callee_info_len + 2 + ED + 3) + 1_000_000 - (callee_info_len + 2 + ED + 3 + 2) ); // Check that deposit due to be charged still includes these 3 Balance - assert_eq!(result.storage_deposit.charge_or_zero(), (callee_info_len + 2 + ED + 3)) + assert_eq!(result.storage_deposit.charge_or_zero(), (callee_info_len + 2 + ED + 3 + 2)) }); } From 068c4e10ab6ad0418b3ba37b6062e0067ee99c49 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Thu, 3 Oct 2024 13:39:36 +0200 Subject: [PATCH 19/35] charge storage deposit for setting immutable data Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/exec.rs | 21 +++++++------------ substrate/frame/revive/src/storage.rs | 29 ++++++++++++++++++--------- substrate/frame/revive/src/tests.rs | 14 ++++++++++++- 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index f4f1dc32faa1..239912a79717 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -53,7 +53,7 @@ use sp_core::{ }; use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; use sp_runtime::{ - traits::{BadOrigin, Convert, Dispatchable, Saturating, Zero}, + traits::{BadOrigin, Convert, Dispatchable, Zero}, DispatchError, SaturatedConversion, }; @@ -1070,21 +1070,11 @@ where return Err(Error::::TerminatedInConstructor.into()); } - let frame = self.top_frame_mut(); - let contract = frame.contract_info.as_contract().inspect(|info| { - // Charge for immutable data stored during constructor execution. - if info.immutable_bytes() == 0 { - return; - }; - let amount = StorageDeposit::Charge( - T::DepositPerByte::get().saturating_mul(info.immutable_bytes().into()), - ); - frame.nested_storage.charge_deposit(frame.account_id.clone(), amount); - }); - // If a special limit was set for the sub-call, we enforce it here. // This is needed because contract constructor might write to storage. // The sub-call will be rolled back in case the limit is exhausted. + let frame = self.top_frame_mut(); + let contract = frame.contract_info.as_contract(); frame.nested_storage.enforce_subcall_limit(contract)?; let caller = T::AddressMapper::to_address(self.caller().account_id()?); @@ -1566,7 +1556,10 @@ where } let account_id = self.account_id().clone(); - self.top_frame_mut().contract_info.get(&account_id).set_immutable_bytes(data.len() as u32); + let bytes = data.len() as u32; + let amount = self.top_frame_mut().contract_info().set_immutable_bytes(bytes); + self.top_frame_mut().nested_storage.charge_deposit(account_id.clone(), amount); + >::insert(T::AddressMapper::to_address(&account_id), &data); Ok(()) diff --git a/substrate/frame/revive/src/storage.rs b/substrate/frame/revive/src/storage.rs index 120bd6a3caf2..f2a3830eee6c 100644 --- a/substrate/frame/revive/src/storage.rs +++ b/substrate/frame/revive/src/storage.rs @@ -26,7 +26,7 @@ use crate::{ storage::meter::Diff, weights::WeightInfo, BalanceOf, CodeInfo, Config, ContractInfoOf, DeletionQueue, DeletionQueueCounter, Error, - TrieId, SENTINEL, + StorageDeposit, TrieId, SENTINEL, }; use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; @@ -36,6 +36,7 @@ use frame_support::{ weights::{Weight, WeightMeter}, CloneNoBound, DefaultNoBound, }; +use meter::DepositOf; use scale_info::TypeInfo; use sp_core::{ConstU32, Get, H160}; use sp_io::KillStorageResult; @@ -205,12 +206,13 @@ impl ContractInfo { if let Some(storage_meter) = storage_meter { let mut diff = meter::Diff::default(); match (old_len, new_value.as_ref().map(|v| v.len() as u32)) { - (Some(old_len), Some(new_len)) => + (Some(old_len), Some(new_len)) => { if new_len > old_len { diff.bytes_added = new_len - old_len; } else { diff.bytes_removed = old_len - new_len; - }, + } + }, (None, Some(new_len)) => { diff.bytes_added = new_len; diff.items_added = 1; @@ -303,8 +305,8 @@ impl ContractInfo { /// of those keys can be deleted from the deletion queue given the supplied weight limit. pub fn deletion_budget(meter: &WeightMeter) -> (Weight, u32) { let base_weight = T::WeightInfo::on_process_deletion_queue_batch(); - let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) - - T::WeightInfo::on_initialize_per_trie_key(0); + let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) + - T::WeightInfo::on_initialize_per_trie_key(0); // `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. @@ -368,10 +370,19 @@ impl ContractInfo { /// Set the number of immutable bytes of this contract. /// - /// Note: Changing the immutable bytes of a contract requires updating - /// the base deposit during the same transaction! - pub fn set_immutable_bytes(&mut self, immutable_bytes: u32) { - self.immutable_bytes = immutable_bytes + /// Returns the storage deposit to be charged. + pub fn set_immutable_bytes(&mut self, immutable_bytes: u32) -> DepositOf { + let diff = self.immutable_bytes.abs_diff(immutable_bytes); + let amount = T::DepositPerByte::get().saturating_mul(diff.into()); + let deposit = if immutable_bytes >= self.immutable_bytes { + StorageDeposit::Charge(amount) + } else { + StorageDeposit::Refund(amount) + }; + + self.immutable_bytes = immutable_bytes; + + deposit } } diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 51647f896590..679f5b590afa 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -139,14 +139,17 @@ pub mod test_utils { } pub fn contract_info_storage_deposit(addr: &H160) -> BalanceOf { let contract_info = self::get_contract(&addr); + let info_size = contract_info.encoded_size() as u64; - let immutable_size = contract_info.immutable_bytes() as u64; let info_deposit = DepositPerByte::get() .saturating_mul(info_size) .saturating_add(DepositPerItem::get()); + + let immutable_size = contract_info.immutable_bytes() as u64; let immutable_deposit = DepositPerByte::get() .saturating_mul(immutable_size) .saturating_add(DepositPerItem::get()); + info_deposit.saturating_add(immutable_deposit) } pub fn expected_deposit(code_len: usize) -> u64 { @@ -4378,6 +4381,15 @@ mod run_tests { .data(data.to_vec()) .build_and_unwrap_contract(); + // Storing immmutable data charges storage deposit; verify it explicitly. + assert_eq!( + test_utils::get_balance_on_hold( + &HoldReason::StorageDepositReserve.into(), + &::AddressMapper::to_account_id(&addr) + ), + test_utils::contract_info_storage_deposit(&addr) + ); + // Call the contract: Asserts the input to equal the immutable data assert_ok!(builder::call(addr).data(data.to_vec()).build()); }); From cccf94c6148b3f212a218e26279b7ba54494675d Mon Sep 17 00:00:00 2001 From: xermicus Date: Thu, 3 Oct 2024 13:50:29 +0200 Subject: [PATCH 20/35] precharge Signed-off-by: xermicus --- substrate/frame/revive/src/wasm/runtime.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index 6b8b0a411b73..452b986c0f6d 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -1528,8 +1528,9 @@ pub mod env { out_ptr: u32, out_len_ptr: u32, ) -> Result<(), TrapReason> { + let charged = self.charge_gas(RuntimeCosts::GetImmutableData(limits::IMMUTABLE_BYTES))?; let data = self.ext.get_immutable_data()?; - self.charge_gas(RuntimeCosts::GetImmutableData(data.len() as u32))?; + self.adjust_gas(charged, RuntimeCosts::GetImmutableData(data.len() as u32)); self.write_sandbox_output(memory, out_ptr, out_len_ptr, &data, false, already_charged)?; Ok(()) } From d4fbe660c5846b73258a37ee9cd04ed6461d58e0 Mon Sep 17 00:00:00 2001 From: xermicus Date: Thu, 3 Oct 2024 14:08:23 +0200 Subject: [PATCH 21/35] revert random fmt changes Signed-off-by: xermicus --- substrate/frame/revive/src/benchmarking/mod.rs | 2 +- substrate/frame/revive/src/limits.rs | 1 + substrate/frame/revive/src/storage.rs | 15 +++++++-------- substrate/frame/revive/src/storage/meter.rs | 4 ++-- substrate/frame/revive/src/tests.rs | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/substrate/frame/revive/src/benchmarking/mod.rs b/substrate/frame/revive/src/benchmarking/mod.rs index 5404a660a906..efddaf1a6f5c 100644 --- a/substrate/frame/revive/src/benchmarking/mod.rs +++ b/substrate/frame/revive/src/benchmarking/mod.rs @@ -169,7 +169,7 @@ where }; if key == &key_new { - continue; + continue } child::put_raw(&child_trie_info, &key_new, &value); } diff --git a/substrate/frame/revive/src/limits.rs b/substrate/frame/revive/src/limits.rs index a09b64eb5b5d..50cdba6d0c91 100644 --- a/substrate/frame/revive/src/limits.rs +++ b/substrate/frame/revive/src/limits.rs @@ -68,6 +68,7 @@ pub const PAGE_SIZE: u32 = 4 * 1024; /// The maximum amount of immutable bytes a single contract can store. /// /// The current limit of 4kb allows storing up 16 U256 immutable variables. +/// Which should always be enough because Solidity allows for 16 local (stack) variables. pub const IMMUTABLE_BYTES: u32 = 4 * 1024; /// Limits that are only enforced on code upload. diff --git a/substrate/frame/revive/src/storage.rs b/substrate/frame/revive/src/storage.rs index f2a3830eee6c..5d8c709c3183 100644 --- a/substrate/frame/revive/src/storage.rs +++ b/substrate/frame/revive/src/storage.rs @@ -206,13 +206,12 @@ impl ContractInfo { if let Some(storage_meter) = storage_meter { let mut diff = meter::Diff::default(); match (old_len, new_value.as_ref().map(|v| v.len() as u32)) { - (Some(old_len), Some(new_len)) => { + (Some(old_len), Some(new_len)) => if new_len > old_len { diff.bytes_added = new_len - old_len; } else { diff.bytes_removed = old_len - new_len; - } - }, + }, (None, Some(new_len)) => { diff.bytes_added = new_len; diff.items_added = 1; @@ -305,8 +304,8 @@ impl ContractInfo { /// of those keys can be deleted from the deletion queue given the supplied weight limit. pub fn deletion_budget(meter: &WeightMeter) -> (Weight, u32) { let base_weight = T::WeightInfo::on_process_deletion_queue_batch(); - let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) - - T::WeightInfo::on_initialize_per_trie_key(0); + let weight_per_key = T::WeightInfo::on_initialize_per_trie_key(1) - + T::WeightInfo::on_initialize_per_trie_key(0); // `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. @@ -322,7 +321,7 @@ impl ContractInfo { /// Delete as many items from the deletion queue possible within the supplied weight limit. pub fn process_deletion_queue_batch(meter: &mut WeightMeter) { if meter.try_consume(T::WeightInfo::on_process_deletion_queue_batch()).is_err() { - return; + return }; let mut queue = >::load(); @@ -345,7 +344,7 @@ impl ContractInfo { // This happens when our budget wasn't large enough to remove all keys. KillStorageResult::SomeRemaining(keys_removed) => { remaining_key_budget.saturating_reduce(keys_removed); - break; + break }, KillStorageResult::AllRemoved(keys_removed) => { entry.remove(); @@ -491,7 +490,7 @@ impl DeletionQueueManager { /// the cost of an extra call to `sp_io::storage::next_key` to lookup the next entry in the map fn next(&mut self) -> Option> { if self.is_empty() { - return None; + return None } let entry = >::get(self.delete_counter); diff --git a/substrate/frame/revive/src/storage/meter.rs b/substrate/frame/revive/src/storage/meter.rs index 325db202b1a2..b1fed0cd8c5d 100644 --- a/substrate/frame/revive/src/storage/meter.rs +++ b/substrate/frame/revive/src/storage/meter.rs @@ -167,7 +167,7 @@ impl Diff { } else { debug_assert_eq!(self.bytes_removed, 0); debug_assert_eq!(self.items_removed, 0); - return bytes_deposit.saturating_add(&items_deposit); + return bytes_deposit.saturating_add(&items_deposit) }; // Refunds are calculated pro rata based on the accumulated storage within the contract @@ -370,7 +370,7 @@ where let limit = E::check_limit(o, limit, min_leftover)?; Ok(Self { limit, ..Default::default() }) }, - }; + } } /// The total amount of deposit that should change hands as result of the execution diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 679f5b590afa..bd38f2e191d5 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -157,8 +157,8 @@ pub mod test_utils { let code_info_len = CodeInfo::::max_encoded_len() as u64; // Calculate deposit to be reserved. // We add 2 storage items: one for code, other for code_info - DepositPerByte::get().saturating_mul(code_len as u64 + code_info_len) - + DepositPerItem::get().saturating_mul(2) + DepositPerByte::get().saturating_mul(code_len as u64 + code_info_len) + + DepositPerItem::get().saturating_mul(2) } pub fn ensure_stored(code_hash: sp_core::H256) -> usize { // Assert that code_info is stored From 4a8c49ba50f79287dfb32962ed61d84c5a6278cf Mon Sep 17 00:00:00 2001 From: xermicus Date: Thu, 3 Oct 2024 14:09:49 +0200 Subject: [PATCH 22/35] remove block Signed-off-by: xermicus --- substrate/frame/revive/uapi/src/host/riscv32.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/substrate/frame/revive/uapi/src/host/riscv32.rs b/substrate/frame/revive/uapi/src/host/riscv32.rs index 26d3c84a230d..866b0ee8dd17 100644 --- a/substrate/frame/revive/uapi/src/host/riscv32.rs +++ b/substrate/frame/revive/uapi/src/host/riscv32.rs @@ -506,9 +506,7 @@ impl HostFn for HostFnImpl { fn get_immutable_data(output: &mut &mut [u8]) { let mut output_len = output.len() as u32; - { - unsafe { sys::get_immutable_data(output.as_mut_ptr(), &mut output_len) }; - } + unsafe { sys::get_immutable_data(output.as_mut_ptr(), &mut output_len) }; extract_from_slice(output, output_len as usize); } From 1257615ef4181fca1ddace0d89b77c6888244575 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Thu, 3 Oct 2024 14:35:57 +0200 Subject: [PATCH 23/35] fix feature gate Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/exec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 239912a79717..b3e98ac41cdb 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -1301,7 +1301,7 @@ where /// Certain APIs, e.g. `{set,get}_immutable_data` behave differently depending /// on the configured entry point. Thus, we allow setting the export manually. - #[cfg(feature = "runtime-benchmarks")] + #[cfg(all(feature = "runtime-benchmarks", feature = "riscv"))] pub(crate) fn override_export(&mut self, export: ExportedFunction) { self.top_frame_mut().entry_point = export; } From a89761b7e598a1dd249a3f4fcf0839bc17dd8df1 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Thu, 3 Oct 2024 16:16:53 +0200 Subject: [PATCH 24/35] add another assertion Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index bd38f2e191d5..60203c7e02e3 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -4389,6 +4389,7 @@ mod run_tests { ), test_utils::contract_info_storage_deposit(&addr) ); + assert_eq!(test_utils::get_contract(&addr).immutable_bytes(), data.len() as u32); // Call the contract: Asserts the input to equal the immutable data assert_ok!(builder::call(addr).data(data.to_vec()).build()); From 40a2e533655937a41411be9bef8050df0b18fe72 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Fri, 4 Oct 2024 16:05:19 +0200 Subject: [PATCH 25/35] do not charge the immutable item if it was not set Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/exec.rs | 2 +- substrate/frame/revive/src/storage.rs | 32 ++++++++++++++-------- substrate/frame/revive/src/tests.rs | 19 +++++++------ substrate/frame/revive/src/wasm/runtime.rs | 2 +- substrate/frame/revive/uapi/src/host.rs | 12 ++++++-- 5 files changed, 42 insertions(+), 25 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index b3e98ac41cdb..3af4facd6b36 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -1557,7 +1557,7 @@ where let account_id = self.account_id().clone(); let bytes = data.len() as u32; - let amount = self.top_frame_mut().contract_info().set_immutable_bytes(bytes); + let amount = self.top_frame_mut().contract_info().set_immutable_bytes(bytes)?; self.top_frame_mut().nested_storage.charge_deposit(account_id.clone(), amount); >::insert(T::AddressMapper::to_address(&account_id), &data); diff --git a/substrate/frame/revive/src/storage.rs b/substrate/frame/revive/src/storage.rs index 5d8c709c3183..ad2a34a4b343 100644 --- a/substrate/frame/revive/src/storage.rs +++ b/substrate/frame/revive/src/storage.rs @@ -242,9 +242,8 @@ impl ContractInfo { /// The base deposit is updated when the `code_hash` of the contract changes, as it depends on /// the deposit paid to upload the contract's code. pub fn update_base_deposit(&mut self, code_info: &CodeInfo) -> BalanceOf { - // The 2 items added are code info and immutable data let info_deposit = - Diff { bytes_added: self.encoded_size() as u32, items_added: 2, ..Default::default() } + Diff { bytes_added: self.encoded_size() as u32, items_added: 1, ..Default::default() } .update_contract::(None) .charge_or_zero(); @@ -369,19 +368,28 @@ impl ContractInfo { /// Set the number of immutable bytes of this contract. /// - /// Returns the storage deposit to be charged. - pub fn set_immutable_bytes(&mut self, immutable_bytes: u32) -> DepositOf { - let diff = self.immutable_bytes.abs_diff(immutable_bytes); - let amount = T::DepositPerByte::get().saturating_mul(diff.into()); - let deposit = if immutable_bytes >= self.immutable_bytes { - StorageDeposit::Charge(amount) - } else { - StorageDeposit::Refund(amount) - }; + /// On success, returns the storage deposit to be charged. + /// + /// Returns `Err(InvalidImmutableAccess)` if: + /// - The immutable bytes of this contract are not 0. + /// This indicates that the immutable data have already been set; + /// it is only valid to set the immutable data exactly once. + /// - The provided `immutable_bytes` value was 0; + /// it is invalid to set empty immutable data. + pub fn set_immutable_bytes( + &mut self, + immutable_bytes: u32, + ) -> Result, DispatchError> { + if self.immutable_bytes != 0 || immutable_bytes == 0 { + return Err(Error::::InvalidImmutableAccess.into()); + } self.immutable_bytes = immutable_bytes; - deposit + let amount = T::DepositPerByte::get() + .saturating_mul(immutable_bytes.into()) + .saturating_add(T::DepositPerItem::get()); + Ok(StorageDeposit::Charge(amount)) } } diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 60203c7e02e3..e4e09762a01b 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -139,18 +139,19 @@ pub mod test_utils { } pub fn contract_info_storage_deposit(addr: &H160) -> BalanceOf { let contract_info = self::get_contract(&addr); - let info_size = contract_info.encoded_size() as u64; let info_deposit = DepositPerByte::get() .saturating_mul(info_size) .saturating_add(DepositPerItem::get()); - let immutable_size = contract_info.immutable_bytes() as u64; - let immutable_deposit = DepositPerByte::get() - .saturating_mul(immutable_size) - .saturating_add(DepositPerItem::get()); - - info_deposit.saturating_add(immutable_deposit) + if immutable_size > 0 { + let immutable_deposit = DepositPerByte::get() + .saturating_mul(immutable_size) + .saturating_add(DepositPerItem::get()); + info_deposit.saturating_add(immutable_deposit) + } else { + info_deposit + } } pub fn expected_deposit(code_len: usize) -> u64 { // For code_info, the deposit for max_encoded_len is taken. @@ -3562,10 +3563,10 @@ mod run_tests { // - Immutable data storage item deposit assert_eq!( ::Currency::free_balance(&BOB), - 1_000_000 - (callee_info_len + 2 + ED + 3 + 2) + 1_000_000 - (callee_info_len + 2 + ED + 3) ); // Check that deposit due to be charged still includes these 3 Balance - assert_eq!(result.storage_deposit.charge_or_zero(), (callee_info_len + 2 + ED + 3 + 2)) + assert_eq!(result.storage_deposit.charge_or_zero(), (callee_info_len + 2 + ED + 3)) }); } diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index 7918e56f7000..485abbfda225 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -1536,7 +1536,7 @@ pub mod env { } /// Attaches the supplied immutable data to the currently executing contract. - /// See [`pallet_revive_uapi::HostFn::get_immutable_data`]. + /// See [`pallet_revive_uapi::HostFn::set_immutable_data`]. #[api_version(0)] fn set_immutable_data(&mut self, memory: &mut M, ptr: u32, len: u32) -> Result<(), TrapReason> { if len > limits::IMMUTABLE_BYTES { diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs index 6706114d198a..f29bd2187e22 100644 --- a/substrate/frame/revive/uapi/src/host.rs +++ b/substrate/frame/revive/uapi/src/host.rs @@ -58,7 +58,10 @@ pub trait HostFn: private::Sealed { /// Get the contract immutable data. /// - /// Traps if called from within the deploy export. + /// Traps if: + /// - Called from within the deploy export. + /// - Called by contracts that didn't set immutable data by calling [`set_immutable_data`] + /// during their constructor execution. /// /// # Parameters /// - `output`: A reference to the output buffer to write the immutable bytes. @@ -66,7 +69,12 @@ pub trait HostFn: private::Sealed { /// Set the contract immutable data. /// - /// Traps if called from within the call export. + /// It is only valid to set non-empty immutable data in the constructor once. + /// + /// Traps if: + /// - Called from within the call export. + /// - Called more than once. + /// - The provided data was empty. /// /// # Parameters /// - `data`: A reference to the data to be stored as immutable bytes. From d374385bd9eb6ea78bc75e1652276d3795586686 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Fri, 4 Oct 2024 16:12:32 +0200 Subject: [PATCH 26/35] Update substrate/frame/revive/src/storage/meter.rs Co-authored-by: PG Herveou --- substrate/frame/revive/src/storage/meter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/storage/meter.rs b/substrate/frame/revive/src/storage/meter.rs index b1fed0cd8c5d..780cd0d23cca 100644 --- a/substrate/frame/revive/src/storage/meter.rs +++ b/substrate/frame/revive/src/storage/meter.rs @@ -479,7 +479,7 @@ impl> RawMeter { } if let Deposit::Charge(amount) = total_deposit { if amount > self.limit { - return Err(>::StorageDepositLimitExhausted.into()); + return Err(>::StorageDepositLimitExhausted.into()) } } Ok(()) From 35b6e2afc6af810e5067997fc8dd88cad09e042e Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Fri, 4 Oct 2024 14:12:58 +0000 Subject: [PATCH 27/35] ".git/.scripts/commands/fmt/fmt.sh" --- substrate/frame/revive/src/storage.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/substrate/frame/revive/src/storage.rs b/substrate/frame/revive/src/storage.rs index ad2a34a4b343..71cfadf77ae2 100644 --- a/substrate/frame/revive/src/storage.rs +++ b/substrate/frame/revive/src/storage.rs @@ -371,11 +371,9 @@ impl ContractInfo { /// On success, returns the storage deposit to be charged. /// /// Returns `Err(InvalidImmutableAccess)` if: - /// - The immutable bytes of this contract are not 0. - /// This indicates that the immutable data have already been set; - /// it is only valid to set the immutable data exactly once. - /// - The provided `immutable_bytes` value was 0; - /// it is invalid to set empty immutable data. + /// - The immutable bytes of this contract are not 0. This indicates that the immutable data + /// have already been set; it is only valid to set the immutable data exactly once. + /// - The provided `immutable_bytes` value was 0; it is invalid to set empty immutable data. pub fn set_immutable_bytes( &mut self, immutable_bytes: u32, From fe83697ea661118691e9939a2a1d7df6ee246c07 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Fri, 4 Oct 2024 16:49:45 +0200 Subject: [PATCH 28/35] add test for error conditions Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/exec.rs | 70 +++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 3af4facd6b36..f8e0527f3210 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -4355,7 +4355,7 @@ mod tests { let value = ::Currency::minimum_balance().into(); assert_eq!( - ctx.ext.set_immutable_data(Default::default()), + ctx.ext.set_immutable_data(vec![0, 1, 2, 3].try_into().unwrap()), Err(Error::::InvalidImmutableAccess.into()) ); @@ -4461,4 +4461,72 @@ mod tests { .unwrap() }); } + + #[test] + fn immutable_data_set_works_only_once() { + let dummy_ch = MockLoader::insert(Constructor, move |ctx, _| { + // Calling `set_immutable_data` the first time should work + assert_ok!(ctx.ext.set_immutable_data(vec![0, 1, 2, 3].try_into().unwrap())); + // Calling `set_immutable_data` the second time should error out + assert_eq!( + ctx.ext.set_immutable_data(vec![0, 1, 2, 3].try_into().unwrap()), + Err(Error::::InvalidImmutableAccess.into()) + ); + exec_success() + }); + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .existential_deposit(15) + .build() + .execute_with(|| { + set_balance(&ALICE, 1000); + place_contract(&BOB, dummy_ch); + let origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new(&origin, 200, 0).unwrap(); + + MockStack::run_call( + origin, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + 0, + vec![], + None, + ) + .unwrap() + }); + } + + #[test] + fn immutable_data_set_errors_with_empty_data() { + let dummy_ch = MockLoader::insert(Constructor, move |ctx, _| { + // Calling `set_immutable_data` with empty data should error out + assert_eq!( + ctx.ext.set_immutable_data(Default::default()), + Err(Error::::InvalidImmutableAccess.into()) + ); + exec_success() + }); + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .existential_deposit(15) + .build() + .execute_with(|| { + set_balance(&ALICE, 1000); + place_contract(&BOB, dummy_ch); + let origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new(&origin, 200, 0).unwrap(); + + MockStack::run_call( + origin, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + 0, + vec![], + None, + ) + .unwrap() + }); + } } From 91a3eaa3ba496ebdb4e828bc1a7e777b4366e767 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Fri, 4 Oct 2024 17:04:36 +0200 Subject: [PATCH 29/35] fix docs Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/uapi/src/host.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs index f29bd2187e22..02ce01561f6c 100644 --- a/substrate/frame/revive/uapi/src/host.rs +++ b/substrate/frame/revive/uapi/src/host.rs @@ -60,7 +60,7 @@ pub trait HostFn: private::Sealed { /// /// Traps if: /// - Called from within the deploy export. - /// - Called by contracts that didn't set immutable data by calling [`set_immutable_data`] + /// - Called by contracts that didn't set immutable data by calling `set_immutable_data` /// during their constructor execution. /// /// # Parameters From 19ab687ba4dc674588f133c87ed3684a5d62a7a8 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Fri, 4 Oct 2024 17:19:24 +0200 Subject: [PATCH 30/35] start benchmarks at length 1 since empty immutable data is not valid Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/benchmarking/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/src/benchmarking/mod.rs b/substrate/frame/revive/src/benchmarking/mod.rs index 7ed044f3dca2..ebafb6c7054a 100644 --- a/substrate/frame/revive/src/benchmarking/mod.rs +++ b/substrate/frame/revive/src/benchmarking/mod.rs @@ -629,7 +629,7 @@ mod benchmarks { } #[benchmark(pov_mode = Measured)] - fn seal_get_immutable_data(n: Linear<0, { limits::IMMUTABLE_BYTES }>) { + fn seal_get_immutable_data(n: Linear<1, { limits::IMMUTABLE_BYTES }>) { let len = n as usize; let immutable_data = vec![1u8; len]; @@ -652,7 +652,7 @@ mod benchmarks { } #[benchmark(pov_mode = Measured)] - fn seal_set_immutable_data(n: Linear<0, { limits::IMMUTABLE_BYTES }>) { + fn seal_set_immutable_data(n: Linear<1, { limits::IMMUTABLE_BYTES }>) { let len = n as usize; let mut memory = vec![1u8; len]; let mut setup = CallSetup::::default(); From 3122a774ea0ffb728c57fed178f70111af2b2418 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Fri, 4 Oct 2024 17:33:17 +0200 Subject: [PATCH 31/35] explain all error conditions for InvalidImmutableAccess Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index cfb9efb3942e..6d87fd904c3f 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -551,7 +551,8 @@ pub mod pallet { ExecutionFailed, /// Failed to convert a U256 to a Balance. BalanceConversionFailed, - /// Immutable data can only be during deploys and only be read during calls. + /// Immutable data can only be set during deploys and only be read during calls. + /// Additionally, it is only valid to set the data once and it must not be empty. InvalidImmutableAccess, } From 2a4d34d556631bacb53d91308ce6739e18e45ce7 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Fri, 4 Oct 2024 17:45:20 +0200 Subject: [PATCH 32/35] rename immutable_bytes to immutable_data_len Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/exec.rs | 4 ++-- substrate/frame/revive/src/storage.rs | 20 ++++++++++---------- substrate/frame/revive/src/storage/meter.rs | 12 ++++++------ substrate/frame/revive/src/tests.rs | 4 ++-- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index f8e0527f3210..793363ca9847 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -1556,8 +1556,8 @@ where } let account_id = self.account_id().clone(); - let bytes = data.len() as u32; - let amount = self.top_frame_mut().contract_info().set_immutable_bytes(bytes)?; + let len = data.len() as u32; + let amount = self.top_frame_mut().contract_info().set_immutable_data_len(len)?; self.top_frame_mut().nested_storage.charge_deposit(account_id.clone(), amount); >::insert(T::AddressMapper::to_address(&account_id), &data); diff --git a/substrate/frame/revive/src/storage.rs b/substrate/frame/revive/src/storage.rs index 71cfadf77ae2..db4db3e8eac3 100644 --- a/substrate/frame/revive/src/storage.rs +++ b/substrate/frame/revive/src/storage.rs @@ -77,7 +77,7 @@ pub struct ContractInfo { /// calls. delegate_dependencies: DelegateDependencyMap, /// The size of the immutable data of this contract. - immutable_bytes: u32, + immutable_data_len: u32, } impl ContractInfo { @@ -111,7 +111,7 @@ impl ContractInfo { storage_item_deposit: Zero::zero(), storage_base_deposit: Zero::zero(), delegate_dependencies: Default::default(), - immutable_bytes: 0, + immutable_data_len: 0, }; Ok(contract) @@ -362,8 +362,8 @@ impl ContractInfo { } /// Returns the amount of immutable bytes of this contract. - pub fn immutable_bytes(&self) -> u32 { - self.immutable_bytes + pub fn immutable_data_len(&self) -> u32 { + self.immutable_data_len } /// Set the number of immutable bytes of this contract. @@ -373,19 +373,19 @@ impl ContractInfo { /// Returns `Err(InvalidImmutableAccess)` if: /// - The immutable bytes of this contract are not 0. This indicates that the immutable data /// have already been set; it is only valid to set the immutable data exactly once. - /// - The provided `immutable_bytes` value was 0; it is invalid to set empty immutable data. - pub fn set_immutable_bytes( + /// - The provided `immutable_data_len` value was 0; it is invalid to set empty immutable data. + pub fn set_immutable_data_len( &mut self, - immutable_bytes: u32, + immutable_data_len: u32, ) -> Result, DispatchError> { - if self.immutable_bytes != 0 || immutable_bytes == 0 { + if self.immutable_data_len != 0 || immutable_data_len == 0 { return Err(Error::::InvalidImmutableAccess.into()); } - self.immutable_bytes = immutable_bytes; + self.immutable_data_len = immutable_data_len; let amount = T::DepositPerByte::get() - .saturating_mul(immutable_bytes.into()) + .saturating_mul(immutable_data_len.into()) .saturating_add(T::DepositPerItem::get()); Ok(StorageDeposit::Charge(amount)) } diff --git a/substrate/frame/revive/src/storage/meter.rs b/substrate/frame/revive/src/storage/meter.rs index 780cd0d23cca..712010bc8257 100644 --- a/substrate/frame/revive/src/storage/meter.rs +++ b/substrate/frame/revive/src/storage/meter.rs @@ -674,7 +674,7 @@ mod tests { items: u32, bytes_deposit: BalanceOf, items_deposit: BalanceOf, - immutable_bytes: u32, + immutable_data_len: u32, } fn new_info(info: StorageInfo) -> ContractInfo { @@ -687,7 +687,7 @@ mod tests { storage_item_deposit: info.items_deposit, storage_base_deposit: Default::default(), delegate_dependencies: Default::default(), - immutable_bytes: info.immutable_bytes, + immutable_data_len: info.immutable_data_len, } } @@ -775,7 +775,7 @@ mod tests { items: 5, bytes_deposit: 100, items_deposit: 10, - immutable_bytes: 0, + immutable_data_len: 0, }); let mut nested0 = meter.nested(BalanceOf::::zero()); nested0.charge(&Diff { @@ -791,7 +791,7 @@ mod tests { items: 10, bytes_deposit: 100, items_deposit: 20, - immutable_bytes: 0, + immutable_data_len: 0, }); let mut nested1 = nested0.nested(BalanceOf::::zero()); nested1.charge(&Diff { items_removed: 5, ..Default::default() }); @@ -802,7 +802,7 @@ mod tests { items: 7, bytes_deposit: 100, items_deposit: 20, - immutable_bytes: 0, + immutable_data_len: 0, }); let mut nested2 = nested0.nested(BalanceOf::::zero()); nested2.charge(&Diff { items_removed: 7, ..Default::default() }); @@ -872,7 +872,7 @@ mod tests { items: 10, bytes_deposit: 100, items_deposit: 20, - immutable_bytes: 0, + immutable_data_len: 0, }); let mut nested1 = nested0.nested(BalanceOf::::zero()); nested1.charge(&Diff { items_removed: 5, ..Default::default() }); diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index e4e09762a01b..c7d1a8b2cf0d 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -143,7 +143,7 @@ pub mod test_utils { let info_deposit = DepositPerByte::get() .saturating_mul(info_size) .saturating_add(DepositPerItem::get()); - let immutable_size = contract_info.immutable_bytes() as u64; + let immutable_size = contract_info.immutable_data_len() as u64; if immutable_size > 0 { let immutable_deposit = DepositPerByte::get() .saturating_mul(immutable_size) @@ -4390,7 +4390,7 @@ mod run_tests { ), test_utils::contract_info_storage_deposit(&addr) ); - assert_eq!(test_utils::get_contract(&addr).immutable_bytes(), data.len() as u32); + assert_eq!(test_utils::get_contract(&addr).immutable_data_len(), data.len() as u32); // Call the contract: Asserts the input to equal the immutable data assert_ok!(builder::call(addr).data(data.to_vec()).build()); From 085d5e19291bcb4a393228b0d8d1de5756b193c4 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Fri, 4 Oct 2024 15:46:26 +0000 Subject: [PATCH 33/35] ".git/.scripts/commands/fmt/fmt.sh" --- substrate/frame/revive/uapi/src/host.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs index 02ce01561f6c..2106b8fb49b7 100644 --- a/substrate/frame/revive/uapi/src/host.rs +++ b/substrate/frame/revive/uapi/src/host.rs @@ -60,8 +60,8 @@ pub trait HostFn: private::Sealed { /// /// Traps if: /// - Called from within the deploy export. - /// - Called by contracts that didn't set immutable data by calling `set_immutable_data` - /// during their constructor execution. + /// - Called by contracts that didn't set immutable data by calling `set_immutable_data` during + /// their constructor execution. /// /// # Parameters /// - `output`: A reference to the output buffer to write the immutable bytes. From 15116a5b4187c592e9dedd721295b93fea6800ae Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Fri, 4 Oct 2024 16:04:41 +0000 Subject: [PATCH 34/35] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --features=riscv --pallet=pallet_revive --- substrate/frame/revive/src/weights.rs | 841 +++++++++++++------------- 1 file changed, 425 insertions(+), 416 deletions(-) diff --git a/substrate/frame/revive/src/weights.rs b/substrate/frame/revive/src/weights.rs index abf85b24db65..5e549de3a9fb 100644 --- a/substrate/frame/revive/src/weights.rs +++ b/substrate/frame/revive/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for `pallet_revive` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-10-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-jniz7bxx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -69,6 +69,8 @@ pub trait WeightInfo { fn seal_weight_left() -> Weight; fn seal_balance() -> Weight; fn seal_balance_of() -> Weight; + fn seal_get_immutable_data(n: u32, ) -> Weight; + fn seal_set_immutable_data(n: u32, ) -> Weight; fn seal_value_transferred() -> Weight; fn seal_minimum_balance() -> Weight; fn seal_block_number() -> Weight; @@ -112,8 +114,6 @@ pub trait WeightInfo { fn seal_set_code_hash() -> Weight; fn lock_delegate_dependency() -> Weight; fn unlock_delegate_dependency() -> Weight; - fn seal_get_immutable_data(n: u32,) -> Weight; - fn seal_set_immutable_data(n: u32,) -> Weight; fn instr(r: u32, ) -> Weight; } @@ -126,8 +126,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_783_000 picoseconds. - Weight::from_parts(2_883_000, 1594) + // Minimum execution time: 2_700_000 picoseconds. + Weight::from_parts(2_882_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -137,10 +137,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `392 + k * (69 ±0)` // Estimated: `382 + k * (70 ±0)` - // Minimum execution time: 13_394_000 picoseconds. - Weight::from_parts(305_292, 382) - // Standard Error: 1_217 - .saturating_add(Weight::from_parts(1_233_492, 0).saturating_mul(k.into())) + // Minimum execution time: 13_819_000 picoseconds. + Weight::from_parts(14_021_000, 382) + // Standard Error: 843 + .saturating_add(Weight::from_parts(1_222_715, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -148,7 +148,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(Weight::from_parts(0, 70).saturating_mul(k.into())) } /// Storage: `Revive::ContractInfoOf` (r:1 w:1) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) @@ -160,10 +160,10 @@ impl WeightInfo for SubstrateWeight { /// The range of component `c` is `[0, 262144]`. fn call_with_code_per_byte(_c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `834` - // Estimated: `4299` - // Minimum execution time: 78_977_000 picoseconds. - Weight::from_parts(81_687_641, 4299) + // Measured: `838` + // Estimated: `4303` + // Minimum execution time: 79_748_000 picoseconds. + Weight::from_parts(82_727_773, 4303) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -172,7 +172,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Balances::Holds` (r:2 w:2) /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) @@ -185,12 +185,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `303` // Estimated: `6232` - // Minimum execution time: 179_690_000 picoseconds. - Weight::from_parts(149_042_544, 6232) + // Minimum execution time: 179_270_000 picoseconds. + Weight::from_parts(149_933_578, 6232) // Standard Error: 11 - .saturating_add(Weight::from_parts(33, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(16, 0).saturating_mul(c.into())) // Standard Error: 11 - .saturating_add(Weight::from_parts(4_644, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_675, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -199,7 +199,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Revive::PristineCode` (r:1 w:0) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) @@ -211,15 +211,15 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `657` // Estimated: `4111` - // Minimum execution time: 156_389_000 picoseconds. - Weight::from_parts(130_603_882, 4111) + // Minimum execution time: 156_112_000 picoseconds. + Weight::from_parts(132_715_336, 4111) // Standard Error: 16 - .saturating_add(Weight::from_parts(4_594, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_599, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Revive::ContractInfoOf` (r:1 w:1) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) @@ -230,10 +230,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `834` - // Estimated: `4299` - // Minimum execution time: 80_108_000 picoseconds. - Weight::from_parts(81_555_000, 4299) + // Measured: `838` + // Estimated: `4303` + // Minimum execution time: 82_111_000 picoseconds. + Weight::from_parts(83_659_000, 4303) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -248,8 +248,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 49_297_000 picoseconds. - Weight::from_parts(50_873_587, 3574) + // Minimum execution time: 49_154_000 picoseconds. + Weight::from_parts(50_856_127, 3574) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -263,21 +263,21 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `285` // Estimated: `3750` - // Minimum execution time: 42_556_000 picoseconds. - Weight::from_parts(43_708_000, 3750) + // Minimum execution time: 41_347_000 picoseconds. + Weight::from_parts(42_272_000, 3750) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Revive::ContractInfoOf` (r:1 w:1) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:2 w:2) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `491` - // Estimated: `6431` - // Minimum execution time: 24_623_000 picoseconds. - Weight::from_parts(26_390_000, 6431) + // Measured: `495` + // Estimated: `6435` + // Minimum execution time: 25_234_000 picoseconds. + Weight::from_parts(26_339_000, 6435) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -286,79 +286,79 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_590_000 picoseconds. - Weight::from_parts(8_005_868, 0) - // Standard Error: 396 - .saturating_add(Weight::from_parts(203_612, 0).saturating_mul(r.into())) + // Minimum execution time: 7_509_000 picoseconds. + Weight::from_parts(9_047_452, 0) + // Standard Error: 165 + .saturating_add(Weight::from_parts(197_103, 0).saturating_mul(r.into())) } fn seal_caller() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 285_000 picoseconds. - Weight::from_parts(305_000, 0) + // Minimum execution time: 257_000 picoseconds. + Weight::from_parts(300_000, 0) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) fn seal_is_contract() -> Weight { // Proof Size summary in bytes: // Measured: `272` // Estimated: `3737` - // Minimum execution time: 6_711_000 picoseconds. - Weight::from_parts(7_103_000, 3737) + // Minimum execution time: 6_537_000 picoseconds. + Weight::from_parts(7_024_000, 3737) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) fn seal_code_hash() -> Weight { // Proof Size summary in bytes: - // Measured: `365` - // Estimated: `3830` - // Minimum execution time: 7_572_000 picoseconds. - Weight::from_parts(7_888_000, 3830) + // Measured: `369` + // Estimated: `3834` + // Minimum execution time: 7_571_000 picoseconds. + Weight::from_parts(8_060_000, 3834) .saturating_add(T::DbWeight::get().reads(1_u64)) } fn seal_own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 240_000 picoseconds. - Weight::from_parts(264_000, 0) + // Minimum execution time: 254_000 picoseconds. + Weight::from_parts(281_000, 0) } fn seal_caller_is_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 324_000 picoseconds. - Weight::from_parts(356_000, 0) + // Minimum execution time: 279_000 picoseconds. + Weight::from_parts(338_000, 0) } fn seal_caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 273_000 picoseconds. + // Minimum execution time: 240_000 picoseconds. Weight::from_parts(286_000, 0) } fn seal_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 255_000 picoseconds. - Weight::from_parts(296_000, 0) + // Minimum execution time: 198_000 picoseconds. + Weight::from_parts(262_000, 0) } fn seal_weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 610_000 picoseconds. - Weight::from_parts(701_000, 0) + // Minimum execution time: 593_000 picoseconds. + Weight::from_parts(665_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `0` - // Minimum execution time: 5_207_000 picoseconds. - Weight::from_parts(5_403_000, 0) + // Minimum execution time: 5_393_000 picoseconds. + Weight::from_parts(5_688_000, 0) } /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) @@ -366,62 +366,64 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3517` - // Minimum execution time: 3_829_000 picoseconds. - Weight::from_parts(3_977_000, 3517) + // Minimum execution time: 3_907_000 picoseconds. + Weight::from_parts(4_154_000, 3517) .saturating_add(T::DbWeight::get().reads(1_u64)) } - /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) - /// The range of component `n` is `[0, 4096]`. - fn seal_get_immutable_data(_n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `201 + n * (1 ±0)` - // Estimated: `7766` - // Minimum execution time: 7_711_000 picoseconds. - Weight::from_parts(10_350_000, 0) - .saturating_add(Weight::from_parts(0, 7766)) - .saturating_add(T::DbWeight::get().reads(1)) + /// The range of component `n` is `[1, 4096]`. + fn seal_get_immutable_data(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `205 + n * (1 ±0)` + // Estimated: `3670 + n * (1 ±0)` + // Minimum execution time: 5_700_000 picoseconds. + Weight::from_parts(6_362_270, 3670) + // Standard Error: 4 + .saturating_add(Weight::from_parts(749, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Revive::ImmutableDataOf` (r:0 w:1) /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) - /// The range of component `n` is `[0, 4096]`. - fn seal_set_immutable_data(_n: u32, ) -> Weight { + /// The range of component `n` is `[1, 4096]`. + fn seal_set_immutable_data(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_780_000 picoseconds. - Weight::from_parts(7_790_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) + // Minimum execution time: 2_041_000 picoseconds. + Weight::from_parts(2_216_694, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(620, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().writes(1_u64)) } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 245_000 picoseconds. - Weight::from_parts(266_000, 0) + // Minimum execution time: 229_000 picoseconds. + Weight::from_parts(261_000, 0) } fn seal_minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 256_000 picoseconds. - Weight::from_parts(288_000, 0) + // Minimum execution time: 226_000 picoseconds. + Weight::from_parts(270_000, 0) } fn seal_block_number() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 265_000 picoseconds. - Weight::from_parts(278_000, 0) + // Minimum execution time: 215_000 picoseconds. + Weight::from_parts(273_000, 0) } fn seal_now() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 243_000 picoseconds. - Weight::from_parts(272_000, 0) + // Minimum execution time: 242_000 picoseconds. + Weight::from_parts(271_000, 0) } /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `Measured`) @@ -429,8 +431,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `67` // Estimated: `1552` - // Minimum execution time: 5_467_000 picoseconds. - Weight::from_parts(5_607_000, 1552) + // Minimum execution time: 5_438_000 picoseconds. + Weight::from_parts(5_695_000, 1552) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// The range of component `n` is `[0, 262140]`. @@ -438,8 +440,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 438_000 picoseconds. - Weight::from_parts(532_907, 0) + // Minimum execution time: 405_000 picoseconds. + Weight::from_parts(539_737, 0) // Standard Error: 0 .saturating_add(Weight::from_parts(148, 0).saturating_mul(n.into())) } @@ -448,8 +450,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 259_000 picoseconds. - Weight::from_parts(629_625, 0) + // Minimum execution time: 222_000 picoseconds. + Weight::from_parts(539_301, 0) // Standard Error: 0 .saturating_add(Weight::from_parts(294, 0).saturating_mul(n.into())) } @@ -459,18 +461,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Revive::DeletionQueue` (r:0 w:1) /// Proof: `Revive::DeletionQueue` (`max_values`: None, `max_size`: Some(142), added: 2617, mode: `Measured`) + /// Storage: `Revive::ImmutableDataOf` (r:0 w:1) + /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) /// The range of component `n` is `[0, 32]`. fn seal_terminate(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `272 + n * (88 ±0)` // Estimated: `3738 + n * (2563 ±0)` - // Minimum execution time: 14_997_000 picoseconds. - Weight::from_parts(17_752_993, 3738) - // Standard Error: 9_865 - .saturating_add(Weight::from_parts(4_159_693, 0).saturating_mul(n.into())) + // Minimum execution time: 15_971_000 picoseconds. + Weight::from_parts(18_759_349, 3738) + // Standard Error: 10_298 + .saturating_add(Weight::from_parts(4_194_635, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2563).saturating_mul(n.into())) } @@ -480,20 +484,20 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_277_000 picoseconds. - Weight::from_parts(4_023_910, 0) - // Standard Error: 2_210 - .saturating_add(Weight::from_parts(202_823, 0).saturating_mul(t.into())) - // Standard Error: 19 - .saturating_add(Weight::from_parts(1_141, 0).saturating_mul(n.into())) + // Minimum execution time: 4_341_000 picoseconds. + Weight::from_parts(4_292_048, 0) + // Standard Error: 2_476 + .saturating_add(Weight::from_parts(193_480, 0).saturating_mul(t.into())) + // Standard Error: 22 + .saturating_add(Weight::from_parts(959, 0).saturating_mul(n.into())) } /// The range of component `i` is `[0, 262144]`. fn seal_debug_message(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 309_000 picoseconds. - Weight::from_parts(834_030, 0) + // Minimum execution time: 287_000 picoseconds. + Weight::from_parts(758_020, 0) // Standard Error: 1 .saturating_add(Weight::from_parts(814, 0).saturating_mul(i.into())) } @@ -503,8 +507,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `744` // Estimated: `744` - // Minimum execution time: 7_705_000 picoseconds. - Weight::from_parts(7_923_000, 744) + // Minimum execution time: 7_944_000 picoseconds. + Weight::from_parts(8_358_000, 744) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -513,8 +517,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `10754` // Estimated: `10754` - // Minimum execution time: 44_510_000 picoseconds. - Weight::from_parts(45_840_000, 10754) + // Minimum execution time: 44_950_000 picoseconds. + Weight::from_parts(45_575_000, 10754) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -523,8 +527,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `744` // Estimated: `744` - // Minimum execution time: 8_842_000 picoseconds. - Weight::from_parts(9_363_000, 744) + // Minimum execution time: 9_095_000 picoseconds. + Weight::from_parts(9_484_000, 744) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -534,8 +538,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `10754` // Estimated: `10754` - // Minimum execution time: 46_172_000 picoseconds. - Weight::from_parts(47_586_000, 10754) + // Minimum execution time: 46_814_000 picoseconds. + Weight::from_parts(47_710_000, 10754) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -547,12 +551,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + o * (1 ±0)` // Estimated: `247 + o * (1 ±0)` - // Minimum execution time: 9_158_000 picoseconds. - Weight::from_parts(9_708_320, 247) - // Standard Error: 36 - .saturating_add(Weight::from_parts(499, 0).saturating_mul(n.into())) - // Standard Error: 36 - .saturating_add(Weight::from_parts(672, 0).saturating_mul(o.into())) + // Minimum execution time: 9_496_000 picoseconds. + Weight::from_parts(9_875_533, 247) + // Standard Error: 34 + .saturating_add(Weight::from_parts(712, 0).saturating_mul(n.into())) + // Standard Error: 34 + .saturating_add(Weight::from_parts(777, 0).saturating_mul(o.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(o.into())) @@ -564,10 +568,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_885_000 picoseconds. - Weight::from_parts(9_597_656, 247) - // Standard Error: 48 - .saturating_add(Weight::from_parts(649, 0).saturating_mul(n.into())) + // Minimum execution time: 9_185_000 picoseconds. + Weight::from_parts(9_912_715, 247) + // Standard Error: 59 + .saturating_add(Weight::from_parts(567, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -579,10 +583,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_473_000 picoseconds. - Weight::from_parts(9_246_006, 247) - // Standard Error: 47 - .saturating_add(Weight::from_parts(1_468, 0).saturating_mul(n.into())) + // Minimum execution time: 8_586_000 picoseconds. + Weight::from_parts(9_536_041, 247) + // Standard Error: 54 + .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -593,10 +597,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 7_996_000 picoseconds. - Weight::from_parts(8_784_165, 247) + // Minimum execution time: 8_162_000 picoseconds. + Weight::from_parts(8_813_128, 247) // Standard Error: 43 - .saturating_add(Weight::from_parts(591, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(880, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -607,10 +611,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 9_246_000 picoseconds. - Weight::from_parts(10_239_803, 247) - // Standard Error: 57 - .saturating_add(Weight::from_parts(1_305, 0).saturating_mul(n.into())) + // Minimum execution time: 9_717_000 picoseconds. + Weight::from_parts(10_635_621, 247) + // Standard Error: 58 + .saturating_add(Weight::from_parts(1_430, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -619,36 +623,36 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_422_000 picoseconds. - Weight::from_parts(1_531_000, 0) + // Minimum execution time: 1_503_000 picoseconds. + Weight::from_parts(1_592_000, 0) } fn set_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_858_000 picoseconds. - Weight::from_parts(1_944_000, 0) + // Minimum execution time: 1_903_000 picoseconds. + Weight::from_parts(1_996_000, 0) } fn get_transient_storage_empty() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_443_000 picoseconds. - Weight::from_parts(1_506_000, 0) + // Minimum execution time: 1_432_000 picoseconds. + Weight::from_parts(1_534_000, 0) } fn get_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_592_000 picoseconds. - Weight::from_parts(1_651_000, 0) + // Minimum execution time: 1_606_000 picoseconds. + Weight::from_parts(1_669_000, 0) } fn rollback_transient_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 960_000 picoseconds. - Weight::from_parts(1_060_000, 0) + Weight::from_parts(1_089_000, 0) } /// The range of component `n` is `[0, 512]`. /// The range of component `o` is `[0, 512]`. @@ -656,62 +660,62 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_151_000 picoseconds. - Weight::from_parts(2_294_801, 0) + // Minimum execution time: 2_317_000 picoseconds. + Weight::from_parts(2_449_933, 0) // Standard Error: 11 - .saturating_add(Weight::from_parts(375, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(315, 0).saturating_mul(n.into())) // Standard Error: 11 - .saturating_add(Weight::from_parts(415, 0).saturating_mul(o.into())) + .saturating_add(Weight::from_parts(387, 0).saturating_mul(o.into())) } /// The range of component `n` is `[0, 512]`. fn seal_clear_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_880_000 picoseconds. - Weight::from_parts(2_259_773, 0) + // Minimum execution time: 1_980_000 picoseconds. + Weight::from_parts(2_352_243, 0) // Standard Error: 17 - .saturating_add(Weight::from_parts(356, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(372, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_get_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_755_000 picoseconds. - Weight::from_parts(1_968_235, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(387, 0).saturating_mul(n.into())) + // Minimum execution time: 1_857_000 picoseconds. + Weight::from_parts(2_082_050, 0) + // Standard Error: 13 + .saturating_add(Weight::from_parts(373, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_contains_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_618_000 picoseconds. - Weight::from_parts(1_811_972, 0) - // Standard Error: 12 - .saturating_add(Weight::from_parts(174, 0).saturating_mul(n.into())) + // Minimum execution time: 1_693_000 picoseconds. + Weight::from_parts(1_892_600, 0) + // Standard Error: 13 + .saturating_add(Weight::from_parts(193, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_take_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_482_000 picoseconds. - Weight::from_parts(2_682_484, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(2, 0).saturating_mul(n.into())) + // Minimum execution time: 2_620_000 picoseconds. + Weight::from_parts(2_818_388, 0) + // Standard Error: 15 + .saturating_add(Weight::from_parts(39, 0).saturating_mul(n.into())) } fn seal_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `0` - // Minimum execution time: 9_899_000 picoseconds. - Weight::from_parts(10_342_000, 0) + // Minimum execution time: 10_207_000 picoseconds. + Weight::from_parts(10_627_000, 0) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) @@ -720,12 +724,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 262144]`. fn seal_call(t: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `626 + t * (140 ±0)` - // Estimated: `4091 + t * (140 ±0)` - // Minimum execution time: 33_645_000 picoseconds. - Weight::from_parts(34_407_662, 4091) - // Standard Error: 36_930 - .saturating_add(Weight::from_parts(2_062_425, 0).saturating_mul(t.into())) + // Measured: `630 + t * (140 ±0)` + // Estimated: `4095 + t * (140 ±0)` + // Minimum execution time: 34_452_000 picoseconds. + Weight::from_parts(34_837_900, 4095) + // Standard Error: 30_385 + .saturating_add(Weight::from_parts(1_981_565, 0).saturating_mul(t.into())) // Standard Error: 0 .saturating_add(Weight::from_parts(3, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) @@ -740,8 +744,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `457` // Estimated: `3922` - // Minimum execution time: 26_924_000 picoseconds. - Weight::from_parts(27_753_000, 3922) + // Minimum execution time: 27_287_000 picoseconds. + Weight::from_parts(28_450_000, 3922) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) @@ -749,7 +753,7 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Revive::PristineCode` (r:1 w:0) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// The range of component `i` is `[0, 262144]`. @@ -757,10 +761,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `703` // Estimated: `4160` - // Minimum execution time: 117_979_000 picoseconds. - Weight::from_parts(105_415_117, 4160) + // Minimum execution time: 118_660_000 picoseconds. + Weight::from_parts(104_638_796, 4160) // Standard Error: 11 - .saturating_add(Weight::from_parts(4_293, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_296, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -769,64 +773,64 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 620_000 picoseconds. - Weight::from_parts(3_414_286, 0) + // Minimum execution time: 683_000 picoseconds. + Weight::from_parts(3_836_563, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(1_463, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_keccak_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_043_000 picoseconds. - Weight::from_parts(3_402_639, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_667, 0).saturating_mul(n.into())) + // Minimum execution time: 1_082_000 picoseconds. + Weight::from_parts(5_027_764, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_644, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_blake2_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 642_000 picoseconds. - Weight::from_parts(3_359_294, 0) + // Minimum execution time: 660_000 picoseconds. + Weight::from_parts(3_585_640, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(1_590, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_586, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_blake2_128(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 606_000 picoseconds. - Weight::from_parts(3_789_868, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_575, 0).saturating_mul(n.into())) + // Minimum execution time: 638_000 picoseconds. + Weight::from_parts(3_763_242, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_582, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 261889]`. fn seal_sr25519_verify(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 46_195_000 picoseconds. - Weight::from_parts(31_420_941, 0) + // Minimum execution time: 42_962_000 picoseconds. + Weight::from_parts(27_938_396, 0) // Standard Error: 13 - .saturating_add(Weight::from_parts(5_165, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(5_269, 0).saturating_mul(n.into())) } fn seal_ecdsa_recover() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 46_933_000 picoseconds. - Weight::from_parts(48_054_000, 0) + // Minimum execution time: 47_133_000 picoseconds. + Weight::from_parts(48_458_000, 0) } fn seal_ecdsa_to_eth_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_531_000 picoseconds. - Weight::from_parts(12_690_000, 0) + // Minimum execution time: 13_249_000 picoseconds. + Weight::from_parts(13_518_000, 0) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -834,8 +838,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `266` // Estimated: `3731` - // Minimum execution time: 14_694_000 picoseconds. - Weight::from_parts(15_032_000, 3731) + // Minimum execution time: 14_696_000 picoseconds. + Weight::from_parts(15_106_000, 3731) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -845,8 +849,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `304` // Estimated: `3769` - // Minimum execution time: 10_205_000 picoseconds. - Weight::from_parts(10_707_000, 3769) + // Minimum execution time: 10_292_000 picoseconds. + Weight::from_parts(10_670_000, 3769) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -856,8 +860,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `304` // Estimated: `3561` - // Minimum execution time: 9_025_000 picoseconds. - Weight::from_parts(9_517_000, 3561) + // Minimum execution time: 9_056_000 picoseconds. + Weight::from_parts(9_350_000, 3561) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -866,10 +870,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_451_000 picoseconds. - Weight::from_parts(10_620_260, 0) - // Standard Error: 77 - .saturating_add(Weight::from_parts(84_885, 0).saturating_mul(r.into())) + // Minimum execution time: 9_145_000 picoseconds. + Weight::from_parts(10_744_073, 0) + // Standard Error: 72 + .saturating_add(Weight::from_parts(84_813, 0).saturating_mul(r.into())) } } @@ -881,8 +885,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_783_000 picoseconds. - Weight::from_parts(2_883_000, 1594) + // Minimum execution time: 2_700_000 picoseconds. + Weight::from_parts(2_882_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -892,10 +896,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `392 + k * (69 ±0)` // Estimated: `382 + k * (70 ±0)` - // Minimum execution time: 13_394_000 picoseconds. - Weight::from_parts(305_292, 382) - // Standard Error: 1_217 - .saturating_add(Weight::from_parts(1_233_492, 0).saturating_mul(k.into())) + // Minimum execution time: 13_819_000 picoseconds. + Weight::from_parts(14_021_000, 382) + // Standard Error: 843 + .saturating_add(Weight::from_parts(1_222_715, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -903,7 +907,7 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 70).saturating_mul(k.into())) } /// Storage: `Revive::ContractInfoOf` (r:1 w:1) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) @@ -915,10 +919,10 @@ impl WeightInfo for () { /// The range of component `c` is `[0, 262144]`. fn call_with_code_per_byte(_c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `834` - // Estimated: `4299` - // Minimum execution time: 78_977_000 picoseconds. - Weight::from_parts(81_687_641, 4299) + // Measured: `838` + // Estimated: `4303` + // Minimum execution time: 79_748_000 picoseconds. + Weight::from_parts(82_727_773, 4303) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -927,7 +931,7 @@ impl WeightInfo for () { /// Storage: `Balances::Holds` (r:2 w:2) /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) @@ -940,12 +944,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `303` // Estimated: `6232` - // Minimum execution time: 179_690_000 picoseconds. - Weight::from_parts(149_042_544, 6232) + // Minimum execution time: 179_270_000 picoseconds. + Weight::from_parts(149_933_578, 6232) // Standard Error: 11 - .saturating_add(Weight::from_parts(33, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(16, 0).saturating_mul(c.into())) // Standard Error: 11 - .saturating_add(Weight::from_parts(4_644, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_675, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -954,7 +958,7 @@ impl WeightInfo for () { /// Storage: `Revive::PristineCode` (r:1 w:0) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) @@ -966,15 +970,15 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `657` // Estimated: `4111` - // Minimum execution time: 156_389_000 picoseconds. - Weight::from_parts(130_603_882, 4111) + // Minimum execution time: 156_112_000 picoseconds. + Weight::from_parts(132_715_336, 4111) // Standard Error: 16 - .saturating_add(Weight::from_parts(4_594, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_599, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Revive::ContractInfoOf` (r:1 w:1) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) @@ -985,10 +989,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `834` - // Estimated: `4299` - // Minimum execution time: 80_108_000 picoseconds. - Weight::from_parts(81_555_000, 4299) + // Measured: `838` + // Estimated: `4303` + // Minimum execution time: 82_111_000 picoseconds. + Weight::from_parts(83_659_000, 4303) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1003,8 +1007,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 49_297_000 picoseconds. - Weight::from_parts(50_873_587, 3574) + // Minimum execution time: 49_154_000 picoseconds. + Weight::from_parts(50_856_127, 3574) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1018,21 +1022,21 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `285` // Estimated: `3750` - // Minimum execution time: 42_556_000 picoseconds. - Weight::from_parts(43_708_000, 3750) + // Minimum execution time: 41_347_000 picoseconds. + Weight::from_parts(42_272_000, 3750) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Revive::ContractInfoOf` (r:1 w:1) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:2 w:2) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `491` - // Estimated: `6431` - // Minimum execution time: 24_623_000 picoseconds. - Weight::from_parts(26_390_000, 6431) + // Measured: `495` + // Estimated: `6435` + // Minimum execution time: 25_234_000 picoseconds. + Weight::from_parts(26_339_000, 6435) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1041,79 +1045,79 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_590_000 picoseconds. - Weight::from_parts(8_005_868, 0) - // Standard Error: 396 - .saturating_add(Weight::from_parts(203_612, 0).saturating_mul(r.into())) + // Minimum execution time: 7_509_000 picoseconds. + Weight::from_parts(9_047_452, 0) + // Standard Error: 165 + .saturating_add(Weight::from_parts(197_103, 0).saturating_mul(r.into())) } fn seal_caller() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 285_000 picoseconds. - Weight::from_parts(305_000, 0) + // Minimum execution time: 257_000 picoseconds. + Weight::from_parts(300_000, 0) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) fn seal_is_contract() -> Weight { // Proof Size summary in bytes: // Measured: `272` // Estimated: `3737` - // Minimum execution time: 6_711_000 picoseconds. - Weight::from_parts(7_103_000, 3737) + // Minimum execution time: 6_537_000 picoseconds. + Weight::from_parts(7_024_000, 3737) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) fn seal_code_hash() -> Weight { // Proof Size summary in bytes: - // Measured: `365` - // Estimated: `3830` - // Minimum execution time: 7_572_000 picoseconds. - Weight::from_parts(7_888_000, 3830) + // Measured: `369` + // Estimated: `3834` + // Minimum execution time: 7_571_000 picoseconds. + Weight::from_parts(8_060_000, 3834) .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn seal_own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 240_000 picoseconds. - Weight::from_parts(264_000, 0) + // Minimum execution time: 254_000 picoseconds. + Weight::from_parts(281_000, 0) } fn seal_caller_is_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 324_000 picoseconds. - Weight::from_parts(356_000, 0) + // Minimum execution time: 279_000 picoseconds. + Weight::from_parts(338_000, 0) } fn seal_caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 273_000 picoseconds. + // Minimum execution time: 240_000 picoseconds. Weight::from_parts(286_000, 0) } fn seal_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 255_000 picoseconds. - Weight::from_parts(296_000, 0) + // Minimum execution time: 198_000 picoseconds. + Weight::from_parts(262_000, 0) } fn seal_weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 610_000 picoseconds. - Weight::from_parts(701_000, 0) + // Minimum execution time: 593_000 picoseconds. + Weight::from_parts(665_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `0` - // Minimum execution time: 5_207_000 picoseconds. - Weight::from_parts(5_403_000, 0) + // Minimum execution time: 5_393_000 picoseconds. + Weight::from_parts(5_688_000, 0) } /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) @@ -1121,61 +1125,64 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3517` - // Minimum execution time: 3_829_000 picoseconds. - Weight::from_parts(3_977_000, 3517) + // Minimum execution time: 3_907_000 picoseconds. + Weight::from_parts(4_154_000, 3517) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) - /// The range of component `n` is `[0, 4096]`. - fn seal_get_immutable_data(_n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `201 + n * (1 ±0)` - // Estimated: `7766` - // Minimum execution time: 7_711_000 picoseconds. - Weight::from_parts(10_350_000, 0) - .saturating_add(Weight::from_parts(0, 7766)) - .saturating_add(RocksDbWeight::get().reads(1)) + /// The range of component `n` is `[1, 4096]`. + fn seal_get_immutable_data(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `205 + n * (1 ±0)` + // Estimated: `3670 + n * (1 ±0)` + // Minimum execution time: 5_700_000 picoseconds. + Weight::from_parts(6_362_270, 3670) + // Standard Error: 4 + .saturating_add(Weight::from_parts(749, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Revive::ImmutableDataOf` (r:0 w:1) /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) - /// The range of component `n` is `[0, 4096]`. - fn seal_set_immutable_data(_n: u32, ) -> Weight { + /// The range of component `n` is `[1, 4096]`. + fn seal_set_immutable_data(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_780_000 picoseconds. - Weight::from_parts(7_790_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Minimum execution time: 2_041_000 picoseconds. + Weight::from_parts(2_216_694, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(620, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 245_000 picoseconds. - Weight::from_parts(266_000, 0) + // Minimum execution time: 229_000 picoseconds. + Weight::from_parts(261_000, 0) } fn seal_minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 256_000 picoseconds. - Weight::from_parts(288_000, 0) + // Minimum execution time: 226_000 picoseconds. + Weight::from_parts(270_000, 0) } fn seal_block_number() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 265_000 picoseconds. - Weight::from_parts(278_000, 0) + // Minimum execution time: 215_000 picoseconds. + Weight::from_parts(273_000, 0) } fn seal_now() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 243_000 picoseconds. - Weight::from_parts(272_000, 0) + // Minimum execution time: 242_000 picoseconds. + Weight::from_parts(271_000, 0) } /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `Measured`) @@ -1183,8 +1190,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `67` // Estimated: `1552` - // Minimum execution time: 5_467_000 picoseconds. - Weight::from_parts(5_607_000, 1552) + // Minimum execution time: 5_438_000 picoseconds. + Weight::from_parts(5_695_000, 1552) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// The range of component `n` is `[0, 262140]`. @@ -1192,8 +1199,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 438_000 picoseconds. - Weight::from_parts(532_907, 0) + // Minimum execution time: 405_000 picoseconds. + Weight::from_parts(539_737, 0) // Standard Error: 0 .saturating_add(Weight::from_parts(148, 0).saturating_mul(n.into())) } @@ -1202,8 +1209,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 259_000 picoseconds. - Weight::from_parts(629_625, 0) + // Minimum execution time: 222_000 picoseconds. + Weight::from_parts(539_301, 0) // Standard Error: 0 .saturating_add(Weight::from_parts(294, 0).saturating_mul(n.into())) } @@ -1213,18 +1220,20 @@ impl WeightInfo for () { /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Revive::DeletionQueue` (r:0 w:1) /// Proof: `Revive::DeletionQueue` (`max_values`: None, `max_size`: Some(142), added: 2617, mode: `Measured`) + /// Storage: `Revive::ImmutableDataOf` (r:0 w:1) + /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) /// The range of component `n` is `[0, 32]`. fn seal_terminate(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `272 + n * (88 ±0)` // Estimated: `3738 + n * (2563 ±0)` - // Minimum execution time: 14_997_000 picoseconds. - Weight::from_parts(17_752_993, 3738) - // Standard Error: 9_865 - .saturating_add(Weight::from_parts(4_159_693, 0).saturating_mul(n.into())) + // Minimum execution time: 15_971_000 picoseconds. + Weight::from_parts(18_759_349, 3738) + // Standard Error: 10_298 + .saturating_add(Weight::from_parts(4_194_635, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 2563).saturating_mul(n.into())) } @@ -1234,20 +1243,20 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_277_000 picoseconds. - Weight::from_parts(4_023_910, 0) - // Standard Error: 2_210 - .saturating_add(Weight::from_parts(202_823, 0).saturating_mul(t.into())) - // Standard Error: 19 - .saturating_add(Weight::from_parts(1_141, 0).saturating_mul(n.into())) + // Minimum execution time: 4_341_000 picoseconds. + Weight::from_parts(4_292_048, 0) + // Standard Error: 2_476 + .saturating_add(Weight::from_parts(193_480, 0).saturating_mul(t.into())) + // Standard Error: 22 + .saturating_add(Weight::from_parts(959, 0).saturating_mul(n.into())) } /// The range of component `i` is `[0, 262144]`. fn seal_debug_message(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 309_000 picoseconds. - Weight::from_parts(834_030, 0) + // Minimum execution time: 287_000 picoseconds. + Weight::from_parts(758_020, 0) // Standard Error: 1 .saturating_add(Weight::from_parts(814, 0).saturating_mul(i.into())) } @@ -1257,8 +1266,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `744` // Estimated: `744` - // Minimum execution time: 7_705_000 picoseconds. - Weight::from_parts(7_923_000, 744) + // Minimum execution time: 7_944_000 picoseconds. + Weight::from_parts(8_358_000, 744) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1267,8 +1276,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `10754` // Estimated: `10754` - // Minimum execution time: 44_510_000 picoseconds. - Weight::from_parts(45_840_000, 10754) + // Minimum execution time: 44_950_000 picoseconds. + Weight::from_parts(45_575_000, 10754) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1277,8 +1286,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `744` // Estimated: `744` - // Minimum execution time: 8_842_000 picoseconds. - Weight::from_parts(9_363_000, 744) + // Minimum execution time: 9_095_000 picoseconds. + Weight::from_parts(9_484_000, 744) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1288,8 +1297,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `10754` // Estimated: `10754` - // Minimum execution time: 46_172_000 picoseconds. - Weight::from_parts(47_586_000, 10754) + // Minimum execution time: 46_814_000 picoseconds. + Weight::from_parts(47_710_000, 10754) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1301,12 +1310,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + o * (1 ±0)` // Estimated: `247 + o * (1 ±0)` - // Minimum execution time: 9_158_000 picoseconds. - Weight::from_parts(9_708_320, 247) - // Standard Error: 36 - .saturating_add(Weight::from_parts(499, 0).saturating_mul(n.into())) - // Standard Error: 36 - .saturating_add(Weight::from_parts(672, 0).saturating_mul(o.into())) + // Minimum execution time: 9_496_000 picoseconds. + Weight::from_parts(9_875_533, 247) + // Standard Error: 34 + .saturating_add(Weight::from_parts(712, 0).saturating_mul(n.into())) + // Standard Error: 34 + .saturating_add(Weight::from_parts(777, 0).saturating_mul(o.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(o.into())) @@ -1318,10 +1327,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_885_000 picoseconds. - Weight::from_parts(9_597_656, 247) - // Standard Error: 48 - .saturating_add(Weight::from_parts(649, 0).saturating_mul(n.into())) + // Minimum execution time: 9_185_000 picoseconds. + Weight::from_parts(9_912_715, 247) + // Standard Error: 59 + .saturating_add(Weight::from_parts(567, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1333,10 +1342,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_473_000 picoseconds. - Weight::from_parts(9_246_006, 247) - // Standard Error: 47 - .saturating_add(Weight::from_parts(1_468, 0).saturating_mul(n.into())) + // Minimum execution time: 8_586_000 picoseconds. + Weight::from_parts(9_536_041, 247) + // Standard Error: 54 + .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1347,10 +1356,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 7_996_000 picoseconds. - Weight::from_parts(8_784_165, 247) + // Minimum execution time: 8_162_000 picoseconds. + Weight::from_parts(8_813_128, 247) // Standard Error: 43 - .saturating_add(Weight::from_parts(591, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(880, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1361,10 +1370,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 9_246_000 picoseconds. - Weight::from_parts(10_239_803, 247) - // Standard Error: 57 - .saturating_add(Weight::from_parts(1_305, 0).saturating_mul(n.into())) + // Minimum execution time: 9_717_000 picoseconds. + Weight::from_parts(10_635_621, 247) + // Standard Error: 58 + .saturating_add(Weight::from_parts(1_430, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1373,36 +1382,36 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_422_000 picoseconds. - Weight::from_parts(1_531_000, 0) + // Minimum execution time: 1_503_000 picoseconds. + Weight::from_parts(1_592_000, 0) } fn set_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_858_000 picoseconds. - Weight::from_parts(1_944_000, 0) + // Minimum execution time: 1_903_000 picoseconds. + Weight::from_parts(1_996_000, 0) } fn get_transient_storage_empty() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_443_000 picoseconds. - Weight::from_parts(1_506_000, 0) + // Minimum execution time: 1_432_000 picoseconds. + Weight::from_parts(1_534_000, 0) } fn get_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_592_000 picoseconds. - Weight::from_parts(1_651_000, 0) + // Minimum execution time: 1_606_000 picoseconds. + Weight::from_parts(1_669_000, 0) } fn rollback_transient_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 960_000 picoseconds. - Weight::from_parts(1_060_000, 0) + Weight::from_parts(1_089_000, 0) } /// The range of component `n` is `[0, 512]`. /// The range of component `o` is `[0, 512]`. @@ -1410,62 +1419,62 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_151_000 picoseconds. - Weight::from_parts(2_294_801, 0) + // Minimum execution time: 2_317_000 picoseconds. + Weight::from_parts(2_449_933, 0) // Standard Error: 11 - .saturating_add(Weight::from_parts(375, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(315, 0).saturating_mul(n.into())) // Standard Error: 11 - .saturating_add(Weight::from_parts(415, 0).saturating_mul(o.into())) + .saturating_add(Weight::from_parts(387, 0).saturating_mul(o.into())) } /// The range of component `n` is `[0, 512]`. fn seal_clear_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_880_000 picoseconds. - Weight::from_parts(2_259_773, 0) + // Minimum execution time: 1_980_000 picoseconds. + Weight::from_parts(2_352_243, 0) // Standard Error: 17 - .saturating_add(Weight::from_parts(356, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(372, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_get_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_755_000 picoseconds. - Weight::from_parts(1_968_235, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(387, 0).saturating_mul(n.into())) + // Minimum execution time: 1_857_000 picoseconds. + Weight::from_parts(2_082_050, 0) + // Standard Error: 13 + .saturating_add(Weight::from_parts(373, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_contains_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_618_000 picoseconds. - Weight::from_parts(1_811_972, 0) - // Standard Error: 12 - .saturating_add(Weight::from_parts(174, 0).saturating_mul(n.into())) + // Minimum execution time: 1_693_000 picoseconds. + Weight::from_parts(1_892_600, 0) + // Standard Error: 13 + .saturating_add(Weight::from_parts(193, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_take_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_482_000 picoseconds. - Weight::from_parts(2_682_484, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(2, 0).saturating_mul(n.into())) + // Minimum execution time: 2_620_000 picoseconds. + Weight::from_parts(2_818_388, 0) + // Standard Error: 15 + .saturating_add(Weight::from_parts(39, 0).saturating_mul(n.into())) } fn seal_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `0` - // Minimum execution time: 9_899_000 picoseconds. - Weight::from_parts(10_342_000, 0) + // Minimum execution time: 10_207_000 picoseconds. + Weight::from_parts(10_627_000, 0) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:1 w:0) @@ -1474,12 +1483,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 262144]`. fn seal_call(t: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `626 + t * (140 ±0)` - // Estimated: `4091 + t * (140 ±0)` - // Minimum execution time: 33_645_000 picoseconds. - Weight::from_parts(34_407_662, 4091) - // Standard Error: 36_930 - .saturating_add(Weight::from_parts(2_062_425, 0).saturating_mul(t.into())) + // Measured: `630 + t * (140 ±0)` + // Estimated: `4095 + t * (140 ±0)` + // Minimum execution time: 34_452_000 picoseconds. + Weight::from_parts(34_837_900, 4095) + // Standard Error: 30_385 + .saturating_add(Weight::from_parts(1_981_565, 0).saturating_mul(t.into())) // Standard Error: 0 .saturating_add(Weight::from_parts(3, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) @@ -1494,8 +1503,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `457` // Estimated: `3922` - // Minimum execution time: 26_924_000 picoseconds. - Weight::from_parts(27_753_000, 3922) + // Minimum execution time: 27_287_000 picoseconds. + Weight::from_parts(28_450_000, 3922) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) @@ -1503,7 +1512,7 @@ impl WeightInfo for () { /// Storage: `Revive::PristineCode` (r:1 w:0) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) - /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1775), added: 4250, mode: `Measured`) + /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// The range of component `i` is `[0, 262144]`. @@ -1511,10 +1520,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `703` // Estimated: `4160` - // Minimum execution time: 117_979_000 picoseconds. - Weight::from_parts(105_415_117, 4160) + // Minimum execution time: 118_660_000 picoseconds. + Weight::from_parts(104_638_796, 4160) // Standard Error: 11 - .saturating_add(Weight::from_parts(4_293, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_296, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1523,64 +1532,64 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 620_000 picoseconds. - Weight::from_parts(3_414_286, 0) + // Minimum execution time: 683_000 picoseconds. + Weight::from_parts(3_836_563, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(1_463, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_keccak_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_043_000 picoseconds. - Weight::from_parts(3_402_639, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(3_667, 0).saturating_mul(n.into())) + // Minimum execution time: 1_082_000 picoseconds. + Weight::from_parts(5_027_764, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(3_644, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_blake2_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 642_000 picoseconds. - Weight::from_parts(3_359_294, 0) + // Minimum execution time: 660_000 picoseconds. + Weight::from_parts(3_585_640, 0) // Standard Error: 2 - .saturating_add(Weight::from_parts(1_590, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_586, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_blake2_128(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 606_000 picoseconds. - Weight::from_parts(3_789_868, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_575, 0).saturating_mul(n.into())) + // Minimum execution time: 638_000 picoseconds. + Weight::from_parts(3_763_242, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_582, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 261889]`. fn seal_sr25519_verify(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 46_195_000 picoseconds. - Weight::from_parts(31_420_941, 0) + // Minimum execution time: 42_962_000 picoseconds. + Weight::from_parts(27_938_396, 0) // Standard Error: 13 - .saturating_add(Weight::from_parts(5_165, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(5_269, 0).saturating_mul(n.into())) } fn seal_ecdsa_recover() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 46_933_000 picoseconds. - Weight::from_parts(48_054_000, 0) + // Minimum execution time: 47_133_000 picoseconds. + Weight::from_parts(48_458_000, 0) } fn seal_ecdsa_to_eth_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_531_000 picoseconds. - Weight::from_parts(12_690_000, 0) + // Minimum execution time: 13_249_000 picoseconds. + Weight::from_parts(13_518_000, 0) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -1588,8 +1597,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `266` // Estimated: `3731` - // Minimum execution time: 14_694_000 picoseconds. - Weight::from_parts(15_032_000, 3731) + // Minimum execution time: 14_696_000 picoseconds. + Weight::from_parts(15_106_000, 3731) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1599,8 +1608,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `304` // Estimated: `3769` - // Minimum execution time: 10_205_000 picoseconds. - Weight::from_parts(10_707_000, 3769) + // Minimum execution time: 10_292_000 picoseconds. + Weight::from_parts(10_670_000, 3769) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1610,8 +1619,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `304` // Estimated: `3561` - // Minimum execution time: 9_025_000 picoseconds. - Weight::from_parts(9_517_000, 3561) + // Minimum execution time: 9_056_000 picoseconds. + Weight::from_parts(9_350_000, 3561) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1620,9 +1629,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_451_000 picoseconds. - Weight::from_parts(10_620_260, 0) - // Standard Error: 77 - .saturating_add(Weight::from_parts(84_885, 0).saturating_mul(r.into())) + // Minimum execution time: 9_145_000 picoseconds. + Weight::from_parts(10_744_073, 0) + // Standard Error: 72 + .saturating_add(Weight::from_parts(84_813, 0).saturating_mul(r.into())) } } From c95025d923f99167f36c1800f5c3d76f24d1f58f Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Fri, 4 Oct 2024 18:06:53 +0200 Subject: [PATCH 35/35] use instantiators everywhere Signed-off-by: Cyrill Leutwiler --- substrate/frame/revive/src/exec.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 793363ca9847..c6d2f205ae22 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -4474,13 +4474,24 @@ mod tests { ); exec_success() }); + let instantiator_ch = MockLoader::insert(Call, { + move |ctx, _| { + let value = ::Currency::minimum_balance().into(); + ctx.ext + .instantiate(Weight::zero(), U256::zero(), dummy_ch, value, vec![], None) + .unwrap(); + + exec_success() + } + }); ExtBuilder::default() .with_code_hashes(MockLoader::code_hashes()) .existential_deposit(15) .build() .execute_with(|| { set_balance(&ALICE, 1000); - place_contract(&BOB, dummy_ch); + set_balance(&BOB_CONTRACT_ID, 100); + place_contract(&BOB, instantiator_ch); let origin = Origin::from_account_id(ALICE); let mut storage_meter = storage::meter::Meter::new(&origin, 200, 0).unwrap(); @@ -4507,13 +4518,24 @@ mod tests { ); exec_success() }); + let instantiator_ch = MockLoader::insert(Call, { + move |ctx, _| { + let value = ::Currency::minimum_balance().into(); + ctx.ext + .instantiate(Weight::zero(), U256::zero(), dummy_ch, value, vec![], None) + .unwrap(); + + exec_success() + } + }); ExtBuilder::default() .with_code_hashes(MockLoader::code_hashes()) .existential_deposit(15) .build() .execute_with(|| { set_balance(&ALICE, 1000); - place_contract(&BOB, dummy_ch); + set_balance(&BOB_CONTRACT_ID, 100); + place_contract(&BOB, instantiator_ch); let origin = Origin::from_account_id(ALICE); let mut storage_meter = storage::meter::Meter::new(&origin, 200, 0).unwrap();