Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
5 changes: 4 additions & 1 deletion bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1682,7 +1682,10 @@ pub type Executive = frame_executive::Executive<
frame_system::ChainContext<Runtime>,
Runtime,
AllPalletsWithSystem,
pallet_nomination_pools::migration::v2::MigrateToV2<Runtime>,
(
pallet_nomination_pools::migration::v2::MigrateToV2<Runtime>,
pallet_contracts::Migration<Runtime>,
),
>;

/// MMR helper types.
Expand Down
5 changes: 3 additions & 2 deletions frame/balances/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ use sp_runtime::{
AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedSub, MaybeSerializeDeserialize,
Saturating, StaticLookup, Zero,
},
ArithmeticError, DispatchError, RuntimeDebug,
ArithmeticError, DispatchError, FixedPointOperand, RuntimeDebug,
};
use sp_std::{cmp, fmt::Debug, mem, ops::BitOr, prelude::*, result};
pub use weights::WeightInfo;
Expand All @@ -212,7 +212,8 @@ pub mod pallet {
+ MaybeSerializeDeserialize
+ Debug
+ MaxEncodedLen
+ TypeInfo;
+ TypeInfo
+ FixedPointOperand;

/// Handler for the unbalanced reduction when removing a dust account.
type DustRemoval: OnUnbalanced<NegativeImbalance<Self, I>>;
Expand Down
55 changes: 55 additions & 0 deletions frame/contracts/fixtures/create_storage_and_call.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
;; This calls another contract as passed as its account id. It also creates some storage.
(module
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
(import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32)))
(import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32)))
(import "env" "memory" (memory 1 1))

(func $assert (param i32)
(block $ok
(br_if $ok
(get_local 0)
)
(unreachable)
)
)

(func (export "deploy"))

(func (export "call")
;; store length of input buffer
(i32.store (i32.const 0) (i32.const 512))

;; copy input at address 4
(call $seal_input (i32.const 4) (i32.const 0))

;; create 4 byte of storage before calling
(call $seal_set_storage
(i32.const 0) ;; Pointer to storage key
(i32.const 0) ;; Pointer to value
(i32.const 4) ;; Size of value
)

;; call passed contract
(call $assert (i32.eqz
(call $seal_call
(i32.const 0) ;; No flags
(i32.const 8) ;; Pointer to "callee" address.
(i64.const 0) ;; How much gas to devote for the execution. 0 = all.
(i32.const 512) ;; Pointer to the buffer with value to transfer
(i32.const 4) ;; Pointer to input data buffer address
(i32.const 4) ;; Length of input data buffer
(i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output
(i32.const 0) ;; Length is ignored in this case
)
))

;; create 8 byte of storage after calling
;; item of 12 bytes because we override 4 bytes
(call $seal_set_storage
(i32.const 0) ;; Pointer to storage key
(i32.const 0) ;; Pointer to value
(i32.const 12) ;; Size of value
)
)
)
15 changes: 12 additions & 3 deletions frame/contracts/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,15 @@ where
.execute(self, &entry_point, input_data)
.map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })?;

// Storage limit is enforced as late as possible (when the last frame returns) so that
// the ordering of storage accesses does not matter.
if self.frames.is_empty() {
let frame = top_frame_mut!(self);
Comment thread
athei marked this conversation as resolved.
Outdated
frame.contract_info.load(&frame.account_id);
let contract = frame.contract_info.as_contract();
frame.nested_storage.enforce_limit(contract)?;
}

// Additional work needs to be performed in case of an instantiation.
if !output.did_revert() && entry_point == ExportedFunction::Constructor {
let frame = self.top_frame();
Expand Down Expand Up @@ -2340,10 +2349,10 @@ mod tests {
let code_bob = MockLoader::insert(Call, |ctx, _| {
if ctx.input_data[0] == 0 {
let info = ctx.ext.contract_info();
assert_eq!(info.storage_deposit, 0);
info.storage_deposit = 42;
assert_eq!(info.storage_byte_deposit, 0);
info.storage_byte_deposit = 42;
assert_eq!(ctx.ext.call(0, CHARLIE, 0, vec![], true), exec_trapped());
assert_eq!(ctx.ext.contract_info().storage_deposit, 42);
assert_eq!(ctx.ext.contract_info().storage_byte_deposit, 42);
}
exec_success()
});
Expand Down
7 changes: 4 additions & 3 deletions frame/contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@
mod gas;
mod benchmarking;
mod exec;
mod migration;
mod schedule;
mod storage;
mod wasm;

pub mod chain_extension;
pub mod migration;
pub mod weights;

#[cfg(test)]
Expand Down Expand Up @@ -126,6 +126,7 @@ use sp_std::{fmt::Debug, marker::PhantomData, prelude::*};

pub use crate::{
exec::{Frame, VarSizedKey as StorageKey},
migration::Migration,
pallet::*,
schedule::{HostFnWeights, InstructionWeights, Limits, Schedule},
};
Expand Down Expand Up @@ -225,7 +226,7 @@ pub mod pallet {
use frame_system::pallet_prelude::*;

/// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(7);
const STORAGE_VERSION: StorageVersion = StorageVersion::new(8);

#[pallet::pallet]
#[pallet::storage_version(STORAGE_VERSION)]
Expand All @@ -236,7 +237,7 @@ pub mod pallet {
/// The time implementation used to supply timestamps to contracts through `seal_now`.
type Time: Time;

/// The generator used to supply randomness to contracts through `seal_random`.
/// The generator used to supply randomness to contracts through `seal_random`
type Randomness: Randomness<Self::Hash, Self::BlockNumber>;

/// The currency in which fees are paid and contract balances are held.
Expand Down
139 changes: 112 additions & 27 deletions frame/contracts/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,50 @@
use crate::{BalanceOf, CodeHash, Config, Pallet, TrieId, Weight};
use codec::{Decode, Encode};
use frame_support::{
codec, pallet_prelude::*, storage::migration, storage_alias, traits::Get, Identity,
Twox64Concat,
codec,
pallet_prelude::*,
storage::migration,
storage_alias,
traits::{Get, OnRuntimeUpgrade},
Identity, Twox64Concat,
};
use sp_runtime::traits::Saturating;
use sp_std::{marker::PhantomData, prelude::*};

/// Wrapper for all migrations of this pallet, based on `StorageVersion`.
pub fn migrate<T: Config>() -> Weight {
let version = StorageVersion::get::<Pallet<T>>();
let mut weight: Weight = 0;
/// Performs all necessary migrations based on `StorageVersion`.
pub struct Migration<T: Config>(PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for Migration<T> {
fn on_runtime_upgrade() -> Weight {
let version = StorageVersion::get::<Pallet<T>>();
let mut weight: Weight = 0;

if version < 4 {
weight = weight.saturating_add(v4::migrate::<T>());
StorageVersion::new(4).put::<Pallet<T>>();
}
if version < 4 {
weight = weight.saturating_add(v4::migrate::<T>());
StorageVersion::new(4).put::<Pallet<T>>();
}

if version < 5 {
weight = weight.saturating_add(v5::migrate::<T>());
StorageVersion::new(5).put::<Pallet<T>>();
}
if version < 5 {
weight = weight.saturating_add(v5::migrate::<T>());
StorageVersion::new(5).put::<Pallet<T>>();
}

if version < 6 {
weight = weight.saturating_add(v6::migrate::<T>());
StorageVersion::new(6).put::<Pallet<T>>();
}
if version < 6 {
weight = weight.saturating_add(v6::migrate::<T>());
StorageVersion::new(6).put::<Pallet<T>>();
}

if version < 7 {
weight = weight.saturating_add(v7::migrate::<T>());
StorageVersion::new(7).put::<Pallet<T>>();
}
if version < 7 {
weight = weight.saturating_add(v7::migrate::<T>());
StorageVersion::new(7).put::<Pallet<T>>();
}

if version < 8 {
weight = weight.saturating_add(v8::migrate::<T>());
StorageVersion::new(8).put::<Pallet<T>>();
}

weight
weight
}
}

/// V4: `Schedule` is changed to be a config item rather than an in-storage value.
Expand Down Expand Up @@ -185,9 +198,9 @@ mod v6 {

#[derive(Encode, Decode)]
pub struct RawContractInfo<CodeHash, Balance> {
trie_id: TrieId,
code_hash: CodeHash,
storage_deposit: Balance,
pub trie_id: TrieId,
pub code_hash: CodeHash,
pub storage_deposit: Balance,
}

#[derive(Encode, Decode)]
Expand All @@ -199,7 +212,7 @@ mod v6 {
refcount: u64,
}

type ContractInfo<T> = RawContractInfo<CodeHash<T>, BalanceOf<T>>;
pub type ContractInfo<T> = RawContractInfo<CodeHash<T>, BalanceOf<T>>;

#[storage_alias]
type ContractInfoOf<T: Config> = StorageMap<
Expand Down Expand Up @@ -266,3 +279,75 @@ mod v7 {
T::DbWeight::get().reads_writes(1, 2)
}
}

/// Update `ContractInfo` with new fields that track storage deposits.
mod v8 {
use super::*;
use sp_io::default_child_storage as child;
use v6::ContractInfo as OldContractInfo;

#[derive(Encode, Decode)]
struct ContractInfo<T: Config> {
trie_id: TrieId,
code_hash: CodeHash<T>,
storage_bytes: u32,
storage_items: u32,
storage_byte_deposit: BalanceOf<T>,
storage_item_deposit: BalanceOf<T>,
storage_base_deposit: BalanceOf<T>,
}

#[storage_alias]
type ContractInfoOf<T: Config> = StorageMap<
Pallet<T>,
Twox64Concat,
<T as frame_system::Config>::AccountId,
ContractInfo<T>,
>;

pub fn migrate<T: Config>() -> Weight {
let mut weight: Weight = 0;

<ContractInfoOf<T>>::translate(|_key, old: OldContractInfo<T>| {
// Count storage items of this contract
let mut storage_bytes = 0u32;
let mut storage_items = 0u32;
let mut key = Vec::new();
while let Some(next) = child::next_key(&old.trie_id, &key) {
key = next;
let mut val_out = [];
let len = child::read(&old.trie_id, &key, &mut val_out, 0)
.expect("The loop conditions checks for existence of the key; qed");
storage_bytes.saturating_accrue(len);
storage_items.saturating_accrue(1);
}

let storage_byte_deposit =
T::DepositPerByte::get().saturating_mul(storage_bytes.into());
let storage_item_deposit =
T::DepositPerItem::get().saturating_mul(storage_items.into());
let storage_base_deposit = old
.storage_deposit
.saturating_sub(storage_byte_deposit)
.saturating_sub(storage_item_deposit);
Comment thread
athei marked this conversation as resolved.

// Reads: One read for each storage item plus the contract info itself.
// Writes: Only the new contract info.
weight = weight.saturating_add(
T::DbWeight::get().reads_writes(Weight::from(storage_items) + 1, 1),
);

Some(ContractInfo {
trie_id: old.trie_id,
code_hash: old.code_hash,
storage_bytes,
storage_items,
storage_byte_deposit,
storage_item_deposit,
storage_base_deposit,
})
});

weight
}
}
Comment thread
athei marked this conversation as resolved.
Loading