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

Contracts add code_len to ContractsInfo (#14523) #14580

Merged
merged 1 commit into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions frame/contracts/src/migration/v12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ pub struct CodeInfo<T: Config> {
#[codec(compact)]
refcount: u64,
determinism: Determinism,
code_len: u32,
}

#[storage_alias]
Expand Down Expand Up @@ -177,6 +178,7 @@ impl<T: Config> MigrationStep for Migration<T> {
owner: old_info.owner,
deposit,
refcount: old_info.refcount,
code_len: code_len as u32,
};

let amount = old_info.deposit.saturating_sub(info.deposit);
Expand Down Expand Up @@ -221,6 +223,7 @@ impl<T: Config> MigrationStep for Migration<T> {
deposit: v.deposit,
refcount: v.refcount,
owner: v.owner,
code_len: module.code.len() as u32,
};
(k, info)
})
Expand Down
14 changes: 7 additions & 7 deletions frame/contracts/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// This file is part of Substrate.
mod pallet_dummy;

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
Expand Down Expand Up @@ -72,6 +73,7 @@ frame_support::construct_runtime!(
Utility: pallet_utility::{Pallet, Call, Storage, Event},
Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>},
Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>},
Dummy: pallet_dummy
}
);

Expand Down Expand Up @@ -378,6 +380,8 @@ impl pallet_proxy::Config for Test {
type AnnouncementDepositFactor = ConstU64<1>;
}

impl pallet_dummy::Config for Test {}

parameter_types! {
pub MySchedule: Schedule<Test> = {
let schedule = <Schedule<Test>>::default();
Expand Down Expand Up @@ -3004,7 +3008,7 @@ fn gas_estimation_call_runtime() {
.unwrap()
.account_id;

let addr_callee = Contracts::bare_instantiate(
Contracts::bare_instantiate(
ALICE,
min_balance * 100,
GAS_LIMIT,
Expand All @@ -3016,15 +3020,11 @@ fn gas_estimation_call_runtime() {
CollectEvents::Skip,
)
.result
.unwrap()
.account_id;
.unwrap();

// Call something trivial with a huge gas limit so that we can observe the effects
// of pre-charging. This should create a difference between consumed and required.
let call = RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death {
dest: addr_callee,
value: min_balance * 10,
});
let call = RuntimeCall::Dummy(pallet_dummy::Call::overestimate_pre_charge {});
let result = Contracts::bare_call(
ALICE,
addr_caller.clone(),
Expand Down
33 changes: 33 additions & 0 deletions frame/contracts/src/tests/pallet_dummy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
pub use pallet::*;

#[frame_support::pallet(dev_mode)]
pub mod pallet {
use frame_support::{
dispatch::{Pays, PostDispatchInfo},
pallet_prelude::DispatchResultWithPostInfo,
weights::Weight,
};
use frame_system::pallet_prelude::*;

#[pallet::pallet]
pub struct Pallet<T>(_);

#[pallet::config]
pub trait Config: frame_system::Config {}

#[pallet::call]
impl<T: Config> Pallet<T> {
/// Dummy function that overcharges the predispatch weight, allowing us to test the correct
/// values of [`ContractResult::gas_consumed`] and [`ContractResult::gas_required`] in
/// tests.
#[pallet::call_index(1)]
#[pallet::weight(Weight::from_parts(10_000_000, 0))]
pub fn overestimate_pre_charge(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
ensure_signed(origin)?;
Ok(PostDispatchInfo {
actual_weight: Some(Weight::from_parts(100, 0)),
pays_fee: Pays::Yes,
})
}
}
}
22 changes: 7 additions & 15 deletions frame/contracts/src/wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ pub struct CodeInfo<T: Config> {
/// to be run on-chain. Specifically, such a code can never be instantiated into a contract
/// and can just be used through a delegate call.
determinism: Determinism,
/// length of the code in bytes.
code_len: u32,
}

/// Defines the required determinism level of a wasm blob when either running or uploading code.
Expand Down Expand Up @@ -268,15 +270,11 @@ impl<T: Config> WasmBlob<T> {
fn load_code(
code_hash: CodeHash<T>,
gas_meter: &mut GasMeter<T>,
) -> Result<CodeVec<T>, DispatchError> {
let max_code_len = T::MaxCodeLen::get();
let charged = gas_meter.charge(CodeLoadToken(max_code_len))?;

) -> Result<(CodeVec<T>, CodeInfo<T>), DispatchError> {
let code_info = <CodeInfoOf<T>>::get(code_hash).ok_or(Error::<T>::CodeNotFound)?;
gas_meter.charge(CodeLoadToken(code_info.code_len))?;
let code = <PristineCode<T>>::get(code_hash).ok_or(Error::<T>::CodeNotFound)?;
let code_len = code.len() as u32;
gas_meter.adjust_gas(charged, CodeLoadToken(code_len));

Ok(code)
Ok((code, code_info))
}

/// Create the module without checking the passed code.
Expand Down Expand Up @@ -309,13 +307,7 @@ impl<T: Config> Executable<T> for WasmBlob<T> {
code_hash: CodeHash<T>,
gas_meter: &mut GasMeter<T>,
) -> Result<Self, DispatchError> {
let code = Self::load_code(code_hash, gas_meter)?;
// We store `code_info` at the same time as contract code,
// therefore this query shouldn't really fail.
// We consider its failure equal to `CodeNotFound`, as contract code without
// `code_info` is unusable in this pallet.
let code_info = <CodeInfoOf<T>>::get(code_hash).ok_or(Error::<T>::CodeNotFound)?;

let (code, code_info) = Self::load_code(code_hash, gas_meter)?;
Ok(Self { code, code_info, code_hash })
}

Expand Down
6 changes: 4 additions & 2 deletions frame/contracts/src/wasm/prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,11 +286,12 @@ where
validate::<E, T>(code.as_ref(), schedule, determinism)?;

// Calculate deposit for storing contract code and `code_info` in two different storage items.
let bytes_added = code.len().saturating_add(<CodeInfo<T>>::max_encoded_len()) as u32;
let code_len = code.len() as u32;
let bytes_added = code_len.saturating_add(<CodeInfo<T>>::max_encoded_len() as u32);
let deposit = Diff { bytes_added, items_added: 2, ..Default::default() }
.update_contract::<T>(None)
.charge_or_zero();
let code_info = CodeInfo { owner, deposit, determinism, refcount: 0 };
let code_info = CodeInfo { owner, deposit, determinism, refcount: 0, code_len };
let code_hash = T::Hashing::hash(&code);

Ok(WasmBlob { code, code_info, code_hash })
Expand Down Expand Up @@ -320,6 +321,7 @@ pub mod benchmarking {
// this is a helper function for benchmarking which skips deposit collection
deposit: Default::default(),
refcount: 0,
code_len: code.len() as u32,
determinism,
};
let code_hash = T::Hashing::hash(&code);
Expand Down