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

Commit

Permalink
Contracts add code_len to ContractsInfo (#14523)
Browse files Browse the repository at this point in the history
* add code_len to v12

* fix

* Update frame/contracts/src/wasm/mod.rs

* fix

* fixes

* rm test

* add test back

* fix

* update test

* Fix comments

* fix build

* del

* fix clippy

* fix

* re-rename
  • Loading branch information
pgherveou authored and coderobe committed Jul 14, 2023
1 parent 2b76b44 commit efe6615
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 24 deletions.
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

0 comments on commit efe6615

Please sign in to comment.