From 3beae172f019feb2ba9491c75ce7b3a8a2159d5a Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 2 Nov 2021 13:21:30 +0100 Subject: [PATCH 01/58] initial idea --- Cargo.lock | 14 ++++ Cargo.toml | 1 + frame/preimage/Cargo.toml | 38 +++++++++++ frame/preimage/src/lib.rs | 130 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100644 frame/preimage/Cargo.toml create mode 100644 frame/preimage/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 20499facb5b71..caf3ad09c23df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5807,6 +5807,20 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-preimage" +version = "4.0.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-proxy" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 32d10ca8978dd..d84c87a6b70b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,6 +103,7 @@ members = [ "frame/nicks", "frame/node-authorization", "frame/offences", + "frame/preimage", "frame/proxy", "frame/randomness-collective-flip", "frame/recovery", diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml new file mode 100644 index 0000000000000..35b99c6335b16 --- /dev/null +++ b/frame/preimage/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "pallet-preimage" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME pallet for storing preimages of hashes" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } + +[dev-dependencies] +sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "sp-std/std", + "sp-io/std", + "sp-runtime/std", + "frame-support/std", + "frame-system/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs new file mode 100644 index 0000000000000..4d32d4d3308d8 --- /dev/null +++ b/frame/preimage/src/lib.rs @@ -0,0 +1,130 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 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. + +//! # Preimage Pallet +//! +//! - [`Config`] +//! - [`Call`] +//! +//! ## Overview +//! +//! The Preimage pallet allows for the users and the runtime to store the preimage +//! of a hash on chain. This can be used by other pallets where storing and managing +//! large byte-blobs. + +#![cfg_attr(not(feature = "std"), no_std)] + +use sp_runtime::DispatchResult; +use sp_std::{convert::TryFrom, prelude::*}; + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ + pallet_prelude::Get, + traits::{Currency, ReservableCurrency}, + BoundedVec, +}; +use scale_info::TypeInfo; + +pub use pallet::*; + +#[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] +pub struct Preimage +where + MaxSize: Get, +{ + preimage: BoundedVec, + deposit: Option<(Balance, AccountId)>, +} + +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +#[frame_support::pallet] +pub mod pallet { + use super::{DispatchResult, *}; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; + + /// Currency type for this pallet. + type Currency: ReservableCurrency; + + /// An origin that can bypass deposits to place a preimage on-chain. + type ForceOrigin: EnsureOrigin; + + /// Max size allowed for a preimage. + type MaxSize: Get + TypeInfo + MaxEncodedLen; + + /// The base deposit for placing a preimage on chain. + type BaseDeposit: Get>; + + /// The per-byte deposit for placing a preimage on chain. + type ByteDeposit: Get>; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::generate_storage_info] + pub struct Pallet(PhantomData); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A sudo just took place. \[result\] + Sudid(DispatchResult), + /// The \[sudoer\] just switched identity; the old key is supplied. + KeyChanged(T::AccountId), + /// A sudo just took place. \[result\] + SudoAsDone(DispatchResult), + } + + #[pallet::error] + pub enum Error { + /// Preimage is too large to store on-chain. + TooLarge, + } + + /// The preimages stored by this pallet. + #[pallet::storage] + #[pallet::getter(fn key)] + pub(super) type Key = StorageMap< + _, + Identity, // TODO: Double Check + T::Hash, + Preimage, T::AccountId>, + >; + + #[pallet::call] + impl Pallet { + /// Register a preimage by paying a deposit proportional to the length of the preimage. + #[pallet::weight(0)] //T::WeightInfo::note_preimage(encoded_proposal.len() as u32))] + pub fn note_preimage(origin: OriginFor, bytes: Vec) -> DispatchResult { + // This is a public call, so we ensure that the origin is some signed account. + let sender = ensure_signed(origin)?; + ensure!(bytes.len() as u32 <= T::MaxSize::get(), Error::::TooLarge); + + let bounded_vec = + BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; + + Ok(()) + } + } +} From 3f033482e6adf56278f6eda66e657dc34ca0a93b Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 2 Nov 2021 14:47:14 +0100 Subject: [PATCH 02/58] more --- frame/preimage/src/lib.rs | 76 +++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 4d32d4d3308d8..10ef7ecd2444e 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -28,11 +28,15 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_runtime::DispatchResult; +use sp_runtime::{ + traits::{BadOrigin, Hash, Saturating}, + DispatchResult, +}; use sp_std::{convert::TryFrom, prelude::*}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ + ensure, pallet_prelude::Get, traits::{Currency, ReservableCurrency}, BoundedVec, @@ -42,11 +46,8 @@ use scale_info::TypeInfo; pub use pallet::*; #[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct Preimage -where - MaxSize: Get, -{ - preimage: BoundedVec, +pub struct Preimage { + preimage: BoundedVec, deposit: Option<(Balance, AccountId)>, } @@ -71,7 +72,7 @@ pub mod pallet { type ForceOrigin: EnsureOrigin; /// Max size allowed for a preimage. - type MaxSize: Get + TypeInfo + MaxEncodedLen; + type MaxSize: Get; /// The base deposit for placing a preimage on chain. type BaseDeposit: Get>; @@ -88,28 +89,26 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A sudo just took place. \[result\] - Sudid(DispatchResult), - /// The \[sudoer\] just switched identity; the old key is supplied. - KeyChanged(T::AccountId), - /// A sudo just took place. \[result\] - SudoAsDone(DispatchResult), + /// A preimage has been noted. + Noted { hash: T::Hash }, } #[pallet::error] pub enum Error { /// Preimage is too large to store on-chain. TooLarge, + /// Preimage has already been noted on-chain. + AlreadyNoted, } /// The preimages stored by this pallet. #[pallet::storage] #[pallet::getter(fn key)] - pub(super) type Key = StorageMap< + pub(super) type Preimages = StorageMap< _, Identity, // TODO: Double Check T::Hash, - Preimage, T::AccountId>, + Preimage, BalanceOf, T::AccountId>, >; #[pallet::call] @@ -117,14 +116,47 @@ pub mod pallet { /// Register a preimage by paying a deposit proportional to the length of the preimage. #[pallet::weight(0)] //T::WeightInfo::note_preimage(encoded_proposal.len() as u32))] pub fn note_preimage(origin: OriginFor, bytes: Vec) -> DispatchResult { - // This is a public call, so we ensure that the origin is some signed account. - let sender = ensure_signed(origin)?; - ensure!(bytes.len() as u32 <= T::MaxSize::get(), Error::::TooLarge); - - let bounded_vec = - BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; - + // We accept a signed origin which will pay a deposit, or a root origin where a deposit + // is not taken. + let maybe_sender = Self::ensure_signed_or_root(origin)?; + Self::note_bytes(bytes, maybe_sender)?; Ok(()) } } } + +impl Pallet { + /// Ensure that the origin is either root, or `PalletOwner`. + fn ensure_signed_or_root(origin: T::Origin) -> Result, BadOrigin> { + use frame_system::RawOrigin; + match origin.into() { + Ok(RawOrigin::Root) => Ok(None), + Ok(RawOrigin::Signed(signer)) => Ok(Some(signer)), + _ => Err(BadOrigin), + } + } + + pub fn note_bytes(bytes: Vec, maybe_depositor: Option) -> DispatchResult { + let bounded_vec = + BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; + + let hash = T::Hashing::hash(&bounded_vec); + ensure!(!Preimages::::contains_key(hash), Error::::AlreadyNoted); + + let deposit = if let Some(depositor) = maybe_depositor { + let length = bounded_vec.len() as u32; + let deposit = T::BaseDeposit::get() + .saturating_add(T::ByteDeposit::get().saturating_mul(length.into())); + T::Currency::reserve(&depositor, deposit)?; + Some((depositor, deposit)) + } else { + None + }; + + let preimage = Preimage { preimage: bounded_vec, deposit }; + + //Preimages::::insert(hash, preimage); + Self::deposit_event(Event::Noted { hash }); + Ok(()) + } +} From 5c23c8ed633387bd3a9b02ec842a16b609a2ed72 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 2 Nov 2021 15:06:18 +0100 Subject: [PATCH 03/58] fix compile --- frame/preimage/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 10ef7ecd2444e..469c26f3fd960 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -48,7 +48,7 @@ pub use pallet::*; #[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct Preimage { preimage: BoundedVec, - deposit: Option<(Balance, AccountId)>, + deposit: Option<(AccountId, Balance)>, } type BalanceOf = @@ -155,7 +155,7 @@ impl Pallet { let preimage = Preimage { preimage: bounded_vec, deposit }; - //Preimages::::insert(hash, preimage); + Preimages::::insert(hash, preimage); Self::deposit_event(Event::Noted { hash }); Ok(()) } From 0f801118e8ab0bb2c3f0100aa550624e9817d563 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 2 Nov 2021 17:02:12 +0100 Subject: [PATCH 04/58] add clear and request logic --- frame/preimage/src/lib.rs | 130 ++++++++++++++++++++++++++++++-------- 1 file changed, 105 insertions(+), 25 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 469c26f3fd960..56f3e1e81a042 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -28,10 +28,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_runtime::{ - traits::{BadOrigin, Hash, Saturating}, - DispatchResult, -}; +use sp_runtime::traits::{BadOrigin, Hash, Saturating}; use sp_std::{convert::TryFrom, prelude::*}; use codec::{Decode, Encode, MaxEncodedLen}; @@ -39,10 +36,14 @@ use frame_support::{ ensure, pallet_prelude::Get, traits::{Currency, ReservableCurrency}, + weights::Pays, BoundedVec, }; use scale_info::TypeInfo; +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + pub use pallet::*; #[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] @@ -56,9 +57,7 @@ type BalanceOf = #[frame_support::pallet] pub mod pallet { - use super::{DispatchResult, *}; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; + use super::*; #[pallet::config] pub trait Config: frame_system::Config { @@ -68,8 +67,9 @@ pub mod pallet { /// Currency type for this pallet. type Currency: ReservableCurrency; - /// An origin that can bypass deposits to place a preimage on-chain. - type ForceOrigin: EnsureOrigin; + /// An origin that can request a preimage be placed on-chain without a deposit or fee, or + /// manage existing preimages. + type ManagerOrigin: EnsureOrigin; /// Max size allowed for a preimage. type MaxSize: Get; @@ -91,6 +91,10 @@ pub mod pallet { pub enum Event { /// A preimage has been noted. Noted { hash: T::Hash }, + /// A preimage has been requested. + Requested { hash: T::Hash }, + /// A preimage has ben cleared. + Cleared { hash: T::Hash }, } #[pallet::error] @@ -102,8 +106,8 @@ pub mod pallet { } /// The preimages stored by this pallet. + // TODO: Maybe store preimage metadata in its own storage. #[pallet::storage] - #[pallet::getter(fn key)] pub(super) type Preimages = StorageMap< _, Identity, // TODO: Double Check @@ -111,39 +115,68 @@ pub mod pallet { Preimage, BalanceOf, T::AccountId>, >; + /// The preimages stored by this pallet. + #[pallet::storage] + pub(super) type Requests = StorageMap< + _, + Identity, // TODO: Double Check + T::Hash, + (), + >; + #[pallet::call] impl Pallet { /// Register a preimage by paying a deposit proportional to the length of the preimage. - #[pallet::weight(0)] //T::WeightInfo::note_preimage(encoded_proposal.len() as u32))] - pub fn note_preimage(origin: OriginFor, bytes: Vec) -> DispatchResult { + #[pallet::weight(0)] + pub fn note_preimage(origin: OriginFor, bytes: Vec) -> DispatchResultWithPostInfo { // We accept a signed origin which will pay a deposit, or a root origin where a deposit // is not taken. - let maybe_sender = Self::ensure_signed_or_root(origin)?; - Self::note_bytes(bytes, maybe_sender)?; + let maybe_sender = Self::ensure_signed_or_manager(origin)?; + Self::note_bytes(bytes, maybe_sender) + } + + #[pallet::weight(0)] + pub fn request_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { + T::ManagerOrigin::ensure_origin(origin)?; + Self::do_request_preimage(hash); + Ok(()) + } + + #[pallet::weight(0)] + pub fn clear_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { + let maybe_sender = Self::ensure_signed_or_manager(origin)?; + Self::do_clear_preimage(hash, maybe_sender); Ok(()) } } } impl Pallet { - /// Ensure that the origin is either root, or `PalletOwner`. - fn ensure_signed_or_root(origin: T::Origin) -> Result, BadOrigin> { - use frame_system::RawOrigin; - match origin.into() { - Ok(RawOrigin::Root) => Ok(None), - Ok(RawOrigin::Signed(signer)) => Ok(Some(signer)), - _ => Err(BadOrigin), + /// Ensure that the origin is either the `ManagerOrigin` or a signed origin. + fn ensure_signed_or_manager(origin: T::Origin) -> Result, BadOrigin> { + if T::ManagerOrigin::ensure_origin(origin.clone()).is_ok() { + return Ok(None) } + let who = ensure_signed(origin)?; + Ok(Some(who)) } - pub fn note_bytes(bytes: Vec, maybe_depositor: Option) -> DispatchResult { + fn note_bytes( + bytes: Vec, + maybe_depositor: Option, + ) -> DispatchResultWithPostInfo { let bounded_vec = BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; let hash = T::Hashing::hash(&bounded_vec); ensure!(!Preimages::::contains_key(hash), Error::::AlreadyNoted); - let deposit = if let Some(depositor) = maybe_depositor { + // We take a deposit only if there is a provided depositor, and the preimage was not + // previously requested. This also allows the tx to pay no fee. + let deposit = if Requests::::contains_key(hash) { + Requests::::remove(hash); + None + } else if let Some(depositor) = maybe_depositor { let length = bounded_vec.len() as u32; let deposit = T::BaseDeposit::get() .saturating_add(T::ByteDeposit::get().saturating_mul(length.into())); @@ -153,10 +186,57 @@ impl Pallet { None }; - let preimage = Preimage { preimage: bounded_vec, deposit }; + let preimage = Preimage { preimage: bounded_vec, deposit: deposit.clone() }; Preimages::::insert(hash, preimage); Self::deposit_event(Event::Noted { hash }); - Ok(()) + + // We don't pay a fee if a deposit wasn't taken. + if deposit.is_none() { + Ok(Pays::No.into()) + } else { + Ok(().into()) + } + } + + // This function will add a hash to the list of requested preimages. + // + // If the preimage already exists before the request is made, the deposit for the preimage is + // returned to the user, and removed from their management. + fn do_request_preimage(hash: T::Hash) { + // Preimage already exists. + if let Some(preimage_metadata) = Preimages::::get(hash) { + if let Some((who, amount)) = preimage_metadata.deposit { + T::Currency::unreserve(&who, amount); + } + } else { + Requests::::insert(hash, ()); + Self::deposit_event(Event::Requested { hash }); + } + } + + // Clear a preimage from the storage of the chain, returning any deposit that may be reserved. + // + // If `maybe_owner` is provided, we verify that it is the correct owner before clearing the + // data. + fn do_clear_preimage(hash: T::Hash, maybe_owner: Option) { + Preimages::::mutate_exists(hash, |maybe_value| { + if let Some(preimage_metadata) = maybe_value { + // If there is a deposit on hold, we return it if there is no `maybe_owner` or + // if the owner matches. + if let Some((who, amount)) = &preimage_metadata.deposit { + if let Some(owner) = maybe_owner { + if &owner != who { + // Ownership check did not pass. Return early without mutating anything. + return + } + } + // At this point, we have done all the authorization needed, and we can simply + // unreserve the deposit. + T::Currency::unreserve(&who, *amount); + } + *maybe_value = None; + } + }); } } From 6fd3ccfc5191142315e85b4e5d604e832ac80190 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 2 Nov 2021 17:15:49 +0100 Subject: [PATCH 05/58] improve some docs --- frame/preimage/src/lib.rs | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 56f3e1e81a042..4a42ca0d71bc2 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -115,7 +115,7 @@ pub mod pallet { Preimage, BalanceOf, T::AccountId>, >; - /// The preimages stored by this pallet. + /// Any outstanding preimage requests. #[pallet::storage] pub(super) type Requests = StorageMap< _, @@ -126,7 +126,10 @@ pub mod pallet { #[pallet::call] impl Pallet { - /// Register a preimage by paying a deposit proportional to the length of the preimage. + /// Register a preimage on-chain. + /// + /// If the preimage was previously requested, no fees or deposits are taken for providing + /// the preimage. Otherwise, a deposit is taken proportional to the size of the preimage. #[pallet::weight(0)] pub fn note_preimage(origin: OriginFor, bytes: Vec) -> DispatchResultWithPostInfo { // We accept a signed origin which will pay a deposit, or a root origin where a deposit @@ -135,6 +138,10 @@ pub mod pallet { Self::note_bytes(bytes, maybe_sender) } + /// Request a preimage be uploaded to the chain without paying any fees or deposits. + /// + /// If the preimage requests has already been provided on-chain, we unreserve any deposit + /// a user may have paid, and take the control of the preimage out of their hands. #[pallet::weight(0)] pub fn request_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; @@ -142,6 +149,14 @@ pub mod pallet { Ok(()) } + /// Clear a preimage from the runtime storage. + /// + /// If a signed origin is requesting to clear a preimage, they must be managing that + /// preimage by holding a deposit against it. After the preimage is cleared, any held + /// deposit will be returned to the user. + /// + /// Otherwise, the `ManagerOrigin` can clear any preimage, and will correctly handle + /// deposits. #[pallet::weight(0)] pub fn clear_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { let maybe_sender = Self::ensure_signed_or_manager(origin)?; @@ -161,6 +176,11 @@ impl Pallet { Ok(Some(who)) } + /// Store some preimage on chain. + /// + /// We verify that the preimage is within the bounds of what the pallet supports. + /// + /// If the preimage was requested to be uploaded, then the user pays no deposits or tx fees. fn note_bytes( bytes: Vec, maybe_depositor: Option, @@ -186,17 +206,15 @@ impl Pallet { None }; - let preimage = Preimage { preimage: bounded_vec, deposit: deposit.clone() }; + // We don't pay a fee if a deposit wasn't taken. + let dispatch_result = if deposit.is_none() { Ok(Pays::No.into()) } else { Ok(().into()) }; + + let preimage = Preimage { preimage: bounded_vec, deposit }; Preimages::::insert(hash, preimage); Self::deposit_event(Event::Noted { hash }); - // We don't pay a fee if a deposit wasn't taken. - if deposit.is_none() { - Ok(Pays::No.into()) - } else { - Ok(().into()) - } + dispatch_result } // This function will add a hash to the list of requested preimages. @@ -204,8 +222,8 @@ impl Pallet { // If the preimage already exists before the request is made, the deposit for the preimage is // returned to the user, and removed from their management. fn do_request_preimage(hash: T::Hash) { - // Preimage already exists. if let Some(preimage_metadata) = Preimages::::get(hash) { + // Preimage already exists, so we return the deposit of the user who uploaded it. if let Some((who, amount)) = preimage_metadata.deposit { T::Currency::unreserve(&who, amount); } @@ -236,6 +254,7 @@ impl Pallet { T::Currency::unreserve(&who, *amount); } *maybe_value = None; + Self::deposit_event(Event::Cleared { hash }); } }); } From 8847f9f60d4f5c14c328bf86d642a265b082cebf Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Tue, 2 Nov 2021 18:00:38 +0100 Subject: [PATCH 06/58] Add and implement trait --- frame/preimage/src/lib.rs | 44 ++++++++++++++++++++++++++++---- frame/support/src/traits.rs | 4 +-- frame/support/src/traits/misc.rs | 20 +++++++++++++++ 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 4a42ca0d71bc2..ca1687a4ee9d9 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -103,6 +103,8 @@ pub mod pallet { TooLarge, /// Preimage has already been noted on-chain. AlreadyNoted, + /// The user is not authorized to perform this action. + NotAuthorized, } /// The preimages stored by this pallet. @@ -160,7 +162,7 @@ pub mod pallet { #[pallet::weight(0)] pub fn clear_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { let maybe_sender = Self::ensure_signed_or_manager(origin)?; - Self::do_clear_preimage(hash, maybe_sender); + Self::do_clear_preimage(hash, maybe_sender)?; Ok(()) } } @@ -237,8 +239,10 @@ impl Pallet { // // If `maybe_owner` is provided, we verify that it is the correct owner before clearing the // data. - fn do_clear_preimage(hash: T::Hash, maybe_owner: Option) { - Preimages::::mutate_exists(hash, |maybe_value| { + // + // If `maybe_owner` is not provided, this function cannot return an error. + fn do_clear_preimage(hash: T::Hash, maybe_owner: Option) -> DispatchResult { + Preimages::::mutate_exists(hash, |maybe_value| -> DispatchResult { if let Some(preimage_metadata) = maybe_value { // If there is a deposit on hold, we return it if there is no `maybe_owner` or // if the owner matches. @@ -246,7 +250,7 @@ impl Pallet { if let Some(owner) = maybe_owner { if &owner != who { // Ownership check did not pass. Return early without mutating anything. - return + return Err(Error::::NotAuthorized.into()) } } // At this point, we have done all the authorization needed, and we can simply @@ -256,6 +260,36 @@ impl Pallet { *maybe_value = None; Self::deposit_event(Event::Cleared { hash }); } - }); + Ok(()) + }) + } +} + +impl frame_support::traits::PreimageHandler for Pallet { + fn preimage_exists(hash: T::Hash) -> bool { + Preimages::::contains_key(hash) + } + + fn preimage_requested(hash: T::Hash) -> bool { + Requests::::contains_key(hash) + } + + fn get_preimage(hash: T::Hash) -> Option> { + Preimages::::get(hash).map(|preimage| preimage.preimage.to_vec()) + } + + fn note_preimage(bytes: Vec) -> Result<(), ()> { + Self::note_bytes(bytes, None).map_err(|_| ())?; + Ok(()) + } + + fn request_preimage(hash: T::Hash) { + Self::do_request_preimage(hash) + } + + fn clear_preimage(hash: T::Hash) { + // Should never fail if authorization check is skipped. + let res = Self::do_clear_preimage(hash, None); + debug_assert!(res.is_ok(), "do_clear_preimage failed when authorization check was skipped"); } } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index bb990e25646db..dd03ed75d3ccb 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -52,8 +52,8 @@ mod misc; pub use misc::{ Backing, ConstU32, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, - OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, SameOrOther, Time, TryDrop, - UnixTime, WrapperKeepOpaque, WrapperOpaque, + OffchainWorker, OnKilledAccount, OnNewAccount, PreimageHandler, PrivilegeCmp, SameOrOther, + Time, TryDrop, UnixTime, WrapperKeepOpaque, WrapperOpaque, }; mod stored_map; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 0a3fb045d6c1d..aa8d0c6c73d2a 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -564,6 +564,26 @@ impl TypeInfo for WrapperKeepOpaque { } } +/// A interface for managing preimages to hashes on chain. +/// +/// Note that this API does not assume any underlying user is calling, and thus +/// does not handle any preimage ownership or fees. Other system level logic that +/// uses this API should implement that on their own side. +pub trait PreimageHandler { + /// Returns whether a preimage exists for a given hash. + fn preimage_exists(hash: Hash) -> bool; + /// Returns whether a preimage request exists for a given hash. + fn preimage_requested(hash: Hash) -> bool; + /// Returns the preimage for a given hash. + fn get_preimage(hash: Hash) -> Option>; + /// Store the bytes of a preimage on chain. + fn note_preimage(bytes: Vec) -> Result<(), ()>; + /// Request that someone report a preimage.å + fn request_preimage(hash: Hash); + /// Clear an existing preimage. + fn clear_preimage(hash: Hash); +} + #[cfg(test)] mod test { use super::*; From ccd6bb86b2a6c55eac2f2bb8c788b0160274cf56 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 4 Nov 2021 12:31:15 +0100 Subject: [PATCH 07/58] continuing to improve --- frame/preimage/src/lib.rs | 128 ++++++++++++++++++++++++------- frame/support/src/traits/misc.rs | 6 +- 2 files changed, 104 insertions(+), 30 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index ca1687a4ee9d9..15b7db6488f50 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -28,7 +28,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_runtime::traits::{BadOrigin, Hash, Saturating}; +use sp_runtime::traits::{BadOrigin, Hash, Saturating, One}; use sp_std::{convert::TryFrom, prelude::*}; use codec::{Decode, Encode, MaxEncodedLen}; @@ -46,10 +46,19 @@ use frame_system::pallet_prelude::*; pub use pallet::*; +pub enum RefCount { + User(AccountId, Balance), + System(u32), +} + #[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct Preimage { + // The preimage we are storing. preimage: BoundedVec, + // The user who has a deposit for holding this preimage, if any. deposit: Option<(AccountId, Balance)>, + // A reference counter for how many different resources are using this preimage. + ref_count: u32, } type BalanceOf = @@ -123,7 +132,8 @@ pub mod pallet { _, Identity, // TODO: Double Check T::Hash, - (), + u32, + ValueQuery, >; #[pallet::call] @@ -137,18 +147,12 @@ pub mod pallet { // We accept a signed origin which will pay a deposit, or a root origin where a deposit // is not taken. let maybe_sender = Self::ensure_signed_or_manager(origin)?; - Self::note_bytes(bytes, maybe_sender) - } - - /// Request a preimage be uploaded to the chain without paying any fees or deposits. - /// - /// If the preimage requests has already been provided on-chain, we unreserve any deposit - /// a user may have paid, and take the control of the preimage out of their hands. - #[pallet::weight(0)] - pub fn request_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { - T::ManagerOrigin::ensure_origin(origin)?; - Self::do_request_preimage(hash); - Ok(()) + if let Some(sender) = maybe_sender { + Self::note_user_bytes(bytes, sender) + } else { + Self::note_bytes(bytes)?; + Ok(Pays::No.into()) + } } /// Clear a preimage from the runtime storage. @@ -165,6 +169,25 @@ pub mod pallet { Self::do_clear_preimage(hash, maybe_sender)?; Ok(()) } + + /// Request a preimage be uploaded to the chain without paying any fees or deposits. + /// + /// If the preimage requests has already been provided on-chain, we unreserve any deposit + /// a user may have paid, and take the control of the preimage out of their hands. + #[pallet::weight(0)] + pub fn request_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { + T::ManagerOrigin::ensure_origin(origin)?; + Self::do_request_preimage(hash); + Ok(()) + } + + /// Clear the request for a preimage. + #[pallet::weight(0)] + pub fn clear_request(origin: OriginFor, hash: T::Hash) -> DispatchResult { + T::ManagerOrigin::ensure_origin(origin)?; + Self::do_clear_request(hash); + Ok(()) + } } } @@ -178,14 +201,41 @@ impl Pallet { Ok(Some(who)) } + /// Store some preimage on chain from a trusted source. + /// + /// We verify that the preimage is within the bounds of what the pallet supports. + /// + /// If the preimage is already uploaded, we increase the reference counter, ensuring it is + /// not cleared before all uses of this preimage is complete. + fn note_bytes( + bytes: Vec, + ) -> DispatchResult { + let bounded_vec = + BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; + + let hash = T::Hashing::hash(&bounded_vec); + Preimages::::mutate_exists(hash, |maybe_preimage| { + if let Some(preimage) = maybe_preimage { + preimage.ref_count = preimage.ref_count.saturating_add(One::one()); + } else { + *maybe_preimage = Some( + Preimage { preimage: bounded_vec, deposit: None, ref_count: One::one() } + ) + } + }); + + Self::deposit_event(Event::Noted { hash }); + Ok(()) + } + /// Store some preimage on chain. /// /// We verify that the preimage is within the bounds of what the pallet supports. /// /// If the preimage was requested to be uploaded, then the user pays no deposits or tx fees. - fn note_bytes( + fn note_user_bytes( bytes: Vec, - maybe_depositor: Option, + depositor: T::AccountId, ) -> DispatchResultWithPostInfo { let bounded_vec = BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; @@ -195,23 +245,21 @@ impl Pallet { // We take a deposit only if there is a provided depositor, and the preimage was not // previously requested. This also allows the tx to pay no fee. - let deposit = if Requests::::contains_key(hash) { - Requests::::remove(hash); - None - } else if let Some(depositor) = maybe_depositor { + let requests = Requests::::take(hash); + let (deposit, ref_count) = if requests > 0 { + (None, requests) + } else { let length = bounded_vec.len() as u32; let deposit = T::BaseDeposit::get() .saturating_add(T::ByteDeposit::get().saturating_mul(length.into())); T::Currency::reserve(&depositor, deposit)?; - Some((depositor, deposit)) - } else { - None + (Some((depositor, deposit)), One::one()) }; // We don't pay a fee if a deposit wasn't taken. let dispatch_result = if deposit.is_none() { Ok(Pays::No.into()) } else { Ok(().into()) }; - let preimage = Preimage { preimage: bounded_vec, deposit }; + let preimage = Preimage { preimage: bounded_vec, deposit, ref_count }; Preimages::::insert(hash, preimage); Self::deposit_event(Event::Noted { hash }); @@ -224,13 +272,17 @@ impl Pallet { // If the preimage already exists before the request is made, the deposit for the preimage is // returned to the user, and removed from their management. fn do_request_preimage(hash: T::Hash) { - if let Some(preimage_metadata) = Preimages::::get(hash) { + if let Some(mut preimage_metadata) = Preimages::::get(hash) { // Preimage already exists, so we return the deposit of the user who uploaded it. - if let Some((who, amount)) = preimage_metadata.deposit { - T::Currency::unreserve(&who, amount); + if let Some((ref who, amount)) = preimage_metadata.deposit { + T::Currency::unreserve(who, amount); } + // Increase the ref_count + preimage_metadata.ref_count.saturating_inc(); + Preimages::::insert(hash, preimage_metadata); } else { - Requests::::insert(hash, ()); + // Increase the number of requests + Requests::::mutate(hash, |requests| requests.saturating_inc()); Self::deposit_event(Event::Requested { hash }); } } @@ -244,6 +296,13 @@ impl Pallet { fn do_clear_preimage(hash: T::Hash, maybe_owner: Option) -> DispatchResult { Preimages::::mutate_exists(hash, |maybe_value| -> DispatchResult { if let Some(preimage_metadata) = maybe_value { + // If this preimage still has reference counters, decrement, and exit early. + if preimage_metadata.ref_count > 1 { + preimage_metadata.ref_count.saturating_dec(); + return Ok(()) + } + // So we are definitely cleaning up this preimage now... + // If there is a deposit on hold, we return it if there is no `maybe_owner` or // if the owner matches. if let Some((who, amount)) = &preimage_metadata.deposit { @@ -263,9 +322,16 @@ impl Pallet { Ok(()) }) } + + /// Clear a preimage request. + fn do_clear_request(hash: T::Hash) { + Requests::::remove(hash); + } } impl frame_support::traits::PreimageHandler for Pallet { + type MaxSize = T::MaxSize; + fn preimage_exists(hash: T::Hash) -> bool { Preimages::::contains_key(hash) } @@ -279,7 +345,7 @@ impl frame_support::traits::PreimageHandler for Pallet { } fn note_preimage(bytes: Vec) -> Result<(), ()> { - Self::note_bytes(bytes, None).map_err(|_| ())?; + Self::note_bytes(bytes).map_err(|_| ())?; Ok(()) } @@ -292,4 +358,8 @@ impl frame_support::traits::PreimageHandler for Pallet { let res = Self::do_clear_preimage(hash, None); debug_assert!(res.is_ok(), "do_clear_preimage failed when authorization check was skipped"); } + + fn clear_request(hash: T::Hash) { + Self::do_clear_request(hash); + } } diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index aa8d0c6c73d2a..5f6a5eb25ad6a 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -570,6 +570,8 @@ impl TypeInfo for WrapperKeepOpaque { /// does not handle any preimage ownership or fees. Other system level logic that /// uses this API should implement that on their own side. pub trait PreimageHandler { + /// Maximum size of a preimage. + type MaxSize: Get; /// Returns whether a preimage exists for a given hash. fn preimage_exists(hash: Hash) -> bool; /// Returns whether a preimage request exists for a given hash. @@ -578,10 +580,12 @@ pub trait PreimageHandler { fn get_preimage(hash: Hash) -> Option>; /// Store the bytes of a preimage on chain. fn note_preimage(bytes: Vec) -> Result<(), ()>; - /// Request that someone report a preimage.å + /// Request that someone report a preimage. fn request_preimage(hash: Hash); /// Clear an existing preimage. fn clear_preimage(hash: Hash); + /// Clear a preimage request. + fn clear_request(hash: Hash); } #[cfg(test)] From ec2b0f0406633a13024a3307a4f8e01124d15570 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 4 Nov 2021 12:58:26 +0100 Subject: [PATCH 08/58] refcount type --- frame/preimage/src/lib.rs | 107 ++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 40 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 15b7db6488f50..a27ac3dde129e 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -46,19 +46,18 @@ use frame_system::pallet_prelude::*; pub use pallet::*; +#[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] pub enum RefCount { User(AccountId, Balance), System(u32), } #[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct Preimage { +pub struct Preimage { // The preimage we are storing. preimage: BoundedVec, - // The user who has a deposit for holding this preimage, if any. - deposit: Option<(AccountId, Balance)>, - // A reference counter for how many different resources are using this preimage. - ref_count: u32, + // A reference counter for who depends on this resource. + ref_count: RefCount, } type BalanceOf = @@ -123,7 +122,7 @@ pub mod pallet { _, Identity, // TODO: Double Check T::Hash, - Preimage, BalanceOf, T::AccountId>, + Preimage, T::AccountId, BalanceOf>, >; /// Any outstanding preimage requests. @@ -150,7 +149,7 @@ pub mod pallet { if let Some(sender) = maybe_sender { Self::note_user_bytes(bytes, sender) } else { - Self::note_bytes(bytes)?; + Self::note_system_bytes(bytes)?; Ok(Pays::No.into()) } } @@ -207,7 +206,7 @@ impl Pallet { /// /// If the preimage is already uploaded, we increase the reference counter, ensuring it is /// not cleared before all uses of this preimage is complete. - fn note_bytes( + fn note_system_bytes( bytes: Vec, ) -> DispatchResult { let bounded_vec = @@ -216,10 +215,20 @@ impl Pallet { let hash = T::Hashing::hash(&bounded_vec); Preimages::::mutate_exists(hash, |maybe_preimage| { if let Some(preimage) = maybe_preimage { - preimage.ref_count = preimage.ref_count.saturating_add(One::one()); + // If the preimage already exists, it could be owned by a user. + // We have the system take over control of the preimage. + match &preimage.ref_count { + RefCount::User(who, deposit) => { + T::Currency::unreserve(who, *deposit); + preimage.ref_count = RefCount::System(One::one()); + }, + RefCount::System(mut count) => { + count.saturating_inc(); + } + } } else { *maybe_preimage = Some( - Preimage { preimage: bounded_vec, deposit: None, ref_count: One::one() } + Preimage { preimage: bounded_vec, ref_count: RefCount::System(One::one()) } ) } }); @@ -246,20 +255,23 @@ impl Pallet { // We take a deposit only if there is a provided depositor, and the preimage was not // previously requested. This also allows the tx to pay no fee. let requests = Requests::::take(hash); - let (deposit, ref_count) = if requests > 0 { - (None, requests) + let ref_count = if requests > 0 { + RefCount::System(requests) } else { let length = bounded_vec.len() as u32; let deposit = T::BaseDeposit::get() .saturating_add(T::ByteDeposit::get().saturating_mul(length.into())); T::Currency::reserve(&depositor, deposit)?; - (Some((depositor, deposit)), One::one()) + RefCount::User(depositor, deposit) }; - // We don't pay a fee if a deposit wasn't taken. - let dispatch_result = if deposit.is_none() { Ok(Pays::No.into()) } else { Ok(().into()) }; + // We don't pay a fee if it is a system preimage. + let dispatch_result = match ref_count { + RefCount::System(_) => Ok(Pays::No.into()), + RefCount::User(_, _) => Ok(().into()) + }; - let preimage = Preimage { preimage: bounded_vec, deposit, ref_count }; + let preimage = Preimage { preimage: bounded_vec, ref_count }; Preimages::::insert(hash, preimage); Self::deposit_event(Event::Noted { hash }); @@ -273,15 +285,22 @@ impl Pallet { // returned to the user, and removed from their management. fn do_request_preimage(hash: T::Hash) { if let Some(mut preimage_metadata) = Preimages::::get(hash) { - // Preimage already exists, so we return the deposit of the user who uploaded it. - if let Some((ref who, amount)) = preimage_metadata.deposit { - T::Currency::unreserve(who, amount); + match preimage_metadata.ref_count { + RefCount::User(who, deposit) => { + // Preimage already exists and owned by a user. + // We return the deposit and change ownership to the system. + T::Currency::unreserve(&who, deposit); + preimage_metadata.ref_count = RefCount::System(One::one()); + }, + RefCount::System(mut count) => { + // Preimage already exists and is owned by the system. + // We simply increase the number of reference counters. + count.saturating_inc(); + } } - // Increase the ref_count - preimage_metadata.ref_count.saturating_inc(); Preimages::::insert(hash, preimage_metadata); } else { - // Increase the number of requests + // Preimage does not exist yet, so increase the number of requests. Requests::::mutate(hash, |requests| requests.saturating_inc()); Self::deposit_event(Event::Requested { hash }); } @@ -296,26 +315,34 @@ impl Pallet { fn do_clear_preimage(hash: T::Hash, maybe_owner: Option) -> DispatchResult { Preimages::::mutate_exists(hash, |maybe_value| -> DispatchResult { if let Some(preimage_metadata) = maybe_value { - // If this preimage still has reference counters, decrement, and exit early. - if preimage_metadata.ref_count > 1 { - preimage_metadata.ref_count.saturating_dec(); - return Ok(()) - } - // So we are definitely cleaning up this preimage now... - - // If there is a deposit on hold, we return it if there is no `maybe_owner` or - // if the owner matches. - if let Some((who, amount)) = &preimage_metadata.deposit { - if let Some(owner) = maybe_owner { - if &owner != who { - // Ownership check did not pass. Return early without mutating anything. + match &preimage_metadata.ref_count { + RefCount::User(who, deposit) => { + // If there is a deposit on hold, we return it if there is no `maybe_owner` or + // if the owner matches. + if let Some(owner) = maybe_owner { + if &owner != who { + // Ownership check did not pass. Return early without mutating anything. + return Err(Error::::NotAuthorized.into()) + } + } + // At this point, we have done all the authorization needed, and we can simply + // unreserve the deposit. + T::Currency::unreserve(who, *deposit); + }, + RefCount::System(mut count) => { + // A regular user cannot clear a system preimage. + if maybe_owner.is_some() { return Err(Error::::NotAuthorized.into()) } + // If this preimage still has reference counters, decrement, and exit early. + if count > 1 { + count.saturating_dec(); + return Ok(()) + } } - // At this point, we have done all the authorization needed, and we can simply - // unreserve the deposit. - T::Currency::unreserve(&who, *amount); - } + }; + + // If we got this far, we are removing the value. *maybe_value = None; Self::deposit_event(Event::Cleared { hash }); } @@ -345,7 +372,7 @@ impl frame_support::traits::PreimageHandler for Pallet { } fn note_preimage(bytes: Vec) -> Result<(), ()> { - Self::note_bytes(bytes).map_err(|_| ())?; + Self::note_system_bytes(bytes).map_err(|_| ())?; Ok(()) } From cb512ef5e69bc8d283eb1db950c2745e9db9c723 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 4 Nov 2021 13:07:34 +0100 Subject: [PATCH 09/58] infallible system preimage upload --- frame/preimage/src/lib.rs | 43 +++++++++++++++----------------- frame/support/src/traits/misc.rs | 2 +- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index a27ac3dde129e..e9c2049081fb7 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -146,10 +146,17 @@ pub mod pallet { // We accept a signed origin which will pay a deposit, or a root origin where a deposit // is not taken. let maybe_sender = Self::ensure_signed_or_manager(origin)?; + let bounded_vec = + BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; if let Some(sender) = maybe_sender { - Self::note_user_bytes(bytes, sender) + let system_requested = Self::note_user_bytes(bounded_vec, sender)?; + if system_requested { + Ok(Pays::No.into()) + } else { + Ok(().into()) + } } else { - Self::note_system_bytes(bytes)?; + Self::note_system_bytes(bounded_vec); Ok(Pays::No.into()) } } @@ -202,16 +209,11 @@ impl Pallet { /// Store some preimage on chain from a trusted source. /// - /// We verify that the preimage is within the bounds of what the pallet supports. - /// /// If the preimage is already uploaded, we increase the reference counter, ensuring it is /// not cleared before all uses of this preimage is complete. fn note_system_bytes( - bytes: Vec, - ) -> DispatchResult { - let bounded_vec = - BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; - + bounded_vec: BoundedVec, + ) { let hash = T::Hashing::hash(&bounded_vec); Preimages::::mutate_exists(hash, |maybe_preimage| { if let Some(preimage) = maybe_preimage { @@ -234,7 +236,6 @@ impl Pallet { }); Self::deposit_event(Event::Noted { hash }); - Ok(()) } /// Store some preimage on chain. @@ -243,12 +244,9 @@ impl Pallet { /// /// If the preimage was requested to be uploaded, then the user pays no deposits or tx fees. fn note_user_bytes( - bytes: Vec, + bounded_vec: BoundedVec, depositor: T::AccountId, - ) -> DispatchResultWithPostInfo { - let bounded_vec = - BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; - + ) -> Result { let hash = T::Hashing::hash(&bounded_vec); ensure!(!Preimages::::contains_key(hash), Error::::AlreadyNoted); @@ -265,10 +263,10 @@ impl Pallet { RefCount::User(depositor, deposit) }; - // We don't pay a fee if it is a system preimage. - let dispatch_result = match ref_count { - RefCount::System(_) => Ok(Pays::No.into()), - RefCount::User(_, _) => Ok(().into()) + // Return whether this was requested by the system. + let system_request = match ref_count { + RefCount::System(_) => true, + RefCount::User(_, _) => false, }; let preimage = Preimage { preimage: bounded_vec, ref_count }; @@ -276,7 +274,7 @@ impl Pallet { Preimages::::insert(hash, preimage); Self::deposit_event(Event::Noted { hash }); - dispatch_result + Ok(system_request) } // This function will add a hash to the list of requested preimages. @@ -371,9 +369,8 @@ impl frame_support::traits::PreimageHandler for Pallet { Preimages::::get(hash).map(|preimage| preimage.preimage.to_vec()) } - fn note_preimage(bytes: Vec) -> Result<(), ()> { - Self::note_system_bytes(bytes).map_err(|_| ())?; - Ok(()) + fn note_preimage(bytes: BoundedVec) { + Self::note_system_bytes(bytes) } fn request_preimage(hash: T::Hash) { diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 5f6a5eb25ad6a..6198d1be1273d 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -579,7 +579,7 @@ pub trait PreimageHandler { /// Returns the preimage for a given hash. fn get_preimage(hash: Hash) -> Option>; /// Store the bytes of a preimage on chain. - fn note_preimage(bytes: Vec) -> Result<(), ()>; + fn note_preimage(bytes: crate::BoundedVec); /// Request that someone report a preimage. fn request_preimage(hash: Hash); /// Clear an existing preimage. From 7dc3b43449d47c1e560906fc09c35750cb088a57 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 4 Nov 2021 13:09:07 +0100 Subject: [PATCH 10/58] fmt --- frame/preimage/src/lib.rs | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index e9c2049081fb7..049c9e02b4aee 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -28,7 +28,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_runtime::traits::{BadOrigin, Hash, Saturating, One}; +use sp_runtime::traits::{BadOrigin, Hash, One, Saturating}; use sp_std::{convert::TryFrom, prelude::*}; use codec::{Decode, Encode, MaxEncodedLen}; @@ -46,9 +46,12 @@ use frame_system::pallet_prelude::*; pub use pallet::*; +/// A type to note whether a preimage is owned by a user or the system. #[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] pub enum RefCount { + /// This preimage is owned by a user who has the following deposit on hold. User(AccountId, Balance), + /// This preimage is managed by the system with a number of reference counters. System(u32), } @@ -211,9 +214,7 @@ impl Pallet { /// /// If the preimage is already uploaded, we increase the reference counter, ensuring it is /// not cleared before all uses of this preimage is complete. - fn note_system_bytes( - bounded_vec: BoundedVec, - ) { + fn note_system_bytes(bounded_vec: BoundedVec) { let hash = T::Hashing::hash(&bounded_vec); Preimages::::mutate_exists(hash, |maybe_preimage| { if let Some(preimage) = maybe_preimage { @@ -226,12 +227,13 @@ impl Pallet { }, RefCount::System(mut count) => { count.saturating_inc(); - } + }, } } else { - *maybe_preimage = Some( - Preimage { preimage: bounded_vec, ref_count: RefCount::System(One::one()) } - ) + *maybe_preimage = Some(Preimage { + preimage: bounded_vec, + ref_count: RefCount::System(One::one()), + }) } }); @@ -294,7 +296,7 @@ impl Pallet { // Preimage already exists and is owned by the system. // We simply increase the number of reference counters. count.saturating_inc(); - } + }, } Preimages::::insert(hash, preimage_metadata); } else { @@ -315,16 +317,17 @@ impl Pallet { if let Some(preimage_metadata) = maybe_value { match &preimage_metadata.ref_count { RefCount::User(who, deposit) => { - // If there is a deposit on hold, we return it if there is no `maybe_owner` or - // if the owner matches. + // If there is a deposit on hold, we return it if there is no `maybe_owner` + // or if the owner matches. if let Some(owner) = maybe_owner { if &owner != who { - // Ownership check did not pass. Return early without mutating anything. + // Ownership check did not pass. Return early without mutating + // anything. return Err(Error::::NotAuthorized.into()) } } - // At this point, we have done all the authorization needed, and we can simply - // unreserve the deposit. + // At this point, we have done all the authorization needed, and we can + // simply unreserve the deposit. T::Currency::unreserve(who, *deposit); }, RefCount::System(mut count) => { @@ -337,7 +340,7 @@ impl Pallet { count.saturating_dec(); return Ok(()) } - } + }, }; // If we got this far, we are removing the value. From d1621fb4c973d39a23f3d31a380525879684c8d4 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Thu, 4 Nov 2021 13:13:22 +0100 Subject: [PATCH 11/58] fix requests --- frame/preimage/src/lib.rs | 12 +++++++++--- frame/support/src/traits/misc.rs | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 049c9e02b4aee..b3c7835aaca7c 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -55,12 +55,13 @@ pub enum RefCount { System(u32), } +/// The preimage metadata. #[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct Preimage { // The preimage we are storing. - preimage: BoundedVec, + pub preimage: BoundedVec, // A reference counter for who depends on this resource. - ref_count: RefCount, + pub ref_count: RefCount, } type BalanceOf = @@ -353,7 +354,12 @@ impl Pallet { /// Clear a preimage request. fn do_clear_request(hash: T::Hash) { - Requests::::remove(hash); + let count = Requests::::get(hash); + if count > 1 { + Requests::::insert(hash, count - 1); + } else { + Requests::::remove(hash); + } } } diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 6198d1be1273d..6486eb387ac09 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -580,10 +580,10 @@ pub trait PreimageHandler { fn get_preimage(hash: Hash) -> Option>; /// Store the bytes of a preimage on chain. fn note_preimage(bytes: crate::BoundedVec); - /// Request that someone report a preimage. - fn request_preimage(hash: Hash); /// Clear an existing preimage. fn clear_preimage(hash: Hash); + /// Request that someone report a preimage. + fn request_preimage(hash: Hash); /// Clear a preimage request. fn clear_request(hash: Hash); } From b9f64dafd0d24157ff02975cb8fdc56caec42db3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 23 Nov 2021 17:47:25 +0100 Subject: [PATCH 12/58] Make it simple --- frame/preimage/src/lib.rs | 270 +++++++++++++++----------------------- 1 file changed, 103 insertions(+), 167 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index b3c7835aaca7c..8d7e4a134411f 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -28,7 +28,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_runtime::traits::{BadOrigin, Hash, One, Saturating}; +use sp_runtime::traits::{BadOrigin, Hash, Saturating}; use sp_std::{convert::TryFrom, prelude::*}; use codec::{Decode, Encode, MaxEncodedLen}; @@ -48,20 +48,13 @@ pub use pallet::*; /// A type to note whether a preimage is owned by a user or the system. #[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub enum RefCount { - /// This preimage is owned by a user who has the following deposit on hold. - User(AccountId, Balance), - /// This preimage is managed by the system with a number of reference counters. - System(u32), -} - -/// The preimage metadata. -#[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct Preimage { - // The preimage we are storing. - pub preimage: BoundedVec, - // A reference counter for who depends on this resource. - pub ref_count: RefCount, +pub enum RequestStatus { + /// The associated preimage has not yet been requested by the system. The given deposit (if + /// some) is being held until either it becomes requested or the user retracts the primage. + Unrequested(Option<(AccountId, Balance)>), + /// There are a non-zero number of outstanding requests for this hash by this chain. If there + /// is a preimage registered, then it may be removed iff this counter becomes zero. + Requested(u32), } type BalanceOf = @@ -117,26 +110,30 @@ pub mod pallet { AlreadyNoted, /// The user is not authorized to perform this action. NotAuthorized, + /// The preimage cannot be removed since it has not yet been noted. + NotNoted, + /// A preimage may not be removed when there are outstanding requests. + Requested, + /// The preimage request cannot be removed since no outstanding requests exist. + NotRequested, } - /// The preimages stored by this pallet. - // TODO: Maybe store preimage metadata in its own storage. + /// The request status of a given hash. #[pallet::storage] - pub(super) type Preimages = StorageMap< + pub(super) type StatusFor = StorageMap< _, - Identity, // TODO: Double Check + Identity, T::Hash, - Preimage, T::AccountId, BalanceOf>, + RequestStatus>, >; - /// Any outstanding preimage requests. + /// The preimages stored by this pallet. #[pallet::storage] - pub(super) type Requests = StorageMap< + pub(super) type PreimageFor = StorageMap< _, - Identity, // TODO: Double Check + Identity, T::Hash, - u32, - ValueQuery, + BoundedVec, >; #[pallet::call] @@ -152,32 +149,19 @@ pub mod pallet { let maybe_sender = Self::ensure_signed_or_manager(origin)?; let bounded_vec = BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; - if let Some(sender) = maybe_sender { - let system_requested = Self::note_user_bytes(bounded_vec, sender)?; - if system_requested { - Ok(Pays::No.into()) - } else { - Ok(().into()) - } - } else { - Self::note_system_bytes(bounded_vec); + let system_requested = Self::note_bytes(bounded_vec, maybe_sender.as_ref())?; + if system_requested || maybe_sender.is_none() { Ok(Pays::No.into()) + } else { + Ok(().into()) } } - /// Clear a preimage from the runtime storage. - /// - /// If a signed origin is requesting to clear a preimage, they must be managing that - /// preimage by holding a deposit against it. After the preimage is cleared, any held - /// deposit will be returned to the user. - /// - /// Otherwise, the `ManagerOrigin` can clear any preimage, and will correctly handle - /// deposits. + /// Clear an unrequested preimage from the runtime storage. #[pallet::weight(0)] pub fn clear_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { let maybe_sender = Self::ensure_signed_or_manager(origin)?; - Self::do_clear_preimage(hash, maybe_sender)?; - Ok(()) + Self::do_clear_preimage(hash, maybe_sender) } /// Request a preimage be uploaded to the chain without paying any fees or deposits. @@ -191,12 +175,13 @@ pub mod pallet { Ok(()) } - /// Clear the request for a preimage. + /// Clear a previously made request for a preimage. + /// + /// NOTE: THIS MUST NOT BE CALLED ON `hash` MORE TIMES THAN `request_preimage`. #[pallet::weight(0)] pub fn clear_request(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; - Self::do_clear_request(hash); - Ok(()) + Self::do_clear_request(hash) } } } @@ -211,73 +196,39 @@ impl Pallet { Ok(Some(who)) } - /// Store some preimage on chain from a trusted source. - /// - /// If the preimage is already uploaded, we increase the reference counter, ensuring it is - /// not cleared before all uses of this preimage is complete. - fn note_system_bytes(bounded_vec: BoundedVec) { - let hash = T::Hashing::hash(&bounded_vec); - Preimages::::mutate_exists(hash, |maybe_preimage| { - if let Some(preimage) = maybe_preimage { - // If the preimage already exists, it could be owned by a user. - // We have the system take over control of the preimage. - match &preimage.ref_count { - RefCount::User(who, deposit) => { - T::Currency::unreserve(who, *deposit); - preimage.ref_count = RefCount::System(One::one()); - }, - RefCount::System(mut count) => { - count.saturating_inc(); - }, - } - } else { - *maybe_preimage = Some(Preimage { - preimage: bounded_vec, - ref_count: RefCount::System(One::one()), - }) - } - }); - - Self::deposit_event(Event::Noted { hash }); - } - /// Store some preimage on chain. /// /// We verify that the preimage is within the bounds of what the pallet supports. /// /// If the preimage was requested to be uploaded, then the user pays no deposits or tx fees. - fn note_user_bytes( - bounded_vec: BoundedVec, - depositor: T::AccountId, + fn note_bytes( + preimage: BoundedVec, + maybe_depositor: Option<&T::AccountId>, ) -> Result { - let hash = T::Hashing::hash(&bounded_vec); - ensure!(!Preimages::::contains_key(hash), Error::::AlreadyNoted); + let hash = T::Hashing::hash(&preimage); + ensure!(!PreimageFor::::contains_key(hash), Error::::AlreadyNoted); // We take a deposit only if there is a provided depositor, and the preimage was not // previously requested. This also allows the tx to pay no fee. - let requests = Requests::::take(hash); - let ref_count = if requests > 0 { - RefCount::System(requests) - } else { - let length = bounded_vec.len() as u32; - let deposit = T::BaseDeposit::get() - .saturating_add(T::ByteDeposit::get().saturating_mul(length.into())); - T::Currency::reserve(&depositor, deposit)?; - RefCount::User(depositor, deposit) + let was_requested = match (StatusFor::::get(hash), maybe_depositor) { + (Some(RequestStatus::Requested(_)), _) => true, + (Some(RequestStatus::Unrequested(..)), _) => Err(Error::::AlreadyNoted)?, + (_, None) => true, + (None, Some(depositor)) => { + let length = preimage.len() as u32; + let deposit = T::BaseDeposit::get() + .saturating_add(T::ByteDeposit::get().saturating_mul(length.into())); + T::Currency::reserve(depositor, deposit)?; + let status = RequestStatus::Unrequested(Some((depositor.clone(), deposit))); + StatusFor::::insert(hash, status); + false + }, }; - // Return whether this was requested by the system. - let system_request = match ref_count { - RefCount::System(_) => true, - RefCount::User(_, _) => false, - }; - - let preimage = Preimage { preimage: bounded_vec, ref_count }; - - Preimages::::insert(hash, preimage); + PreimageFor::::insert(hash, preimage); Self::deposit_event(Event::Noted { hash }); - Ok(system_request) + Ok(was_requested) } // This function will add a hash to the list of requested preimages. @@ -285,24 +236,20 @@ impl Pallet { // If the preimage already exists before the request is made, the deposit for the preimage is // returned to the user, and removed from their management. fn do_request_preimage(hash: T::Hash) { - if let Some(mut preimage_metadata) = Preimages::::get(hash) { - match preimage_metadata.ref_count { - RefCount::User(who, deposit) => { - // Preimage already exists and owned by a user. - // We return the deposit and change ownership to the system. - T::Currency::unreserve(&who, deposit); - preimage_metadata.ref_count = RefCount::System(One::one()); - }, - RefCount::System(mut count) => { - // Preimage already exists and is owned by the system. - // We simply increase the number of reference counters. - count.saturating_inc(); - }, + let count = StatusFor::::get(hash).map_or(1, |x| match x { + RequestStatus::Requested(mut count) => { + count.saturating_inc(); + count } - Preimages::::insert(hash, preimage_metadata); - } else { - // Preimage does not exist yet, so increase the number of requests. - Requests::::mutate(hash, |requests| requests.saturating_inc()); + RequestStatus::Unrequested(None) => 1, + RequestStatus::Unrequested(Some((owner, deposit))) => { + // Return the deposit - the preimage now has outstanding requests. + T::Currency::unreserve(&owner, deposit); + 1 + }, + }); + StatusFor::::insert(&hash, RequestStatus::Requested(count)); + if count == 1 { Self::deposit_event(Event::Requested { hash }); } } @@ -313,53 +260,39 @@ impl Pallet { // data. // // If `maybe_owner` is not provided, this function cannot return an error. - fn do_clear_preimage(hash: T::Hash, maybe_owner: Option) -> DispatchResult { - Preimages::::mutate_exists(hash, |maybe_value| -> DispatchResult { - if let Some(preimage_metadata) = maybe_value { - match &preimage_metadata.ref_count { - RefCount::User(who, deposit) => { - // If there is a deposit on hold, we return it if there is no `maybe_owner` - // or if the owner matches. - if let Some(owner) = maybe_owner { - if &owner != who { - // Ownership check did not pass. Return early without mutating - // anything. - return Err(Error::::NotAuthorized.into()) - } - } - // At this point, we have done all the authorization needed, and we can - // simply unreserve the deposit. - T::Currency::unreserve(who, *deposit); - }, - RefCount::System(mut count) => { - // A regular user cannot clear a system preimage. - if maybe_owner.is_some() { - return Err(Error::::NotAuthorized.into()) - } - // If this preimage still has reference counters, decrement, and exit early. - if count > 1 { - count.saturating_dec(); - return Ok(()) - } - }, - }; - - // If we got this far, we are removing the value. - *maybe_value = None; - Self::deposit_event(Event::Cleared { hash }); - } - Ok(()) - }) + fn do_clear_preimage(hash: T::Hash, maybe_check_owner: Option) -> DispatchResult { + match StatusFor::::get(&hash).ok_or(Error::::NotNoted)? { + RequestStatus::Unrequested(Some((owner, deposit))) => { + ensure!(maybe_check_owner.map_or(true, |c| &c == &owner), Error::::NotAuthorized); + T::Currency::unreserve(&owner, deposit); + }, + RequestStatus::Unrequested(None) => { + ensure!(maybe_check_owner.is_none(), Error::::NotAuthorized); + }, + RequestStatus::Requested(_) => Err(Error::::Requested)?, + } + StatusFor::::remove(&hash); + PreimageFor::::remove(&hash); + Self::deposit_event(Event::Cleared { hash }); + Ok(()) } /// Clear a preimage request. - fn do_clear_request(hash: T::Hash) { - let count = Requests::::get(hash); - if count > 1 { - Requests::::insert(hash, count - 1); - } else { - Requests::::remove(hash); + fn do_clear_request(hash: T::Hash) -> DispatchResult { + match StatusFor::::get(hash).ok_or(Error::::NotRequested)? { + RequestStatus::Requested(mut count) if count > 1 => { + count.saturating_dec(); + StatusFor::::insert(&hash, RequestStatus::Requested(count)); + } + RequestStatus::Requested(count) => { + debug_assert!(count == 1, "preimage request counter at zero?"); + PreimageFor::::remove(&hash); + StatusFor::::remove(&hash); + Self::deposit_event(Event::Cleared { hash }); + } + RequestStatus::Unrequested(_) => Err(Error::::NotRequested)?, } + Ok(()) } } @@ -367,19 +300,21 @@ impl frame_support::traits::PreimageHandler for Pallet { type MaxSize = T::MaxSize; fn preimage_exists(hash: T::Hash) -> bool { - Preimages::::contains_key(hash) + PreimageFor::::contains_key(hash) } fn preimage_requested(hash: T::Hash) -> bool { - Requests::::contains_key(hash) + matches!(StatusFor::::get(hash), Some(RequestStatus::Requested(..))) } fn get_preimage(hash: T::Hash) -> Option> { - Preimages::::get(hash).map(|preimage| preimage.preimage.to_vec()) + PreimageFor::::get(hash).map(|preimage| preimage.to_vec()) } fn note_preimage(bytes: BoundedVec) { - Self::note_system_bytes(bytes) + // We don't really care if this fails, since that's only the case if someone else has + // already noted it. + let _ = Self::note_bytes(bytes, None); } fn request_preimage(hash: T::Hash) { @@ -389,10 +324,11 @@ impl frame_support::traits::PreimageHandler for Pallet { fn clear_preimage(hash: T::Hash) { // Should never fail if authorization check is skipped. let res = Self::do_clear_preimage(hash, None); - debug_assert!(res.is_ok(), "do_clear_preimage failed when authorization check was skipped"); + debug_assert!(res.is_ok(), "do_clear_preimage failed - request outstanding?"); } fn clear_request(hash: T::Hash) { - Self::do_clear_request(hash); + let res = Self::do_clear_request(hash); + debug_assert!(res.is_ok(), "do_clear_request failed - counter underflow?"); } } From 23485e7fd65d31da64ad83c23ae66c1f248946c0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 23 Nov 2021 18:01:30 +0100 Subject: [PATCH 13/58] Make it simple --- frame/preimage/src/lib.rs | 39 ++++++++++++++------------ frame/support/src/traits/misc.rs | 41 +++++++++++++++++++--------- frame/support/src/traits/schedule.rs | 1 + 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 8d7e4a134411f..d0970a5ef3368 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -40,6 +40,7 @@ use frame_support::{ BoundedVec, }; use scale_info::TypeInfo; +use frame_support::traits::{PreimageProvider, PreimageRecipient}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -159,9 +160,9 @@ pub mod pallet { /// Clear an unrequested preimage from the runtime storage. #[pallet::weight(0)] - pub fn clear_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { + pub fn unnote_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { let maybe_sender = Self::ensure_signed_or_manager(origin)?; - Self::do_clear_preimage(hash, maybe_sender) + Self::unnote_preimage(hash, maybe_sender) } /// Request a preimage be uploaded to the chain without paying any fees or deposits. @@ -260,7 +261,7 @@ impl Pallet { // data. // // If `maybe_owner` is not provided, this function cannot return an error. - fn do_clear_preimage(hash: T::Hash, maybe_check_owner: Option) -> DispatchResult { + fn unnote_preimage(hash: T::Hash, maybe_check_owner: Option) -> DispatchResult { match StatusFor::::get(&hash).ok_or(Error::::NotNoted)? { RequestStatus::Unrequested(Some((owner, deposit))) => { ensure!(maybe_check_owner.map_or(true, |c| &c == &owner), Error::::NotAuthorized); @@ -296,9 +297,7 @@ impl Pallet { } } -impl frame_support::traits::PreimageHandler for Pallet { - type MaxSize = T::MaxSize; - +impl PreimageProvider for Pallet { fn preimage_exists(hash: T::Hash) -> bool { PreimageFor::::contains_key(hash) } @@ -311,24 +310,28 @@ impl frame_support::traits::PreimageHandler for Pallet { PreimageFor::::get(hash).map(|preimage| preimage.to_vec()) } - fn note_preimage(bytes: BoundedVec) { - // We don't really care if this fails, since that's only the case if someone else has - // already noted it. - let _ = Self::note_bytes(bytes, None); - } - fn request_preimage(hash: T::Hash) { Self::do_request_preimage(hash) } - fn clear_preimage(hash: T::Hash) { - // Should never fail if authorization check is skipped. - let res = Self::do_clear_preimage(hash, None); - debug_assert!(res.is_ok(), "do_clear_preimage failed - request outstanding?"); - } - fn clear_request(hash: T::Hash) { let res = Self::do_clear_request(hash); debug_assert!(res.is_ok(), "do_clear_request failed - counter underflow?"); } } + +impl PreimageRecipient for Pallet { + type MaxSize = T::MaxSize; + + fn note_preimage(bytes: BoundedVec) { + // We don't really care if this fails, since that's only the case if someone else has + // already noted it. + let _ = Self::note_bytes(bytes, None); + } + + fn unnote_preimage(hash: T::Hash) { + // Should never fail if authorization check is skipped. + let res = Self::unnote_preimage(hash, None); + debug_assert!(res.is_ok(), "unnote_preimage failed - request outstanding?"); + } +} diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 6486eb387ac09..1beb29eeafa72 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -564,28 +564,43 @@ impl TypeInfo for WrapperKeepOpaque { } } +/// A interface for looking up preimages from their hash on chain. +pub trait PreimageProvider { + /// Returns whether a preimage exists for a given hash. + /// + /// A value of `true` implies that `get_preimage` is `Some`. + fn preimage_exists(hash: Hash) -> bool; + + /// Returns the preimage for a given hash. + fn get_preimage(hash: Hash) -> Option>; + + /// Returns whether a preimage request exists for a given hash. + fn preimage_requested(hash: Hash) -> bool; + + /// Request that someone report a preimage. Providers use this to optimise the economics for + /// preimage reporting. + fn request_preimage(hash: Hash); + + /// Clear a preimage request. + fn clear_request(hash: Hash); +} + /// A interface for managing preimages to hashes on chain. /// /// Note that this API does not assume any underlying user is calling, and thus /// does not handle any preimage ownership or fees. Other system level logic that /// uses this API should implement that on their own side. -pub trait PreimageHandler { +pub trait PreimageRecipient { /// Maximum size of a preimage. type MaxSize: Get; - /// Returns whether a preimage exists for a given hash. - fn preimage_exists(hash: Hash) -> bool; - /// Returns whether a preimage request exists for a given hash. - fn preimage_requested(hash: Hash) -> bool; - /// Returns the preimage for a given hash. - fn get_preimage(hash: Hash) -> Option>; + /// Store the bytes of a preimage on chain. fn note_preimage(bytes: crate::BoundedVec); - /// Clear an existing preimage. - fn clear_preimage(hash: Hash); - /// Request that someone report a preimage. - fn request_preimage(hash: Hash); - /// Clear a preimage request. - fn clear_request(hash: Hash); + + /// Clear a previously noted preimage. This is infallible and should be treated more like a + /// hint - if it was not previously noted or if it is now requested, then this will not do + /// anything. + fn unnote_preimage(hash: Hash); } #[cfg(test)] diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 19f50a93c0681..fad0484bb2b7e 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -20,6 +20,7 @@ use codec::{Codec, Decode, Encode, EncodeLike}; use scale_info::TypeInfo; use sp_runtime::{DispatchError, RuntimeDebug}; +use frame_support::traits::PreimageProvider; use sp_std::{fmt::Debug, prelude::*}; /// Information relating to the period of a scheduled task. First item is the length of the From 6679e5be233d96bda37ac2190ba7ac1a2ef4b4ff Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 23 Nov 2021 18:55:48 +0100 Subject: [PATCH 14/58] Formatting --- client/consensus/babe/src/verification.rs | 4 +-- .../src/protocol/notifications/behaviour.rs | 4 +-- client/network/src/protocol/sync/blocks.rs | 2 +- client/network/src/service/tests.rs | 2 +- client/network/src/transactions.rs | 4 +-- .../election-provider-multi-phase/src/lib.rs | 2 +- frame/preimage/src/lib.rs | 30 ++++++++----------- .../src/pallet/parse/pallet_struct.rs | 4 +-- frame/support/src/traits/schedule.rs | 2 +- 9 files changed, 24 insertions(+), 30 deletions(-) diff --git a/client/consensus/babe/src/verification.rs b/client/consensus/babe/src/verification.rs index af118312dd07c..1554fa6de31be 100644 --- a/client/consensus/babe/src/verification.rs +++ b/client/consensus/babe/src/verification.rs @@ -114,7 +114,7 @@ where ); check_secondary_plain_header::(pre_hash, secondary, sig, &epoch)?; - } + }, PreDigest::SecondaryVRF(secondary) if epoch.config.allowed_slots.is_secondary_vrf_slots_allowed() => { @@ -125,7 +125,7 @@ where ); check_secondary_vrf_header::(pre_hash, secondary, sig, &epoch)?; - } + }, _ => return Err(babe_err(Error::SecondarySlotAssignmentsDisabled)), } diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 01138e3207570..f66f1fbe9e95a 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -712,7 +712,7 @@ impl Notifications { timer: delay_id, timer_deadline: *backoff, }; - } + }, // Disabled => Enabled PeerState::Disabled { mut connections, backoff_until } => { @@ -2085,7 +2085,7 @@ impl NetworkBehaviour for Notifications { .boxed(), ); } - } + }, // We intentionally never remove elements from `delays`, and it may // thus contain obsolete entries. This is a normal situation. diff --git a/client/network/src/protocol/sync/blocks.rs b/client/network/src/protocol/sync/blocks.rs index 30ba7ffafeffc..ce4535dc0b45f 100644 --- a/client/network/src/protocol/sync/blocks.rs +++ b/client/network/src/protocol/sync/blocks.rs @@ -203,7 +203,7 @@ impl BlockCollection { { *downloading -= 1; false - } + }, Some(&mut BlockRangeState::Downloading { .. }) => true, _ => false, }; diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 69b172d07edfe..87e481dc87f2d 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -530,7 +530,7 @@ fn fallback_name_working() { { assert_eq!(negotiated_fallback, Some(PROTOCOL_NAME)); break - } + }, _ => {}, }; } diff --git a/client/network/src/transactions.rs b/client/network/src/transactions.rs index 99350f603a375..6d190651160f0 100644 --- a/client/network/src/transactions.rs +++ b/client/network/src/transactions.rs @@ -336,13 +336,13 @@ impl TransactionsHandler { }, ); debug_assert!(_was_in.is_none()); - } + }, Event::NotificationStreamClosed { remote, protocol } if protocol == self.protocol_name => { let _peer = self.peers.remove(&remote); debug_assert!(_peer.is_some()); - } + }, Event::NotificationsReceived { remote, messages } => { for (protocol, message) in messages { diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index a7863fafa7747..ab8b1523f0509 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -772,7 +772,7 @@ pub mod pallet { Self::on_initialize_open_unsigned(enabled, now); T::WeightInfo::on_initialize_open_unsigned() } - } + }, _ => T::WeightInfo::on_initialize_nothing(), } } diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index d0970a5ef3368..aa263ee269972 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -35,12 +35,11 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ ensure, pallet_prelude::Get, - traits::{Currency, ReservableCurrency}, + traits::{Currency, PreimageProvider, PreimageRecipient, ReservableCurrency}, weights::Pays, BoundedVec, }; use scale_info::TypeInfo; -use frame_support::traits::{PreimageProvider, PreimageRecipient}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -121,21 +120,13 @@ pub mod pallet { /// The request status of a given hash. #[pallet::storage] - pub(super) type StatusFor = StorageMap< - _, - Identity, - T::Hash, - RequestStatus>, - >; + pub(super) type StatusFor = + StorageMap<_, Identity, T::Hash, RequestStatus>>; /// The preimages stored by this pallet. #[pallet::storage] - pub(super) type PreimageFor = StorageMap< - _, - Identity, - T::Hash, - BoundedVec, - >; + pub(super) type PreimageFor = + StorageMap<_, Identity, T::Hash, BoundedVec>; #[pallet::call] impl Pallet { @@ -241,7 +232,7 @@ impl Pallet { RequestStatus::Requested(mut count) => { count.saturating_inc(); count - } + }, RequestStatus::Unrequested(None) => 1, RequestStatus::Unrequested(Some((owner, deposit))) => { // Return the deposit - the preimage now has outstanding requests. @@ -264,7 +255,10 @@ impl Pallet { fn unnote_preimage(hash: T::Hash, maybe_check_owner: Option) -> DispatchResult { match StatusFor::::get(&hash).ok_or(Error::::NotNoted)? { RequestStatus::Unrequested(Some((owner, deposit))) => { - ensure!(maybe_check_owner.map_or(true, |c| &c == &owner), Error::::NotAuthorized); + ensure!( + maybe_check_owner.map_or(true, |c| &c == &owner), + Error::::NotAuthorized + ); T::Currency::unreserve(&owner, deposit); }, RequestStatus::Unrequested(None) => { @@ -284,13 +278,13 @@ impl Pallet { RequestStatus::Requested(mut count) if count > 1 => { count.saturating_dec(); StatusFor::::insert(&hash, RequestStatus::Requested(count)); - } + }, RequestStatus::Requested(count) => { debug_assert!(count == 1, "preimage request counter at zero?"); PreimageFor::::remove(&hash); StatusFor::::remove(&hash); Self::deposit_event(Event::Cleared { hash }); - } + }, RequestStatus::Unrequested(_) => Err(Error::::NotRequested)?, } Ok(()) diff --git a/frame/support/procedural/src/pallet/parse/pallet_struct.rs b/frame/support/procedural/src/pallet/parse/pallet_struct.rs index 278f46e13818e..c528faf669ee3 100644 --- a/frame/support/procedural/src/pallet/parse/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/parse/pallet_struct.rs @@ -130,12 +130,12 @@ impl PalletStructDef { if generate_storage_info.is_none() => { generate_storage_info = Some(span); - } + }, PalletStructAttr::StorageVersion { storage_version, .. } if storage_version_found.is_none() => { storage_version_found = Some(storage_version); - } + }, attr => { let msg = "Unexpected duplicated attribute"; return Err(syn::Error::new(attr.span(), msg)) diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index fad0484bb2b7e..314e480e1332e 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -18,9 +18,9 @@ //! Traits and associated utilities for scheduling dispatchables in FRAME. use codec::{Codec, Decode, Encode, EncodeLike}; +use frame_support::traits::PreimageProvider; use scale_info::TypeInfo; use sp_runtime::{DispatchError, RuntimeDebug}; -use frame_support::traits::PreimageProvider; use sp_std::{fmt::Debug, prelude::*}; /// Information relating to the period of a scheduled task. First item is the length of the From 4699aa21851d6158c75faa2b971274e8c67755ba Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 23 Nov 2021 22:13:13 +0100 Subject: [PATCH 15/58] Initial draft --- Cargo.lock | 1 + frame/preimage/src/lib.rs | 49 +-- frame/scheduler/Cargo.toml | 2 + frame/scheduler/src/lib.rs | 283 ++++++++----- frame/support/src/traits.rs | 4 +- frame/support/src/traits/misc.rs | 16 +- frame/support/src/traits/schedule.rs | 390 ++++++++++++++---- frame/support/src/traits/tokens/currency.rs | 63 +++ .../src/traits/tokens/currency/reservable.rs | 17 + frame/support/src/traits/tokens/imbalance.rs | 33 ++ 10 files changed, 646 insertions(+), 212 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 79d5a6b4cc96b..99b234f45fe2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5882,6 +5882,7 @@ dependencies = [ "frame-support", "frame-system", "log 0.4.14", + "pallet-preimage", "parity-scale-codec", "scale-info", "sp-core", diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index aa263ee269972..da9090b727d6b 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -153,7 +153,7 @@ pub mod pallet { #[pallet::weight(0)] pub fn unnote_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { let maybe_sender = Self::ensure_signed_or_manager(origin)?; - Self::unnote_preimage(hash, maybe_sender) + Self::do_unnote_preimage(&hash, maybe_sender) } /// Request a preimage be uploaded to the chain without paying any fees or deposits. @@ -163,7 +163,7 @@ pub mod pallet { #[pallet::weight(0)] pub fn request_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; - Self::do_request_preimage(hash); + Self::do_request_preimage(&hash); Ok(()) } @@ -173,7 +173,7 @@ pub mod pallet { #[pallet::weight(0)] pub fn clear_request(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; - Self::do_clear_request(hash) + Self::do_clear_request(&hash) } } } @@ -227,7 +227,7 @@ impl Pallet { // // If the preimage already exists before the request is made, the deposit for the preimage is // returned to the user, and removed from their management. - fn do_request_preimage(hash: T::Hash) { + fn do_request_preimage(hash: &T::Hash) { let count = StatusFor::::get(hash).map_or(1, |x| match x { RequestStatus::Requested(mut count) => { count.saturating_inc(); @@ -240,9 +240,9 @@ impl Pallet { 1 }, }); - StatusFor::::insert(&hash, RequestStatus::Requested(count)); + StatusFor::::insert(hash, RequestStatus::Requested(count)); if count == 1 { - Self::deposit_event(Event::Requested { hash }); + Self::deposit_event(Event::Requested { hash: hash.clone() }); } } @@ -252,8 +252,11 @@ impl Pallet { // data. // // If `maybe_owner` is not provided, this function cannot return an error. - fn unnote_preimage(hash: T::Hash, maybe_check_owner: Option) -> DispatchResult { - match StatusFor::::get(&hash).ok_or(Error::::NotNoted)? { + fn do_unnote_preimage( + hash: &T::Hash, + maybe_check_owner: Option, + ) -> DispatchResult { + match StatusFor::::get(hash).ok_or(Error::::NotNoted)? { RequestStatus::Unrequested(Some((owner, deposit))) => { ensure!( maybe_check_owner.map_or(true, |c| &c == &owner), @@ -266,24 +269,24 @@ impl Pallet { }, RequestStatus::Requested(_) => Err(Error::::Requested)?, } - StatusFor::::remove(&hash); - PreimageFor::::remove(&hash); - Self::deposit_event(Event::Cleared { hash }); + StatusFor::::remove(hash); + PreimageFor::::remove(hash); + Self::deposit_event(Event::Cleared { hash: hash.clone() }); Ok(()) } /// Clear a preimage request. - fn do_clear_request(hash: T::Hash) -> DispatchResult { + fn do_clear_request(hash: &T::Hash) -> DispatchResult { match StatusFor::::get(hash).ok_or(Error::::NotRequested)? { RequestStatus::Requested(mut count) if count > 1 => { count.saturating_dec(); - StatusFor::::insert(&hash, RequestStatus::Requested(count)); + StatusFor::::insert(hash, RequestStatus::Requested(count)); }, RequestStatus::Requested(count) => { debug_assert!(count == 1, "preimage request counter at zero?"); - PreimageFor::::remove(&hash); - StatusFor::::remove(&hash); - Self::deposit_event(Event::Cleared { hash }); + PreimageFor::::remove(hash); + StatusFor::::remove(hash); + Self::deposit_event(Event::Cleared { hash: hash.clone() }); }, RequestStatus::Unrequested(_) => Err(Error::::NotRequested)?, } @@ -292,23 +295,23 @@ impl Pallet { } impl PreimageProvider for Pallet { - fn preimage_exists(hash: T::Hash) -> bool { + fn preimage_exists(hash: &T::Hash) -> bool { PreimageFor::::contains_key(hash) } - fn preimage_requested(hash: T::Hash) -> bool { + fn preimage_requested(hash: &T::Hash) -> bool { matches!(StatusFor::::get(hash), Some(RequestStatus::Requested(..))) } - fn get_preimage(hash: T::Hash) -> Option> { + fn get_preimage(hash: &T::Hash) -> Option> { PreimageFor::::get(hash).map(|preimage| preimage.to_vec()) } - fn request_preimage(hash: T::Hash) { + fn request_preimage(hash: &T::Hash) { Self::do_request_preimage(hash) } - fn clear_request(hash: T::Hash) { + fn clear_request(hash: &T::Hash) { let res = Self::do_clear_request(hash); debug_assert!(res.is_ok(), "do_clear_request failed - counter underflow?"); } @@ -323,9 +326,9 @@ impl PreimageRecipient for Pallet { let _ = Self::note_bytes(bytes, None); } - fn unnote_preimage(hash: T::Hash) { + fn unnote_preimage(hash: &T::Hash) { // Should never fail if authorization check is skipped. - let res = Self::unnote_preimage(hash, None); + let res = Self::do_unnote_preimage(hash, None); debug_assert!(res.is_ok(), "unnote_preimage failed - request outstanding?"); } } diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 862321dfa6f26..2f6119868169d 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -24,6 +24,7 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " [dev-dependencies] sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } +pallet-preimage = { version = "4.0.0-dev", default-features = false, path = "../preimage" } [features] default = ["std"] @@ -34,6 +35,7 @@ std = [ "frame-benchmarking/std", "frame-support/std", "frame-system/std", + "pallet-preimage/std", "sp-io/std", "sp-std/std", "log/std", diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index d59c42cc850dd..806dd00ef344b 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -57,7 +57,7 @@ use codec::{Codec, Decode, Encode}; use frame_support::{ dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter}, traits::{ - schedule::{self, DispatchTime}, + schedule::{self, DispatchTime, CallOrHash}, PreimageProvider, EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp, }, weights::{GetDispatchInfo, Weight}, @@ -77,6 +77,11 @@ pub type PeriodicIndex = u32; /// The location of a scheduled task that can be used to remove it. pub type TaskAddress = (BlockNumber, u32); +pub type CallOrHashOf = CallOrHash< + ::Call, + ::Hash, +>; + #[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] #[derive(Clone, RuntimeDebug, Encode, Decode)] struct ScheduledV1 { @@ -89,7 +94,7 @@ struct ScheduledV1 { /// Information regarding an item to be executed in the future. #[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] #[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo)] -pub struct ScheduledV2 { +pub struct ScheduledV3 { /// The unique identity for this task, if there is one. maybe_id: Option>, /// This task's priority. @@ -103,10 +108,33 @@ pub struct ScheduledV2 { _phantom: PhantomData, } +use crate::ScheduledV3 as ScheduledV2; + +pub type ScheduledV2Of = ScheduledV3< + ::Call, + ::BlockNumber, + ::PalletsOrigin, + ::AccountId, +>; + +pub type ScheduledV3Of = ScheduledV3< + CallOrHashOf, + ::BlockNumber, + ::PalletsOrigin, + ::AccountId, +>; + +pub type ScheduledOf = ScheduledV3Of; + /// The current version of Scheduled struct. pub type Scheduled = ScheduledV2; +// TODO: request when scheduled +// TODO: unrequest when cancelled +// TODO: unrequest when non-periodic executed + + // A value placed in storage that represents the current version of the Scheduler storage. // This value is used by the `on_runtime_upgrade` logic to determine whether we run // storage migration logic. @@ -114,6 +142,7 @@ pub type Scheduled = enum Releases { V1, V2, + V3, } impl Default for Releases { @@ -125,7 +154,7 @@ impl Default for Releases { #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, traits::{PreimageProvider, schedule::LookupError}}; use frame_system::pallet_prelude::*; #[pallet::pallet] @@ -176,6 +205,9 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + /// The preimage provider with which we look up call hashes to get the call. + type PreimageProvider: PreimageProvider; } /// Items to be executed, indexed by the block number that they should be executed on. @@ -184,7 +216,7 @@ pub mod pallet { _, Twox64Concat, T::BlockNumber, - Vec::Call, T::BlockNumber, T::PalletsOrigin, T::AccountId>>>, + Vec>>, ValueQuery, >; @@ -209,6 +241,8 @@ pub mod pallet { Canceled(T::BlockNumber, u32), /// Dispatched some task. \[task, id, result\] Dispatched(TaskAddress, Option>, DispatchResult), + /// The call for the provided hash was not found so the task has been aborted. + CallLookupFailed(TaskAddress, Option>, LookupError), } #[pallet::error] @@ -258,7 +292,12 @@ pub mod pallet { let mut queued = Agenda::::take(now) .into_iter() .enumerate() - .filter_map(|(index, s)| s.map(|inner| (index as u32, inner))) + .filter_map(|(index, s)| { + let ScheduledV3 { maybe_id, priority, call, maybe_periodic, origin, _phantom } = s?; + let call = call.resolved::(); + let s = ScheduledV3 { maybe_id, priority, call, maybe_periodic, origin, _phantom }; + Some((index as u32, s)) + }) .collect::>(); if queued.len() as u32 > T::MaxScheduledPerBlock::get() { log::warn!( @@ -269,22 +308,25 @@ pub mod pallet { } queued.sort_by_key(|(_, s)| s.priority); let base_weight: Weight = T::DbWeight::get().reads_writes(1, 2); // Agenda + Agenda(next) + let next = now + One::one(); let mut total_weight: Weight = 0; queued .into_iter() .enumerate() .scan(base_weight, |cumulative_weight, (order, (index, s))| { - *cumulative_weight = - cumulative_weight.saturating_add(s.call.get_dispatch_info().weight); - - let origin = - <::Origin as From>::from(s.origin.clone()) - .into(); - if ensure_signed(origin).is_ok() { - // AccountData for inner call origin accountdata. + if let Some(c) = s.call.as_call() { *cumulative_weight = - cumulative_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + cumulative_weight.saturating_add(c.get_dispatch_info().weight); + let origin = + <::Origin as From>::from(s.origin.clone()) + .into(); + + if ensure_signed(origin).is_ok() { + // AccountData for inner call origin accountdata. + *cumulative_weight = + cumulative_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + } } if s.maybe_id.is_some() { @@ -301,6 +343,10 @@ pub mod pallet { Some((order, index, *cumulative_weight, s)) }) .filter_map(|(order, index, cumulative_weight, mut s)| { + let call = match s.call.as_ref().cloned() { + Some(c) => c, + None => return Some(Some(s)), + }; // We allow a scheduled call if any is true: // - It's priority is `HARD_DEADLINE` // - It does not push the weight past the limit. @@ -309,7 +355,7 @@ pub mod pallet { cumulative_weight <= limit || order == 0 { - let r = s.call.clone().dispatch(s.origin.clone().into()); + let r = call.dispatch(s.origin.clone().into()); let maybe_id = s.maybe_id.clone(); if let &Some((period, count)) = &s.maybe_periodic { if count > 1 { @@ -323,7 +369,7 @@ pub mod pallet { let next_index = Agenda::::decode_len(now + period).unwrap_or(0); Lookup::::insert(id, (next, next_index as u32)); } - Agenda::::append(next, Some(s)); + Agenda::::append(next, Some(s.into())); } else { if let Some(ref id) = s.maybe_id { Lookup::::remove(id); @@ -340,10 +386,7 @@ pub mod pallet { Some(Some(s)) } }) - .for_each(|unused| { - let next = now + One::one(); - Agenda::::append(next, unused); - }); + .for_each(|unused| Agenda::::append(next, unused)); total_weight } @@ -367,7 +410,7 @@ pub mod pallet { when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box<::Call>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -416,7 +459,7 @@ pub mod pallet { when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box<::Call>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -460,7 +503,7 @@ pub mod pallet { after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box<::Call>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -486,7 +529,7 @@ pub mod pallet { after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box<::Call>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -504,9 +547,9 @@ pub mod pallet { } impl Pallet { - /// Migrate storage format from V1 to V2. + /// Migrate storage format from V1 to V3. /// Return true if migration is performed. - pub fn migrate_v1_to_t2() -> bool { + pub fn migrate_v1_to_v3() -> bool { if StorageVersion::::get() == Releases::V1 { StorageVersion::::put(Releases::V2); @@ -518,10 +561,43 @@ impl Pallet { agenda .into_iter() .map(|schedule| { - schedule.map(|schedule| ScheduledV2 { + schedule.map(|schedule| ScheduledV3 { maybe_id: schedule.maybe_id, priority: schedule.priority, - call: schedule.call, + call: CallOrHash::Call(schedule.call), + maybe_periodic: schedule.maybe_periodic, + origin: system::RawOrigin::Root.into(), + _phantom: Default::default(), + }) + }) + .collect::>(), + ) + }); + + true + } else { + false + } + } + + /// Migrate storage format from V2 to V3. + /// Return true if migration is performed. + pub fn migrate_v2_to_v3() -> bool { + if StorageVersion::::get() == Releases::V1 { + StorageVersion::::put(Releases::V2); + + Agenda::::translate::< + Vec>>, + _, + >(|_, agenda| { + Some( + agenda + .into_iter() + .map(|schedule| { + schedule.map(|schedule| ScheduledV3 { + maybe_id: schedule.maybe_id, + priority: schedule.priority, + call: CallOrHash::Call(schedule.call), maybe_periodic: schedule.maybe_periodic, origin: system::RawOrigin::Root.into(), _phantom: Default::default(), @@ -539,10 +615,7 @@ impl Pallet { /// Helper to migrate scheduler when the pallet origin type has changed. pub fn migrate_origin + codec::Decode>() { - Agenda::::translate::< - Vec::Call, T::BlockNumber, OldOrigin, T::AccountId>>>, - _, - >(|_, agenda| { + Agenda::::translate::>>, _>(|_, agenda| { Some( agenda .into_iter() @@ -583,7 +656,7 @@ impl Pallet { maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: ::Call, + call: CallOrHashOf, ) -> Result, DispatchError> { let when = Self::resolve_time(when)?; @@ -675,7 +748,7 @@ impl Pallet { maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: ::Call, + call: CallOrHashOf, ) -> Result, DispatchError> { // ensure id it is unique if Lookup::::contains_key(&id) { @@ -775,17 +848,18 @@ impl Pallet { } } -impl schedule::Anon::Call, T::PalletsOrigin> +impl schedule::v2::Anon::Call, T::PalletsOrigin> for Pallet { type Address = TaskAddress; + type Hash = T::Hash; fn schedule( when: DispatchTime, maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: ::Call, + call: CallOrHashOf, ) -> Result { Self::do_schedule(when, maybe_periodic, priority, origin, call) } @@ -806,10 +880,11 @@ impl schedule::Anon::Call, T::PalletsOr } } -impl schedule::Named::Call, T::PalletsOrigin> +impl schedule::v2::Named::Call, T::PalletsOrigin> for Pallet { type Address = TaskAddress; + type Hash = T::Hash; fn schedule_named( id: Vec, @@ -817,7 +892,7 @@ impl schedule::Named::Call, T::PalletsO maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: ::Call, + call: CallOrHashOf, ) -> Result { Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call).map_err(|_| ()) } @@ -934,6 +1009,7 @@ mod tests { System: frame_system::{Pallet, Call, Config, Storage, Event}, Logger: logger::{Pallet, Call, Event}, Scheduler: scheduler::{Pallet, Call, Storage, Event}, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event}, } ); @@ -981,11 +1057,21 @@ mod tests { parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; pub const MaxScheduledPerBlock: u32 = 10; + pub const MaxSize: u32 = 1024; } ord_parameter_types! { pub const One: u64 = 1; } + impl pallet_preimage::Config for Test { + type Event = Event; + type Currency = (); + type ManagerOrigin = EnsureRoot; + type MaxSize = MaxSize; + type BaseDeposit = (); + type ByteDeposit = (); + } + impl Config for Test { type Event = Event; type Origin = Origin; @@ -996,6 +1082,7 @@ mod tests { type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; + type PreimageProvider = Preimage; } pub type LoggerCall = logger::Call; @@ -1022,7 +1109,7 @@ mod tests { new_test_ext().execute_with(|| { let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); assert!(!::BaseCallFilter::contains(&call)); - assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call)); + assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into())); run_to_block(3); assert!(logger::log().is_empty()); run_to_block(4); @@ -1039,7 +1126,7 @@ mod tests { let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); assert!(!::BaseCallFilter::contains(&call)); // This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6 - assert_ok!(Scheduler::do_schedule(DispatchTime::After(3), None, 127, root(), call)); + assert_ok!(Scheduler::do_schedule(DispatchTime::After(3), None, 127, root(), call.into())); run_to_block(5); assert!(logger::log().is_empty()); run_to_block(6); @@ -1055,7 +1142,7 @@ mod tests { run_to_block(2); let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); assert!(!::BaseCallFilter::contains(&call)); - assert_ok!(Scheduler::do_schedule(DispatchTime::After(0), None, 127, root(), call)); + assert_ok!(Scheduler::do_schedule(DispatchTime::After(0), None, 127, root(), call.into())); // Will trigger on the next block. run_to_block(3); assert_eq!(logger::log(), vec![(root(), 42u32)]); @@ -1073,7 +1160,7 @@ mod tests { Some((3, 3)), 127, root(), - Call::Logger(logger::Call::log { i: 42, weight: 1000 }) + Call::Logger(logger::Call::log { i: 42, weight: 1000 }).into() )); run_to_block(3); assert!(logger::log().is_empty()); @@ -1098,7 +1185,7 @@ mod tests { let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( - Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call).unwrap(), + Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into()).unwrap(), (4, 0) ); @@ -1135,7 +1222,7 @@ mod tests { None, 127, root(), - call + call.into(), ) .unwrap(), (4, 0) @@ -1177,7 +1264,7 @@ mod tests { Some((3, 3)), 127, root(), - call + call.into(), ) .unwrap(), (4, 0) @@ -1230,7 +1317,7 @@ mod tests { None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), + Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), ) .unwrap(); let i = Scheduler::do_schedule( @@ -1238,7 +1325,7 @@ mod tests { None, 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: 1000 }), + Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into(), ) .unwrap(); run_to_block(3); @@ -1260,7 +1347,7 @@ mod tests { Some((3, 3)), 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: 1000 }), + Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into(), ) .unwrap(); // same id results in error. @@ -1270,7 +1357,7 @@ mod tests { None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: 1000 }) + Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), ) .is_err()); // different id is ok. @@ -1280,7 +1367,7 @@ mod tests { None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), + Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), ) .unwrap(); run_to_block(3); @@ -1302,14 +1389,14 @@ mod tests { None, 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }).into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), )); // 69 and 42 do not fit together run_to_block(4); @@ -1327,14 +1414,14 @@ mod tests { None, 0, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }).into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 0, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), )); // With base weights, 69 and 42 should not fit together, but do because of hard // deadlines @@ -1351,14 +1438,14 @@ mod tests { None, 1, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }).into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 0, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), )); run_to_block(4); assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]); @@ -1373,14 +1460,14 @@ mod tests { None, 255, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 3 }) + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 3 }).into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), @@ -1390,7 +1477,7 @@ mod tests { Call::Logger(LoggerCall::log { i: 2600, weight: MaximumSchedulerWeight::get() / 2 - }) + }).into(), )); // 2600 does not fit with 69 or 42, but has higher priority, so will go through @@ -1419,7 +1506,7 @@ mod tests { None, 255, root(), - Call::Logger(LoggerCall::log { i: 3, weight: MaximumSchedulerWeight::get() / 3 }) + Call::Logger(LoggerCall::log { i: 3, weight: MaximumSchedulerWeight::get() / 3 }).into(), )); // Anon Periodic assert_ok!(Scheduler::do_schedule( @@ -1427,7 +1514,7 @@ mod tests { Some((1000, 3)), 128, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 3 }) + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 3 }).into(), )); // Anon assert_ok!(Scheduler::do_schedule( @@ -1435,7 +1522,7 @@ mod tests { None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), )); // Named Periodic assert_ok!(Scheduler::do_schedule_named( @@ -1447,7 +1534,7 @@ mod tests { Call::Logger(LoggerCall::log { i: 2600, weight: MaximumSchedulerWeight::get() / 2 - }) + }).into(), )); // Will include the named periodic only @@ -1499,7 +1586,7 @@ mod tests { 4, None, 127, - call + call.into(), )); assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2)); run_to_block(3); @@ -1519,8 +1606,8 @@ mod tests { new_test_ext().execute_with(|| { run_to_block(3); - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 })); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 })); + let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); assert_err!( Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call), @@ -1542,22 +1629,22 @@ mod tests { #[test] fn should_use_orign() { new_test_ext().execute_with(|| { - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 })); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 })); + let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); assert_ok!(Scheduler::schedule_named( system::RawOrigin::Signed(1).into(), 1u32.encode(), 4, None, 127, - call + call.into(), )); assert_ok!(Scheduler::schedule( system::RawOrigin::Signed(1).into(), 4, None, 127, - call2 + call2.into(), )); run_to_block(3); // Scheduled calls are in the agenda. @@ -1574,8 +1661,8 @@ mod tests { #[test] fn should_check_orign() { new_test_ext().execute_with(|| { - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 })); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 })); + let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); assert_noop!( Scheduler::schedule_named( system::RawOrigin::Signed(2).into(), @@ -1598,23 +1685,23 @@ mod tests { fn should_check_orign_for_cancel() { new_test_ext().execute_with(|| { let call = - Box::new(Call::Logger(LoggerCall::log_without_filter { i: 69, weight: 1000 })); + Box::new(Call::Logger(LoggerCall::log_without_filter { i: 69, weight: 1000 }).into()); let call2 = - Box::new(Call::Logger(LoggerCall::log_without_filter { i: 42, weight: 1000 })); + Box::new(Call::Logger(LoggerCall::log_without_filter { i: 42, weight: 1000 }).into()); assert_ok!(Scheduler::schedule_named( system::RawOrigin::Signed(1).into(), 1u32.encode(), 4, None, 127, - call + call, )); assert_ok!(Scheduler::schedule( system::RawOrigin::Signed(1).into(), 4, None, 127, - call2 + call2, )); run_to_block(3); // Scheduled calls are in the agenda. @@ -1642,7 +1729,7 @@ mod tests { } #[test] - fn migration_to_v2_works() { + fn migration_to_v3_works() { new_test_ext().execute_with(|| { for i in 0..3u64 { let k = i.twox_64_concat(); @@ -1666,7 +1753,7 @@ mod tests { assert_eq!(StorageVersion::::get(), Releases::V1); - assert!(Scheduler::migrate_v1_to_t2()); + assert!(Scheduler::migrate_v1_to_v3()); assert_eq_uvec!( Agenda::::iter().collect::>(), @@ -1674,19 +1761,19 @@ mod tests { ( 0, vec![ - Some(ScheduledV2 { + Some(ScheduledV3 { maybe_id: None, priority: 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), maybe_periodic: None, origin: root(), _phantom: PhantomData::::default(), }), None, - Some(ScheduledV2 { + Some(ScheduledV3 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), maybe_periodic: Some((456u64, 10)), origin: root(), _phantom: PhantomData::::default(), @@ -1696,19 +1783,19 @@ mod tests { ( 1, vec![ - Some(ScheduledV2 { + Some(ScheduledV3 { maybe_id: None, priority: 11, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), maybe_periodic: None, origin: root(), _phantom: PhantomData::::default(), }), None, - Some(ScheduledV2 { + Some(ScheduledV3 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), maybe_periodic: Some((456u64, 10)), origin: root(), _phantom: PhantomData::::default(), @@ -1718,19 +1805,19 @@ mod tests { ( 2, vec![ - Some(ScheduledV2 { + Some(ScheduledV3 { maybe_id: None, priority: 12, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), maybe_periodic: None, origin: root(), _phantom: PhantomData::::default(), }), None, - Some(ScheduledV2 { + Some(ScheduledV3 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), maybe_periodic: Some((456u64, 10)), origin: root(), _phantom: PhantomData::::default(), @@ -1753,7 +1840,7 @@ mod tests { Some(Scheduled { maybe_id: None, priority: i as u8 + 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), origin: 3u32, maybe_periodic: None, _phantom: Default::default(), @@ -1763,7 +1850,7 @@ mod tests { maybe_id: Some(b"test".to_vec()), priority: 123, origin: 2u32, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), maybe_periodic: Some((456u64, 10)), _phantom: Default::default(), }), @@ -1792,7 +1879,7 @@ mod tests { Some(ScheduledV2::<_, _, OriginCaller, u64> { maybe_id: None, priority: 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), maybe_periodic: None, origin: system::RawOrigin::Root.into(), _phantom: PhantomData::::default(), @@ -1801,7 +1888,7 @@ mod tests { Some(ScheduledV2 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), maybe_periodic: Some((456u64, 10)), origin: system::RawOrigin::None.into(), _phantom: PhantomData::::default(), @@ -1814,7 +1901,7 @@ mod tests { Some(ScheduledV2 { maybe_id: None, priority: 11, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), maybe_periodic: None, origin: system::RawOrigin::Root.into(), _phantom: PhantomData::::default(), @@ -1823,7 +1910,7 @@ mod tests { Some(ScheduledV2 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), maybe_periodic: Some((456u64, 10)), origin: system::RawOrigin::None.into(), _phantom: PhantomData::::default(), @@ -1836,7 +1923,7 @@ mod tests { Some(ScheduledV2 { maybe_id: None, priority: 12, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), maybe_periodic: None, origin: system::RawOrigin::Root.into(), _phantom: PhantomData::::default(), @@ -1845,7 +1932,7 @@ mod tests { Some(ScheduledV2 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), maybe_periodic: Some((456u64, 10)), origin: system::RawOrigin::None.into(), _phantom: PhantomData::::default(), diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index dd03ed75d3ccb..0612ab3847993 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -52,8 +52,8 @@ mod misc; pub use misc::{ Backing, ConstU32, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, - OffchainWorker, OnKilledAccount, OnNewAccount, PreimageHandler, PrivilegeCmp, SameOrOther, - Time, TryDrop, UnixTime, WrapperKeepOpaque, WrapperOpaque, + OffchainWorker, OnKilledAccount, OnNewAccount, PreimageProvider, PreimageRecipient, + PrivilegeCmp, SameOrOther, Time, TryDrop, UnixTime, WrapperKeepOpaque, WrapperOpaque, }; mod stored_map; diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 1beb29eeafa72..2647824e23fc2 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -81,6 +81,10 @@ pub trait TryDrop: Sized { fn try_drop(self) -> Result<(), Self>; } +impl TryDrop for () { + fn try_drop(self) -> Result<(), Self> { Ok(()) } +} + /// Return type used when we need to return one of two items, each of the opposite direction or /// sign, with one (`Same`) being of the same type as the `self` or primary argument of the function /// that returned it. @@ -569,20 +573,20 @@ pub trait PreimageProvider { /// Returns whether a preimage exists for a given hash. /// /// A value of `true` implies that `get_preimage` is `Some`. - fn preimage_exists(hash: Hash) -> bool; + fn preimage_exists(hash: &Hash) -> bool; /// Returns the preimage for a given hash. - fn get_preimage(hash: Hash) -> Option>; + fn get_preimage(hash: &Hash) -> Option>; /// Returns whether a preimage request exists for a given hash. - fn preimage_requested(hash: Hash) -> bool; + fn preimage_requested(hash: &Hash) -> bool; /// Request that someone report a preimage. Providers use this to optimise the economics for /// preimage reporting. - fn request_preimage(hash: Hash); + fn request_preimage(hash: &Hash); /// Clear a preimage request. - fn clear_request(hash: Hash); + fn clear_request(hash: &Hash); } /// A interface for managing preimages to hashes on chain. @@ -600,7 +604,7 @@ pub trait PreimageRecipient { /// Clear a previously noted preimage. This is infallible and should be treated more like a /// hint - if it was not previously noted or if it is now requested, then this will not do /// anything. - fn unnote_preimage(hash: Hash); + fn unnote_preimage(hash: &Hash); } #[cfg(test)] diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 314e480e1332e..e8ef2a87628e8 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -17,11 +17,10 @@ //! Traits and associated utilities for scheduling dispatchables in FRAME. -use codec::{Codec, Decode, Encode, EncodeLike}; -use frame_support::traits::PreimageProvider; +use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{DispatchError, RuntimeDebug}; -use sp_std::{fmt::Debug, prelude::*}; +use sp_std::{fmt::Debug, result::Result, prelude::*}; /// Information relating to the period of a scheduled task. First item is the length of the /// period and the second is the number of times it should be executed in total before the task @@ -50,86 +49,311 @@ pub const HARD_DEADLINE: Priority = 63; /// The lowest priority. Most stuff should be around here. pub const LOWEST_PRIORITY: Priority = 255; -/// A type that can be used as a scheduler. -pub trait Anon { - /// An address which can be used for removing a scheduled task. - type Address: Codec + Clone + Eq + EncodeLike + Debug; - - /// Schedule a dispatch to happen at the beginning of some block in the future. - /// - /// This is not named. - fn schedule( - when: DispatchTime, - maybe_periodic: Option>, - priority: Priority, - origin: Origin, - call: Call, - ) -> Result; - - /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that, - /// also. - /// - /// Will return an error if the `address` is invalid. - /// - /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. - /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. - /// - /// NOTE2: This will not work to cancel periodic tasks after their initial execution. For - /// that, you must name the task explicitly using the `Named` trait. - fn cancel(address: Self::Address) -> Result<(), ()>; - - /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed - /// only if it is executed *before* the currently scheduled block. For periodic tasks, - /// this dispatch is guaranteed to succeed only before the *initial* execution; for - /// others, use `reschedule_named`. - /// - /// Will return an error if the `address` is invalid. - fn reschedule( - address: Self::Address, - when: DispatchTime, - ) -> Result; - - /// Return the next dispatch time for a given task. - /// - /// Will return an error if the `address` is invalid. - fn next_dispatch_time(address: Self::Address) -> Result; +/// Type representing a call. Can be either the `Call` value itself or the hash of the encoded +/// `Call`. +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum CallOrHash { + /// The `Call` value itself. + Call(Call), + /// The hash of the encoded `Call` which this value represents. + Hash(Hash), } -/// A type that can be used as a scheduler. -pub trait Named { - /// An address which can be used for removing a scheduled task. - type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug; - - /// Schedule a dispatch to happen at the beginning of some block in the future. - /// - /// - `id`: The identity of the task. This must be unique and will return an error if not. - fn schedule_named( - id: Vec, - when: DispatchTime, - maybe_periodic: Option>, - priority: Priority, - origin: Origin, - call: Call, - ) -> Result; - - /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances - /// of that, also. - /// - /// Will return an error if the `id` is invalid. - /// - /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. - /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. - fn cancel_named(id: Vec) -> Result<(), ()>; - - /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed - /// only if it is executed *before* the currently scheduled block. - fn reschedule_named( - id: Vec, - when: DispatchTime, - ) -> Result; - - /// Return the next dispatch time for a given task. - /// - /// Will return an error if the `id` is invalid. - fn next_dispatch_time(id: Vec) -> Result; +impl From for CallOrHash { + fn from(c: C) -> Self { + CallOrHash::Call(c) + } } + +/// Error type for `CallOrHash::lookup`. +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum LookupError { + /// A call of this hash was not known. + Unknown, + /// The preimage for this hash was known but could not be decoded into a `Call`. + BadFormat, +} + +impl CallOrHash { + pub fn as_call(&self) -> Option<&C> { + match &self { + Self::Call(c) => Some(c), + Self::Hash(_) => None, + } + } + + pub fn resolved>(self) -> Self { + match self { + Self::Call(c) => Self::Call(c), + Self::Hash(h) => { + let data = match P::get_preimage(&h) { + Some(p) => p, + None => return Self::Hash(h), + }; + match C::decode(&mut &data[..]) { + Ok(c) => Self::Call(c), + Err(_) => Self::Hash(h), + } + } + } + } + + pub fn try_resolve>(self) -> Result { + match self { + Self::Call(c) => Ok(c), + Self::Hash(h) => { + let data = P::get_preimage(&h).ok_or(LookupError::Unknown)?; + C::decode(&mut &data[..]).map_err(|_| LookupError::BadFormat) + } + } + } +} + +pub mod v1 { + use super::*; + + /// A type that can be used as a scheduler. + pub trait Anon { + /// An address which can be used for removing a scheduled task. + type Address: Codec + Clone + Eq + EncodeLike + Debug; + + /// Schedule a dispatch to happen at the beginning of some block in the future. + /// + /// This is not named. + fn schedule( + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: Call, + ) -> Result; + + /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that, + /// also. + /// + /// Will return an error if the `address` is invalid. + /// + /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. + /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. + /// + /// NOTE2: This will not work to cancel periodic tasks after their initial execution. For + /// that, you must name the task explicitly using the `Named` trait. + fn cancel(address: Self::Address) -> Result<(), ()>; + + /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed + /// only if it is executed *before* the currently scheduled block. For periodic tasks, + /// this dispatch is guaranteed to succeed only before the *initial* execution; for + /// others, use `reschedule_named`. + /// + /// Will return an error if the `address` is invalid. + fn reschedule( + address: Self::Address, + when: DispatchTime, + ) -> Result; + + /// Return the next dispatch time for a given task. + /// + /// Will return an error if the `address` is invalid. + fn next_dispatch_time(address: Self::Address) -> Result; + } + + /// A type that can be used as a scheduler. + pub trait Named { + /// An address which can be used for removing a scheduled task. + type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug; + + /// Schedule a dispatch to happen at the beginning of some block in the future. + /// + /// - `id`: The identity of the task. This must be unique and will return an error if not. + fn schedule_named( + id: Vec, + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: Call, + ) -> Result; + + /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances + /// of that, also. + /// + /// Will return an error if the `id` is invalid. + /// + /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. + /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. + fn cancel_named(id: Vec) -> Result<(), ()>; + + /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed + /// only if it is executed *before* the currently scheduled block. + fn reschedule_named( + id: Vec, + when: DispatchTime, + ) -> Result; + + /// Return the next dispatch time for a given task. + /// + /// Will return an error if the `id` is invalid. + fn next_dispatch_time(id: Vec) -> Result; + } + + impl Anon for T where + T: v2::Anon, + { + type Address = T::Address; + + fn schedule( + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: Call, + ) -> Result { + let c = CallOrHash::::Call(call); + T::schedule(when, maybe_periodic, priority, origin, c) + } + + fn cancel(address: Self::Address) -> Result<(), ()> { + T::cancel(address) + } + + fn reschedule( + address: Self::Address, + when: DispatchTime, + ) -> Result { + T::reschedule(address, when) + } + + fn next_dispatch_time(address: Self::Address) -> Result { + T::next_dispatch_time(address) + } + } + + impl Named for T where + T: v2::Named, + { + type Address = T::Address; + + fn schedule_named( + id: Vec, + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: Call, + ) -> Result { + let c = CallOrHash::::Call(call); + T::schedule_named(id, when, maybe_periodic, priority, origin, c) + } + + fn cancel_named(id: Vec) -> Result<(), ()> { + T::cancel_named(id) + } + + fn reschedule_named( + id: Vec, + when: DispatchTime, + ) -> Result { + T::reschedule_named(id, when) + } + + fn next_dispatch_time(id: Vec) -> Result { + T::next_dispatch_time(id) + } + } +} + +pub mod v2 { + use super::*; + + /// A type that can be used as a scheduler. + pub trait Anon { + /// An address which can be used for removing a scheduled task. + type Address: Codec + Clone + Eq + EncodeLike + Debug; + /// A means of expressing a call by the hash of its encoded data. + type Hash; + + /// Schedule a dispatch to happen at the beginning of some block in the future. + /// + /// This is not named. + fn schedule( + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: CallOrHash, + ) -> Result; + + /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that, + /// also. + /// + /// Will return an error if the `address` is invalid. + /// + /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. + /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. + /// + /// NOTE2: This will not work to cancel periodic tasks after their initial execution. For + /// that, you must name the task explicitly using the `Named` trait. + fn cancel(address: Self::Address) -> Result<(), ()>; + + /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed + /// only if it is executed *before* the currently scheduled block. For periodic tasks, + /// this dispatch is guaranteed to succeed only before the *initial* execution; for + /// others, use `reschedule_named`. + /// + /// Will return an error if the `address` is invalid. + fn reschedule( + address: Self::Address, + when: DispatchTime, + ) -> Result; + + /// Return the next dispatch time for a given task. + /// + /// Will return an error if the `address` is invalid. + fn next_dispatch_time(address: Self::Address) -> Result; + } + + /// A type that can be used as a scheduler. + pub trait Named { + /// An address which can be used for removing a scheduled task. + type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug; + /// A means of expressing a call by the hash of its encoded data. + type Hash; + + /// Schedule a dispatch to happen at the beginning of some block in the future. + /// + /// - `id`: The identity of the task. This must be unique and will return an error if not. + fn schedule_named( + id: Vec, + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: CallOrHash, + ) -> Result; + + /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances + /// of that, also. + /// + /// Will return an error if the `id` is invalid. + /// + /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. + /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. + fn cancel_named(id: Vec) -> Result<(), ()>; + + /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed + /// only if it is executed *before* the currently scheduled block. + fn reschedule_named( + id: Vec, + when: DispatchTime, + ) -> Result; + + /// Return the next dispatch time for a given task. + /// + /// Will return an error if the `id` is invalid. + fn next_dispatch_time(id: Vec) -> Result; + } +} + +pub use v1::*; + +use super::PreimageProvider; diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index bf078658477f5..fd8ae23322754 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -199,3 +199,66 @@ pub trait Currency { balance: Self::Balance, ) -> SignedImbalance; } + +impl Currency for () { + type Balance = u32; + type PositiveImbalance = (); + type NegativeImbalance = (); + fn total_balance(_: &AccountId) -> Self::Balance { 0 } + fn can_slash(_: &AccountId, _: Self::Balance) -> bool { true } + fn total_issuance() -> Self::Balance { 0 } + fn minimum_balance() -> Self::Balance { 0 } + fn burn(_: Self::Balance) -> Self::PositiveImbalance { () } + fn issue(_: Self::Balance) -> Self::NegativeImbalance { () } + fn pair(_: Self::Balance) -> (Self::PositiveImbalance, Self::NegativeImbalance) { ((), ()) } + fn free_balance(_: &AccountId) -> Self::Balance { 0 } + fn ensure_can_withdraw( + _: &AccountId, + _: Self::Balance, + _: WithdrawReasons, + _: Self::Balance, + ) -> DispatchResult { Ok(()) } + fn transfer( + _: &AccountId, + _: &AccountId, + _: Self::Balance, + _: ExistenceRequirement, + ) -> DispatchResult { Ok(()) } + fn slash(_: &AccountId, _: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) { + ((), 0) + } + fn deposit_into_existing( + _: &AccountId, + _: Self::Balance, + ) -> Result { Ok(()) } + fn resolve_into_existing( + _: &AccountId, + _: Self::NegativeImbalance, + ) -> Result<(), Self::NegativeImbalance> { + Ok(()) + } + fn deposit_creating(_: &AccountId, _: Self::Balance) -> Self::PositiveImbalance { () } + fn resolve_creating(_: &AccountId, _: Self::NegativeImbalance) {} + fn withdraw( + _: &AccountId, + _: Self::Balance, + _: WithdrawReasons, + _: ExistenceRequirement, + ) -> Result { + Ok(()) + } + fn settle( + _: &AccountId, + _: Self::PositiveImbalance, + _: WithdrawReasons, + _: ExistenceRequirement, + ) -> Result<(), Self::PositiveImbalance> { + Ok(()) + } + fn make_free_balance_be( + _: &AccountId, + _: Self::Balance, + ) -> SignedImbalance { + SignedImbalance::Positive(()) + } +} \ No newline at end of file diff --git a/frame/support/src/traits/tokens/currency/reservable.rs b/frame/support/src/traits/tokens/currency/reservable.rs index 0ca7a93dc7f69..f28e97ed3c6f5 100644 --- a/frame/support/src/traits/tokens/currency/reservable.rs +++ b/frame/support/src/traits/tokens/currency/reservable.rs @@ -81,6 +81,23 @@ pub trait ReservableCurrency: Currency { ) -> Result; } +impl ReservableCurrency for () { + fn can_reserve(_: &AccountId, _: Self::Balance) -> bool { true } + fn slash_reserved( + _: &AccountId, + _: Self::Balance, + ) -> (Self::NegativeImbalance, Self::Balance) { ((), 0) } + fn reserved_balance(_: &AccountId) -> Self::Balance { 0 } + fn reserve(_: &AccountId, _: Self::Balance) -> DispatchResult { Ok(()) } + fn unreserve(_: &AccountId, _: Self::Balance) -> Self::Balance { 0 } + fn repatriate_reserved( + _: &AccountId, + _: &AccountId, + _: Self::Balance, + _: BalanceStatus, + ) -> Result { Ok(0) } +} + pub trait NamedReservableCurrency: ReservableCurrency { /// An identifier for a reserve. Used for disambiguating different reserves so that /// they can be individually replaced or removed. diff --git a/frame/support/src/traits/tokens/imbalance.rs b/frame/support/src/traits/tokens/imbalance.rs index 0f7b38a65efc8..c511c2827efb3 100644 --- a/frame/support/src/traits/tokens/imbalance.rs +++ b/frame/support/src/traits/tokens/imbalance.rs @@ -177,3 +177,36 @@ pub trait Imbalance: Sized + TryDrop + Default { /// The raw value of self. fn peek(&self) -> Balance; } + +impl Imbalance for () { + type Opposite = (); + fn zero() -> Self { () } + fn drop_zero(self) -> Result<(), Self> { Ok(()) } + fn split(self, _: Balance) -> (Self, Self) { ((), ()) } + fn ration(self, _: u32, _: u32) -> (Self, Self) where + Balance: From + Saturating + Div, + { + ((), ()) + } + fn split_merge(self, _: Balance, _: (Self, Self)) -> (Self, Self) { + ((), ()) + } + fn ration_merge(self, _: u32, _: u32, _: (Self, Self)) -> (Self, Self) where + Balance: From + Saturating + Div, + { + ((), ()) + } + fn split_merge_into(self, _: Balance, _: &mut (Self, Self)) {} + fn ration_merge_into(self, _: u32, _: u32, _: &mut (Self, Self)) where + Balance: From + Saturating + Div, + {} + fn merge(self, _: Self) -> Self { () } + fn merge_into(self, _: &mut Self) {} + fn maybe_merge(self, _: Option) -> Self { () } + fn subsume(&mut self, _: Self) {} + fn maybe_subsume(&mut self, _: Option) { () } + fn offset(self, _: Self::Opposite) -> SameOrOther { + SameOrOther::None + } + fn peek(&self) -> Balance { Default::default() } +} From 2f6d89f54018623acd552022792c3b42c8b99c81 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 23 Nov 2021 22:26:53 +0100 Subject: [PATCH 16/58] request when scheduled --- frame/support/src/traits/schedule.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index e8ef2a87628e8..6db3206f6bb19 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -82,6 +82,13 @@ impl CallOrHash { } } + pub fn ensure_requested>(&self) { + match &self { + Self::Call(_) => (), + Self::Hash(hash) => P::request_preimage(hash), + } + } + pub fn resolved>(self) -> Self { match self { Self::Call(c) => Self::Call(c), From ea7fdfe3aa0e6cc225ed5daccabc978f27adf971 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 23 Nov 2021 22:27:08 +0100 Subject: [PATCH 17/58] Docs --- frame/scheduler/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 806dd00ef344b..e5b76b0d6dc69 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -130,7 +130,6 @@ pub type ScheduledOf = ScheduledV3Of; pub type Scheduled = ScheduledV2; -// TODO: request when scheduled // TODO: unrequest when cancelled // TODO: unrequest when non-periodic executed @@ -414,6 +413,7 @@ pub mod pallet { ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); + call.ensure_requested::(); Self::do_schedule( DispatchTime::At(when), maybe_periodic, From 9bccd26dd18d0fc6815507b19462d7b85bbcde8a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 01:35:09 +0100 Subject: [PATCH 18/58] Scheduler good --- frame/preimage/src/lib.rs | 12 ++--- frame/scheduler/src/lib.rs | 53 ++++++++++++---------- frame/support/src/traits/misc.rs | 4 +- frame/support/src/traits/schedule.rs | 68 +++++++++++++++------------- 4 files changed, 73 insertions(+), 64 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index da9090b727d6b..35cc2df949de1 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -171,9 +171,9 @@ pub mod pallet { /// /// NOTE: THIS MUST NOT BE CALLED ON `hash` MORE TIMES THAN `request_preimage`. #[pallet::weight(0)] - pub fn clear_request(origin: OriginFor, hash: T::Hash) -> DispatchResult { + pub fn unrequest_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; - Self::do_clear_request(&hash) + Self::do_unrequest_preimage(&hash) } } } @@ -276,7 +276,7 @@ impl Pallet { } /// Clear a preimage request. - fn do_clear_request(hash: &T::Hash) -> DispatchResult { + fn do_unrequest_preimage(hash: &T::Hash) -> DispatchResult { match StatusFor::::get(hash).ok_or(Error::::NotRequested)? { RequestStatus::Requested(mut count) if count > 1 => { count.saturating_dec(); @@ -311,9 +311,9 @@ impl PreimageProvider for Pallet { Self::do_request_preimage(hash) } - fn clear_request(hash: &T::Hash) { - let res = Self::do_clear_request(hash); - debug_assert!(res.is_ok(), "do_clear_request failed - counter underflow?"); + fn unrequest_preimage(hash: &T::Hash) { + let res = Self::do_unrequest_preimage(hash); + debug_assert!(res.is_ok(), "do_unrequest_preimage failed - counter underflow?"); } } diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index e5b76b0d6dc69..fffba7e9a1b72 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -57,7 +57,7 @@ use codec::{Codec, Decode, Encode}; use frame_support::{ dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter}, traits::{ - schedule::{self, DispatchTime, CallOrHash}, PreimageProvider, + schedule::{self, DispatchTime, MaybeHashed}, EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp, }, weights::{GetDispatchInfo, Weight}, @@ -77,7 +77,7 @@ pub type PeriodicIndex = u32; /// The location of a scheduled task that can be used to remove it. pub type TaskAddress = (BlockNumber, u32); -pub type CallOrHashOf = CallOrHash< +pub type CallOfHashOf = MaybeHashed< ::Call, ::Hash, >; @@ -118,7 +118,7 @@ pub type ScheduledV2Of = ScheduledV3< >; pub type ScheduledV3Of = ScheduledV3< - CallOrHashOf, + CallOfHashOf, ::BlockNumber, ::PalletsOrigin, ::AccountId, @@ -130,10 +130,6 @@ pub type ScheduledOf = ScheduledV3Of; pub type Scheduled = ScheduledV2; -// TODO: unrequest when cancelled -// TODO: unrequest when non-periodic executed - - // A value placed in storage that represents the current version of the Scheduler storage. // This value is used by the `on_runtime_upgrade` logic to determine whether we run // storage migration logic. @@ -206,7 +202,7 @@ pub mod pallet { type WeightInfo: WeightInfo; /// The preimage provider with which we look up call hashes to get the call. - type PreimageProvider: PreimageProvider; + type Preimages: PreimageProvider; } /// Items to be executed, indexed by the block number that they should be executed on. @@ -287,13 +283,19 @@ pub mod pallet { /// - Write: Agenda + Lookup * N + Agenda(future) * P /// # fn on_initialize(now: T::BlockNumber) -> Weight { + let mut base_weight: Weight = T::DbWeight::get().reads_writes(1, 2); // Agenda + Agenda(next) let limit = T::MaximumWeight::get(); let mut queued = Agenda::::take(now) .into_iter() .enumerate() .filter_map(|(index, s)| { let ScheduledV3 { maybe_id, priority, call, maybe_periodic, origin, _phantom } = s?; - let call = call.resolved::(); + let (call, maybe_completed) = call.resolved::(); + if let Some(completed) = maybe_completed { + // TODO Benchmark individually. + base_weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + T::Preimages::unrequest_preimage(&completed); + } let s = ScheduledV3 { maybe_id, priority, call, maybe_periodic, origin, _phantom }; Some((index as u32, s)) }) @@ -306,7 +308,6 @@ pub mod pallet { ); } queued.sort_by_key(|(_, s)| s.priority); - let base_weight: Weight = T::DbWeight::get().reads_writes(1, 2); // Agenda + Agenda(next) let next = now + One::one(); let mut total_weight: Weight = 0; queued @@ -314,7 +315,7 @@ pub mod pallet { .enumerate() .scan(base_weight, |cumulative_weight, (order, (index, s))| { - if let Some(c) = s.call.as_call() { + if let Some(c) = s.call.as_value() { *cumulative_weight = cumulative_weight.saturating_add(c.get_dispatch_info().weight); let origin = @@ -342,7 +343,7 @@ pub mod pallet { Some((order, index, *cumulative_weight, s)) }) .filter_map(|(order, index, cumulative_weight, mut s)| { - let call = match s.call.as_ref().cloned() { + let call = match s.call.as_value().cloned() { Some(c) => c, None => return Some(Some(s)), }; @@ -368,7 +369,7 @@ pub mod pallet { let next_index = Agenda::::decode_len(now + period).unwrap_or(0); Lookup::::insert(id, (next, next_index as u32)); } - Agenda::::append(next, Some(s.into())); + Agenda::::append(next, Some(s)); } else { if let Some(ref id) = s.maybe_id { Lookup::::remove(id); @@ -409,11 +410,10 @@ pub mod pallet { when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); - call.ensure_requested::(); Self::do_schedule( DispatchTime::At(when), maybe_periodic, @@ -459,7 +459,7 @@ pub mod pallet { when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -503,7 +503,7 @@ pub mod pallet { after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -529,7 +529,7 @@ pub mod pallet { after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -564,7 +564,7 @@ impl Pallet { schedule.map(|schedule| ScheduledV3 { maybe_id: schedule.maybe_id, priority: schedule.priority, - call: CallOrHash::Call(schedule.call), + call: schedule.call.into(), maybe_periodic: schedule.maybe_periodic, origin: system::RawOrigin::Root.into(), _phantom: Default::default(), @@ -597,7 +597,7 @@ impl Pallet { schedule.map(|schedule| ScheduledV3 { maybe_id: schedule.maybe_id, priority: schedule.priority, - call: CallOrHash::Call(schedule.call), + call: schedule.call.into(), maybe_periodic: schedule.maybe_periodic, origin: system::RawOrigin::Root.into(), _phantom: Default::default(), @@ -656,9 +656,10 @@ impl Pallet { maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: CallOrHashOf, + call: CallOfHashOf, ) -> Result, DispatchError> { let when = Self::resolve_time(when)?; + call.ensure_requested::(); // sanitize maybe_periodic let maybe_periodic = maybe_periodic @@ -708,6 +709,7 @@ impl Pallet { ) })?; if let Some(s) = scheduled { + s.call.ensure_unrequested::(); if let Some(id) = s.maybe_id { Lookup::::remove(id); } @@ -748,7 +750,7 @@ impl Pallet { maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: CallOrHashOf, + call: CallOfHashOf, ) -> Result, DispatchError> { // ensure id it is unique if Lookup::::contains_key(&id) { @@ -757,6 +759,8 @@ impl Pallet { let when = Self::resolve_time(when)?; + call.ensure_requested::(); + // sanitize maybe_periodic let maybe_periodic = maybe_periodic .filter(|p| p.1 > 1 && !p.0.is_zero()) @@ -800,6 +804,7 @@ impl Pallet { ) { return Err(BadOrigin.into()) } + s.call.ensure_unrequested::(); } *s = None; } @@ -859,7 +864,7 @@ impl schedule::v2::Anon::Call, T::Palle maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: CallOrHashOf, + call: CallOfHashOf, ) -> Result { Self::do_schedule(when, maybe_periodic, priority, origin, call) } @@ -892,7 +897,7 @@ impl schedule::v2::Named::Call, T::Pall maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: CallOrHashOf, + call: CallOfHashOf, ) -> Result { Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call).map_err(|_| ()) } diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 2647824e23fc2..5bd865fc98e5a 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -585,8 +585,8 @@ pub trait PreimageProvider { /// preimage reporting. fn request_preimage(hash: &Hash); - /// Clear a preimage request. - fn clear_request(hash: &Hash); + /// Cancel a previous preimage request. + fn unrequest_preimage(hash: &Hash); } /// A interface for managing preimages to hashes on chain. diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 6db3206f6bb19..31a06d0f4c765 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -52,20 +52,20 @@ pub const LOWEST_PRIORITY: Priority = 255; /// Type representing a call. Can be either the `Call` value itself or the hash of the encoded /// `Call`. #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub enum CallOrHash { - /// The `Call` value itself. - Call(Call), - /// The hash of the encoded `Call` which this value represents. +pub enum MaybeHashed { + /// The value itself. + Value(T), + /// The hash of the encoded value which this value represents. Hash(Hash), } -impl From for CallOrHash { - fn from(c: C) -> Self { - CallOrHash::Call(c) +impl From for MaybeHashed { + fn from(t: T) -> Self { + MaybeHashed::Value(t) } } -/// Error type for `CallOrHash::lookup`. +/// Error type for `MaybeHashed::lookup`. #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum LookupError { /// A call of this hash was not known. @@ -74,46 +74,50 @@ pub enum LookupError { BadFormat, } -impl CallOrHash { - pub fn as_call(&self) -> Option<&C> { +impl MaybeHashed { + pub fn as_value(&self) -> Option<&T> { match &self { - Self::Call(c) => Some(c), + Self::Value(c) => Some(c), Self::Hash(_) => None, } } + pub fn as_hash(&self) -> Option<&H> { + match &self { + Self::Value(_) => None, + Self::Hash(h) => Some(h), + } + } + pub fn ensure_requested>(&self) { match &self { - Self::Call(_) => (), + Self::Value(_) => (), Self::Hash(hash) => P::request_preimage(hash), } } - pub fn resolved>(self) -> Self { + pub fn ensure_unrequested>(&self) { + match &self { + Self::Value(_) => (), + Self::Hash(hash) => P::unrequest_preimage(hash), + } + } + + pub fn resolved>(self) -> (Self, Option) { match self { - Self::Call(c) => Self::Call(c), + Self::Value(c) => (Self::Value(c), None), Self::Hash(h) => { let data = match P::get_preimage(&h) { Some(p) => p, - None => return Self::Hash(h), + None => return (Self::Hash(h), None), }; - match C::decode(&mut &data[..]) { - Ok(c) => Self::Call(c), - Err(_) => Self::Hash(h), + match T::decode(&mut &data[..]) { + Ok(c) => (Self::Value(c), Some(h)), + Err(_) => (Self::Hash(h), None), } } } } - - pub fn try_resolve>(self) -> Result { - match self { - Self::Call(c) => Ok(c), - Self::Hash(h) => { - let data = P::get_preimage(&h).ok_or(LookupError::Unknown)?; - C::decode(&mut &data[..]).map_err(|_| LookupError::BadFormat) - } - } - } } pub mod v1 { @@ -215,7 +219,7 @@ pub mod v1 { origin: Origin, call: Call, ) -> Result { - let c = CallOrHash::::Call(call); + let c = MaybeHashed::::Value(call); T::schedule(when, maybe_periodic, priority, origin, c) } @@ -248,7 +252,7 @@ pub mod v1 { origin: Origin, call: Call, ) -> Result { - let c = CallOrHash::::Call(call); + let c = MaybeHashed::::Value(call); T::schedule_named(id, when, maybe_periodic, priority, origin, c) } @@ -287,7 +291,7 @@ pub mod v2 { maybe_periodic: Option>, priority: Priority, origin: Origin, - call: CallOrHash, + call: MaybeHashed, ) -> Result; /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that, @@ -335,7 +339,7 @@ pub mod v2 { maybe_periodic: Option>, priority: Priority, origin: Origin, - call: CallOrHash, + call: MaybeHashed, ) -> Result; /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances From 5625a49f57b54af2503745140040ee674ade268e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 09:40:25 +0100 Subject: [PATCH 19/58] Scheduler good --- frame/scheduler/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index fffba7e9a1b72..b38702eab1633 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -1087,7 +1087,7 @@ mod tests { type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; - type PreimageProvider = Preimage; + type Preimages = Preimage; } pub type LoggerCall = logger::Call; @@ -1583,15 +1583,15 @@ mod tests { #[test] fn root_calls_works() { new_test_ext().execute_with(|| { - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 })); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 })); + let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); assert_ok!(Scheduler::schedule_named( Origin::root(), 1u32.encode(), 4, None, 127, - call.into(), + call, )); assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2)); run_to_block(3); From cd392422055f8d40e1518eec0525f0172ba5c739 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 10:18:35 +0100 Subject: [PATCH 20/58] Scheduler tests working --- frame/scheduler/src/lib.rs | 54 ++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index b38702eab1633..29bacb1e1301b 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -77,7 +77,7 @@ pub type PeriodicIndex = u32; /// The location of a scheduled task that can be used to remove it. pub type TaskAddress = (BlockNumber, u32); -pub type CallOfHashOf = MaybeHashed< +pub type CallOrHashOf = MaybeHashed< ::Call, ::Hash, >; @@ -118,7 +118,7 @@ pub type ScheduledV2Of = ScheduledV3< >; pub type ScheduledV3Of = ScheduledV3< - CallOfHashOf, + CallOrHashOf, ::BlockNumber, ::PalletsOrigin, ::AccountId, @@ -410,7 +410,7 @@ pub mod pallet { when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -459,7 +459,7 @@ pub mod pallet { when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -503,7 +503,7 @@ pub mod pallet { after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -529,7 +529,7 @@ pub mod pallet { after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); @@ -615,7 +615,10 @@ impl Pallet { /// Helper to migrate scheduler when the pallet origin type has changed. pub fn migrate_origin + codec::Decode>() { - Agenda::::translate::>>, _>(|_, agenda| { + Agenda::::translate::< + Vec, T::BlockNumber, OldOrigin, T::AccountId>>>, + _ + >(|_, agenda| { Some( agenda .into_iter() @@ -656,7 +659,7 @@ impl Pallet { maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: CallOfHashOf, + call: CallOrHashOf, ) -> Result, DispatchError> { let when = Self::resolve_time(when)?; call.ensure_requested::(); @@ -750,7 +753,7 @@ impl Pallet { maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: CallOfHashOf, + call: CallOrHashOf, ) -> Result, DispatchError> { // ensure id it is unique if Lookup::::contains_key(&id) { @@ -864,7 +867,7 @@ impl schedule::v2::Anon::Call, T::Palle maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: CallOfHashOf, + call: CallOrHashOf, ) -> Result { Self::do_schedule(when, maybe_periodic, priority, origin, call) } @@ -897,7 +900,7 @@ impl schedule::v2::Named::Call, T::Pall maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: CallOfHashOf, + call: CallOrHashOf, ) -> Result { Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call).map_err(|_| ()) } @@ -1611,21 +1614,22 @@ mod tests { new_test_ext().execute_with(|| { run_to_block(3); - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call1 = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + let call3 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); assert_err!( - Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call), + Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call1), Error::::TargetBlockNumberInPast, ); assert_err!( - Scheduler::schedule(Origin::root(), 2, None, 127, call2.clone()), + Scheduler::schedule(Origin::root(), 2, None, 127, call2), Error::::TargetBlockNumberInPast, ); assert_err!( - Scheduler::schedule(Origin::root(), 3, None, 127, call2), + Scheduler::schedule(Origin::root(), 3, None, 127, call3), Error::::TargetBlockNumberInPast, ); }); @@ -1642,14 +1646,14 @@ mod tests { 4, None, 127, - call.into(), + call, )); assert_ok!(Scheduler::schedule( system::RawOrigin::Signed(1).into(), 4, None, 127, - call2.into(), + call2, )); run_to_block(3); // Scheduled calls are in the agenda. @@ -1766,7 +1770,7 @@ mod tests { ( 0, vec![ - Some(ScheduledV3 { + Some(ScheduledV3Of:: { maybe_id: None, priority: 10, call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), @@ -1775,7 +1779,7 @@ mod tests { _phantom: PhantomData::::default(), }), None, - Some(ScheduledV3 { + Some(ScheduledV3Of:: { maybe_id: Some(b"test".to_vec()), priority: 123, call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), @@ -1788,7 +1792,7 @@ mod tests { ( 1, vec![ - Some(ScheduledV3 { + Some(ScheduledV3Of:: { maybe_id: None, priority: 11, call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), @@ -1797,7 +1801,7 @@ mod tests { _phantom: PhantomData::::default(), }), None, - Some(ScheduledV3 { + Some(ScheduledV3Of:: { maybe_id: Some(b"test".to_vec()), priority: 123, call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), @@ -1810,7 +1814,7 @@ mod tests { ( 2, vec![ - Some(ScheduledV3 { + Some(ScheduledV3Of:: { maybe_id: None, priority: 12, call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), @@ -1819,7 +1823,7 @@ mod tests { _phantom: PhantomData::::default(), }), None, - Some(ScheduledV3 { + Some(ScheduledV3Of:: { maybe_id: Some(b"test".to_vec()), priority: 123, call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), @@ -1841,7 +1845,7 @@ mod tests { new_test_ext().execute_with(|| { for i in 0..3u64 { let k = i.twox_64_concat(); - let old: Vec>> = vec![ + let old: Vec, u64, u32, u64>>> = vec![ Some(Scheduled { maybe_id: None, priority: i as u8 + 10, @@ -1881,7 +1885,7 @@ mod tests { ( 0, vec![ - Some(ScheduledV2::<_, _, OriginCaller, u64> { + Some(ScheduledV2::, u64, OriginCaller, u64> { maybe_id: None, priority: 10, call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), From 6b5a27443e88139c7fdde5c1368440dda46980f9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 11:20:39 +0100 Subject: [PATCH 21/58] Add new files --- frame/scheduler/src/benchmarking.rs | 2 - frame/scheduler/src/lib.rs | 1036 +-------------------------- frame/scheduler/src/mock.rs | 205 ++++++ frame/scheduler/src/tests.rs | 878 +++++++++++++++++++++++ 4 files changed, 1088 insertions(+), 1033 deletions(-) create mode 100644 frame/scheduler/src/mock.rs create mode 100644 frame/scheduler/src/tests.rs diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 1065f17027744..c029993e4674f 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -17,8 +17,6 @@ //! Scheduler pallet benchmarking. -#![cfg(feature = "runtime-benchmarks")] - use super::*; use frame_benchmarking::benchmarks; use frame_support::{ensure, traits::OnInitialize}; diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 29bacb1e1301b..2cb2de4c675e5 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -50,8 +50,13 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] +#![cfg(feature = "runtime-benchmarks")] mod benchmarking; pub mod weights; +#[cfg(test)] +mod tests; +#[cfg(test)] +mod mock; use codec::{Codec, Decode, Encode}; use frame_support::{ @@ -922,1034 +927,3 @@ impl schedule::v2::Named::Call, T::Pall .ok_or(()) } } - -#[cfg(test)] -mod tests { - use super::*; - - use crate as scheduler; - use frame_support::{ - assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, - weights::constants::RocksDbWeight, - Hashable, - }; - use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; - use sp_core::H256; - use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - Perbill, - }; - use substrate_test_utils::assert_eq_uvec; - - // Logger module to track execution. - #[frame_support::pallet] - pub mod logger { - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - use std::cell::RefCell; - - thread_local! { - static LOG: RefCell> = RefCell::new(Vec::new()); - } - pub fn log() -> Vec<(OriginCaller, u32)> { - LOG.with(|log| log.borrow().clone()) - } - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(PhantomData); - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::config] - pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - Logged(u32, Weight), - } - - #[pallet::call] - impl Pallet - where - ::Origin: OriginTrait, - { - #[pallet::weight(*weight)] - pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { - Self::deposit_event(Event::Logged(i, weight)); - LOG.with(|log| { - log.borrow_mut().push((origin.caller().clone(), i)); - }); - Ok(()) - } - - #[pallet::weight(*weight)] - pub fn log_without_filter( - origin: OriginFor, - i: u32, - weight: Weight, - ) -> DispatchResult { - Self::deposit_event(Event::Logged(i, weight)); - LOG.with(|log| { - log.borrow_mut().push((origin.caller().clone(), i)); - }); - Ok(()) - } - } - } - - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; - type Block = frame_system::mocking::MockBlock; - - frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Logger: logger::{Pallet, Call, Event}, - Scheduler: scheduler::{Pallet, Call, Storage, Event}, - Preimage: pallet_preimage::{Pallet, Call, Storage, Event}, - } - ); - - // Scheduler must dispatch with root and no filter, this tests base filter is indeed not used. - pub struct BaseFilter; - impl Contains for BaseFilter { - fn contains(call: &Call) -> bool { - !matches!(call, Call::Logger(LoggerCall::log { .. })) - } - } - - parameter_types! { - pub const BlockHashCount: u64 = 250; - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); - } - impl system::Config for Test { - type BaseCallFilter = BaseFilter; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = RocksDbWeight; - type Origin = Origin; - type Call = Call; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = Event; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - } - impl logger::Config for Test { - type Event = Event; - } - parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; - pub const MaxScheduledPerBlock: u32 = 10; - pub const MaxSize: u32 = 1024; - } - ord_parameter_types! { - pub const One: u64 = 1; - } - - impl pallet_preimage::Config for Test { - type Event = Event; - type Currency = (); - type ManagerOrigin = EnsureRoot; - type MaxSize = MaxSize; - type BaseDeposit = (); - type ByteDeposit = (); - } - - impl Config for Test { - type Event = Event; - type Origin = Origin; - type PalletsOrigin = OriginCaller; - type Call = Call; - type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; - type MaxScheduledPerBlock = MaxScheduledPerBlock; - type WeightInfo = (); - type OriginPrivilegeCmp = EqualPrivilegeOnly; - type Preimages = Preimage; - } - - pub type LoggerCall = logger::Call; - - pub fn new_test_ext() -> sp_io::TestExternalities { - let t = system::GenesisConfig::default().build_storage::().unwrap(); - t.into() - } - - fn run_to_block(n: u64) { - while System::block_number() < n { - Scheduler::on_finalize(System::block_number()); - System::set_block_number(System::block_number() + 1); - Scheduler::on_initialize(System::block_number()); - } - } - - fn root() -> OriginCaller { - system::RawOrigin::Root.into() - } - - #[test] - fn basic_scheduling_works() { - new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); - assert!(!::BaseCallFilter::contains(&call)); - assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into())); - run_to_block(3); - assert!(logger::log().is_empty()); - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); - } - - #[test] - fn schedule_after_works() { - new_test_ext().execute_with(|| { - run_to_block(2); - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); - assert!(!::BaseCallFilter::contains(&call)); - // This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6 - assert_ok!(Scheduler::do_schedule(DispatchTime::After(3), None, 127, root(), call.into())); - run_to_block(5); - assert!(logger::log().is_empty()); - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); - } - - #[test] - fn schedule_after_zero_works() { - new_test_ext().execute_with(|| { - run_to_block(2); - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); - assert!(!::BaseCallFilter::contains(&call)); - assert_ok!(Scheduler::do_schedule(DispatchTime::After(0), None, 127, root(), call.into())); - // Will trigger on the next block. - run_to_block(3); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); - } - - #[test] - fn periodic_scheduling_works() { - new_test_ext().execute_with(|| { - // at #4, every 3 blocks, 3 times. - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - Some((3, 3)), - 127, - root(), - Call::Logger(logger::Call::log { i: 42, weight: 1000 }).into() - )); - run_to_block(3); - assert!(logger::log().is_empty()); - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(7); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); - run_to_block(9); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); - run_to_block(10); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); - }); - } - - #[test] - fn reschedule_works() { - new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); - assert!(!::BaseCallFilter::contains(&call)); - assert_eq!( - Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into()).unwrap(), - (4, 0) - ); - - run_to_block(3); - assert!(logger::log().is_empty()); - - assert_eq!(Scheduler::do_reschedule((4, 0), DispatchTime::At(6)).unwrap(), (6, 0)); - - assert_noop!( - Scheduler::do_reschedule((6, 0), DispatchTime::At(6)), - Error::::RescheduleNoChange - ); - - run_to_block(4); - assert!(logger::log().is_empty()); - - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); - } - - #[test] - fn reschedule_named_works() { - new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); - assert!(!::BaseCallFilter::contains(&call)); - assert_eq!( - Scheduler::do_schedule_named( - 1u32.encode(), - DispatchTime::At(4), - None, - 127, - root(), - call.into(), - ) - .unwrap(), - (4, 0) - ); - - run_to_block(3); - assert!(logger::log().is_empty()); - - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), - (6, 0) - ); - - assert_noop!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)), - Error::::RescheduleNoChange - ); - - run_to_block(4); - assert!(logger::log().is_empty()); - - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); - } - - #[test] - fn reschedule_named_perodic_works() { - new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); - assert!(!::BaseCallFilter::contains(&call)); - assert_eq!( - Scheduler::do_schedule_named( - 1u32.encode(), - DispatchTime::At(4), - Some((3, 3)), - 127, - root(), - call.into(), - ) - .unwrap(), - (4, 0) - ); - - run_to_block(3); - assert!(logger::log().is_empty()); - - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(5)).unwrap(), - (5, 0) - ); - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), - (6, 0) - ); - - run_to_block(5); - assert!(logger::log().is_empty()); - - run_to_block(6); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(10)).unwrap(), - (10, 0) - ); - - run_to_block(9); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - - run_to_block(10); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); - - run_to_block(13); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); - - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); - }); - } - - #[test] - fn cancel_named_scheduling_works_with_normal_cancel() { - new_test_ext().execute_with(|| { - // at #4. - Scheduler::do_schedule_named( - 1u32.encode(), - DispatchTime::At(4), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), - ) - .unwrap(); - let i = Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into(), - ) - .unwrap(); - run_to_block(3); - assert!(logger::log().is_empty()); - assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode())); - assert_ok!(Scheduler::do_cancel(None, i)); - run_to_block(100); - assert!(logger::log().is_empty()); - }); - } - - #[test] - fn cancel_named_periodic_scheduling_works() { - new_test_ext().execute_with(|| { - // at #4, every 3 blocks, 3 times. - Scheduler::do_schedule_named( - 1u32.encode(), - DispatchTime::At(4), - Some((3, 3)), - 127, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into(), - ) - .unwrap(); - // same id results in error. - assert!(Scheduler::do_schedule_named( - 1u32.encode(), - DispatchTime::At(4), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), - ) - .is_err()); - // different id is ok. - Scheduler::do_schedule_named( - 2u32.encode(), - DispatchTime::At(8), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), - ) - .unwrap(); - run_to_block(3); - assert!(logger::log().is_empty()); - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(6); - assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode())); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); - }); - } - - #[test] - fn scheduler_respects_weight_limits() { - new_test_ext().execute_with(|| { - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }).into(), - )); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), - )); - // 69 and 42 do not fit together - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(5); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); - }); - } - - #[test] - fn scheduler_respects_hard_deadlines_more() { - new_test_ext().execute_with(|| { - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 0, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }).into(), - )); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 0, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), - )); - // With base weights, 69 and 42 should not fit together, but do because of hard - // deadlines - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); - }); - } - - #[test] - fn scheduler_respects_priority_ordering() { - new_test_ext().execute_with(|| { - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 1, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }).into(), - )); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 0, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), - )); - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]); - }); - } - - #[test] - fn scheduler_respects_priority_ordering_with_soft_deadlines() { - new_test_ext().execute_with(|| { - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 255, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 3 }).into(), - )); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), - )); - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(4), - None, - 126, - root(), - Call::Logger(LoggerCall::log { - i: 2600, - weight: MaximumSchedulerWeight::get() / 2 - }).into(), - )); - - // 2600 does not fit with 69 or 42, but has higher priority, so will go through - run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 2600u32)]); - // 69 and 42 fit together - run_to_block(5); - assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); - }); - } - - #[test] - fn on_initialize_weight_is_correct() { - new_test_ext().execute_with(|| { - let base_weight: Weight = - ::DbWeight::get().reads_writes(1, 2); - let base_multiplier = 0; - let named_multiplier = ::DbWeight::get().writes(1); - let periodic_multiplier = - ::DbWeight::get().reads_writes(1, 1); - - // Named - assert_ok!(Scheduler::do_schedule_named( - 1u32.encode(), - DispatchTime::At(1), - None, - 255, - root(), - Call::Logger(LoggerCall::log { i: 3, weight: MaximumSchedulerWeight::get() / 3 }).into(), - )); - // Anon Periodic - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(1), - Some((1000, 3)), - 128, - root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 3 }).into(), - )); - // Anon - assert_ok!(Scheduler::do_schedule( - DispatchTime::At(1), - None, - 127, - root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), - )); - // Named Periodic - assert_ok!(Scheduler::do_schedule_named( - 2u32.encode(), - DispatchTime::At(1), - Some((1000, 3)), - 126, - root(), - Call::Logger(LoggerCall::log { - i: 2600, - weight: MaximumSchedulerWeight::get() / 2 - }).into(), - )); - - // Will include the named periodic only - let actual_weight = Scheduler::on_initialize(1); - let call_weight = MaximumSchedulerWeight::get() / 2; - assert_eq!( - actual_weight, - call_weight + - base_weight + base_multiplier + - named_multiplier + periodic_multiplier - ); - assert_eq!(logger::log(), vec![(root(), 2600u32)]); - - // Will include anon and anon periodic - let actual_weight = Scheduler::on_initialize(2); - let call_weight = MaximumSchedulerWeight::get() / 2 + MaximumSchedulerWeight::get() / 3; - assert_eq!( - actual_weight, - call_weight + base_weight + base_multiplier * 2 + periodic_multiplier - ); - assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); - - // Will include named only - let actual_weight = Scheduler::on_initialize(3); - let call_weight = MaximumSchedulerWeight::get() / 3; - assert_eq!( - actual_weight, - call_weight + base_weight + base_multiplier + named_multiplier - ); - assert_eq!( - logger::log(), - vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32), (root(), 3u32)] - ); - - // Will contain none - let actual_weight = Scheduler::on_initialize(4); - assert_eq!(actual_weight, 0); - }); - } - - #[test] - fn root_calls_works() { - new_test_ext().execute_with(|| { - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); - assert_ok!(Scheduler::schedule_named( - Origin::root(), - 1u32.encode(), - 4, - None, - 127, - call, - )); - assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2)); - run_to_block(3); - // Scheduled calls are in the agenda. - assert_eq!(Agenda::::get(4).len(), 2); - assert!(logger::log().is_empty()); - assert_ok!(Scheduler::cancel_named(Origin::root(), 1u32.encode())); - assert_ok!(Scheduler::cancel(Origin::root(), 4, 1)); - // Scheduled calls are made NONE, so should not effect state - run_to_block(100); - assert!(logger::log().is_empty()); - }); - } - - #[test] - fn fails_to_schedule_task_in_the_past() { - new_test_ext().execute_with(|| { - run_to_block(3); - - let call1 = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); - let call3 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); - - assert_err!( - Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call1), - Error::::TargetBlockNumberInPast, - ); - - assert_err!( - Scheduler::schedule(Origin::root(), 2, None, 127, call2), - Error::::TargetBlockNumberInPast, - ); - - assert_err!( - Scheduler::schedule(Origin::root(), 3, None, 127, call3), - Error::::TargetBlockNumberInPast, - ); - }); - } - - #[test] - fn should_use_orign() { - new_test_ext().execute_with(|| { - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); - assert_ok!(Scheduler::schedule_named( - system::RawOrigin::Signed(1).into(), - 1u32.encode(), - 4, - None, - 127, - call, - )); - assert_ok!(Scheduler::schedule( - system::RawOrigin::Signed(1).into(), - 4, - None, - 127, - call2, - )); - run_to_block(3); - // Scheduled calls are in the agenda. - assert_eq!(Agenda::::get(4).len(), 2); - assert!(logger::log().is_empty()); - assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), 1u32.encode())); - assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1)); - // Scheduled calls are made NONE, so should not effect state - run_to_block(100); - assert!(logger::log().is_empty()); - }); - } - - #[test] - fn should_check_orign() { - new_test_ext().execute_with(|| { - let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); - let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); - assert_noop!( - Scheduler::schedule_named( - system::RawOrigin::Signed(2).into(), - 1u32.encode(), - 4, - None, - 127, - call - ), - BadOrigin - ); - assert_noop!( - Scheduler::schedule(system::RawOrigin::Signed(2).into(), 4, None, 127, call2), - BadOrigin - ); - }); - } - - #[test] - fn should_check_orign_for_cancel() { - new_test_ext().execute_with(|| { - let call = - Box::new(Call::Logger(LoggerCall::log_without_filter { i: 69, weight: 1000 }).into()); - let call2 = - Box::new(Call::Logger(LoggerCall::log_without_filter { i: 42, weight: 1000 }).into()); - assert_ok!(Scheduler::schedule_named( - system::RawOrigin::Signed(1).into(), - 1u32.encode(), - 4, - None, - 127, - call, - )); - assert_ok!(Scheduler::schedule( - system::RawOrigin::Signed(1).into(), - 4, - None, - 127, - call2, - )); - run_to_block(3); - // Scheduled calls are in the agenda. - assert_eq!(Agenda::::get(4).len(), 2); - assert!(logger::log().is_empty()); - assert_noop!( - Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), 1u32.encode()), - BadOrigin - ); - assert_noop!(Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1), BadOrigin); - assert_noop!( - Scheduler::cancel_named(system::RawOrigin::Root.into(), 1u32.encode()), - BadOrigin - ); - assert_noop!(Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1), BadOrigin); - run_to_block(5); - assert_eq!( - logger::log(), - vec![ - (system::RawOrigin::Signed(1).into(), 69u32), - (system::RawOrigin::Signed(1).into(), 42u32) - ] - ); - }); - } - - #[test] - fn migration_to_v3_works() { - new_test_ext().execute_with(|| { - for i in 0..3u64 { - let k = i.twox_64_concat(); - let old = vec![ - Some(ScheduledV1 { - maybe_id: None, - priority: i as u8 + 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), - maybe_periodic: None, - }), - None, - Some(ScheduledV1 { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), - maybe_periodic: Some((456u64, 10)), - }), - ]; - frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); - } - - assert_eq!(StorageVersion::::get(), Releases::V1); - - assert!(Scheduler::migrate_v1_to_v3()); - - assert_eq_uvec!( - Agenda::::iter().collect::>(), - vec![ - ( - 0, - vec![ - Some(ScheduledV3Of:: { - maybe_id: None, - priority: 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), - maybe_periodic: None, - origin: root(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV3Of:: { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), - maybe_periodic: Some((456u64, 10)), - origin: root(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 1, - vec![ - Some(ScheduledV3Of:: { - maybe_id: None, - priority: 11, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), - maybe_periodic: None, - origin: root(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV3Of:: { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), - maybe_periodic: Some((456u64, 10)), - origin: root(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 2, - vec![ - Some(ScheduledV3Of:: { - maybe_id: None, - priority: 12, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), - maybe_periodic: None, - origin: root(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV3Of:: { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), - maybe_periodic: Some((456u64, 10)), - origin: root(), - _phantom: PhantomData::::default(), - }), - ] - ) - ] - ); - - assert_eq!(StorageVersion::::get(), Releases::V2); - }); - } - - #[test] - fn test_migrate_origin() { - new_test_ext().execute_with(|| { - for i in 0..3u64 { - let k = i.twox_64_concat(); - let old: Vec, u64, u32, u64>>> = vec![ - Some(Scheduled { - maybe_id: None, - priority: i as u8 + 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), - origin: 3u32, - maybe_periodic: None, - _phantom: Default::default(), - }), - None, - Some(Scheduled { - maybe_id: Some(b"test".to_vec()), - priority: 123, - origin: 2u32, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), - maybe_periodic: Some((456u64, 10)), - _phantom: Default::default(), - }), - ]; - frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); - } - - impl Into for u32 { - fn into(self) -> OriginCaller { - match self { - 3u32 => system::RawOrigin::Root.into(), - 2u32 => system::RawOrigin::None.into(), - _ => unreachable!("test make no use of it"), - } - } - } - - Scheduler::migrate_origin::(); - - assert_eq_uvec!( - Agenda::::iter().collect::>(), - vec![ - ( - 0, - vec![ - Some(ScheduledV2::, u64, OriginCaller, u64> { - maybe_id: None, - priority: 10, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), - maybe_periodic: None, - origin: system::RawOrigin::Root.into(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), - maybe_periodic: Some((456u64, 10)), - origin: system::RawOrigin::None.into(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 1, - vec![ - Some(ScheduledV2 { - maybe_id: None, - priority: 11, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), - maybe_periodic: None, - origin: system::RawOrigin::Root.into(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), - maybe_periodic: Some((456u64, 10)), - origin: system::RawOrigin::None.into(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 2, - vec![ - Some(ScheduledV2 { - maybe_id: None, - priority: 12, - call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), - maybe_periodic: None, - origin: system::RawOrigin::Root.into(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), - maybe_periodic: Some((456u64, 10)), - origin: system::RawOrigin::None.into(), - _phantom: PhantomData::::default(), - }), - ] - ) - ] - ); - }); - } -} diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs new file mode 100644 index 0000000000000..92b5e58f44850 --- /dev/null +++ b/frame/scheduler/src/mock.rs @@ -0,0 +1,205 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 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. + +//! # Scheduler test environment. + +use super::*; + +use crate as scheduler; +use frame_support::{ + assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, + traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, + weights::constants::RocksDbWeight, + Hashable, +}; +use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, +}; +use substrate_test_utils::assert_eq_uvec; + +// Logger module to track execution. +#[frame_support::pallet] +pub mod logger { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use std::cell::RefCell; + + thread_local! { + static LOG: RefCell> = RefCell::new(Vec::new()); + } + pub fn log() -> Vec<(OriginCaller, u32)> { + LOG.with(|log| log.borrow().clone()) + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::config] + pub trait Config: frame_system::Config { + type Event: From> + IsType<::Event>; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + Logged(u32, Weight), + } + + #[pallet::call] + impl Pallet + where + ::Origin: OriginTrait, + { + #[pallet::weight(*weight)] + pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { + Self::deposit_event(Event::Logged(i, weight)); + LOG.with(|log| { + log.borrow_mut().push((origin.caller().clone(), i)); + }); + Ok(()) + } + + #[pallet::weight(*weight)] + pub fn log_without_filter( + origin: OriginFor, + i: u32, + weight: Weight, + ) -> DispatchResult { + Self::deposit_event(Event::Logged(i, weight)); + LOG.with(|log| { + log.borrow_mut().push((origin.caller().clone(), i)); + }); + Ok(()) + } + } +} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Logger: logger::{Pallet, Call, Event}, + Scheduler: scheduler::{Pallet, Call, Storage, Event}, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event}, + } +); + +// Scheduler must dispatch with root and no filter, this tests base filter is indeed not used. +pub struct BaseFilter; +impl Contains for BaseFilter { + fn contains(call: &Call) -> bool { + !matches!(call, Call::Logger(LoggerCall::log { .. })) + } +} + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); +} +impl system::Config for Test { + type BaseCallFilter = BaseFilter; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = RocksDbWeight; + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); +} +impl logger::Config for Test { + type Event = Event; +} +parameter_types! { + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; + pub const MaxScheduledPerBlock: u32 = 10; + pub const MaxSize: u32 = 1024; +} +ord_parameter_types! { + pub const One: u64 = 1; +} + +impl pallet_preimage::Config for Test { + type Event = Event; + type Currency = (); + type ManagerOrigin = EnsureRoot; + type MaxSize = MaxSize; + type BaseDeposit = (); + type ByteDeposit = (); +} + +impl Config for Test { + type Event = Event; + type Origin = Origin; + type PalletsOrigin = OriginCaller; + type Call = Call; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; + type MaxScheduledPerBlock = MaxScheduledPerBlock; + type WeightInfo = (); + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = Preimage; +} + +pub type LoggerCall = logger::Call; + +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = system::GenesisConfig::default().build_storage::().unwrap(); + t.into() +} + +fn run_to_block(n: u64) { + while System::block_number() < n { + Scheduler::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + Scheduler::on_initialize(System::block_number()); + } +} + +fn root() -> OriginCaller { + system::RawOrigin::Root.into() +} diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs new file mode 100644 index 0000000000000..e32aaef85472e --- /dev/null +++ b/frame/scheduler/src/tests.rs @@ -0,0 +1,878 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 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. + +//! # Scheduler tests. + +use super::*; +use crate::mock::*; + +use crate as scheduler; +use frame_support::{ + assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, + traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, + weights::constants::RocksDbWeight, + Hashable, +}; +use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, +}; +use substrate_test_utils::assert_eq_uvec; + +#[test] +fn basic_scheduling_works() { + new_test_ext().execute_with(|| { + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + assert!(!::BaseCallFilter::contains(&call)); + assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into())); + run_to_block(3); + assert!(logger::log().is_empty()); + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn schedule_after_works() { + new_test_ext().execute_with(|| { + run_to_block(2); + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + assert!(!::BaseCallFilter::contains(&call)); + // This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6 + assert_ok!(Scheduler::do_schedule(DispatchTime::After(3), None, 127, root(), call.into())); + run_to_block(5); + assert!(logger::log().is_empty()); + run_to_block(6); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn schedule_after_zero_works() { + new_test_ext().execute_with(|| { + run_to_block(2); + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + assert!(!::BaseCallFilter::contains(&call)); + assert_ok!(Scheduler::do_schedule(DispatchTime::After(0), None, 127, root(), call.into())); + // Will trigger on the next block. + run_to_block(3); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn periodic_scheduling_works() { + new_test_ext().execute_with(|| { + // at #4, every 3 blocks, 3 times. + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + Some((3, 3)), + 127, + root(), + Call::Logger(logger::Call::log { i: 42, weight: 1000 }).into() + )); + run_to_block(3); + assert!(logger::log().is_empty()); + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(6); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(7); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + run_to_block(9); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + run_to_block(10); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); + }); +} + +#[test] +fn reschedule_works() { + new_test_ext().execute_with(|| { + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + assert!(!::BaseCallFilter::contains(&call)); + assert_eq!( + Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into()).unwrap(), + (4, 0) + ); + + run_to_block(3); + assert!(logger::log().is_empty()); + + assert_eq!(Scheduler::do_reschedule((4, 0), DispatchTime::At(6)).unwrap(), (6, 0)); + + assert_noop!( + Scheduler::do_reschedule((6, 0), DispatchTime::At(6)), + Error::::RescheduleNoChange + ); + + run_to_block(4); + assert!(logger::log().is_empty()); + + run_to_block(6); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn reschedule_named_works() { + new_test_ext().execute_with(|| { + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + assert!(!::BaseCallFilter::contains(&call)); + assert_eq!( + Scheduler::do_schedule_named( + 1u32.encode(), + DispatchTime::At(4), + None, + 127, + root(), + call.into(), + ) + .unwrap(), + (4, 0) + ); + + run_to_block(3); + assert!(logger::log().is_empty()); + + assert_eq!( + Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), + (6, 0) + ); + + assert_noop!( + Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)), + Error::::RescheduleNoChange + ); + + run_to_block(4); + assert!(logger::log().is_empty()); + + run_to_block(6); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn reschedule_named_perodic_works() { + new_test_ext().execute_with(|| { + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + assert!(!::BaseCallFilter::contains(&call)); + assert_eq!( + Scheduler::do_schedule_named( + 1u32.encode(), + DispatchTime::At(4), + Some((3, 3)), + 127, + root(), + call.into(), + ) + .unwrap(), + (4, 0) + ); + + run_to_block(3); + assert!(logger::log().is_empty()); + + assert_eq!( + Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(5)).unwrap(), + (5, 0) + ); + assert_eq!( + Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), + (6, 0) + ); + + run_to_block(5); + assert!(logger::log().is_empty()); + + run_to_block(6); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + + assert_eq!( + Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(10)).unwrap(), + (10, 0) + ); + + run_to_block(9); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + + run_to_block(10); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + + run_to_block(13); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); + + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]); + }); +} + +#[test] +fn cancel_named_scheduling_works_with_normal_cancel() { + new_test_ext().execute_with(|| { + // at #4. + Scheduler::do_schedule_named( + 1u32.encode(), + DispatchTime::At(4), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + ) + .unwrap(); + let i = Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into(), + ) + .unwrap(); + run_to_block(3); + assert!(logger::log().is_empty()); + assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode())); + assert_ok!(Scheduler::do_cancel(None, i)); + run_to_block(100); + assert!(logger::log().is_empty()); + }); +} + +#[test] +fn cancel_named_periodic_scheduling_works() { + new_test_ext().execute_with(|| { + // at #4, every 3 blocks, 3 times. + Scheduler::do_schedule_named( + 1u32.encode(), + DispatchTime::At(4), + Some((3, 3)), + 127, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into(), + ) + .unwrap(); + // same id results in error. + assert!(Scheduler::do_schedule_named( + 1u32.encode(), + DispatchTime::At(4), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + ) + .is_err()); + // different id is ok. + Scheduler::do_schedule_named( + 2u32.encode(), + DispatchTime::At(8), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + ) + .unwrap(); + run_to_block(3); + assert!(logger::log().is_empty()); + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(6); + assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode())); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); + }); +} + +#[test] +fn scheduler_respects_weight_limits() { + new_test_ext().execute_with(|| { + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }).into(), + )); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), + )); + // 69 and 42 do not fit together + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(5); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); + }); +} + +#[test] +fn scheduler_respects_hard_deadlines_more() { + new_test_ext().execute_with(|| { + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 0, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }).into(), + )); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 0, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), + )); + // With base weights, 69 and 42 should not fit together, but do because of hard + // deadlines + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); + }); +} + +#[test] +fn scheduler_respects_priority_ordering() { + new_test_ext().execute_with(|| { + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 1, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }).into(), + )); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 0, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), + )); + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]); + }); +} + +#[test] +fn scheduler_respects_priority_ordering_with_soft_deadlines() { + new_test_ext().execute_with(|| { + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 255, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 3 }).into(), + )); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), + )); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 126, + root(), + Call::Logger(LoggerCall::log { + i: 2600, + weight: MaximumSchedulerWeight::get() / 2 + }).into(), + )); + + // 2600 does not fit with 69 or 42, but has higher priority, so will go through + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 2600u32)]); + // 69 and 42 fit together + run_to_block(5); + assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); + }); +} + +#[test] +fn on_initialize_weight_is_correct() { + new_test_ext().execute_with(|| { + let base_weight: Weight = + ::DbWeight::get().reads_writes(1, 2); + let base_multiplier = 0; + let named_multiplier = ::DbWeight::get().writes(1); + let periodic_multiplier = + ::DbWeight::get().reads_writes(1, 1); + + // Named + assert_ok!(Scheduler::do_schedule_named( + 1u32.encode(), + DispatchTime::At(1), + None, + 255, + root(), + Call::Logger(LoggerCall::log { i: 3, weight: MaximumSchedulerWeight::get() / 3 }).into(), + )); + // Anon Periodic + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(1), + Some((1000, 3)), + 128, + root(), + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 3 }).into(), + )); + // Anon + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(1), + None, + 127, + root(), + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), + )); + // Named Periodic + assert_ok!(Scheduler::do_schedule_named( + 2u32.encode(), + DispatchTime::At(1), + Some((1000, 3)), + 126, + root(), + Call::Logger(LoggerCall::log { + i: 2600, + weight: MaximumSchedulerWeight::get() / 2 + }).into(), + )); + + // Will include the named periodic only + let actual_weight = Scheduler::on_initialize(1); + let call_weight = MaximumSchedulerWeight::get() / 2; + assert_eq!( + actual_weight, + call_weight + + base_weight + base_multiplier + + named_multiplier + periodic_multiplier + ); + assert_eq!(logger::log(), vec![(root(), 2600u32)]); + + // Will include anon and anon periodic + let actual_weight = Scheduler::on_initialize(2); + let call_weight = MaximumSchedulerWeight::get() / 2 + MaximumSchedulerWeight::get() / 3; + assert_eq!( + actual_weight, + call_weight + base_weight + base_multiplier * 2 + periodic_multiplier + ); + assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); + + // Will include named only + let actual_weight = Scheduler::on_initialize(3); + let call_weight = MaximumSchedulerWeight::get() / 3; + assert_eq!( + actual_weight, + call_weight + base_weight + base_multiplier + named_multiplier + ); + assert_eq!( + logger::log(), + vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32), (root(), 3u32)] + ); + + // Will contain none + let actual_weight = Scheduler::on_initialize(4); + assert_eq!(actual_weight, 0); + }); +} + +#[test] +fn root_calls_works() { + new_test_ext().execute_with(|| { + let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + assert_ok!(Scheduler::schedule_named( + Origin::root(), + 1u32.encode(), + 4, + None, + 127, + call, + )); + assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2)); + run_to_block(3); + // Scheduled calls are in the agenda. + assert_eq!(Agenda::::get(4).len(), 2); + assert!(logger::log().is_empty()); + assert_ok!(Scheduler::cancel_named(Origin::root(), 1u32.encode())); + assert_ok!(Scheduler::cancel(Origin::root(), 4, 1)); + // Scheduled calls are made NONE, so should not effect state + run_to_block(100); + assert!(logger::log().is_empty()); + }); +} + +#[test] +fn fails_to_schedule_task_in_the_past() { + new_test_ext().execute_with(|| { + run_to_block(3); + + let call1 = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + let call3 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + + assert_err!( + Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call1), + Error::::TargetBlockNumberInPast, + ); + + assert_err!( + Scheduler::schedule(Origin::root(), 2, None, 127, call2), + Error::::TargetBlockNumberInPast, + ); + + assert_err!( + Scheduler::schedule(Origin::root(), 3, None, 127, call3), + Error::::TargetBlockNumberInPast, + ); + }); +} + +#[test] +fn should_use_orign() { + new_test_ext().execute_with(|| { + let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + assert_ok!(Scheduler::schedule_named( + system::RawOrigin::Signed(1).into(), + 1u32.encode(), + 4, + None, + 127, + call, + )); + assert_ok!(Scheduler::schedule( + system::RawOrigin::Signed(1).into(), + 4, + None, + 127, + call2, + )); + run_to_block(3); + // Scheduled calls are in the agenda. + assert_eq!(Agenda::::get(4).len(), 2); + assert!(logger::log().is_empty()); + assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), 1u32.encode())); + assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1)); + // Scheduled calls are made NONE, so should not effect state + run_to_block(100); + assert!(logger::log().is_empty()); + }); +} + +#[test] +fn should_check_orign() { + new_test_ext().execute_with(|| { + let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); + let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); + assert_noop!( + Scheduler::schedule_named( + system::RawOrigin::Signed(2).into(), + 1u32.encode(), + 4, + None, + 127, + call + ), + BadOrigin + ); + assert_noop!( + Scheduler::schedule(system::RawOrigin::Signed(2).into(), 4, None, 127, call2), + BadOrigin + ); + }); +} + +#[test] +fn should_check_orign_for_cancel() { + new_test_ext().execute_with(|| { + let call = + Box::new(Call::Logger(LoggerCall::log_without_filter { i: 69, weight: 1000 }).into()); + let call2 = + Box::new(Call::Logger(LoggerCall::log_without_filter { i: 42, weight: 1000 }).into()); + assert_ok!(Scheduler::schedule_named( + system::RawOrigin::Signed(1).into(), + 1u32.encode(), + 4, + None, + 127, + call, + )); + assert_ok!(Scheduler::schedule( + system::RawOrigin::Signed(1).into(), + 4, + None, + 127, + call2, + )); + run_to_block(3); + // Scheduled calls are in the agenda. + assert_eq!(Agenda::::get(4).len(), 2); + assert!(logger::log().is_empty()); + assert_noop!( + Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), 1u32.encode()), + BadOrigin + ); + assert_noop!(Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1), BadOrigin); + assert_noop!( + Scheduler::cancel_named(system::RawOrigin::Root.into(), 1u32.encode()), + BadOrigin + ); + assert_noop!(Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1), BadOrigin); + run_to_block(5); + assert_eq!( + logger::log(), + vec![ + (system::RawOrigin::Signed(1).into(), 69u32), + (system::RawOrigin::Signed(1).into(), 42u32) + ] + ); + }); +} + +#[test] +fn migration_to_v3_works() { + new_test_ext().execute_with(|| { + for i in 0..3u64 { + let k = i.twox_64_concat(); + let old = vec![ + Some(ScheduledV1 { + maybe_id: None, + priority: i as u8 + 10, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }), + maybe_periodic: None, + }), + None, + Some(ScheduledV1 { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }), + maybe_periodic: Some((456u64, 10)), + }), + ]; + frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); + } + + assert_eq!(StorageVersion::::get(), Releases::V1); + + assert!(Scheduler::migrate_v1_to_v3()); + + assert_eq_uvec!( + Agenda::::iter().collect::>(), + vec![ + ( + 0, + vec![ + Some(ScheduledV3Of:: { + maybe_id: None, + priority: 10, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV3Of:: { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ] + ), + ( + 1, + vec![ + Some(ScheduledV3Of:: { + maybe_id: None, + priority: 11, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV3Of:: { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ] + ), + ( + 2, + vec![ + Some(ScheduledV3Of:: { + maybe_id: None, + priority: 12, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV3Of:: { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ] + ) + ] + ); + + assert_eq!(StorageVersion::::get(), Releases::V2); + }); +} + +#[test] +fn test_migrate_origin() { + new_test_ext().execute_with(|| { + for i in 0..3u64 { + let k = i.twox_64_concat(); + let old: Vec, u64, u32, u64>>> = vec![ + Some(Scheduled { + maybe_id: None, + priority: i as u8 + 10, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + origin: 3u32, + maybe_periodic: None, + _phantom: Default::default(), + }), + None, + Some(Scheduled { + maybe_id: Some(b"test".to_vec()), + priority: 123, + origin: 2u32, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + _phantom: Default::default(), + }), + ]; + frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); + } + + impl Into for u32 { + fn into(self) -> OriginCaller { + match self { + 3u32 => system::RawOrigin::Root.into(), + 2u32 => system::RawOrigin::None.into(), + _ => unreachable!("test make no use of it"), + } + } + } + + Scheduler::migrate_origin::(); + + assert_eq_uvec!( + Agenda::::iter().collect::>(), + vec![ + ( + 0, + vec![ + Some(ScheduledV2::, u64, OriginCaller, u64> { + maybe_id: None, + priority: 10, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + maybe_periodic: None, + origin: system::RawOrigin::Root.into(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV2 { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + origin: system::RawOrigin::None.into(), + _phantom: PhantomData::::default(), + }), + ] + ), + ( + 1, + vec![ + Some(ScheduledV2 { + maybe_id: None, + priority: 11, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + maybe_periodic: None, + origin: system::RawOrigin::Root.into(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV2 { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + origin: system::RawOrigin::None.into(), + _phantom: PhantomData::::default(), + }), + ] + ), + ( + 2, + vec![ + Some(ScheduledV2 { + maybe_id: None, + priority: 12, + call: Call::Logger(LoggerCall::log { i: 96, weight: 100 }).into(), + maybe_periodic: None, + origin: system::RawOrigin::Root.into(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV2 { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into(), + maybe_periodic: Some((456u64, 10)), + origin: system::RawOrigin::None.into(), + _phantom: PhantomData::::default(), + }), + ] + ) + ] + ); + }); +} From 50829990085cb5a0f9297b159c4f3619052306fe Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 11:21:12 +0100 Subject: [PATCH 22/58] Missing stuff --- frame/scheduler/src/mock.rs | 264 ++++++++++++++++++------------------ 1 file changed, 132 insertions(+), 132 deletions(-) diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 92b5e58f44850..98fbecaf02193 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -21,185 +21,185 @@ use super::*; use crate as scheduler; use frame_support::{ - assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, - weights::constants::RocksDbWeight, - Hashable, + assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, + traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, + weights::constants::RocksDbWeight, + Hashable, }; use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; use sp_core::H256; use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - Perbill, + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, }; use substrate_test_utils::assert_eq_uvec; // Logger module to track execution. #[frame_support::pallet] pub mod logger { - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - use std::cell::RefCell; - - thread_local! { - static LOG: RefCell> = RefCell::new(Vec::new()); - } - pub fn log() -> Vec<(OriginCaller, u32)> { - LOG.with(|log| log.borrow().clone()) - } - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(PhantomData); - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::config] - pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - Logged(u32, Weight), - } - - #[pallet::call] - impl Pallet - where - ::Origin: OriginTrait, - { - #[pallet::weight(*weight)] - pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { - Self::deposit_event(Event::Logged(i, weight)); - LOG.with(|log| { - log.borrow_mut().push((origin.caller().clone(), i)); - }); - Ok(()) - } - - #[pallet::weight(*weight)] - pub fn log_without_filter( - origin: OriginFor, - i: u32, - weight: Weight, - ) -> DispatchResult { - Self::deposit_event(Event::Logged(i, weight)); - LOG.with(|log| { - log.borrow_mut().push((origin.caller().clone(), i)); - }); - Ok(()) - } - } + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use std::cell::RefCell; + + thread_local! { + static LOG: RefCell> = RefCell::new(Vec::new()); + } + pub fn log() -> Vec<(OriginCaller, u32)> { + LOG.with(|log| log.borrow().clone()) + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::config] + pub trait Config: frame_system::Config { + type Event: From> + IsType<::Event>; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + Logged(u32, Weight), + } + + #[pallet::call] + impl Pallet + where + ::Origin: OriginTrait, + { + #[pallet::weight(*weight)] + pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { + Self::deposit_event(Event::Logged(i, weight)); + LOG.with(|log| { + log.borrow_mut().push((origin.caller().clone(), i)); + }); + Ok(()) + } + + #[pallet::weight(*weight)] + pub fn log_without_filter( + origin: OriginFor, + i: u32, + weight: Weight, + ) -> DispatchResult { + Self::deposit_event(Event::Logged(i, weight)); + LOG.with(|log| { + log.borrow_mut().push((origin.caller().clone(), i)); + }); + Ok(()) + } + } } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Logger: logger::{Pallet, Call, Event}, - Scheduler: scheduler::{Pallet, Call, Storage, Event}, - Preimage: pallet_preimage::{Pallet, Call, Storage, Event}, - } + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Logger: logger::{Pallet, Call, Event}, + Scheduler: scheduler::{Pallet, Call, Storage, Event}, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event}, + } ); // Scheduler must dispatch with root and no filter, this tests base filter is indeed not used. pub struct BaseFilter; impl Contains for BaseFilter { - fn contains(call: &Call) -> bool { - !matches!(call, Call::Logger(LoggerCall::log { .. })) - } + fn contains(call: &Call) -> bool { + !matches!(call, Call::Logger(LoggerCall::log { .. })) + } } parameter_types! { - pub const BlockHashCount: u64 = 250; - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); + pub const BlockHashCount: u64 = 250; + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); } impl system::Config for Test { - type BaseCallFilter = BaseFilter; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = RocksDbWeight; - type Origin = Origin; - type Call = Call; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = Event; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); + type BaseCallFilter = BaseFilter; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = RocksDbWeight; + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); } impl logger::Config for Test { - type Event = Event; + type Event = Event; } parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; - pub const MaxScheduledPerBlock: u32 = 10; - pub const MaxSize: u32 = 1024; + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; + pub const MaxScheduledPerBlock: u32 = 10; + pub const MaxSize: u32 = 1024; } ord_parameter_types! { - pub const One: u64 = 1; + pub const One: u64 = 1; } impl pallet_preimage::Config for Test { - type Event = Event; - type Currency = (); - type ManagerOrigin = EnsureRoot; - type MaxSize = MaxSize; - type BaseDeposit = (); - type ByteDeposit = (); + type Event = Event; + type Currency = (); + type ManagerOrigin = EnsureRoot; + type MaxSize = MaxSize; + type BaseDeposit = (); + type ByteDeposit = (); } impl Config for Test { - type Event = Event; - type Origin = Origin; - type PalletsOrigin = OriginCaller; - type Call = Call; - type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; - type MaxScheduledPerBlock = MaxScheduledPerBlock; - type WeightInfo = (); - type OriginPrivilegeCmp = EqualPrivilegeOnly; - type Preimages = Preimage; + type Event = Event; + type Origin = Origin; + type PalletsOrigin = OriginCaller; + type Call = Call; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; + type MaxScheduledPerBlock = MaxScheduledPerBlock; + type WeightInfo = (); + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = Preimage; } pub type LoggerCall = logger::Call; pub fn new_test_ext() -> sp_io::TestExternalities { - let t = system::GenesisConfig::default().build_storage::().unwrap(); - t.into() + let t = system::GenesisConfig::default().build_storage::().unwrap(); + t.into() } fn run_to_block(n: u64) { - while System::block_number() < n { - Scheduler::on_finalize(System::block_number()); - System::set_block_number(System::block_number() + 1); - Scheduler::on_initialize(System::block_number()); - } + while System::block_number() < n { + Scheduler::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + Scheduler::on_initialize(System::block_number()); + } } fn root() -> OriginCaller { - system::RawOrigin::Root.into() + system::RawOrigin::Root.into() } From a2699863dfdb1c98b4d9f482bb2d181d881f80f3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 11:43:12 +0100 Subject: [PATCH 23/58] Repotting, add weights. --- Cargo.lock | 1 + frame/preimage/Cargo.toml | 1 + frame/preimage/src/benchmarking.rs | 142 ++++++++++++++++++++++++++++ frame/preimage/src/lib.rs | 20 +++- frame/preimage/src/mock.rs | 144 +++++++++++++++++++++++++++++ frame/preimage/src/tests.rs | 37 ++++++++ frame/preimage/src/weights.rs | 103 +++++++++++++++++++++ frame/scheduler/src/lib.rs | 2 +- frame/scheduler/src/mock.rs | 9 +- frame/scheduler/src/tests.rs | 17 +--- 10 files changed, 454 insertions(+), 22 deletions(-) create mode 100644 frame/preimage/src/benchmarking.rs create mode 100644 frame/preimage/src/mock.rs create mode 100644 frame/preimage/src/tests.rs create mode 100644 frame/preimage/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 5e45fefb879ef..da4f7d9784b73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5892,6 +5892,7 @@ version = "4.0.0-dev" dependencies = [ "frame-support", "frame-system", + "pallet-balances", "parity-scale-codec", "scale-info", "sp-core", diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 35b99c6335b16..7d28846323029 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -23,6 +23,7 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys [dev-dependencies] sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs new file mode 100644 index 0000000000000..c029993e4674f --- /dev/null +++ b/frame/preimage/src/benchmarking.rs @@ -0,0 +1,142 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2021 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. + +//! Scheduler pallet benchmarking. + +use super::*; +use frame_benchmarking::benchmarks; +use frame_support::{ensure, traits::OnInitialize}; +use frame_system::RawOrigin; +use sp_std::{prelude::*, vec}; + +use crate::Pallet as Scheduler; +use frame_system::Pallet as System; + +const BLOCK_NUMBER: u32 = 2; + +// Add `n` named items to the schedule +fn fill_schedule(when: T::BlockNumber, n: u32) -> Result<(), &'static str> { + // Essentially a no-op call. + let call = frame_system::Call::set_storage { items: vec![] }; + for i in 0..n { + // Named schedule is strictly heavier than anonymous + Scheduler::::do_schedule_named( + i.encode(), + DispatchTime::At(when), + // Add periodicity + Some((T::BlockNumber::one(), 100)), + // HARD_DEADLINE priority means it gets executed no matter what + 0, + frame_system::RawOrigin::Root.into(), + call.clone().into(), + )?; + } + ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); + Ok(()) +} + +benchmarks! { + schedule { + let s in 0 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + let periodic = Some((T::BlockNumber::one(), 100)); + let priority = 0; + // Essentially a no-op call. + let call = Box::new(frame_system::Call::set_storage { items: vec![] }.into()); + + fill_schedule::(when, s)?; + }: _(RawOrigin::Root, when, periodic, priority, call) + verify { + ensure!( + Agenda::::get(when).len() == (s + 1) as usize, + "didn't add to schedule" + ); + } + + cancel { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + + fill_schedule::(when, s)?; + assert_eq!(Agenda::::get(when).len(), s as usize); + }: _(RawOrigin::Root, when, 0) + verify { + ensure!( + Lookup::::get(0.encode()).is_none(), + "didn't remove from lookup" + ); + // Removed schedule is NONE + ensure!( + Agenda::::get(when)[0].is_none(), + "didn't remove from schedule" + ); + } + + schedule_named { + let s in 0 .. T::MaxScheduledPerBlock::get(); + let id = s.encode(); + let when = BLOCK_NUMBER.into(); + let periodic = Some((T::BlockNumber::one(), 100)); + let priority = 0; + // Essentially a no-op call. + let call = Box::new(frame_system::Call::set_storage { items: vec![] }.into()); + + fill_schedule::(when, s)?; + }: _(RawOrigin::Root, id, when, periodic, priority, call) + verify { + ensure!( + Agenda::::get(when).len() == (s + 1) as usize, + "didn't add to schedule" + ); + } + + cancel_named { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + + fill_schedule::(when, s)?; + }: _(RawOrigin::Root, 0.encode()) + verify { + ensure!( + Lookup::::get(0.encode()).is_none(), + "didn't remove from lookup" + ); + // Removed schedule is NONE + ensure!( + Agenda::::get(when)[0].is_none(), + "didn't remove from schedule" + ); + } + + // TODO [#7141]: Make this more complex and flexible so it can be used in automation. + #[extra] + on_initialize { + let s in 0 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s)?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s); + // Next block should have all the schedules again + ensure!( + Agenda::::get(when + T::BlockNumber::one()).len() == s as usize, + "didn't append schedule" + ); + } + + impl_benchmark_test_suite!(Scheduler, crate::tests::new_test_ext(), crate::tests::Test); +} diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 35cc2df949de1..c350cbf462663 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -28,6 +28,14 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +pub mod weights; +#[cfg(test)] +mod tests; +#[cfg(test)] +mod mock; + use sp_runtime::traits::{BadOrigin, Hash, Saturating}; use sp_std::{convert::TryFrom, prelude::*}; @@ -40,6 +48,7 @@ use frame_support::{ BoundedVec, }; use scale_info::TypeInfo; +use weights::WeightInfo; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -69,6 +78,9 @@ pub mod pallet { /// The overarching event type. type Event: From> + IsType<::Event>; + /// The Weight information for this pallet. + type WeightInfo: weights::WeightInfo; + /// Currency type for this pallet. type Currency: ReservableCurrency; @@ -134,7 +146,7 @@ pub mod pallet { /// /// If the preimage was previously requested, no fees or deposits are taken for providing /// the preimage. Otherwise, a deposit is taken proportional to the size of the preimage. - #[pallet::weight(0)] + #[pallet::weight(T::WeightInfo::note_preimage(bytes.len() as u32))] pub fn note_preimage(origin: OriginFor, bytes: Vec) -> DispatchResultWithPostInfo { // We accept a signed origin which will pay a deposit, or a root origin where a deposit // is not taken. @@ -150,7 +162,7 @@ pub mod pallet { } /// Clear an unrequested preimage from the runtime storage. - #[pallet::weight(0)] + #[pallet::weight(T::WeightInfo::unnote_preimage())] pub fn unnote_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { let maybe_sender = Self::ensure_signed_or_manager(origin)?; Self::do_unnote_preimage(&hash, maybe_sender) @@ -160,7 +172,7 @@ pub mod pallet { /// /// If the preimage requests has already been provided on-chain, we unreserve any deposit /// a user may have paid, and take the control of the preimage out of their hands. - #[pallet::weight(0)] + #[pallet::weight(T::WeightInfo::request_preimage())] pub fn request_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; Self::do_request_preimage(&hash); @@ -170,7 +182,7 @@ pub mod pallet { /// Clear a previously made request for a preimage. /// /// NOTE: THIS MUST NOT BE CALLED ON `hash` MORE TIMES THAN `request_preimage`. - #[pallet::weight(0)] + #[pallet::weight(T::WeightInfo::unrequest_preimage())] pub fn unrequest_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; Self::do_unrequest_preimage(&hash) diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs new file mode 100644 index 0000000000000..13d0baef8a602 --- /dev/null +++ b/frame/preimage/src/mock.rs @@ -0,0 +1,144 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 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. + +//! # Scheduler test environment. + +use super::*; + +use crate as pallet_preimage; +use frame_support::{ + assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, + traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, + weights::constants::RocksDbWeight, + Hashable, +}; +use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, +}; +use substrate_test_utils::assert_eq_uvec; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Logger: logger::{Pallet, Call, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Preimage: pallet_preimage::{Pallet, Call, Storage, Event}, + } +); + +// Scheduler must dispatch with root and no filter, this tests base filter is indeed not used. +pub struct BaseFilter; +impl Contains for BaseFilter { + fn contains(call: &Call) -> bool { + !matches!(call, Call::Logger(LoggerCall::log { .. })) + } +} + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); +} +impl system::Config for Test { + type BaseCallFilter = BaseFilter; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = RocksDbWeight; + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); +} + +parameter_types! { + pub const ExistentialDeposit: u64 = 5; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Test { + type Balance = u64; + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; + pub const MaxScheduledPerBlock: u32 = 10; + pub const MaxSize: u32 = 1024; + pub const BaseDeposit: u64 = 2; + pub const ByteDeposit: u64 = 1; +} + +impl Config for Test { + type Event = Event; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type MaxSize = MaxSize; + type BaseDeposit = BaseDeposit; + type ByteDeposit = ByteDeposit; +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = system::GenesisConfig::default().build_storage::().unwrap(); + let balances = pallet_balances::GenesisConfig:: { + balances: vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100)], + }; + balances.assimilate_storage(&mut t).unwrap(); + t.into() +} + +fn run_to_block(n: u64) { + while System::block_number() < n { + System::set_block_number(System::block_number() + 1); + } +} + +fn root() -> OriginCaller { + system::RawOrigin::Root.into() +} diff --git a/frame/preimage/src/tests.rs b/frame/preimage/src/tests.rs new file mode 100644 index 0000000000000..de84ad23e0af9 --- /dev/null +++ b/frame/preimage/src/tests.rs @@ -0,0 +1,37 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 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. + +//! # Scheduler tests. + +use super::*; +use crate::mock::*; + +use crate as scheduler; +use frame_support::{ + assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, + traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, + weights::constants::RocksDbWeight, + Hashable, +}; +use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, +}; +use substrate_test_utils::assert_eq_uvec; diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs new file mode 100644 index 0000000000000..734b496aa7ddf --- /dev/null +++ b/frame/preimage/src/weights.rs @@ -0,0 +1,103 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 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. + +//! Autogenerated weights for pallet_scheduler +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// target/release/substrate +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_preimage +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./frame/scheduler/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_preimage. +pub trait WeightInfo { + fn note_preimage(s: u32, ) -> Weight; + fn unnote_preimage() -> Weight; + fn request_preimage() -> Weight; + fn unrequest_preimage() -> Weight; +} + +/// Weights for pallet_scheduler using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn note_preimage(s: u32, ) -> Weight { + (24_730_000 as Weight) + .saturating_add((77_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + fn unnote_preimage() -> Weight { + (23_272_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + fn request_preimage() -> Weight { + (30_971_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + fn unrequest_preimage() -> Weight { + (25_778_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + fn note_preimage(s: u32, ) -> Weight { + (24_730_000 as Weight) + .saturating_add((77_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + fn unnote_preimage() -> Weight { + (23_272_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + fn request_preimage() -> Weight { + (30_971_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + fn unrequest_preimage() -> Weight { + (25_778_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } +} diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 2cb2de4c675e5..e5bfb06039ed9 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -50,7 +50,7 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -#![cfg(feature = "runtime-benchmarks")] +#[cfg(feature = "runtime-benchmarks")] mod benchmarking; pub mod weights; #[cfg(test)] diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 98fbecaf02193..eef1f1e97d434 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -21,10 +21,9 @@ use super::*; use crate as scheduler; use frame_support::{ - assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, + ord_parameter_types, parameter_types, traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, weights::constants::RocksDbWeight, - Hashable, }; use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; use sp_core::H256; @@ -33,7 +32,6 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, Perbill, }; -use substrate_test_utils::assert_eq_uvec; // Logger module to track execution. #[frame_support::pallet] @@ -165,6 +163,7 @@ ord_parameter_types! { impl pallet_preimage::Config for Test { type Event = Event; + type WeightInfo = (); type Currency = (); type ManagerOrigin = EnsureRoot; type MaxSize = MaxSize; @@ -192,7 +191,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { t.into() } -fn run_to_block(n: u64) { +pub fn run_to_block(n: u64) { while System::block_number() < n { Scheduler::on_finalize(System::block_number()); System::set_block_number(System::block_number() + 1); @@ -200,6 +199,6 @@ fn run_to_block(n: u64) { } } -fn root() -> OriginCaller { +pub fn root() -> OriginCaller { system::RawOrigin::Root.into() } diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index e32aaef85472e..621089c430960 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -18,22 +18,15 @@ //! # Scheduler tests. use super::*; -use crate::mock::*; +use crate::mock::{ + *, Call, root, run_to_block, new_test_ext, LoggerCall, Test, logger, Scheduler +}; -use crate as scheduler; use frame_support::{ - assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, - weights::constants::RocksDbWeight, + assert_err, assert_noop, assert_ok, + traits::{Contains, OnInitialize}, Hashable, }; -use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; -use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - Perbill, -}; use substrate_test_utils::assert_eq_uvec; #[test] From 67a043e1d385e45c66cc0d5cd16426c296ff6fee Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 13:09:44 +0100 Subject: [PATCH 24/58] Add some tests to preimage pallet --- frame/preimage/src/lib.rs | 9 +- frame/preimage/src/mock.rs | 53 ++++------- frame/preimage/src/tests.rs | 147 +++++++++++++++++++++++++++---- frame/support/src/traits/misc.rs | 2 +- 4 files changed, 156 insertions(+), 55 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index c350cbf462663..e5d843bea635a 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -215,9 +215,12 @@ impl Pallet { // We take a deposit only if there is a provided depositor, and the preimage was not // previously requested. This also allows the tx to pay no fee. let was_requested = match (StatusFor::::get(hash), maybe_depositor) { - (Some(RequestStatus::Requested(_)), _) => true, + (Some(RequestStatus::Requested(..)), _) => true, (Some(RequestStatus::Unrequested(..)), _) => Err(Error::::AlreadyNoted)?, - (_, None) => true, + (None, None) => { + StatusFor::::insert(hash, RequestStatus::Unrequested(None)); + true + }, (None, Some(depositor)) => { let length = preimage.len() as u32; let deposit = T::BaseDeposit::get() @@ -307,7 +310,7 @@ impl Pallet { } impl PreimageProvider for Pallet { - fn preimage_exists(hash: &T::Hash) -> bool { + fn have_preimage(hash: &T::Hash) -> bool { PreimageFor::::contains_key(hash) } diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index 13d0baef8a602..4257f9d7505b0 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -20,20 +20,11 @@ use super::*; use crate as pallet_preimage; -use frame_support::{ - assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, - weights::constants::RocksDbWeight, - Hashable, -}; -use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - Perbill, -}; -use substrate_test_utils::assert_eq_uvec; +use sp_runtime::{testing::Header, traits::{BlakeTwo256, IdentityLookup}, Perbill}; +use frame_support::{parameter_types, ord_parameter_types, traits::Everything}; +use frame_support::weights::constants::RocksDbWeight; +use frame_system::EnsureSignedBy; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -45,27 +36,18 @@ frame_support::construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, - Logger: logger::{Pallet, Call, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Preimage: pallet_preimage::{Pallet, Call, Storage, Event}, } ); -// Scheduler must dispatch with root and no filter, this tests base filter is indeed not used. -pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(call: &Call) -> bool { - !matches!(call, Call::Logger(LoggerCall::log { .. })) - } -} - parameter_types! { pub const BlockHashCount: u64 = 250; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(2_000_000_000_000); } -impl system::Config for Test { - type BaseCallFilter = BaseFilter; +impl frame_system::Config for Test { + type BaseCallFilter = Everything; type BlockWeights = (); type BlockLength = (); type DbWeight = RocksDbWeight; @@ -82,7 +64,7 @@ impl system::Config for Test { type BlockHashCount = BlockHashCount; type Version = (); type PalletInfo = PalletInfo; - type AccountData = (); + type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); @@ -115,17 +97,22 @@ parameter_types! { pub const ByteDeposit: u64 = 1; } +ord_parameter_types! { + pub const One: u64 = 1; +} + impl Config for Test { + type WeightInfo = (); type Event = Event; type Currency = Balances; - type ManagerOrigin = EnsureRoot; + type ManagerOrigin = EnsureSignedBy; type MaxSize = MaxSize; type BaseDeposit = BaseDeposit; type ByteDeposit = ByteDeposit; } pub fn new_test_ext() -> sp_io::TestExternalities { - let t = system::GenesisConfig::default().build_storage::().unwrap(); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); let balances = pallet_balances::GenesisConfig:: { balances: vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100)], }; @@ -133,12 +120,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { t.into() } -fn run_to_block(n: u64) { - while System::block_number() < n { - System::set_block_number(System::block_number() + 1); - } -} - -fn root() -> OriginCaller { - system::RawOrigin::Root.into() -} +pub fn hashed(data: impl AsRef<[u8]>) -> H256 { + BlakeTwo256::hash(data.as_ref()) +} \ No newline at end of file diff --git a/frame/preimage/src/tests.rs b/frame/preimage/src/tests.rs index de84ad23e0af9..3e1cd0a6277d2 100644 --- a/frame/preimage/src/tests.rs +++ b/frame/preimage/src/tests.rs @@ -20,18 +20,135 @@ use super::*; use crate::mock::*; -use crate as scheduler; -use frame_support::{ - assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types, - traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, - weights::constants::RocksDbWeight, - Hashable, -}; -use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; -use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - Perbill, -}; -use substrate_test_utils::assert_eq_uvec; +use frame_support::{assert_noop, assert_ok}; +use pallet_balances::Error as BalancesError; + +#[test] +fn user_note_preimage_works() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_eq!(Balances::reserved_balance(2), 3); + assert_eq!(Balances::free_balance(2), 97); + + let h = hashed([1]); + assert!(Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + + assert_noop!(Preimage::note_preimage(Origin::signed(2), vec![1]), Error::::AlreadyNoted); + assert_noop!(Preimage::note_preimage(Origin::signed(0), vec![2]), BalancesError::::InsufficientBalance); + }); +} + +#[test] +fn manager_note_preimage_works() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_eq!(Balances::reserved_balance(1), 0); + assert_eq!(Balances::free_balance(1), 100); + + let h = hashed([1]); + assert!(Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + + assert_noop!(Preimage::note_preimage(Origin::signed(1), vec![1]), Error::::AlreadyNoted); + }); +} + +#[test] +fn user_unnote_preimage_works() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_noop!(Preimage::unnote_preimage(Origin::signed(3), hashed([1])), Error::::NotAuthorized); + assert_noop!(Preimage::unnote_preimage(Origin::signed(2), hashed([2])), Error::::NotNoted); + + assert_ok!(Preimage::unnote_preimage(Origin::signed(2), hashed([1]))); + assert_noop!(Preimage::unnote_preimage(Origin::signed(2), hashed([1])), Error::::NotNoted); + + let h = hashed([1]); + assert!(!Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), None); + }); +} + +#[test] +fn manager_unnote_preimage_works() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_ok!(Preimage::unnote_preimage(Origin::signed(1), hashed([1]))); + assert_noop!(Preimage::unnote_preimage(Origin::signed(1), hashed([1])), Error::::NotNoted); + + let h = hashed([1]); + assert!(!Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), None); + }); +} + +#[test] +fn manager_unnote_user_preimage_works() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_noop!(Preimage::unnote_preimage(Origin::signed(3), hashed([1])), Error::::NotAuthorized); + assert_noop!(Preimage::unnote_preimage(Origin::signed(2), hashed([2])), Error::::NotNoted); + + assert_ok!(Preimage::unnote_preimage(Origin::signed(1), hashed([1]))); + + let h = hashed([1]); + assert!(!Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), None); + }); +} + +#[test] +fn requested_then_noted_preimage_cannot_be_unnoted() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_noop!(Preimage::unnote_preimage(Origin::signed(1), hashed([1])), Error::::Requested); + + let h = hashed([1]); + assert!(Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + }); +} + +#[test] +fn noted_then_requested_preimage_cannot_be_unnoted() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_noop!(Preimage::unnote_preimage(Origin::signed(1), hashed([1])), Error::::Requested); + + let h = hashed([1]); + assert!(Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + }); +} + +#[test] +fn requested_then_user_noted_preimage_is_free() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(Balances::free_balance(2), 100); + + let h = hashed([1]); + assert!(Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + }); +} + + +#[test] +fn user_noted_then_requested_preimage_is_refunded() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_eq!(Balances::reserved_balance(2), 0); + assert_eq!(Balances::free_balance(2), 100); + + let h = hashed([1]); + assert!(Preimage::have_preimage(&h)); + assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + }); +} diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 4ced1f81d4ace..1b8092ca1400c 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -573,7 +573,7 @@ pub trait PreimageProvider { /// Returns whether a preimage exists for a given hash. /// /// A value of `true` implies that `get_preimage` is `Some`. - fn preimage_exists(hash: &Hash) -> bool; + fn have_preimage(hash: &Hash) -> bool; /// Returns the preimage for a given hash. fn get_preimage(hash: &Hash) -> Option>; From 2f41259d67464b4893f42c0d3cf299c903bd1dbb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 13:24:56 +0100 Subject: [PATCH 25/58] More tests --- frame/preimage/src/lib.rs | 2 +- frame/preimage/src/tests.rs | 71 +++++++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index e5d843bea635a..99fb99d83ec43 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -56,7 +56,7 @@ use frame_system::pallet_prelude::*; pub use pallet::*; /// A type to note whether a preimage is owned by a user or the system. -#[derive(Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)] pub enum RequestStatus { /// The associated preimage has not yet been requested by the system. The given deposit (if /// some) is being held until either it becomes requested or the user retracts the primage. diff --git a/frame/preimage/src/tests.rs b/frame/preimage/src/tests.rs index 3e1cd0a6277d2..7acbada5a3fdd 100644 --- a/frame/preimage/src/tests.rs +++ b/frame/preimage/src/tests.rs @@ -112,15 +112,23 @@ fn requested_then_noted_preimage_cannot_be_unnoted() { } #[test] -fn noted_then_requested_preimage_cannot_be_unnoted() { - new_test_ext().execute_with(|| { +fn request_note_order_makes_no_difference() { + let one_way = new_test_ext().execute_with(|| { assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); - assert_noop!(Preimage::unnote_preimage(Origin::signed(1), hashed([1])), Error::::Requested); - - let h = hashed([1]); - assert!(Preimage::have_preimage(&h)); - assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + ( + StatusFor::::iter().collect::>(), + PreimageFor::::iter().collect::>(), + ) + }); + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + let other_way = ( + StatusFor::::iter().collect::>(), + PreimageFor::::iter().collect::>(), + ); + assert_eq!(one_way, other_way); }); } @@ -138,17 +146,52 @@ fn requested_then_user_noted_preimage_is_free() { }); } - #[test] -fn user_noted_then_requested_preimage_is_refunded() { +fn request_user_note_order_makes_no_difference() { + let one_way = new_test_ext().execute_with(|| { + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + ( + StatusFor::::iter().collect::>(), + PreimageFor::::iter().collect::>(), + ) + }); new_test_ext().execute_with(|| { assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_eq!(Balances::reserved_balance(2), 0); - assert_eq!(Balances::free_balance(2), 100); + let other_way = ( + StatusFor::::iter().collect::>(), + PreimageFor::::iter().collect::>(), + ); + assert_eq!(one_way, other_way); + }); +} - let h = hashed([1]); - assert!(Preimage::have_preimage(&h)); - assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); +#[test] +fn unrequest_preimage_works() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_noop!(Preimage::unrequest_preimage(Origin::signed(1), hashed([2])), Error::::NotRequested); + + assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); + assert!(Preimage::have_preimage(&hashed([1]))); + + assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); + assert_noop!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1])), Error::::NotRequested); + }); +} + +#[test] +fn user_noted_then_requested_preimage_is_refunded_once_only() { + new_test_ext().execute_with(|| { + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1; 3])); + assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); + // Still have reserve from `vec[1; 3]`. + assert_eq!(Balances::reserved_balance(2), 5); + assert_eq!(Balances::free_balance(2), 95); }); } From 9c60fe8d2cb0ccde910f9381499bc63d090da3ce Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 15:55:34 +0100 Subject: [PATCH 26/58] Fix benchmarks --- Cargo.lock | 1 + frame/preimage/Cargo.toml | 9 ++ frame/preimage/src/benchmarking.rs | 136 +++++----------------------- frame/scheduler/src/benchmarking.rs | 10 +- 4 files changed, 41 insertions(+), 115 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index da4f7d9784b73..e0c010165367e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5890,6 +5890,7 @@ dependencies = [ name = "pallet-preimage" version = "4.0.0-dev" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "pallet-balances", diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 7d28846323029..98627d4108085 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -21,12 +21,21 @@ sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../pr frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-core = { version = "4.0.0-dev", optional = true, path = "../../primitives/core" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } + [dev-dependencies] sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] +runtime-benchmarks = [ + "sp-core", + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] std = [ "codec/std", "scale-info/std", diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index c029993e4674f..2137506f92b8b 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -15,128 +15,42 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Scheduler pallet benchmarking. +//! Preimage pallet benchmarking. use super::*; -use frame_benchmarking::benchmarks; -use frame_support::{ensure, traits::OnInitialize}; +use sp_core::Hasher; +use sp_runtime::traits::BlakeTwo256; +use frame_benchmarking::{benchmarks, whitelist_account, account}; +use frame_support::ensure; use frame_system::RawOrigin; use sp_std::{prelude::*, vec}; +use crate::mock::*; -use crate::Pallet as Scheduler; +use crate::Pallet as Preimage; use frame_system::Pallet as System; -const BLOCK_NUMBER: u32 = 2; +const SEED: u32 = 0; -// Add `n` named items to the schedule -fn fill_schedule(when: T::BlockNumber, n: u32) -> Result<(), &'static str> { - // Essentially a no-op call. - let call = frame_system::Call::set_storage { items: vec![] }; - for i in 0..n { - // Named schedule is strictly heavier than anonymous - Scheduler::::do_schedule_named( - i.encode(), - DispatchTime::At(when), - // Add periodicity - Some((T::BlockNumber::one(), 100)), - // HARD_DEADLINE priority means it gets executed no matter what - 0, - frame_system::RawOrigin::Root.into(), - call.clone().into(), - )?; - } - ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); - Ok(()) +fn assert_last_event(generic_event: ::Event) { + System::::assert_last_event(generic_event.into()); } -benchmarks! { - schedule { - let s in 0 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - let periodic = Some((T::BlockNumber::one(), 100)); - let priority = 0; - // Essentially a no-op call. - let call = Box::new(frame_system::Call::set_storage { items: vec![] }.into()); - - fill_schedule::(when, s)?; - }: _(RawOrigin::Root, when, periodic, priority, call) - verify { - ensure!( - Agenda::::get(when).len() == (s + 1) as usize, - "didn't add to schedule" - ); - } - - cancel { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - - fill_schedule::(when, s)?; - assert_eq!(Agenda::::get(when).len(), s as usize); - }: _(RawOrigin::Root, when, 0) - verify { - ensure!( - Lookup::::get(0.encode()).is_none(), - "didn't remove from lookup" - ); - // Removed schedule is NONE - ensure!( - Agenda::::get(when)[0].is_none(), - "didn't remove from schedule" - ); - } - - schedule_named { - let s in 0 .. T::MaxScheduledPerBlock::get(); - let id = s.encode(); - let when = BLOCK_NUMBER.into(); - let periodic = Some((T::BlockNumber::one(), 100)); - let priority = 0; - // Essentially a no-op call. - let call = Box::new(frame_system::Call::set_storage { items: vec![] }.into()); - - fill_schedule::(when, s)?; - }: _(RawOrigin::Root, id, when, periodic, priority, call) - verify { - ensure!( - Agenda::::get(when).len() == (s + 1) as usize, - "didn't add to schedule" - ); - } - - cancel_named { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - - fill_schedule::(when, s)?; - }: _(RawOrigin::Root, 0.encode()) - verify { - ensure!( - Lookup::::get(0.encode()).is_none(), - "didn't remove from lookup" - ); - // Removed schedule is NONE - ensure!( - Agenda::::get(when)[0].is_none(), - "didn't remove from schedule" - ); - } +fn funded_account(name: &'static str, index: u32) -> T::AccountId { + let caller: T::AccountId = account(name, index, SEED); + T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); + caller +} - // TODO [#7141]: Make this more complex and flexible so it can be used in automation. - #[extra] - on_initialize { - let s in 0 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s)?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } +benchmarks! { + note_preimage { + let s in 0 .. T::MaxSize::get(); + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + let mut preimage = vec![]; + preimage.resize(s as usize, 0); + }: _(RawOrigin::Signed(caller), preimage) verify { - assert_eq!(System::::event_count(), s); - // Next block should have all the schedules again - ensure!( - Agenda::::get(when + T::BlockNumber::one()).len() == s as usize, - "didn't append schedule" - ); + assert!(Pallet::have_preimage(BlakeTwo256::hash(&preimage[..]))); } - - impl_benchmark_test_suite!(Scheduler, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Preimage, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index c029993e4674f..d903c7b48008b 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -31,7 +31,7 @@ const BLOCK_NUMBER: u32 = 2; // Add `n` named items to the schedule fn fill_schedule(when: T::BlockNumber, n: u32) -> Result<(), &'static str> { // Essentially a no-op call. - let call = frame_system::Call::set_storage { items: vec![] }; + let call = CallOrHashOf::::Value(frame_system::Call::set_storage { items: vec![] }.into()); for i in 0..n { // Named schedule is strictly heavier than anonymous Scheduler::::do_schedule_named( @@ -56,7 +56,8 @@ benchmarks! { let periodic = Some((T::BlockNumber::one(), 100)); let priority = 0; // Essentially a no-op call. - let call = Box::new(frame_system::Call::set_storage { items: vec![] }.into()); + let inner_call = frame_system::Call::set_storage { items: vec![] }.into(); + let call = Box::new(CallOrHashOf::::Value(inner_call)); fill_schedule::(when, s)?; }: _(RawOrigin::Root, when, periodic, priority, call) @@ -93,7 +94,8 @@ benchmarks! { let periodic = Some((T::BlockNumber::one(), 100)); let priority = 0; // Essentially a no-op call. - let call = Box::new(frame_system::Call::set_storage { items: vec![] }.into()); + let inner_call = frame_system::Call::set_storage { items: vec![] }.into(); + let call = Box::new(CallOrHashOf::::Value(inner_call)); fill_schedule::(when, s)?; }: _(RawOrigin::Root, id, when, periodic, priority, call) @@ -138,5 +140,5 @@ benchmarks! { ); } - impl_benchmark_test_suite!(Scheduler, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test); } From 961dd690e6ff4c2b819dacb4c7c626645d3753e9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 16:34:02 +0100 Subject: [PATCH 27/58] preimage benchmarks --- frame/preimage/src/benchmarking.rs | 79 +++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index 2137506f92b8b..f567c3caa5042 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -18,19 +18,18 @@ //! Preimage pallet benchmarking. use super::*; -use sp_core::Hasher; -use sp_runtime::traits::BlakeTwo256; +use sp_std::{prelude::*, vec}; +use sp_runtime::traits::Bounded; use frame_benchmarking::{benchmarks, whitelist_account, account}; -use frame_support::ensure; use frame_system::RawOrigin; -use sp_std::{prelude::*, vec}; -use crate::mock::*; +use frame_support::{assert_ok}; use crate::Pallet as Preimage; use frame_system::Pallet as System; const SEED: u32 = 0; +#[allow(dead_code)] fn assert_last_event(generic_event: ::Event) { System::::assert_last_event(generic_event.into()); } @@ -41,16 +40,80 @@ fn funded_account(name: &'static str, index: u32) -> T::AccountId { caller } +fn preimage_and_hash() -> (Vec, T::Hash) { + sized_preimage_and_hash::(T::MaxSize::get()) +} + +fn sized_preimage_and_hash(size: u32) -> (Vec, T::Hash) { + let mut preimage = vec![]; + preimage.resize(size as usize, 0); + let hash = ::Hashing::hash(&preimage[..]); + (preimage, hash) +} + benchmarks! { note_preimage { let s in 0 .. T::MaxSize::get(); let caller = funded_account::("caller", 0); whitelist_account!(caller); - let mut preimage = vec![]; - preimage.resize(s as usize, 0); + let (preimage, hash) = sized_preimage_and_hash::(s); }: _(RawOrigin::Signed(caller), preimage) verify { - assert!(Pallet::have_preimage(BlakeTwo256::hash(&preimage[..]))); + assert!(Preimage::::have_preimage(&hash)); + } + note_requested_preimage { + let s in 0 .. T::MaxSize::get(); + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + let (preimage, hash) = sized_preimage_and_hash::(s); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + }: note_preimage(RawOrigin::Signed(caller), preimage) + verify { + assert!(Preimage::::have_preimage(&hash)); + } + unnote_preimage { + let caller = funded_account::("caller", 0); + whitelist_account!(caller); + let (preimage, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(caller.clone()).into(), preimage)); + }: _(RawOrigin::Signed(caller), hash.clone()) + verify { + assert!(!Preimage::::have_preimage(&hash)); + } + request_preimage { + let (preimage, hash) = preimage_and_hash::(); + let noter = funded_account::("noter", 0); + whitelist_account!(noter); + // Must be a normal account to force the unreserve operation during request_preimage. + assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter).into(), preimage)); + }: _(T::ManagerOrigin::successful_origin(), hash) + verify { + assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + } + request_unnoted_preimage { + let (_, hash) = preimage_and_hash::(); + }: request_preimage(T::ManagerOrigin::successful_origin(), hash) + verify { + assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + } + unrequest_preimage { + let (preimage, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + let noter = funded_account::("noter", 0); + whitelist_account!(noter); + // Must be a normal account to force it to become unnoted during unrequest_preimage. + assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter).into(), preimage)); + }: _(T::ManagerOrigin::successful_origin(), hash.clone()) + verify { + assert_eq!(StatusFor::::get(&hash), None); } + unrequest_unnoted_preimage { + let (_, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash.clone()) + verify { + assert_eq!(StatusFor::::get(&hash), None); + } + impl_benchmark_test_suite!(Preimage, crate::mock::new_test_ext(), crate::mock::Test); } From 293c8d71be9d08bd89169cc0cbe9e1615eed8e98 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 17:00:07 +0100 Subject: [PATCH 28/58] All preimage benchmarks --- frame/preimage/src/benchmarking.rs | 58 +++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index f567c3caa5042..3fd2d59221b2b 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -52,6 +52,7 @@ fn sized_preimage_and_hash(size: u32) -> (Vec, T::Hash) { } benchmarks! { + // Expensive note - will reserve. note_preimage { let s in 0 .. T::MaxSize::get(); let caller = funded_account::("caller", 0); @@ -61,6 +62,7 @@ benchmarks! { verify { assert!(Preimage::::have_preimage(&hash)); } + // Cheap note - will not reserve since it was requested. note_requested_preimage { let s in 0 .. T::MaxSize::get(); let caller = funded_account::("caller", 0); @@ -71,6 +73,17 @@ benchmarks! { verify { assert!(Preimage::::have_preimage(&hash)); } + // Cheap note - will not reserve since it's the manager. + note_no_deposit_preimage { + let s in 0 .. T::MaxSize::get(); + let (preimage, hash) = sized_preimage_and_hash::(s); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + }: note_preimage(T::ManagerOrigin::successful_origin(), preimage) + verify { + assert!(Preimage::::have_preimage(&hash)); + } + + // Expensive unnote - will unreserve. unnote_preimage { let caller = funded_account::("caller", 0); whitelist_account!(caller); @@ -80,33 +93,59 @@ benchmarks! { verify { assert!(!Preimage::::have_preimage(&hash)); } + // Cheap unnote - will not unreserve since there's no deposit held. + unnote_no_deposit_preimage { + let (preimage, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); + }: unnote_preimage(T::ManagerOrigin::successful_origin(), hash.clone()) + verify { + assert!(!Preimage::::have_preimage(&hash)); + } + + // Expensive request - will unreserve the noter's deposit. request_preimage { let (preimage, hash) = preimage_and_hash::(); let noter = funded_account::("noter", 0); whitelist_account!(noter); - // Must be a normal account to force the unreserve operation during request_preimage. assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter).into(), preimage)); }: _(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); } + // Cheap request - would unreserve the deposit but none was held. + request_no_deposit_preimage { + let (preimage, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); + }: request_preimage(T::ManagerOrigin::successful_origin(), hash) + verify { + assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + } + // Cheap request - the preimage is not yet noted, so deposit to unreserve. request_unnoted_preimage { let (_, hash) = preimage_and_hash::(); }: request_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); } + // Cheap request - the preimage is already requested, so just a counter bump. + request_requested_preimage { + let (_, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + }: request_preimage(T::ManagerOrigin::successful_origin(), hash) + verify { + assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(2))); + } + + // Expensive unrequest - last reference and it's noted, so will destroy the preimage. unrequest_preimage { let (preimage, hash) = preimage_and_hash::(); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); - let noter = funded_account::("noter", 0); - whitelist_account!(noter); - // Must be a normal account to force it to become unnoted during unrequest_preimage. - assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter).into(), preimage)); + assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); }: _(T::ManagerOrigin::successful_origin(), hash.clone()) verify { assert_eq!(StatusFor::::get(&hash), None); } + // Cheap unrequest - last reference, but it's not noted. unrequest_unnoted_preimage { let (_, hash) = preimage_and_hash::(); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); @@ -114,6 +153,15 @@ benchmarks! { verify { assert_eq!(StatusFor::::get(&hash), None); } + // Cheap unrequest - not the last reference. + unrequest_multi_referenced_preimage { + let (_, hash) = preimage_and_hash::(); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash.clone())); + }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash.clone()) + verify { + assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + } impl_benchmark_test_suite!(Preimage, crate::mock::new_test_ext(), crate::mock::Test); } From 9677d03640e8d0803aa435adb074abfef772a3ce Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 18:56:48 +0100 Subject: [PATCH 29/58] Tidy cargo --- Cargo.lock | 1 + bin/node/runtime/Cargo.toml | 4 + bin/node/runtime/src/lib.rs | 23 +++- frame/preimage/Cargo.toml | 19 ++- frame/preimage/src/benchmarking.rs | 6 - frame/preimage/src/weights.rs | 200 ++++++++++++++++++++++++----- frame/scheduler/Cargo.toml | 37 +++--- 7 files changed, 218 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e0c010165367e..9aa8b69c8aced 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4739,6 +4739,7 @@ dependencies = [ "pallet-multisig", "pallet-offences", "pallet-offences-benchmarking", + "pallet-preimage", "pallet-proxy", "pallet-randomness-collective-flip", "pallet-recovery", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index f9ce4b0fca900..6252e0b952900 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -77,6 +77,7 @@ pallet-mmr = { version = "4.0.0-dev", default-features = false, path = "../../.. pallet-multisig = { version = "4.0.0-dev", default-features = false, path = "../../../frame/multisig" } pallet-offences = { version = "4.0.0-dev", default-features = false, path = "../../../frame/offences" } pallet-offences-benchmarking = { version = "4.0.0-dev", path = "../../../frame/offences/benchmarking", default-features = false, optional = true } +pallet-preimage = { version = "4.0.0-dev", default-features = false, path = "../../../frame/preimage" } pallet-proxy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/proxy" } pallet-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/randomness-collective-flip" } pallet-recovery = { version = "4.0.0-dev", default-features = false, path = "../../../frame/recovery" } @@ -140,6 +141,7 @@ std = [ "node-primitives/std", "sp-offchain/std", "pallet-offences/std", + "pallet-preimage/std", "pallet-proxy/std", "sp-core/std", "pallet-randomness-collective-flip/std", @@ -199,6 +201,7 @@ runtime-benchmarks = [ "pallet-membership/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-society/runtime-benchmarks", @@ -239,6 +242,7 @@ try-runtime = [ "pallet-identity/try-runtime", "pallet-scheduler/try-runtime", "pallet-offences/try-runtime", + "pallet-preimage/try-runtime", "pallet-proxy/try-runtime", "pallet-randomness-collective-flip/try-runtime", "pallet-session/try-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 299b7257f9d45..ef8e3c2c7193a 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -347,6 +347,24 @@ impl pallet_scheduler::Config for Runtime { type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = pallet_scheduler::weights::SubstrateWeight; type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = Preimage; +} + +parameter_types! { + pub const PreimageMaxSize: u32 = 4096 * 1024; + pub const PreimageBaseDeposit: Balance = 1 * DOLLARS; + // One cent: $10,000 / MB + pub const PreimageByteDeposit: Balance = 1 * CENTS; +} + +impl pallet_preimage::Config for Runtime { + type WeightInfo = pallet_preimage::weights::SubstrateWeight; + type Event = Event; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type MaxSize = PreimageMaxSize; + type BaseDeposit = PreimageBaseDeposit; + type ByteDeposit = PreimageByteDeposit; } parameter_types! { @@ -680,8 +698,6 @@ parameter_types! { pub const MinimumDeposit: Balance = 100 * DOLLARS; pub const EnactmentPeriod: BlockNumber = 30 * 24 * 60 * MINUTES; pub const CooloffPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; - // One cent: $10,000 / MB - pub const PreimageByteDeposit: Balance = 1 * CENTS; pub const MaxVotes: u32 = 100; pub const MaxProposals: u32 = 100; } @@ -1288,6 +1304,7 @@ construct_runtime!( Recovery: pallet_recovery, Vesting: pallet_vesting, Scheduler: pallet_scheduler, + Preimage: pallet_preimage, Proxy: pallet_proxy, Multisig: pallet_multisig, Bounties: pallet_bounties, @@ -1653,6 +1670,7 @@ impl_runtime_apis! { list_benchmark!(list, extra, pallet_mmr, Mmr); list_benchmark!(list, extra, pallet_multisig, Multisig); list_benchmark!(list, extra, pallet_offences, OffencesBench::); + list_benchmark!(list, extra, pallet_preimage, Preimage); list_benchmark!(list, extra, pallet_proxy, Proxy); list_benchmark!(list, extra, pallet_scheduler, Scheduler); list_benchmark!(list, extra, pallet_session, SessionBench::); @@ -1730,6 +1748,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_mmr, Mmr); add_benchmark!(params, batches, pallet_multisig, Multisig); add_benchmark!(params, batches, pallet_offences, OffencesBench::); + add_benchmark!(params, batches, pallet_preimage, Preimage); add_benchmark!(params, batches, pallet_proxy, Proxy); add_benchmark!(params, batches, pallet_scheduler, Scheduler); add_benchmark!(params, batches, pallet_session, SessionBench::); diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 98627d4108085..b9571bbff77f6 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -2,36 +2,33 @@ name = "pallet-preimage" version = "4.0.0-dev" authors = ["Parity Technologies "] -edition = "2018" +edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" description = "FRAME pallet for storing preimages of hashes" readme = "README.md" -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } + sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } +sp-core = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } - -sp-core = { version = "4.0.0-dev", optional = true, path = "../../primitives/core" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core" } +sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } + pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] runtime-benchmarks = [ - "sp-core", "frame-benchmarking", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", @@ -41,8 +38,10 @@ std = [ "scale-info/std", "sp-std/std", "sp-io/std", + "sp-core/std", "sp-runtime/std", - "frame-support/std", "frame-system/std", + "frame-support/std", + "frame-benchmarking/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index 3fd2d59221b2b..d273311dfc49b 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -25,15 +25,9 @@ use frame_system::RawOrigin; use frame_support::{assert_ok}; use crate::Pallet as Preimage; -use frame_system::Pallet as System; const SEED: u32 = 0; -#[allow(dead_code)] -fn assert_last_event(generic_event: ::Event) { - System::::assert_last_event(generic_event.into()); -} - fn funded_account(name: &'static str, index: u32) -> T::AccountId { let caller: T::AccountId = account(name, index, SEED); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index 734b496aa7ddf..43f1133b3412f 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -15,26 +15,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_scheduler +//! Autogenerated weights for pallet_preimage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2021-11-24, STEPS: `5`, REPEAT: 2, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Interpreted, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// target/release/substrate +// ../../../target/release/substrate // benchmark -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_preimage -// --extrinsic=* +// --chain +// dev +// --steps +// 5 +// --repeat +// 2 +// --pallet +// pallet_preimage +// --extrinsic +// * +// --raw // --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/scheduler/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --wasm-execution=interpreted-i-know-what-i-do +// --output +// ../../../frame/preimage/src/weights.rs +// --template +// ../../../.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -46,58 +52,182 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_preimage. pub trait WeightInfo { fn note_preimage(s: u32, ) -> Weight; + fn note_requested_preimage(s: u32, ) -> Weight; + fn note_no_deposit_preimage(s: u32, ) -> Weight; fn unnote_preimage() -> Weight; + fn unnote_no_deposit_preimage() -> Weight; fn request_preimage() -> Weight; + fn request_no_deposit_preimage() -> Weight; + fn request_unnoted_preimage() -> Weight; + fn request_requested_preimage() -> Weight; fn unrequest_preimage() -> Weight; + fn unrequest_unnoted_preimage() -> Weight; + fn unrequest_multi_referenced_preimage() -> Weight; } -/// Weights for pallet_scheduler using the Substrate node and recommended hardware. +/// Weights for pallet_preimage using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - fn note_preimage(s: u32, ) -> Weight { - (24_730_000 as Weight) - .saturating_add((77_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn note_preimage(_s: u32, ) -> Weight { + (219_001_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:0) + fn note_requested_preimage(_s: u32, ) -> Weight { + (221_213_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:0) + fn note_no_deposit_preimage(_s: u32, ) -> Weight { + (199_944_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (23_272_000 as Weight) + (218_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } - fn request_preimage() -> Weight { - (30_971_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn unnote_no_deposit_preimage() -> Weight { + (102_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_preimage() -> Weight { + (198_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_no_deposit_preimage() -> Weight { + (89_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_unnoted_preimage() -> Weight { + (83_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_requested_preimage() -> Weight { + (38_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (25_778_000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) + (102_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn unrequest_unnoted_preimage() -> Weight { + (79_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } + // Storage: Preimage StatusFor (r:1 w:1) + fn unrequest_multi_referenced_preimage() -> Weight { + (35_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } } // For backwards compatibility and tests impl WeightInfo for () { - fn note_preimage(s: u32, ) -> Weight { - (24_730_000 as Weight) - .saturating_add((77_000 as Weight).saturating_mul(s as Weight)) - .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn note_preimage(_s: u32, ) -> Weight { + (219_001_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:0) + fn note_requested_preimage(_s: u32, ) -> Weight { + (221_213_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:0) + fn note_no_deposit_preimage(_s: u32, ) -> Weight { + (199_944_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (23_272_000 as Weight) + (218_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } - fn request_preimage() -> Weight { - (30_971_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn unnote_no_deposit_preimage() -> Weight { + (102_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_preimage() -> Weight { + (198_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_no_deposit_preimage() -> Weight { + (89_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_unnoted_preimage() -> Weight { + (83_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + fn request_requested_preimage() -> Weight { + (38_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (25_778_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + (102_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + fn unrequest_unnoted_preimage() -> Weight { + (79_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } + // Storage: Preimage StatusFor (r:1 w:1) + fn unrequest_multi_referenced_preimage() -> Weight { + (35_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } } diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index 7efd73831e899..c78b515c6a88a 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -3,46 +3,45 @@ name = "pallet-scheduler" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" -license = "Unlicense" +license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" -description = "FRAME example pallet" +description = "FRAME Scheduler pallet" readme = "README.md" [dependencies] -codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +log = { version = "0.4.14", default-features = false } sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -log = { version = "0.4.14", default-features = false } +sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } -pallet-preimage = { version = "4.0.0-dev", default-features = false, path = "../preimage" } +pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } [features] default = ["std"] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] std = [ "codec/std", "scale-info/std", + "log/std", + "sp-std/std", + "sp-io/std", "sp-runtime/std", - "frame-benchmarking/std", - "frame-support/std", "frame-system/std", - "pallet-preimage/std", - "sp-io/std", - "sp-std/std", - "log/std", -] -runtime-benchmarks = [ - "frame-benchmarking", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", + "frame-support/std", + "frame-benchmarking/std", ] try-runtime = ["frame-support/try-runtime"] From f369b04f83f48912b71fa8d4f91ddc5e2b4fedf7 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Wed, 24 Nov 2021 10:05:06 -0800 Subject: [PATCH 30/58] Update weights.rs --- frame/preimage/src/weights.rs | 76 ++++++++++++++++------------------- 1 file changed, 34 insertions(+), 42 deletions(-) diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index 43f1133b3412f..6756409bd6569 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -19,28 +19,20 @@ //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev //! DATE: 2021-11-24, STEPS: `5`, REPEAT: 2, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Interpreted, CHAIN: Some("dev"), DB CACHE: 128 +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// ../../../target/release/substrate +// target/release/substrate // benchmark -// --chain -// dev -// --steps -// 5 -// --repeat -// 2 -// --pallet -// pallet_preimage -// --extrinsic -// * -// --raw +// --chain=dev +// --steps=5 +// --repeat=2 +// --pallet=pallet_preimage +// --extrinsic=* // --execution=wasm -// --wasm-execution=interpreted-i-know-what-i-do -// --output -// ../../../frame/preimage/src/weights.rs -// --template -// ../../../.maintain/frame-weight-template.hbs +// --wasm-execution=compiled +// --output=./frame/preimage/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -71,79 +63,79 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn note_preimage(_s: u32, ) -> Weight { - (219_001_000_000 as Weight) + (4_203_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_requested_preimage(_s: u32, ) -> Weight { - (221_213_000_000 as Weight) + (4_055_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_no_deposit_preimage(_s: u32, ) -> Weight { - (199_944_000_000 as Weight) + (4_421_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (218_000_000 as Weight) + (50_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (102_000_000 as Weight) + (39_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (198_000_000 as Weight) + (41_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (89_000_000 as Weight) + (34_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (83_000_000 as Weight) + (17_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (38_000_000 as Weight) + (6_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (102_000_000 as Weight) + (29_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (79_000_000 as Weight) + (16_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (35_000_000 as Weight) + (4_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -154,79 +146,79 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn note_preimage(_s: u32, ) -> Weight { - (219_001_000_000 as Weight) + (4_203_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_requested_preimage(_s: u32, ) -> Weight { - (221_213_000_000 as Weight) + (4_055_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_no_deposit_preimage(_s: u32, ) -> Weight { - (199_944_000_000 as Weight) + (4_421_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (218_000_000 as Weight) + (50_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (102_000_000 as Weight) + (39_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (198_000_000 as Weight) + (41_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (89_000_000 as Weight) + (34_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (83_000_000 as Weight) + (17_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (38_000_000 as Weight) + (6_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (102_000_000 as Weight) + (29_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (79_000_000 as Weight) + (16_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (35_000_000 as Weight) + (4_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } From b5f534f56c0c5f5225962157adc390787ae23baa Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 19:11:43 +0100 Subject: [PATCH 31/58] Allow hash provision in benchmarks --- frame/scheduler/src/benchmarking.rs | 21 +++++++++++++++++++++ frame/scheduler/src/lib.rs | 22 +++++++++++++++++++--- frame/support/src/traits/misc.rs | 2 +- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index d903c7b48008b..077e587b56804 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -49,6 +49,27 @@ fn fill_schedule(when: T::BlockNumber, n: u32) -> Result<(), &'static Ok(()) } +// Add `n` named items to the schedule +fn fill_schedule_with_call_hashes(when: T::BlockNumber, n: u32) -> Result<(), &'static str> { + // Essentially a no-op call. + let call = CallOrHashOf::::Value(frame_system::Call::set_storage { items: vec![] }.into()); + for i in 0..n { + // Named schedule is strictly heavier than anonymous + Scheduler::::do_schedule_named( + i.encode(), + DispatchTime::At(when), + // Add periodicity + Some((T::BlockNumber::one(), 100)), + // HARD_DEADLINE priority means it gets executed no matter what + 0, + frame_system::RawOrigin::Root.into(), + call.clone().into(), + )?; + } + ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); + Ok(()) +} + benchmarks! { schedule { let s in 0 .. T::MaxScheduledPerBlock::get(); diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index e5bfb06039ed9..f64ef8d83092f 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -62,8 +62,8 @@ use codec::{Codec, Decode, Encode}; use frame_support::{ dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter}, traits::{ - schedule::{self, DispatchTime, MaybeHashed}, - EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp, + EnsureOrigin, Get, IsType, OriginTrait, + PrivilegeCmp, schedule::{self, DispatchTime, MaybeHashed}, }, weights::{GetDispatchInfo, Weight}, }; @@ -151,6 +151,22 @@ impl Default for Releases { } } +#[cfg(feature = "runtime-benchmarks")] +mod preimage_provider { + use frame_support::traits::PreimageRecipient; + pub trait PreimageProviderAndMaybeRecipient: PreimageRecipient {} + impl> PreimageProviderAndMaybeRecipient for T {} +} + +#[cfg(not(feature = "runtime-benchmarks"))] +mod preimage_provider { + use frame_support::traits::PreimageProvider; + pub trait PreimageProviderAndMaybeRecipient: PreimageProvider {} + impl> PreimageProviderAndMaybeRecipient for T {} +} + +pub use preimage_provider::PreimageProviderAndMaybeRecipient; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -207,7 +223,7 @@ pub mod pallet { type WeightInfo: WeightInfo; /// The preimage provider with which we look up call hashes to get the call. - type Preimages: PreimageProvider; + type Preimages: PreimageProviderAndMaybeRecipient; } /// Items to be executed, indexed by the block number that they should be executed on. diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 1b8092ca1400c..128d6e3f98d84 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -594,7 +594,7 @@ pub trait PreimageProvider { /// Note that this API does not assume any underlying user is calling, and thus /// does not handle any preimage ownership or fees. Other system level logic that /// uses this API should implement that on their own side. -pub trait PreimageRecipient { +pub trait PreimageRecipient: PreimageProvider { /// Maximum size of a preimage. type MaxSize: Get; From 54979221692a40c2a3f0adc5c4cbc2359abbdab4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Nov 2021 19:29:41 +0100 Subject: [PATCH 32/58] Initial work on new benchmarks for Scheduler --- frame/scheduler/src/benchmarking.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 077e587b56804..a3fb84931fb61 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -19,9 +19,10 @@ use super::*; use frame_benchmarking::benchmarks; -use frame_support::{ensure, traits::OnInitialize}; +use frame_support::{ensure, traits::{OnInitialize, PreimageRecipient}}; use frame_system::RawOrigin; use sp_std::{prelude::*, vec}; +use sp_runtime::traits::Hash; use crate::Pallet as Scheduler; use frame_system::Pallet as System; @@ -49,11 +50,18 @@ fn fill_schedule(when: T::BlockNumber, n: u32) -> Result<(), &'static Ok(()) } +fn call_and_hash(i: u32) -> (::Call, CallOrHashOf::) { + // Essentially a no-op call. + let call: ::Call = frame_system::Call::set_storage { items: vec![(i.encode(), vec![])] }.into(); + let hash = CallOrHashOf::::Hash(T::Hashing::hash_of(&call)); + (call, hash) +} + // Add `n` named items to the schedule fn fill_schedule_with_call_hashes(when: T::BlockNumber, n: u32) -> Result<(), &'static str> { - // Essentially a no-op call. - let call = CallOrHashOf::::Value(frame_system::Call::set_storage { items: vec![] }.into()); for i in 0..n { + let (call, hash) = call_and_hash::(i); + T::Preimages::note_preimage(call.encode().try_into().unwrap()); // Named schedule is strictly heavier than anonymous Scheduler::::do_schedule_named( i.encode(), @@ -63,7 +71,7 @@ fn fill_schedule_with_call_hashes(when: T::BlockNumber, n: u32) -> Re // HARD_DEADLINE priority means it gets executed no matter what 0, frame_system::RawOrigin::Root.into(), - call.clone().into(), + hash, )?; } ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); From 547b4483d1b6672bcb8a4fdb205956b207bc29e7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Nov 2021 16:38:12 +0100 Subject: [PATCH 33/58] Tests working, refactor looks good --- frame/preimage/src/weights.rs | 94 +++++---- frame/scheduler/src/benchmarking.rs | 204 +++++++++++++----- frame/scheduler/src/lib.rs | 199 +++++++++--------- frame/scheduler/src/mock.rs | 2 + frame/scheduler/src/tests.rs | 54 +++-- frame/scheduler/src/weights.rs | 308 ++++++++++++++++++++++++---- frame/system/src/lib.rs | 16 +- 7 files changed, 624 insertions(+), 253 deletions(-) diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index 6756409bd6569..f5fc74d1b1b50 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -18,21 +18,29 @@ //! Autogenerated weights for pallet_preimage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-11-24, STEPS: `5`, REPEAT: 2, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-11-25, STEPS: `10`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// target/release/substrate +// ../../../target/release/substrate // benchmark -// --chain=dev -// --steps=5 -// --repeat=2 -// --pallet=pallet_preimage -// --extrinsic=* +// --chain +// dev +// --steps +// 10 +// --repeat +// 10 +// --pallet +// pallet_preimage +// --extrinsic +// * +// --raw // --execution=wasm // --wasm-execution=compiled -// --output=./frame/preimage/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --output +// ../../../frame/preimage/src/weights.rs +// --template +// ../../../.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,74 +70,80 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) - fn note_preimage(_s: u32, ) -> Weight { - (4_203_000_000 as Weight) + fn note_preimage(s: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) - fn note_requested_preimage(_s: u32, ) -> Weight { - (4_055_000_000 as Weight) + fn note_requested_preimage(s: u32, ) -> Weight { + (10_356_000 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) - fn note_no_deposit_preimage(_s: u32, ) -> Weight { - (4_421_000_000 as Weight) + fn note_no_deposit_preimage(s: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (50_000_000 as Weight) + (33_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (39_000_000 as Weight) + (19_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (41_000_000 as Weight) + (29_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (34_000_000 as Weight) + (18_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (17_000_000 as Weight) + (13_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (6_000_000 as Weight) + (4_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (29_000_000 as Weight) + (20_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (16_000_000 as Weight) + (14_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -145,74 +159,80 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) - fn note_preimage(_s: u32, ) -> Weight { - (4_203_000_000 as Weight) + fn note_preimage(s: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) - fn note_requested_preimage(_s: u32, ) -> Weight { - (4_055_000_000 as Weight) + fn note_requested_preimage(s: u32, ) -> Weight { + (10_356_000 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) - fn note_no_deposit_preimage(_s: u32, ) -> Weight { - (4_421_000_000 as Weight) + fn note_no_deposit_preimage(s: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 0 + .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (50_000_000 as Weight) + (33_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (39_000_000 as Weight) + (19_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (41_000_000 as Weight) + (29_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (34_000_000 as Weight) + (18_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (17_000_000 as Weight) + (13_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (6_000_000 as Weight) + (4_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (29_000_000 as Weight) + (20_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (16_000_000 as Weight) + (14_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index a3fb84931fb61..db99e5e542a69 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -30,21 +30,38 @@ use frame_system::Pallet as System; const BLOCK_NUMBER: u32 = 2; // Add `n` named items to the schedule -fn fill_schedule(when: T::BlockNumber, n: u32) -> Result<(), &'static str> { - // Essentially a no-op call. - let call = CallOrHashOf::::Value(frame_system::Call::set_storage { items: vec![] }.into()); +fn fill_schedule( + when: T::BlockNumber, + n: u32, + periodic: bool, + named: bool, + resolved: Option, + //^^ None -> aborted (hash without preimage) + // Some(true) -> hash resolves into call + // Some(false) -> plain call +) -> Result<(), &'static str> { for i in 0..n { // Named schedule is strictly heavier than anonymous - Scheduler::::do_schedule_named( - i.encode(), - DispatchTime::At(when), - // Add periodicity - Some((T::BlockNumber::one(), 100)), - // HARD_DEADLINE priority means it gets executed no matter what - 0, - frame_system::RawOrigin::Root.into(), - call.clone().into(), - )?; + let (inner_call, hash) = call_and_hash::(i); + let call = match resolved { + Some(true) => { + T::Preimages::note_preimage(inner_call.encode().try_into().unwrap()); + hash + } + Some(false) => inner_call.into(), + None => hash, + }; + let period = match periodic { + true => Some(((i + 100).into(), 100)), + false => None, + }; + let t = DispatchTime::At(when); + let origin = frame_system::RawOrigin::Root.into(); + if named { + Scheduler::::do_schedule_named(i.encode(), t, period, 0, origin, call)?; + } else { + Scheduler::::do_schedule(t, period, 0, origin, call)?; + } } ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); Ok(()) @@ -52,33 +69,128 @@ fn fill_schedule(when: T::BlockNumber, n: u32) -> Result<(), &'static fn call_and_hash(i: u32) -> (::Call, CallOrHashOf::) { // Essentially a no-op call. - let call: ::Call = frame_system::Call::set_storage { items: vec![(i.encode(), vec![])] }.into(); + let call: ::Call = frame_system::Call::remark { remark: i.encode() }.into(); let hash = CallOrHashOf::::Hash(T::Hashing::hash_of(&call)); (call, hash) } -// Add `n` named items to the schedule -fn fill_schedule_with_call_hashes(when: T::BlockNumber, n: u32) -> Result<(), &'static str> { - for i in 0..n { - let (call, hash) = call_and_hash::(i); - T::Preimages::note_preimage(call.encode().try_into().unwrap()); - // Named schedule is strictly heavier than anonymous - Scheduler::::do_schedule_named( - i.encode(), - DispatchTime::At(when), - // Add periodicity - Some((T::BlockNumber::one(), 100)), - // HARD_DEADLINE priority means it gets executed no matter what - 0, - frame_system::RawOrigin::Root.into(), - hash, - )?; +benchmarks! { + on_initialize_periodic_named_resolved { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, true, true, Some(true))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s * 2); + for i in 0..s { + assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); + } + } + + on_initialize_named_resolved { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, false, true, Some(true))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s * 2); + assert!(Agenda::::iter().count() == 0); + } + + on_initialize_periodic_resolved { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, true, false, Some(true))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s * 2); + for i in 0..s { + assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); + } + } + + on_initialize_resolved { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, false, false, Some(true))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s * 2); + assert!(Agenda::::iter().count() == 0); + } + + on_initialize_named_aborted { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, false, true, None)?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), 0); + if let Some(delay) = T::NoPreimagePostponement::get() { + assert_eq!(Agenda::::get(when + delay).len(), s as usize); + } else { + assert!(Agenda::::iter().count() == 0); + } + } + + on_initialize_aborted { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, false, false, None)?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), 0); + if let Some(delay) = T::NoPreimagePostponement::get() { + assert_eq!(Agenda::::get(when + delay).len(), s as usize); + } else { + assert!(Agenda::::iter().count() == 0); + } + } + + on_initialize_periodic_named { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, true, true, Some(false))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s); + for i in 0..s { + assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); + } + } + + on_initialize_periodic { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, true, false, Some(false))?; + }: { Scheduler::::on_initialize(when); } + verify { + assert_eq!(System::::event_count(), s); + for i in 0..s { + assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); + } + } + + on_initialize_named { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, false, true, Some(false))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s); + assert!(Agenda::::iter().count() == 0); + } + + on_initialize { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + fill_schedule::(when, s, false, false, Some(false))?; + }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } + verify { + assert_eq!(System::::event_count(), s); + assert!(Agenda::::iter().count() == 0); } - ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); - Ok(()) -} -benchmarks! { schedule { let s in 0 .. T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); @@ -88,7 +200,7 @@ benchmarks! { let inner_call = frame_system::Call::set_storage { items: vec![] }.into(); let call = Box::new(CallOrHashOf::::Value(inner_call)); - fill_schedule::(when, s)?; + fill_schedule::(when, s, true, true, Some(false))?; }: _(RawOrigin::Root, when, periodic, priority, call) verify { ensure!( @@ -101,7 +213,7 @@ benchmarks! { let s in 1 .. T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s)?; + fill_schedule::(when, s, true, true, Some(false))?; assert_eq!(Agenda::::get(when).len(), s as usize); }: _(RawOrigin::Root, when, 0) verify { @@ -126,7 +238,7 @@ benchmarks! { let inner_call = frame_system::Call::set_storage { items: vec![] }.into(); let call = Box::new(CallOrHashOf::::Value(inner_call)); - fill_schedule::(when, s)?; + fill_schedule::(when, s, true, true, Some(false))?; }: _(RawOrigin::Root, id, when, periodic, priority, call) verify { ensure!( @@ -139,7 +251,7 @@ benchmarks! { let s in 1 .. T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s)?; + fill_schedule::(when, s, true, true, Some(false))?; }: _(RawOrigin::Root, 0.encode()) verify { ensure!( @@ -153,21 +265,5 @@ benchmarks! { ); } - // TODO [#7141]: Make this more complex and flexible so it can be used in automation. - #[extra] - on_initialize { - let s in 0 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s)?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s); - // Next block should have all the schedules again - ensure!( - Agenda::::get(when + T::BlockNumber::one()).len() == s as usize, - "didn't append schedule" - ); - } - impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index f64ef8d83092f..76a7f3f68e8c2 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -167,6 +167,24 @@ mod preimage_provider { pub use preimage_provider::PreimageProviderAndMaybeRecipient; +pub(crate) trait MarginalWeightInfo: WeightInfo { + fn item(periodic: bool, named: bool, resolved: Option) -> Weight { + match (periodic, named, resolved) { + (_, false, None) => Self::on_initialize_aborted(2) - Self::on_initialize_aborted(1), + (_, true, None) => Self::on_initialize_named_aborted(2) - Self::on_initialize_named_aborted(1), + (false, false, Some(false)) => Self::on_initialize(2) - Self::on_initialize(1), + (false, true, Some(false)) => Self::on_initialize_named(2) - Self::on_initialize_named(1), + (true, false, Some(false)) => Self::on_initialize_periodic(2) - Self::on_initialize_periodic(1), + (true, true, Some(false)) => Self::on_initialize_periodic_named(2) - Self::on_initialize_periodic_named(1), + (false, false, Some(true)) => Self::on_initialize_resolved(2) - Self::on_initialize_resolved(1), + (false, true, Some(true)) => Self::on_initialize_named_resolved(2) - Self::on_initialize_named_resolved(1), + (true, false, Some(true)) => Self::on_initialize_periodic_resolved(2) - Self::on_initialize_periodic_resolved(1), + (true, true, Some(true)) => Self::on_initialize_periodic_named_resolved(2) - Self::on_initialize_periodic_named_resolved(1), + } + } +} +impl MarginalWeightInfo for T {} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -224,6 +242,9 @@ pub mod pallet { /// The preimage provider with which we look up call hashes to get the call. type Preimages: PreimageProviderAndMaybeRecipient; + + /// If `Some` then the number of blocks to postpone execution for when the item is delayed. + type NoPreimagePostponement: Get>; } /// Items to be executed, indexed by the block number that they should be executed on. @@ -293,34 +314,15 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { /// Execute the scheduled calls - /// - /// # - /// - S = Number of already scheduled calls - /// - N = Named scheduled calls - /// - P = Periodic Calls - /// - Base Weight: 9.243 + 23.45 * S µs - /// - DB Weight: - /// - Read: Agenda + Lookup * N + Agenda(Future) * P - /// - Write: Agenda + Lookup * N + Agenda(future) * P - /// # fn on_initialize(now: T::BlockNumber) -> Weight { - let mut base_weight: Weight = T::DbWeight::get().reads_writes(1, 2); // Agenda + Agenda(next) let limit = T::MaximumWeight::get(); + let mut queued = Agenda::::take(now) .into_iter() .enumerate() - .filter_map(|(index, s)| { - let ScheduledV3 { maybe_id, priority, call, maybe_periodic, origin, _phantom } = s?; - let (call, maybe_completed) = call.resolved::(); - if let Some(completed) = maybe_completed { - // TODO Benchmark individually. - base_weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - T::Preimages::unrequest_preimage(&completed); - } - let s = ScheduledV3 { maybe_id, priority, call, maybe_periodic, origin, _phantom }; - Some((index as u32, s)) - }) + .filter_map(|(index, s)| Some((index as u32, s?))) .collect::>(); + if queued.len() as u32 > T::MaxScheduledPerBlock::get() { log::warn!( target: "runtime::scheduler", @@ -328,87 +330,92 @@ pub mod pallet { expected from the runtime configuration. An update might be needed." ); } + queued.sort_by_key(|(_, s)| s.priority); + let next = now + One::one(); - let mut total_weight: Weight = 0; - queued - .into_iter() - .enumerate() - .scan(base_weight, |cumulative_weight, (order, (index, s))| { - - if let Some(c) = s.call.as_value() { - *cumulative_weight = - cumulative_weight.saturating_add(c.get_dispatch_info().weight); - let origin = - <::Origin as From>::from(s.origin.clone()) - .into(); - - if ensure_signed(origin).is_ok() { - // AccountData for inner call origin accountdata. - *cumulative_weight = - cumulative_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + + let mut total_weight: Weight = T::WeightInfo::on_initialize(0); + for (order, (index, mut s)) in queued.into_iter().enumerate() { + + let named = if let Some(ref id) = s.maybe_id { + Lookup::::remove(id); + true + } else { + false + }; + + let (call, maybe_completed) = s.call.resolved::(); + s.call = call; + + let resolved = if let Some(completed) = maybe_completed { + T::Preimages::unrequest_preimage(&completed); + true + } else { + false + }; + + let call = match s.call.as_value().cloned() { + Some(c) => c, + None => { + // Preimage not available - postpone until next block. + total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); + if let Some(delay) = T::NoPreimagePostponement::get() { + Agenda::::append(now.saturating_add(delay), Some(s)); } - } + continue; + }, + }; + + let periodic = s.maybe_periodic.is_some(); + let mut this_weight = T::WeightInfo::item(periodic, named, Some(resolved)) + .saturating_add(call.get_dispatch_info().weight); + + let origin = + <::Origin as From>::from(s.origin.clone()) + .into(); + if ensure_signed(origin).is_ok() { + // Weights of Signed dispatches expect their signing account to be whitelisted. + this_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + } - if s.maybe_id.is_some() { - // Remove/Modify Lookup - *cumulative_weight = - cumulative_weight.saturating_add(T::DbWeight::get().writes(1)); - } - if s.maybe_periodic.is_some() { - // Read/Write Agenda for future block - *cumulative_weight = - cumulative_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); - } + // We allow a scheduled call if any is true: + // - It's priority is `HARD_DEADLINE` + // - It does not push the weight past the limit. + // - It is the first item in the schedule + let hard_deadline = s.priority <= schedule::HARD_DEADLINE; + let new_total_weight = total_weight.saturating_add(this_weight); + if !hard_deadline && order > 0 && new_total_weight > limit { + // Cannot be scheduled this block - postpone until next. + total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); + Agenda::::append(next, Some(s)); + continue; + } - Some((order, index, *cumulative_weight, s)) - }) - .filter_map(|(order, index, cumulative_weight, mut s)| { - let call = match s.call.as_value().cloned() { - Some(c) => c, - None => return Some(Some(s)), - }; - // We allow a scheduled call if any is true: - // - It's priority is `HARD_DEADLINE` - // - It does not push the weight past the limit. - // - It is the first item in the schedule - if s.priority <= schedule::HARD_DEADLINE || - cumulative_weight <= limit || - order == 0 - { - let r = call.dispatch(s.origin.clone().into()); - let maybe_id = s.maybe_id.clone(); - if let &Some((period, count)) = &s.maybe_periodic { - if count > 1 { - s.maybe_periodic = Some((period, count - 1)); - } else { - s.maybe_periodic = None; - } - let next = now + period; - // If scheduled is named, place it's information in `Lookup` - if let Some(ref id) = s.maybe_id { - let next_index = Agenda::::decode_len(now + period).unwrap_or(0); - Lookup::::insert(id, (next, next_index as u32)); - } - Agenda::::append(next, Some(s)); - } else { - if let Some(ref id) = s.maybe_id { - Lookup::::remove(id); - } - } - Self::deposit_event(Event::Dispatched( - (now, index), - maybe_id, - r.map(|_| ()).map_err(|e| e.error), - )); - total_weight = cumulative_weight; - None + total_weight = new_total_weight; + let r = call.dispatch(s.origin.clone().into()); + // OPTIMIZE: add actual weight used, not max. + Self::deposit_event(Event::Dispatched( + (now, index), + s.maybe_id.clone(), + r.map(|_| ()).map_err(|e| e.error), + )); + + if let &Some((period, count)) = &s.maybe_periodic { + if count > 1 { + s.maybe_periodic = Some((period, count - 1)); } else { - Some(Some(s)) + s.maybe_periodic = None; } - }) - .for_each(|unused| Agenda::::append(next, unused)); - + let next = now + period; + // If scheduled is named, place its information in `Lookup` + if let Some(ref id) = s.maybe_id { + let next_index = Agenda::::decode_len(now + period).unwrap_or(0); + Lookup::::insert(id, (next, next_index as u32)); + } + Agenda::::append(next, Some(s)); + } + } total_weight } } diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index eef1f1e97d434..d95e7afbbff2e 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -156,6 +156,7 @@ parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; pub const MaxScheduledPerBlock: u32 = 10; pub const MaxSize: u32 = 1024; + pub const NoPreimagePostponement: Option = Some(1); } ord_parameter_types! { pub const One: u64 = 1; @@ -182,6 +183,7 @@ impl Config for Test { type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; type Preimages = Preimage; + type NoPreimagePostponement = NoPreimagePostponement; } pub type LoggerCall = logger::Call; diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index 621089c430960..1e9e6ac00e22a 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -380,19 +380,27 @@ fn scheduler_respects_priority_ordering() { #[test] fn scheduler_respects_priority_ordering_with_soft_deadlines() { new_test_ext().execute_with(|| { + let max_weight = MaximumSchedulerWeight::get() - <() as WeightInfo>::on_initialize(0); + let item_weight = <() as WeightInfo>::on_initialize(1) - <() as WeightInfo>::on_initialize(0); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 255, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 3 }).into(), + Call::Logger(LoggerCall::log { + i: 42, + weight: max_weight / 2 - item_weight, + }).into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), + Call::Logger(LoggerCall::log { + i: 69, + weight: max_weight / 2 - item_weight, + }).into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), @@ -401,7 +409,7 @@ fn scheduler_respects_priority_ordering_with_soft_deadlines() { root(), Call::Logger(LoggerCall::log { i: 2600, - weight: MaximumSchedulerWeight::get() / 2 + weight: max_weight / 2 - item_weight + 1, }).into(), )); @@ -417,37 +425,33 @@ fn scheduler_respects_priority_ordering_with_soft_deadlines() { #[test] fn on_initialize_weight_is_correct() { new_test_ext().execute_with(|| { - let base_weight: Weight = - ::DbWeight::get().reads_writes(1, 2); - let base_multiplier = 0; - let named_multiplier = ::DbWeight::get().writes(1); - let periodic_multiplier = - ::DbWeight::get().reads_writes(1, 1); + let base_weight = <() as WeightInfo>::on_initialize(0); + let call_weight = MaximumSchedulerWeight::get() / 4; // Named assert_ok!(Scheduler::do_schedule_named( 1u32.encode(), - DispatchTime::At(1), + DispatchTime::At(3), None, 255, root(), - Call::Logger(LoggerCall::log { i: 3, weight: MaximumSchedulerWeight::get() / 3 }).into(), + Call::Logger(LoggerCall::log { i: 3, weight: call_weight + 1 }).into(), )); // Anon Periodic assert_ok!(Scheduler::do_schedule( - DispatchTime::At(1), + DispatchTime::At(2), Some((1000, 3)), 128, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 3 }).into(), + Call::Logger(LoggerCall::log { i: 42, weight: call_weight + 2 }).into(), )); // Anon assert_ok!(Scheduler::do_schedule( - DispatchTime::At(1), + DispatchTime::At(2), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), + Call::Logger(LoggerCall::log { i: 69, weight: call_weight + 3 }).into(), )); // Named Periodic assert_ok!(Scheduler::do_schedule_named( @@ -456,38 +460,32 @@ fn on_initialize_weight_is_correct() { Some((1000, 3)), 126, root(), - Call::Logger(LoggerCall::log { - i: 2600, - weight: MaximumSchedulerWeight::get() / 2 - }).into(), + Call::Logger(LoggerCall::log { i: 2600, weight: call_weight + 4 }).into(), )); // Will include the named periodic only let actual_weight = Scheduler::on_initialize(1); - let call_weight = MaximumSchedulerWeight::get() / 2; assert_eq!( actual_weight, - call_weight + - base_weight + base_multiplier + - named_multiplier + periodic_multiplier + base_weight + call_weight + 4 + <() as MarginalWeightInfo>::item(true, true, Some(false)) ); assert_eq!(logger::log(), vec![(root(), 2600u32)]); // Will include anon and anon periodic let actual_weight = Scheduler::on_initialize(2); - let call_weight = MaximumSchedulerWeight::get() / 2 + MaximumSchedulerWeight::get() / 3; assert_eq!( actual_weight, - call_weight + base_weight + base_multiplier * 2 + periodic_multiplier + base_weight + + call_weight + 2 + <() as MarginalWeightInfo>::item(false, false, Some(false)) + + call_weight + 3 + <() as MarginalWeightInfo>::item(true, false, Some(false)) ); assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); // Will include named only let actual_weight = Scheduler::on_initialize(3); - let call_weight = MaximumSchedulerWeight::get() / 3; assert_eq!( actual_weight, - call_weight + base_weight + base_multiplier + named_multiplier + base_weight + call_weight + 1 + <() as MarginalWeightInfo>::item(false, true, Some(false)) ); assert_eq!( logger::log(), @@ -496,7 +494,7 @@ fn on_initialize_weight_is_correct() { // Will contain none let actual_weight = Scheduler::on_initialize(4); - assert_eq!(actual_weight, 0); + assert_eq!(actual_weight, base_weight); }); } diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index d83aefdc453af..16799228f1ffa 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -18,23 +18,29 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-08-07, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-11-25, STEPS: `4000`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// target/release/substrate +// ../../../target/release/substrate // benchmark -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_scheduler -// --extrinsic=* +// --chain +// dev +// --steps +// 4000 +// --repeat +// 1 +// --pallet +// pallet_scheduler +// --extrinsic +// * +// --raw // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./frame/scheduler/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs - +// --output +// ../../../frame/scheduler/src/weights.rs +// --template +// ../../../.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -45,6 +51,16 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_scheduler. pub trait WeightInfo { + fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight; + fn on_initialize_named_resolved(s: u32, ) -> Weight; + fn on_initialize_periodic_resolved(s: u32, ) -> Weight; + fn on_initialize_resolved(s: u32, ) -> Weight; + fn on_initialize_named_aborted(s: u32, ) -> Weight; + fn on_initialize_aborted(s: u32, ) -> Weight; + fn on_initialize_periodic_named(s: u32, ) -> Weight; + fn on_initialize_periodic(s: u32, ) -> Weight; + fn on_initialize_named(s: u32, ) -> Weight; + fn on_initialize(s: u32, ) -> Weight; fn schedule(s: u32, ) -> Weight; fn cancel(s: u32, ) -> Weight; fn schedule_named(s: u32, ) -> Weight; @@ -54,38 +70,147 @@ pub trait WeightInfo { /// Weights for pallet_scheduler using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { + (6_817_000 as Weight) + // Standard Error: 61_000 + .saturating_add((21_795_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_named_resolved(s: u32, ) -> Weight { + (8_307_000 as Weight) + // Standard Error: 50_000 + .saturating_add((16_702_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn on_initialize_periodic_resolved(s: u32, ) -> Weight { + (7_566_000 as Weight) + // Standard Error: 68_000 + .saturating_add((18_448_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn on_initialize_resolved(s: u32, ) -> Weight { + (8_650_000 as Weight) + // Standard Error: 56_000 + .saturating_add((15_390_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:0) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_named_aborted(s: u32, ) -> Weight { + (7_223_000 as Weight) + // Standard Error: 17_000 + .saturating_add((4_822_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:0) + fn on_initialize_aborted(s: u32, ) -> Weight { + (8_149_000 as Weight) + // Standard Error: 23_000 + .saturating_add((3_632_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_periodic_named(s: u32, ) -> Weight { + (12_947_000 as Weight) + // Standard Error: 48_000 + .saturating_add((10_284_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + fn on_initialize_periodic(s: u32, ) -> Weight { + (18_699_000 as Weight) + // Standard Error: 73_000 + .saturating_add((7_047_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_named(s: u32, ) -> Weight { + (13_833_000 as Weight) + // Standard Error: 27_000 + .saturating_add((5_284_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + fn on_initialize(s: u32, ) -> Weight { + (13_421_000 as Weight) + // Standard Error: 29_000 + .saturating_add((4_080_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } // Storage: Scheduler Agenda (r:1 w:1) - fn schedule(s: u32, ) -> Weight { - (24_730_000 as Weight) - // Standard Error: 1_000 - .saturating_add((77_000 as Weight).saturating_mul(s as Weight)) + fn schedule(_s: u32, ) -> Weight { + (16_388_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (23_272_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_261_000 as Weight).saturating_mul(s as Weight)) + (16_171_000 as Weight) + // Standard Error: 17_000 + .saturating_add((385_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (30_971_000 as Weight) - // Standard Error: 1_000 - .saturating_add((96_000 as Weight).saturating_mul(s as Weight)) + (19_063_000 as Weight) + // Standard Error: 10_000 + .saturating_add((38_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (25_778_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_270_000 as Weight).saturating_mul(s as Weight)) + (17_177_000 as Weight) + // Standard Error: 16_000 + .saturating_add((453_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -93,38 +218,147 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { + (6_817_000 as Weight) + // Standard Error: 61_000 + .saturating_add((21_795_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_named_resolved(s: u32, ) -> Weight { + (8_307_000 as Weight) + // Standard Error: 50_000 + .saturating_add((16_702_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn on_initialize_periodic_resolved(s: u32, ) -> Weight { + (7_566_000 as Weight) + // Standard Error: 68_000 + .saturating_add((18_448_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Preimage PreimageFor (r:1 w:1) + // Storage: Preimage StatusFor (r:1 w:1) + fn on_initialize_resolved(s: u32, ) -> Weight { + (8_650_000 as Weight) + // Standard Error: 56_000 + .saturating_add((15_390_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:0) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_named_aborted(s: u32, ) -> Weight { + (7_223_000 as Weight) + // Standard Error: 17_000 + .saturating_add((4_822_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Preimage PreimageFor (r:1 w:0) + fn on_initialize_aborted(s: u32, ) -> Weight { + (8_149_000 as Weight) + // Standard Error: 23_000 + .saturating_add((3_632_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + // Storage: Scheduler Agenda (r:2 w:2) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_periodic_named(s: u32, ) -> Weight { + (12_947_000 as Weight) + // Standard Error: 48_000 + .saturating_add((10_284_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:2 w:2) + fn on_initialize_periodic(s: u32, ) -> Weight { + (18_699_000 as Weight) + // Standard Error: 73_000 + .saturating_add((7_047_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn on_initialize_named(s: u32, ) -> Weight { + (13_833_000 as Weight) + // Standard Error: 27_000 + .saturating_add((5_284_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) + } + // Storage: Scheduler Agenda (r:1 w:1) + fn on_initialize(s: u32, ) -> Weight { + (13_421_000 as Weight) + // Standard Error: 29_000 + .saturating_add((4_080_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } // Storage: Scheduler Agenda (r:1 w:1) - fn schedule(s: u32, ) -> Weight { - (24_730_000 as Weight) - // Standard Error: 1_000 - .saturating_add((77_000 as Weight).saturating_mul(s as Weight)) + fn schedule(_s: u32, ) -> Weight { + (16_388_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (23_272_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_261_000 as Weight).saturating_mul(s as Weight)) + (16_171_000 as Weight) + // Standard Error: 17_000 + .saturating_add((385_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn schedule_named(s: u32, ) -> Weight { - (30_971_000 as Weight) - // Standard Error: 1_000 - .saturating_add((96_000 as Weight).saturating_mul(s as Weight)) + (19_063_000 as Weight) + // Standard Error: 10_000 + .saturating_add((38_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (25_778_000 as Weight) - // Standard Error: 4_000 - .saturating_add((1_270_000 as Weight).saturating_mul(s as Weight)) + (17_177_000 as Weight) + // Standard Error: 16_000 + .saturating_add((453_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 12361ed859d0e..d36b836a3affe 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -346,7 +346,7 @@ pub mod pallet { /// # #[pallet::weight(T::SystemWeightInfo::remark(_remark.len() as u32))] pub fn remark(origin: OriginFor, _remark: Vec) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; + ensure_signed_or_root(origin)?; Ok(().into()) } @@ -966,6 +966,20 @@ where } } +/// Ensure that the origin `o` represents either a signed extrinsic (i.e. transaction) or the root. +/// Returns `Ok` with the account that signed the extrinsic, `None` if it was root, or an `Err` +/// otherwise. +pub fn ensure_signed_or_root(o: OuterOrigin) -> Result, BadOrigin> +where + OuterOrigin: Into, OuterOrigin>>, +{ + match o.into() { + Ok(RawOrigin::Root) => Ok(None), + Ok(RawOrigin::Signed(t)) => Ok(Some(t)), + _ => Err(BadOrigin), + } +} + /// Ensure that the origin `o` represents the root. Returns `Ok` or an `Err` otherwise. pub fn ensure_root(o: OuterOrigin) -> Result<(), BadOrigin> where From 39eca7dd35686dfc23da9b09409a85e65b66f497 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Nov 2021 19:03:57 +0100 Subject: [PATCH 34/58] Tests for new Scheduler functionality --- frame/scheduler/src/mock.rs | 2 +- frame/scheduler/src/tests.rs | 56 ++++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index d95e7afbbff2e..8686d62fd3947 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -156,7 +156,7 @@ parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; pub const MaxScheduledPerBlock: u32 = 10; pub const MaxSize: u32 = 1024; - pub const NoPreimagePostponement: Option = Some(1); + pub const NoPreimagePostponement: Option = Some(2); } ord_parameter_types! { pub const One: u64 = 1; diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index 1e9e6ac00e22a..d88e29ca6c3be 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -21,10 +21,10 @@ use super::*; use crate::mock::{ *, Call, root, run_to_block, new_test_ext, LoggerCall, Test, logger, Scheduler }; - +use sp_runtime::traits::Hash; use frame_support::{ assert_err, assert_noop, assert_ok, - traits::{Contains, OnInitialize}, + traits::{Contains, OnInitialize, PreimageProvider}, Hashable, }; use substrate_test_utils::assert_eq_uvec; @@ -44,6 +44,58 @@ fn basic_scheduling_works() { }); } +#[test] +fn scheduling_with_preimages_works() { + new_test_ext().execute_with(|| { + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + let hash = ::Hashing::hash_of(&call); + let hashed = MaybeHashed::Hash(hash.clone()); + assert_ok!(Preimage::note_preimage(Origin::signed(0), call.encode())); + assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); + assert!(Preimage::preimage_requested(&hash)); + run_to_block(3); + assert!(logger::log().is_empty()); + run_to_block(4); + assert!(!Preimage::have_preimage(&hash)); + assert!(!Preimage::preimage_requested(&hash)); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn scheduling_with_preimage_postpones_correctly() { + new_test_ext().execute_with(|| { + let call = Call::Logger(LoggerCall::log { i: 42, weight: 1000 }); + let hash = ::Hashing::hash_of(&call); + let hashed = MaybeHashed::Hash(hash.clone()); + + assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); + assert!(Preimage::preimage_requested(&hash)); + + run_to_block(4); + // #4 empty due to no preimage + assert!(logger::log().is_empty()); + + // Register preimage. + assert_ok!(Preimage::note_preimage(Origin::signed(0), call.encode())); + + run_to_block(5); + // #5 empty since postponement is 2 blocks. + assert!(logger::log().is_empty()); + + run_to_block(6); + // #6 is good. + assert_eq!(logger::log(), vec![(root(), 42u32)]); + assert!(!Preimage::have_preimage(&hash)); + assert!(!Preimage::preimage_requested(&hash)); + + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + #[test] fn schedule_after_works() { new_test_ext().execute_with(|| { From 8f4e343cd628819a267b356d82ff244679251ede Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Nov 2021 12:09:36 +0100 Subject: [PATCH 35/58] Use real weight, make tests work with runtimes without Preimage --- bin/node/runtime/src/lib.rs | 3 ++ frame/democracy/src/tests.rs | 2 + frame/scheduler/src/benchmarking.rs | 28 +++++++------ frame/scheduler/src/lib.rs | 61 +++++++++++++++++++---------- frame/support/src/traits/misc.rs | 14 +++++++ 5 files changed, 75 insertions(+), 33 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index ef8e3c2c7193a..3d21d3b2de32a 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -335,6 +335,8 @@ parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; pub const MaxScheduledPerBlock: u32 = 50; + // Retry a scheduled item every 10 blocks (1 minute) until the preimage exists. + pub const NoPreimagePostponement: Option = Some(10); } impl pallet_scheduler::Config for Runtime { @@ -348,6 +350,7 @@ impl pallet_scheduler::Config for Runtime { type WeightInfo = pallet_scheduler::weights::SubstrateWeight; type OriginPrivilegeCmp = EqualPrivilegeOnly; type Preimages = Preimage; + type NoPreimagePostponement = NoPreimagePostponement; } parameter_types! { diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 06c4ac666cfba..526512f3a606b 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -119,6 +119,8 @@ impl pallet_scheduler::Config for Test { type MaxScheduledPerBlock = (); type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = (); + type NoPreimagePostponement = (); } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index db99e5e542a69..044eb2d3f6c9b 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -19,7 +19,7 @@ use super::*; use frame_benchmarking::benchmarks; -use frame_support::{ensure, traits::{OnInitialize, PreimageRecipient}}; +use frame_support::{ensure, traits::{OnInitialize, PreimageProvider, PreimageRecipient}}; use frame_system::RawOrigin; use sp_std::{prelude::*, vec}; use sp_runtime::traits::Hash; @@ -37,19 +37,23 @@ fn fill_schedule( named: bool, resolved: Option, //^^ None -> aborted (hash without preimage) - // Some(true) -> hash resolves into call + // Some(true) -> hash resolves into call if possible, plain call otherwise // Some(false) -> plain call ) -> Result<(), &'static str> { for i in 0..n { // Named schedule is strictly heavier than anonymous - let (inner_call, hash) = call_and_hash::(i); - let call = match resolved { + let (call, hash) = call_and_hash::(i); + let call_or_hash = match resolved { Some(true) => { - T::Preimages::note_preimage(inner_call.encode().try_into().unwrap()); - hash + T::Preimages::note_preimage(call.encode().try_into().unwrap()); + if T::Preimages::have_preimage(&hash) { + CallOrHashOf::::Hash(hash) + } else { + call.into() + } } - Some(false) => inner_call.into(), - None => hash, + Some(false) => call.into(), + None => CallOrHashOf::::Hash(hash), }; let period = match periodic { true => Some(((i + 100).into(), 100)), @@ -58,19 +62,19 @@ fn fill_schedule( let t = DispatchTime::At(when); let origin = frame_system::RawOrigin::Root.into(); if named { - Scheduler::::do_schedule_named(i.encode(), t, period, 0, origin, call)?; + Scheduler::::do_schedule_named(i.encode(), t, period, 0, origin, call_or_hash)?; } else { - Scheduler::::do_schedule(t, period, 0, origin, call)?; + Scheduler::::do_schedule(t, period, 0, origin, call_or_hash)?; } } ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); Ok(()) } -fn call_and_hash(i: u32) -> (::Call, CallOrHashOf::) { +fn call_and_hash(i: u32) -> (::Call, T::Hash) { // Essentially a no-op call. let call: ::Call = frame_system::Call::remark { remark: i.encode() }.into(); - let hash = CallOrHashOf::::Hash(T::Hashing::hash_of(&call)); + let hash = T::Hashing::hash_of(&call); (call, hash) } diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 76a7f3f68e8c2..ddea1f5c57b46 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -188,7 +188,8 @@ impl MarginalWeightInfo for T {} #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{pallet_prelude::*, traits::{PreimageProvider, schedule::LookupError}}; + use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*}; + use frame_support::traits::{PreimageProvider, schedule::LookupError}; use frame_system::pallet_prelude::*; #[pallet::pallet] @@ -211,7 +212,7 @@ pub mod pallet { /// The aggregated call type. type Call: Parameter - + Dispatchable::Origin> + + Dispatchable::Origin, PostInfo = PostDispatchInfo> + GetDispatchInfo + From>; @@ -361,22 +362,26 @@ pub mod pallet { // Preimage not available - postpone until next block. total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); if let Some(delay) = T::NoPreimagePostponement::get() { - Agenda::::append(now.saturating_add(delay), Some(s)); + let until = now.saturating_add(delay); + if let Some(ref id) = s.maybe_id { + let index = Agenda::::decode_len(until).unwrap_or(0); + Lookup::::insert(id, (until, index as u32)); + } + Agenda::::append(until, Some(s)); } continue; }, }; let periodic = s.maybe_periodic.is_some(); - let mut this_weight = T::WeightInfo::item(periodic, named, Some(resolved)) - .saturating_add(call.get_dispatch_info().weight); - + let call_weight = call.get_dispatch_info().weight; + let mut item_weight = T::WeightInfo::item(periodic, named, Some(resolved)); let origin = <::Origin as From>::from(s.origin.clone()) .into(); if ensure_signed(origin).is_ok() { // Weights of Signed dispatches expect their signing account to be whitelisted. - this_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + item_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); } // We allow a scheduled call if any is true: @@ -384,22 +389,36 @@ pub mod pallet { // - It does not push the weight past the limit. // - It is the first item in the schedule let hard_deadline = s.priority <= schedule::HARD_DEADLINE; - let new_total_weight = total_weight.saturating_add(this_weight); - if !hard_deadline && order > 0 && new_total_weight > limit { + let test_weight = total_weight.saturating_add(call_weight).saturating_add(item_weight); + if !hard_deadline && order > 0 && test_weight > limit { // Cannot be scheduled this block - postpone until next. total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); + if let Some(ref id) = s.maybe_id { + // NOTE: We could reasonably not do this (in which case there would be one + // block where the named and delayed item could not be referenced by name), + // but we will do it anyway since it should be mostly free in terms of + // weight and it is slightly cleaner. + let index = Agenda::::decode_len(next).unwrap_or(0); + Lookup::::insert(id, (next, index as u32)); + } Agenda::::append(next, Some(s)); continue; } - total_weight = new_total_weight; - let r = call.dispatch(s.origin.clone().into()); - // OPTIMIZE: add actual weight used, not max. - Self::deposit_event(Event::Dispatched( - (now, index), - s.maybe_id.clone(), - r.map(|_| ()).map_err(|e| e.error), - )); + let dispatch_origin = s.origin.clone().into(); + let (maybe_actual_call_weight, result) = match call.dispatch(dispatch_origin) { + Ok(post_info) => { + (post_info.actual_weight, Ok(())) + }, + Err(error_and_info) => { + (error_and_info.post_info.actual_weight, Err(error_and_info.error)) + }, + }; + let actual_call_weight = maybe_actual_call_weight.unwrap_or(call_weight); + total_weight.saturating_accrue(item_weight); + total_weight.saturating_accrue(actual_call_weight); + + Self::deposit_event(Event::Dispatched((now, index), s.maybe_id.clone(), result)); if let &Some((period, count)) = &s.maybe_periodic { if count > 1 { @@ -407,13 +426,13 @@ pub mod pallet { } else { s.maybe_periodic = None; } - let next = now + period; + let wake = now + period; // If scheduled is named, place its information in `Lookup` if let Some(ref id) = s.maybe_id { - let next_index = Agenda::::decode_len(now + period).unwrap_or(0); - Lookup::::insert(id, (next, next_index as u32)); + let wake_index = Agenda::::decode_len(wake).unwrap_or(0); + Lookup::::insert(id, (wake, wake_index as u32)); } - Agenda::::append(next, Some(s)); + Agenda::::append(wake, Some(s)); } } total_weight diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 128d6e3f98d84..cd47a4405f457 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -589,6 +589,14 @@ pub trait PreimageProvider { fn unrequest_preimage(hash: &Hash); } +impl PreimageProvider for () { + fn have_preimage(_: &Hash) -> bool { false } + fn get_preimage(_: &Hash) -> Option> { None } + fn preimage_requested(_: &Hash) -> bool { false } + fn request_preimage(_: &Hash) {} + fn unrequest_preimage(_: &Hash) {} +} + /// A interface for managing preimages to hashes on chain. /// /// Note that this API does not assume any underlying user is calling, and thus @@ -607,6 +615,12 @@ pub trait PreimageRecipient: PreimageProvider { fn unnote_preimage(hash: &Hash); } +impl PreimageRecipient for () { + type MaxSize = (); + fn note_preimage(_: crate::BoundedVec) {} + fn unnote_preimage(_: &Hash) {} +} + #[cfg(test)] mod test { use super::*; From a1a891d614696ce7581e5afa4b8f783f24934776 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Nov 2021 16:16:00 +0100 Subject: [PATCH 36/58] Rename --- bin/node/runtime/src/lib.rs | 2 +- frame/democracy/src/tests.rs | 2 +- frame/scheduler/src/lib.rs | 2 +- frame/scheduler/src/mock.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 3d21d3b2de32a..95ea2c280a7db 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -349,7 +349,7 @@ impl pallet_scheduler::Config for Runtime { type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = pallet_scheduler::weights::SubstrateWeight; type OriginPrivilegeCmp = EqualPrivilegeOnly; - type Preimages = Preimage; + type PreimageProvider = Preimage; type NoPreimagePostponement = NoPreimagePostponement; } diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 526512f3a606b..0018c9caad1cc 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -119,7 +119,7 @@ impl pallet_scheduler::Config for Test { type MaxScheduledPerBlock = (); type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; - type Preimages = (); + type PreimageProvider = (); type NoPreimagePostponement = (); } parameter_types! { diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index ddea1f5c57b46..04710bf6f2e70 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -242,7 +242,7 @@ pub mod pallet { type WeightInfo: WeightInfo; /// The preimage provider with which we look up call hashes to get the call. - type Preimages: PreimageProviderAndMaybeRecipient; + type PreimageProvider: PreimageProviderAndMaybeRecipient; /// If `Some` then the number of blocks to postpone execution for when the item is delayed. type NoPreimagePostponement: Get>; diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 8686d62fd3947..f99536aa2ca99 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -182,7 +182,7 @@ impl Config for Test { type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; - type Preimages = Preimage; + type PreimageProvider = Preimage; type NoPreimagePostponement = NoPreimagePostponement; } From 88077ba2b2da5ceda77c15fb6a1f9294afe424bb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Nov 2021 16:29:48 +0100 Subject: [PATCH 37/58] Update benchmarks --- bin/node/runtime/src/lib.rs | 6 +- frame/scheduler/src/benchmarking.rs | 4 +- frame/scheduler/src/lib.rs | 12 +-- frame/scheduler/src/weights.rs | 162 ++++++++++++++-------------- 4 files changed, 91 insertions(+), 93 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 95ea2c280a7db..ec8ae0405c3dd 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1799,11 +1799,13 @@ mod tests { #[test] fn call_size() { + let size = core::mem::size_of::(); assert!( - core::mem::size_of::() <= 200, - "size of Call is more than 200 bytes: some calls have too big arguments, use Box to reduce the + size <= 200, + "size of Call {} is more than 200 bytes: some calls have too big arguments, use Box to reduce the size of Call. If the limit is too strong, maybe consider increase the limit to 300.", + size, ); } } diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 044eb2d3f6c9b..7ed4f4a2f1461 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -45,8 +45,8 @@ fn fill_schedule( let (call, hash) = call_and_hash::(i); let call_or_hash = match resolved { Some(true) => { - T::Preimages::note_preimage(call.encode().try_into().unwrap()); - if T::Preimages::have_preimage(&hash) { + T::PreimageProvider::note_preimage(call.encode().try_into().unwrap()); + if T::PreimageProvider::have_preimage(&hash) { CallOrHashOf::::Hash(hash) } else { call.into() diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 04710bf6f2e70..af6529790dfe9 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -346,11 +346,11 @@ pub mod pallet { false }; - let (call, maybe_completed) = s.call.resolved::(); + let (call, maybe_completed) = s.call.resolved::(); s.call = call; let resolved = if let Some(completed) = maybe_completed { - T::Preimages::unrequest_preimage(&completed); + T::PreimageProvider::unrequest_preimage(&completed); true } else { false @@ -709,7 +709,7 @@ impl Pallet { call: CallOrHashOf, ) -> Result, DispatchError> { let when = Self::resolve_time(when)?; - call.ensure_requested::(); + call.ensure_requested::(); // sanitize maybe_periodic let maybe_periodic = maybe_periodic @@ -759,7 +759,7 @@ impl Pallet { ) })?; if let Some(s) = scheduled { - s.call.ensure_unrequested::(); + s.call.ensure_unrequested::(); if let Some(id) = s.maybe_id { Lookup::::remove(id); } @@ -809,7 +809,7 @@ impl Pallet { let when = Self::resolve_time(when)?; - call.ensure_requested::(); + call.ensure_requested::(); // sanitize maybe_periodic let maybe_periodic = maybe_periodic @@ -854,7 +854,7 @@ impl Pallet { ) { return Err(BadOrigin.into()) } - s.call.ensure_unrequested::(); + s.call.ensure_unrequested::(); } *s = None; } diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index 16799228f1ffa..ae2aa388153e3 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-11-25, STEPS: `4000`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-11-26, STEPS: `4000`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -75,9 +75,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (6_817_000 as Weight) - // Standard Error: 61_000 - .saturating_add((21_795_000 as Weight).saturating_mul(s as Weight)) + (17_856_000 as Weight) + // Standard Error: 249_000 + .saturating_add((23_577_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -88,9 +88,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (8_307_000 as Weight) - // Standard Error: 50_000 - .saturating_add((16_702_000 as Weight).saturating_mul(s as Weight)) + (13_722_000 as Weight) + // Standard Error: 163_000 + .saturating_add((18_304_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -100,9 +100,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (7_566_000 as Weight) - // Standard Error: 68_000 - .saturating_add((18_448_000 as Weight).saturating_mul(s as Weight)) + (0 as Weight) + // Standard Error: 795_000 + .saturating_add((21_728_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -112,9 +112,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (8_650_000 as Weight) - // Standard Error: 56_000 - .saturating_add((15_390_000 as Weight).saturating_mul(s as Weight)) + (24_527_000 as Weight) + // Standard Error: 145_000 + .saturating_add((16_666_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -124,9 +124,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (7_223_000 as Weight) - // Standard Error: 17_000 - .saturating_add((4_822_000 as Weight).saturating_mul(s as Weight)) + (5_145_000 as Weight) + // Standard Error: 695_000 + .saturating_add((8_015_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -135,9 +135,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (8_149_000 as Weight) - // Standard Error: 23_000 - .saturating_add((3_632_000 as Weight).saturating_mul(s as Weight)) + (34_707_000 as Weight) + // Standard Error: 508_000 + .saturating_add((3_312_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -145,9 +145,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (12_947_000 as Weight) - // Standard Error: 48_000 - .saturating_add((10_284_000 as Weight).saturating_mul(s as Weight)) + (25_378_000 as Weight) + // Standard Error: 296_000 + .saturating_add((11_234_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -155,9 +155,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (18_699_000 as Weight) - // Standard Error: 73_000 - .saturating_add((7_047_000 as Weight).saturating_mul(s as Weight)) + (15_518_000 as Weight) + // Standard Error: 94_000 + .saturating_add((7_771_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -166,51 +166,49 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (13_833_000 as Weight) - // Standard Error: 27_000 - .saturating_add((5_284_000 as Weight).saturating_mul(s as Weight)) + (19_202_000 as Weight) + // Standard Error: 93_000 + .saturating_add((5_889_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (13_421_000 as Weight) - // Standard Error: 29_000 - .saturating_add((4_080_000 as Weight).saturating_mul(s as Weight)) + (17_143_000 as Weight) + // Standard Error: 76_000 + .saturating_add((4_554_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(_s: u32, ) -> Weight { - (16_388_000 as Weight) + (19_500_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (16_171_000 as Weight) - // Standard Error: 17_000 - .saturating_add((385_000 as Weight).saturating_mul(s as Weight)) + (20_152_000 as Weight) + // Standard Error: 42_000 + .saturating_add((460_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) - fn schedule_named(s: u32, ) -> Weight { - (19_063_000 as Weight) - // Standard Error: 10_000 - .saturating_add((38_000 as Weight).saturating_mul(s as Weight)) + fn schedule_named(_s: u32, ) -> Weight { + (25_941_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (17_177_000 as Weight) - // Standard Error: 16_000 - .saturating_add((453_000 as Weight).saturating_mul(s as Weight)) + (21_413_000 as Weight) + // Standard Error: 32_000 + .saturating_add((429_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -223,9 +221,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (6_817_000 as Weight) - // Standard Error: 61_000 - .saturating_add((21_795_000 as Weight).saturating_mul(s as Weight)) + (17_856_000 as Weight) + // Standard Error: 249_000 + .saturating_add((23_577_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -236,9 +234,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (8_307_000 as Weight) - // Standard Error: 50_000 - .saturating_add((16_702_000 as Weight).saturating_mul(s as Weight)) + (13_722_000 as Weight) + // Standard Error: 163_000 + .saturating_add((18_304_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -248,9 +246,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (7_566_000 as Weight) - // Standard Error: 68_000 - .saturating_add((18_448_000 as Weight).saturating_mul(s as Weight)) + (0 as Weight) + // Standard Error: 795_000 + .saturating_add((21_728_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -260,9 +258,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (8_650_000 as Weight) - // Standard Error: 56_000 - .saturating_add((15_390_000 as Weight).saturating_mul(s as Weight)) + (24_527_000 as Weight) + // Standard Error: 145_000 + .saturating_add((16_666_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -272,9 +270,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (7_223_000 as Weight) - // Standard Error: 17_000 - .saturating_add((4_822_000 as Weight).saturating_mul(s as Weight)) + (5_145_000 as Weight) + // Standard Error: 695_000 + .saturating_add((8_015_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -283,9 +281,9 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (8_149_000 as Weight) - // Standard Error: 23_000 - .saturating_add((3_632_000 as Weight).saturating_mul(s as Weight)) + (34_707_000 as Weight) + // Standard Error: 508_000 + .saturating_add((3_312_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -293,9 +291,9 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (12_947_000 as Weight) - // Standard Error: 48_000 - .saturating_add((10_284_000 as Weight).saturating_mul(s as Weight)) + (25_378_000 as Weight) + // Standard Error: 296_000 + .saturating_add((11_234_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -303,9 +301,9 @@ impl WeightInfo for () { } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (18_699_000 as Weight) - // Standard Error: 73_000 - .saturating_add((7_047_000 as Weight).saturating_mul(s as Weight)) + (15_518_000 as Weight) + // Standard Error: 94_000 + .saturating_add((7_771_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -314,51 +312,49 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (13_833_000 as Weight) - // Standard Error: 27_000 - .saturating_add((5_284_000 as Weight).saturating_mul(s as Weight)) + (19_202_000 as Weight) + // Standard Error: 93_000 + .saturating_add((5_889_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (13_421_000 as Weight) - // Standard Error: 29_000 - .saturating_add((4_080_000 as Weight).saturating_mul(s as Weight)) + (17_143_000 as Weight) + // Standard Error: 76_000 + .saturating_add((4_554_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) fn schedule(_s: u32, ) -> Weight { - (16_388_000 as Weight) + (19_500_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (16_171_000 as Weight) - // Standard Error: 17_000 - .saturating_add((385_000 as Weight).saturating_mul(s as Weight)) + (20_152_000 as Weight) + // Standard Error: 42_000 + .saturating_add((460_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) - fn schedule_named(s: u32, ) -> Weight { - (19_063_000 as Weight) - // Standard Error: 10_000 - .saturating_add((38_000 as Weight).saturating_mul(s as Weight)) + fn schedule_named(_s: u32, ) -> Weight { + (25_941_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (17_177_000 as Weight) - // Standard Error: 16_000 - .saturating_add((453_000 as Weight).saturating_mul(s as Weight)) + (21_413_000 as Weight) + // Standard Error: 32_000 + .saturating_add((429_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } From ebc9b5b1dabc62bcf4e21d5ab50e9e3e439b323a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Nov 2021 17:00:58 +0100 Subject: [PATCH 38/58] Formatting --- frame/preimage/src/benchmarking.rs | 8 +- frame/preimage/src/lib.rs | 6 +- frame/preimage/src/mock.rs | 15 ++-- frame/preimage/src/tests.rs | 60 +++++++++++--- frame/scheduler/src/benchmarking.rs | 15 ++-- frame/scheduler/src/lib.rs | 80 +++++++++---------- frame/scheduler/src/mock.rs | 6 +- frame/scheduler/src/tests.rs | 80 +++++++------------ frame/support/src/traits/misc.rs | 16 +++- frame/support/src/traits/schedule.rs | 10 ++- frame/support/src/traits/tokens/currency.rs | 50 +++++++++--- .../src/traits/tokens/currency/reservable.rs | 27 ++++--- frame/support/src/traits/tokens/imbalance.rs | 40 +++++++--- frame/system/src/lib.rs | 4 +- 14 files changed, 249 insertions(+), 168 deletions(-) diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index d273311dfc49b..c18c27555025d 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -18,11 +18,11 @@ //! Preimage pallet benchmarking. use super::*; -use sp_std::{prelude::*, vec}; -use sp_runtime::traits::Bounded; -use frame_benchmarking::{benchmarks, whitelist_account, account}; +use frame_benchmarking::{account, benchmarks, whitelist_account}; +use frame_support::assert_ok; use frame_system::RawOrigin; -use frame_support::{assert_ok}; +use sp_runtime::traits::Bounded; +use sp_std::{prelude::*, vec}; use crate::Pallet as Preimage; diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 99fb99d83ec43..b6b8326e6e0a5 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -30,11 +30,11 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; -pub mod weights; -#[cfg(test)] -mod tests; #[cfg(test)] mod mock; +#[cfg(test)] +mod tests; +pub mod weights; use sp_runtime::traits::{BadOrigin, Hash, Saturating}; use sp_std::{convert::TryFrom, prelude::*}; diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index 4257f9d7505b0..c67f34e71445c 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -20,11 +20,16 @@ use super::*; use crate as pallet_preimage; -use sp_core::H256; -use sp_runtime::{testing::Header, traits::{BlakeTwo256, IdentityLookup}, Perbill}; -use frame_support::{parameter_types, ord_parameter_types, traits::Everything}; -use frame_support::weights::constants::RocksDbWeight; +use frame_support::{ + ord_parameter_types, parameter_types, traits::Everything, weights::constants::RocksDbWeight, +}; use frame_system::EnsureSignedBy; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, +}; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -122,4 +127,4 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pub fn hashed(data: impl AsRef<[u8]>) -> H256 { BlakeTwo256::hash(data.as_ref()) -} \ No newline at end of file +} diff --git a/frame/preimage/src/tests.rs b/frame/preimage/src/tests.rs index 7acbada5a3fdd..528b263303715 100644 --- a/frame/preimage/src/tests.rs +++ b/frame/preimage/src/tests.rs @@ -34,8 +34,14 @@ fn user_note_preimage_works() { assert!(Preimage::have_preimage(&h)); assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); - assert_noop!(Preimage::note_preimage(Origin::signed(2), vec![1]), Error::::AlreadyNoted); - assert_noop!(Preimage::note_preimage(Origin::signed(0), vec![2]), BalancesError::::InsufficientBalance); + assert_noop!( + Preimage::note_preimage(Origin::signed(2), vec![1]), + Error::::AlreadyNoted + ); + assert_noop!( + Preimage::note_preimage(Origin::signed(0), vec![2]), + BalancesError::::InsufficientBalance + ); }); } @@ -50,7 +56,10 @@ fn manager_note_preimage_works() { assert!(Preimage::have_preimage(&h)); assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); - assert_noop!(Preimage::note_preimage(Origin::signed(1), vec![1]), Error::::AlreadyNoted); + assert_noop!( + Preimage::note_preimage(Origin::signed(1), vec![1]), + Error::::AlreadyNoted + ); }); } @@ -58,11 +67,20 @@ fn manager_note_preimage_works() { fn user_unnote_preimage_works() { new_test_ext().execute_with(|| { assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); - assert_noop!(Preimage::unnote_preimage(Origin::signed(3), hashed([1])), Error::::NotAuthorized); - assert_noop!(Preimage::unnote_preimage(Origin::signed(2), hashed([2])), Error::::NotNoted); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(3), hashed([1])), + Error::::NotAuthorized + ); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(2), hashed([2])), + Error::::NotNoted + ); assert_ok!(Preimage::unnote_preimage(Origin::signed(2), hashed([1]))); - assert_noop!(Preimage::unnote_preimage(Origin::signed(2), hashed([1])), Error::::NotNoted); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(2), hashed([1])), + Error::::NotNoted + ); let h = hashed([1]); assert!(!Preimage::have_preimage(&h)); @@ -75,7 +93,10 @@ fn manager_unnote_preimage_works() { new_test_ext().execute_with(|| { assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); assert_ok!(Preimage::unnote_preimage(Origin::signed(1), hashed([1]))); - assert_noop!(Preimage::unnote_preimage(Origin::signed(1), hashed([1])), Error::::NotNoted); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(1), hashed([1])), + Error::::NotNoted + ); let h = hashed([1]); assert!(!Preimage::have_preimage(&h)); @@ -87,8 +108,14 @@ fn manager_unnote_preimage_works() { fn manager_unnote_user_preimage_works() { new_test_ext().execute_with(|| { assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); - assert_noop!(Preimage::unnote_preimage(Origin::signed(3), hashed([1])), Error::::NotAuthorized); - assert_noop!(Preimage::unnote_preimage(Origin::signed(2), hashed([2])), Error::::NotNoted); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(3), hashed([1])), + Error::::NotAuthorized + ); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(2), hashed([2])), + Error::::NotNoted + ); assert_ok!(Preimage::unnote_preimage(Origin::signed(1), hashed([1]))); @@ -103,7 +130,10 @@ fn requested_then_noted_preimage_cannot_be_unnoted() { new_test_ext().execute_with(|| { assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_noop!(Preimage::unnote_preimage(Origin::signed(1), hashed([1])), Error::::Requested); + assert_noop!( + Preimage::unnote_preimage(Origin::signed(1), hashed([1])), + Error::::Requested + ); let h = hashed([1]); assert!(Preimage::have_preimage(&h)); @@ -173,13 +203,19 @@ fn unrequest_preimage_works() { assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); - assert_noop!(Preimage::unrequest_preimage(Origin::signed(1), hashed([2])), Error::::NotRequested); + assert_noop!( + Preimage::unrequest_preimage(Origin::signed(1), hashed([2])), + Error::::NotRequested + ); assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); assert!(Preimage::have_preimage(&hashed([1]))); assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); - assert_noop!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1])), Error::::NotRequested); + assert_noop!( + Preimage::unrequest_preimage(Origin::signed(1), hashed([1])), + Error::::NotRequested + ); }); } diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 7ed4f4a2f1461..75cdc0fbf6334 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -19,10 +19,13 @@ use super::*; use frame_benchmarking::benchmarks; -use frame_support::{ensure, traits::{OnInitialize, PreimageProvider, PreimageRecipient}}; +use frame_support::{ + ensure, + traits::{OnInitialize, PreimageProvider, PreimageRecipient}, +}; use frame_system::RawOrigin; -use sp_std::{prelude::*, vec}; use sp_runtime::traits::Hash; +use sp_std::{prelude::*, vec}; use crate::Pallet as Scheduler; use frame_system::Pallet as System; @@ -36,9 +39,9 @@ fn fill_schedule( periodic: bool, named: bool, resolved: Option, - //^^ None -> aborted (hash without preimage) - // Some(true) -> hash resolves into call if possible, plain call otherwise - // Some(false) -> plain call + /* None -> aborted (hash without preimage) */ + /* Some(true) -> hash resolves into call if possible, plain call otherwise + * Some(false) -> plain call */ ) -> Result<(), &'static str> { for i in 0..n { // Named schedule is strictly heavier than anonymous @@ -51,7 +54,7 @@ fn fill_schedule( } else { call.into() } - } + }, Some(false) => call.into(), None => CallOrHashOf::::Hash(hash), }; diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index af6529790dfe9..6f51259aa8e8d 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -52,18 +52,18 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; -pub mod weights; -#[cfg(test)] -mod tests; #[cfg(test)] mod mock; +#[cfg(test)] +mod tests; +pub mod weights; use codec::{Codec, Decode, Encode}; use frame_support::{ dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter}, traits::{ - EnsureOrigin, Get, IsType, OriginTrait, - PrivilegeCmp, schedule::{self, DispatchTime, MaybeHashed}, + schedule::{self, DispatchTime, MaybeHashed}, + EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp, }, weights::{GetDispatchInfo, Weight}, }; @@ -82,10 +82,7 @@ pub type PeriodicIndex = u32; /// The location of a scheduled task that can be used to remove it. pub type TaskAddress = (BlockNumber, u32); -pub type CallOrHashOf = MaybeHashed< - ::Call, - ::Hash, ->; +pub type CallOrHashOf = MaybeHashed<::Call, ::Hash>; #[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] #[derive(Clone, RuntimeDebug, Encode, Decode)] @@ -171,15 +168,24 @@ pub(crate) trait MarginalWeightInfo: WeightInfo { fn item(periodic: bool, named: bool, resolved: Option) -> Weight { match (periodic, named, resolved) { (_, false, None) => Self::on_initialize_aborted(2) - Self::on_initialize_aborted(1), - (_, true, None) => Self::on_initialize_named_aborted(2) - Self::on_initialize_named_aborted(1), + (_, true, None) => + Self::on_initialize_named_aborted(2) - Self::on_initialize_named_aborted(1), (false, false, Some(false)) => Self::on_initialize(2) - Self::on_initialize(1), - (false, true, Some(false)) => Self::on_initialize_named(2) - Self::on_initialize_named(1), - (true, false, Some(false)) => Self::on_initialize_periodic(2) - Self::on_initialize_periodic(1), - (true, true, Some(false)) => Self::on_initialize_periodic_named(2) - Self::on_initialize_periodic_named(1), - (false, false, Some(true)) => Self::on_initialize_resolved(2) - Self::on_initialize_resolved(1), - (false, true, Some(true)) => Self::on_initialize_named_resolved(2) - Self::on_initialize_named_resolved(1), - (true, false, Some(true)) => Self::on_initialize_periodic_resolved(2) - Self::on_initialize_periodic_resolved(1), - (true, true, Some(true)) => Self::on_initialize_periodic_named_resolved(2) - Self::on_initialize_periodic_named_resolved(1), + (false, true, Some(false)) => + Self::on_initialize_named(2) - Self::on_initialize_named(1), + (true, false, Some(false)) => + Self::on_initialize_periodic(2) - Self::on_initialize_periodic(1), + (true, true, Some(false)) => + Self::on_initialize_periodic_named(2) - Self::on_initialize_periodic_named(1), + (false, false, Some(true)) => + Self::on_initialize_resolved(2) - Self::on_initialize_resolved(1), + (false, true, Some(true)) => + Self::on_initialize_named_resolved(2) - Self::on_initialize_named_resolved(1), + (true, false, Some(true)) => + Self::on_initialize_periodic_resolved(2) - Self::on_initialize_periodic_resolved(1), + (true, true, Some(true)) => + Self::on_initialize_periodic_named_resolved(2) - + Self::on_initialize_periodic_named_resolved(1), } } } @@ -188,8 +194,11 @@ impl MarginalWeightInfo for T {} #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*}; - use frame_support::traits::{PreimageProvider, schedule::LookupError}; + use frame_support::{ + dispatch::PostDispatchInfo, + pallet_prelude::*, + traits::{schedule::LookupError, PreimageProvider}, + }; use frame_system::pallet_prelude::*; #[pallet::pallet] @@ -250,13 +259,8 @@ pub mod pallet { /// Items to be executed, indexed by the block number that they should be executed on. #[pallet::storage] - pub type Agenda = StorageMap< - _, - Twox64Concat, - T::BlockNumber, - Vec>>, - ValueQuery, - >; + pub type Agenda = + StorageMap<_, Twox64Concat, T::BlockNumber, Vec>>, ValueQuery>; /// Lookup from identity to the block number and index of the task. #[pallet::storage] @@ -338,7 +342,6 @@ pub mod pallet { let mut total_weight: Weight = T::WeightInfo::on_initialize(0); for (order, (index, mut s)) in queued.into_iter().enumerate() { - let named = if let Some(ref id) = s.maybe_id { Lookup::::remove(id); true @@ -369,7 +372,7 @@ pub mod pallet { } Agenda::::append(until, Some(s)); } - continue; + continue }, }; @@ -389,7 +392,8 @@ pub mod pallet { // - It does not push the weight past the limit. // - It is the first item in the schedule let hard_deadline = s.priority <= schedule::HARD_DEADLINE; - let test_weight = total_weight.saturating_add(call_weight).saturating_add(item_weight); + let test_weight = + total_weight.saturating_add(call_weight).saturating_add(item_weight); if !hard_deadline && order > 0 && test_weight > limit { // Cannot be scheduled this block - postpone until next. total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); @@ -402,17 +406,14 @@ pub mod pallet { Lookup::::insert(id, (next, index as u32)); } Agenda::::append(next, Some(s)); - continue; + continue } let dispatch_origin = s.origin.clone().into(); let (maybe_actual_call_weight, result) = match call.dispatch(dispatch_origin) { - Ok(post_info) => { - (post_info.actual_weight, Ok(())) - }, - Err(error_and_info) => { - (error_and_info.post_info.actual_weight, Err(error_and_info.error)) - }, + Ok(post_info) => (post_info.actual_weight, Ok(())), + Err(error_and_info) => + (error_and_info.post_info.actual_weight, Err(error_and_info.error)), }; let actual_call_weight = maybe_actual_call_weight.unwrap_or(call_weight); total_weight.saturating_accrue(item_weight); @@ -633,10 +634,7 @@ impl Pallet { if StorageVersion::::get() == Releases::V1 { StorageVersion::::put(Releases::V2); - Agenda::::translate::< - Vec>>, - _, - >(|_, agenda| { + Agenda::::translate::>>, _>(|_, agenda| { Some( agenda .into_iter() @@ -664,7 +662,7 @@ impl Pallet { pub fn migrate_origin + codec::Decode>() { Agenda::::translate::< Vec, T::BlockNumber, OldOrigin, T::AccountId>>>, - _ + _, >(|_, agenda| { Some( agenda diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index f99536aa2ca99..3f014e47d8911 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -81,11 +81,7 @@ pub mod logger { } #[pallet::weight(*weight)] - pub fn log_without_filter( - origin: OriginFor, - i: u32, - weight: Weight, - ) -> DispatchResult { + pub fn log_without_filter(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { Self::deposit_event(Event::Logged(i, weight)); LOG.with(|log| { log.borrow_mut().push((origin.caller().clone(), i)); diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index d88e29ca6c3be..9e66d72153995 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -18,15 +18,13 @@ //! # Scheduler tests. use super::*; -use crate::mock::{ - *, Call, root, run_to_block, new_test_ext, LoggerCall, Test, logger, Scheduler -}; -use sp_runtime::traits::Hash; +use crate::mock::{logger, new_test_ext, root, run_to_block, Call, LoggerCall, Scheduler, Test, *}; use frame_support::{ assert_err, assert_noop, assert_ok, traits::{Contains, OnInitialize, PreimageProvider}, Hashable, }; +use sp_runtime::traits::Hash; use substrate_test_utils::assert_eq_uvec; #[test] @@ -366,14 +364,16 @@ fn scheduler_respects_weight_limits() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }).into(), + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) + .into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) + .into(), )); // 69 and 42 do not fit together run_to_block(4); @@ -391,14 +391,16 @@ fn scheduler_respects_hard_deadlines_more() { None, 0, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }).into(), + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) + .into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 0, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) + .into(), )); // With base weights, 69 and 42 should not fit together, but do because of hard // deadlines @@ -415,14 +417,16 @@ fn scheduler_respects_priority_ordering() { None, 1, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }).into(), + Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) + .into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 0, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }).into(), + Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) + .into(), )); run_to_block(4); assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]); @@ -433,36 +437,29 @@ fn scheduler_respects_priority_ordering() { fn scheduler_respects_priority_ordering_with_soft_deadlines() { new_test_ext().execute_with(|| { let max_weight = MaximumSchedulerWeight::get() - <() as WeightInfo>::on_initialize(0); - let item_weight = <() as WeightInfo>::on_initialize(1) - <() as WeightInfo>::on_initialize(0); + let item_weight = + <() as WeightInfo>::on_initialize(1) - <() as WeightInfo>::on_initialize(0); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 255, root(), - Call::Logger(LoggerCall::log { - i: 42, - weight: max_weight / 2 - item_weight, - }).into(), + Call::Logger(LoggerCall::log { i: 42, weight: max_weight / 2 - item_weight }).into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - Call::Logger(LoggerCall::log { - i: 69, - weight: max_weight / 2 - item_weight, - }).into(), + Call::Logger(LoggerCall::log { i: 69, weight: max_weight / 2 - item_weight }).into(), )); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 126, root(), - Call::Logger(LoggerCall::log { - i: 2600, - weight: max_weight / 2 - item_weight + 1, - }).into(), + Call::Logger(LoggerCall::log { i: 2600, weight: max_weight / 2 - item_weight + 1 }) + .into(), )); // 2600 does not fit with 69 or 42, but has higher priority, so will go through @@ -519,7 +516,8 @@ fn on_initialize_weight_is_correct() { let actual_weight = Scheduler::on_initialize(1); assert_eq!( actual_weight, - base_weight + call_weight + 4 + <() as MarginalWeightInfo>::item(true, true, Some(false)) + base_weight + + call_weight + 4 + <() as MarginalWeightInfo>::item(true, true, Some(false)) ); assert_eq!(logger::log(), vec![(root(), 2600u32)]); @@ -527,9 +525,9 @@ fn on_initialize_weight_is_correct() { let actual_weight = Scheduler::on_initialize(2); assert_eq!( actual_weight, - base_weight - + call_weight + 2 + <() as MarginalWeightInfo>::item(false, false, Some(false)) - + call_weight + 3 + <() as MarginalWeightInfo>::item(true, false, Some(false)) + base_weight + + call_weight + 2 + <() as MarginalWeightInfo>::item(false, false, Some(false)) + + call_weight + 3 + <() as MarginalWeightInfo>::item(true, false, Some(false)) ); assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); @@ -537,7 +535,8 @@ fn on_initialize_weight_is_correct() { let actual_weight = Scheduler::on_initialize(3); assert_eq!( actual_weight, - base_weight + call_weight + 1 + <() as MarginalWeightInfo>::item(false, true, Some(false)) + base_weight + + call_weight + 1 + <() as MarginalWeightInfo>::item(false, true, Some(false)) ); assert_eq!( logger::log(), @@ -555,14 +554,7 @@ fn root_calls_works() { new_test_ext().execute_with(|| { let call = Box::new(Call::Logger(LoggerCall::log { i: 69, weight: 1000 }).into()); let call2 = Box::new(Call::Logger(LoggerCall::log { i: 42, weight: 1000 }).into()); - assert_ok!(Scheduler::schedule_named( - Origin::root(), - 1u32.encode(), - 4, - None, - 127, - call, - )); + assert_ok!(Scheduler::schedule_named(Origin::root(), 1u32.encode(), 4, None, 127, call,)); assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2)); run_to_block(3); // Scheduled calls are in the agenda. @@ -615,13 +607,7 @@ fn should_use_orign() { 127, call, )); - assert_ok!(Scheduler::schedule( - system::RawOrigin::Signed(1).into(), - 4, - None, - 127, - call2, - )); + assert_ok!(Scheduler::schedule(system::RawOrigin::Signed(1).into(), 4, None, 127, call2,)); run_to_block(3); // Scheduled calls are in the agenda. assert_eq!(Agenda::::get(4).len(), 2); @@ -672,13 +658,7 @@ fn should_check_orign_for_cancel() { 127, call, )); - assert_ok!(Scheduler::schedule( - system::RawOrigin::Signed(1).into(), - 4, - None, - 127, - call2, - )); + assert_ok!(Scheduler::schedule(system::RawOrigin::Signed(1).into(), 4, None, 127, call2,)); run_to_block(3); // Scheduled calls are in the agenda. assert_eq!(Agenda::::get(4).len(), 2); diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index cd47a4405f457..1df874df8a865 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -82,7 +82,9 @@ pub trait TryDrop: Sized { } impl TryDrop for () { - fn try_drop(self) -> Result<(), Self> { Ok(()) } + fn try_drop(self) -> Result<(), Self> { + Ok(()) + } } /// Return type used when we need to return one of two items, each of the opposite direction or @@ -590,9 +592,15 @@ pub trait PreimageProvider { } impl PreimageProvider for () { - fn have_preimage(_: &Hash) -> bool { false } - fn get_preimage(_: &Hash) -> Option> { None } - fn preimage_requested(_: &Hash) -> bool { false } + fn have_preimage(_: &Hash) -> bool { + false + } + fn get_preimage(_: &Hash) -> Option> { + None + } + fn preimage_requested(_: &Hash) -> bool { + false + } fn request_preimage(_: &Hash) {} fn unrequest_preimage(_: &Hash) {} } diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 31a06d0f4c765..3bbc4672bc63d 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -20,7 +20,7 @@ use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{DispatchError, RuntimeDebug}; -use sp_std::{fmt::Debug, result::Result, prelude::*}; +use sp_std::{fmt::Debug, prelude::*, result::Result}; /// Information relating to the period of a scheduled task. First item is the length of the /// period and the second is the number of times it should be executed in total before the task @@ -115,7 +115,7 @@ impl MaybeHashed { Ok(c) => (Self::Value(c), Some(h)), Err(_) => (Self::Hash(h), None), } - } + }, } } } @@ -207,7 +207,8 @@ pub mod v1 { fn next_dispatch_time(id: Vec) -> Result; } - impl Anon for T where + impl Anon for T + where T: v2::Anon, { type Address = T::Address; @@ -239,7 +240,8 @@ pub mod v1 { } } - impl Named for T where + impl Named for T + where T: v2::Named, { type Address = T::Address; diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index fd8ae23322754..8280994f20d8b 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -204,40 +204,64 @@ impl Currency for () { type Balance = u32; type PositiveImbalance = (); type NegativeImbalance = (); - fn total_balance(_: &AccountId) -> Self::Balance { 0 } - fn can_slash(_: &AccountId, _: Self::Balance) -> bool { true } - fn total_issuance() -> Self::Balance { 0 } - fn minimum_balance() -> Self::Balance { 0 } - fn burn(_: Self::Balance) -> Self::PositiveImbalance { () } - fn issue(_: Self::Balance) -> Self::NegativeImbalance { () } - fn pair(_: Self::Balance) -> (Self::PositiveImbalance, Self::NegativeImbalance) { ((), ()) } - fn free_balance(_: &AccountId) -> Self::Balance { 0 } + fn total_balance(_: &AccountId) -> Self::Balance { + 0 + } + fn can_slash(_: &AccountId, _: Self::Balance) -> bool { + true + } + fn total_issuance() -> Self::Balance { + 0 + } + fn minimum_balance() -> Self::Balance { + 0 + } + fn burn(_: Self::Balance) -> Self::PositiveImbalance { + () + } + fn issue(_: Self::Balance) -> Self::NegativeImbalance { + () + } + fn pair(_: Self::Balance) -> (Self::PositiveImbalance, Self::NegativeImbalance) { + ((), ()) + } + fn free_balance(_: &AccountId) -> Self::Balance { + 0 + } fn ensure_can_withdraw( _: &AccountId, _: Self::Balance, _: WithdrawReasons, _: Self::Balance, - ) -> DispatchResult { Ok(()) } + ) -> DispatchResult { + Ok(()) + } fn transfer( _: &AccountId, _: &AccountId, _: Self::Balance, _: ExistenceRequirement, - ) -> DispatchResult { Ok(()) } + ) -> DispatchResult { + Ok(()) + } fn slash(_: &AccountId, _: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) { ((), 0) } fn deposit_into_existing( _: &AccountId, _: Self::Balance, - ) -> Result { Ok(()) } + ) -> Result { + Ok(()) + } fn resolve_into_existing( _: &AccountId, _: Self::NegativeImbalance, ) -> Result<(), Self::NegativeImbalance> { Ok(()) } - fn deposit_creating(_: &AccountId, _: Self::Balance) -> Self::PositiveImbalance { () } + fn deposit_creating(_: &AccountId, _: Self::Balance) -> Self::PositiveImbalance { + () + } fn resolve_creating(_: &AccountId, _: Self::NegativeImbalance) {} fn withdraw( _: &AccountId, @@ -261,4 +285,4 @@ impl Currency for () { ) -> SignedImbalance { SignedImbalance::Positive(()) } -} \ No newline at end of file +} diff --git a/frame/support/src/traits/tokens/currency/reservable.rs b/frame/support/src/traits/tokens/currency/reservable.rs index f28e97ed3c6f5..9717ba25608ad 100644 --- a/frame/support/src/traits/tokens/currency/reservable.rs +++ b/frame/support/src/traits/tokens/currency/reservable.rs @@ -82,20 +82,29 @@ pub trait ReservableCurrency: Currency { } impl ReservableCurrency for () { - fn can_reserve(_: &AccountId, _: Self::Balance) -> bool { true } - fn slash_reserved( - _: &AccountId, - _: Self::Balance, - ) -> (Self::NegativeImbalance, Self::Balance) { ((), 0) } - fn reserved_balance(_: &AccountId) -> Self::Balance { 0 } - fn reserve(_: &AccountId, _: Self::Balance) -> DispatchResult { Ok(()) } - fn unreserve(_: &AccountId, _: Self::Balance) -> Self::Balance { 0 } + fn can_reserve(_: &AccountId, _: Self::Balance) -> bool { + true + } + fn slash_reserved(_: &AccountId, _: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) { + ((), 0) + } + fn reserved_balance(_: &AccountId) -> Self::Balance { + 0 + } + fn reserve(_: &AccountId, _: Self::Balance) -> DispatchResult { + Ok(()) + } + fn unreserve(_: &AccountId, _: Self::Balance) -> Self::Balance { + 0 + } fn repatriate_reserved( _: &AccountId, _: &AccountId, _: Self::Balance, _: BalanceStatus, - ) -> Result { Ok(0) } + ) -> Result { + Ok(0) + } } pub trait NamedReservableCurrency: ReservableCurrency { diff --git a/frame/support/src/traits/tokens/imbalance.rs b/frame/support/src/traits/tokens/imbalance.rs index c511c2827efb3..60efb67324ac9 100644 --- a/frame/support/src/traits/tokens/imbalance.rs +++ b/frame/support/src/traits/tokens/imbalance.rs @@ -180,10 +180,17 @@ pub trait Imbalance: Sized + TryDrop + Default { impl Imbalance for () { type Opposite = (); - fn zero() -> Self { () } - fn drop_zero(self) -> Result<(), Self> { Ok(()) } - fn split(self, _: Balance) -> (Self, Self) { ((), ()) } - fn ration(self, _: u32, _: u32) -> (Self, Self) where + fn zero() -> Self { + () + } + fn drop_zero(self) -> Result<(), Self> { + Ok(()) + } + fn split(self, _: Balance) -> (Self, Self) { + ((), ()) + } + fn ration(self, _: u32, _: u32) -> (Self, Self) + where Balance: From + Saturating + Div, { ((), ()) @@ -191,22 +198,33 @@ impl Imbalance for () { fn split_merge(self, _: Balance, _: (Self, Self)) -> (Self, Self) { ((), ()) } - fn ration_merge(self, _: u32, _: u32, _: (Self, Self)) -> (Self, Self) where + fn ration_merge(self, _: u32, _: u32, _: (Self, Self)) -> (Self, Self) + where Balance: From + Saturating + Div, { ((), ()) } fn split_merge_into(self, _: Balance, _: &mut (Self, Self)) {} - fn ration_merge_into(self, _: u32, _: u32, _: &mut (Self, Self)) where + fn ration_merge_into(self, _: u32, _: u32, _: &mut (Self, Self)) + where Balance: From + Saturating + Div, - {} - fn merge(self, _: Self) -> Self { () } + { + } + fn merge(self, _: Self) -> Self { + () + } fn merge_into(self, _: &mut Self) {} - fn maybe_merge(self, _: Option) -> Self { () } + fn maybe_merge(self, _: Option) -> Self { + () + } fn subsume(&mut self, _: Self) {} - fn maybe_subsume(&mut self, _: Option) { () } + fn maybe_subsume(&mut self, _: Option) { + () + } fn offset(self, _: Self::Opposite) -> SameOrOther { SameOrOther::None } - fn peek(&self) -> Balance { Default::default() } + fn peek(&self) -> Balance { + Default::default() + } } diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index d36b836a3affe..44f69a83305db 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -969,7 +969,9 @@ where /// Ensure that the origin `o` represents either a signed extrinsic (i.e. transaction) or the root. /// Returns `Ok` with the account that signed the extrinsic, `None` if it was root, or an `Err` /// otherwise. -pub fn ensure_signed_or_root(o: OuterOrigin) -> Result, BadOrigin> +pub fn ensure_signed_or_root( + o: OuterOrigin, +) -> Result, BadOrigin> where OuterOrigin: Into, OuterOrigin>>, { From 257a209cd86bec9511b48456e84f7034f23e571d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Nov 2021 18:58:43 +0100 Subject: [PATCH 39/58] Formatting --- frame/scheduler/src/benchmarking.rs | 2 +- frame/scheduler/src/lib.rs | 32 ++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 75cdc0fbf6334..611c7dcc5b781 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -40,7 +40,7 @@ fn fill_schedule( named: bool, resolved: Option, /* None -> aborted (hash without preimage) */ - /* Some(true) -> hash resolves into call if possible, plain call otherwise + * Some(true) -> hash resolves into call if possible, plain call otherwise * Some(false) -> plain call */ ) -> Result<(), &'static str> { for i in 0..n { diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 6f51259aa8e8d..212951b85017c 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -135,7 +135,7 @@ pub type Scheduled = // A value placed in storage that represents the current version of the Scheduler storage. // This value is used by the `on_runtime_upgrade` logic to determine whether we run // storage migration logic. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo)] enum Releases { V1, V2, @@ -599,7 +599,7 @@ impl Pallet { /// Return true if migration is performed. pub fn migrate_v1_to_v3() -> bool { if StorageVersion::::get() == Releases::V1 { - StorageVersion::::put(Releases::V2); + StorageVersion::::put(Releases::V3); Agenda::::translate::< Vec::Call, T::BlockNumber>>>, @@ -630,15 +630,18 @@ impl Pallet { /// Migrate storage format from V2 to V3. /// Return true if migration is performed. - pub fn migrate_v2_to_v3() -> bool { - if StorageVersion::::get() == Releases::V1 { - StorageVersion::::put(Releases::V2); + pub fn migrate_v2_to_v3() -> Weight { + if StorageVersion::::get() == Releases::V2 { + StorageVersion::::put(Releases::V3); + + let mut weight = T::DbWeight::get().reads_writes(1, 1); Agenda::::translate::>>, _>(|_, agenda| { Some( agenda .into_iter() .map(|schedule| { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); schedule.map(|schedule| ScheduledV3 { maybe_id: schedule.maybe_id, priority: schedule.priority, @@ -652,10 +655,25 @@ impl Pallet { ) }); - true + weight } else { - false + 0 + } + } + + #[cfg(feature = "try-runtime")] + pub fn pre_migrate_to_v3() -> Result<(), &'static str> { + assert!(StorageVersion::::get() < Releases::V3); + Ok(()) + } + + #[cfg(feature = "try-runtime")] + pub fn post_migrate_to_v3() -> Result<(), &'static str> { + assert!(StorageVersion::::get() == Releases::V3); + for k in Agenda::::iter_keys() { + let _ = Agenda::::try_get(k)?; } + Ok(()) } /// Helper to migrate scheduler when the pallet origin type has changed. From bc7e330bb54613d962ca827d6ac274cf84f7ff28 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Nov 2021 19:00:40 +0100 Subject: [PATCH 40/58] Fix weird formatting --- frame/scheduler/src/benchmarking.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 611c7dcc5b781..22e3e4f4530ba 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -32,16 +32,18 @@ use frame_system::Pallet as System; const BLOCK_NUMBER: u32 = 2; -// Add `n` named items to the schedule +/// Add `n` named items to the schedule. +/// +/// For `resolved`: +/// - `None`: aborted (hash without preimage) +/// - `Some(true)`: hash resolves into call if possible, plain call otherwise +/// - `Some(false)`: plain call fn fill_schedule( when: T::BlockNumber, n: u32, periodic: bool, named: bool, resolved: Option, - /* None -> aborted (hash without preimage) */ - * Some(true) -> hash resolves into call if possible, plain call otherwise - * Some(false) -> plain call */ ) -> Result<(), &'static str> { for i in 0..n { // Named schedule is strictly heavier than anonymous From 191ce6815272849ba337c2d7e67e16425cc99fb4 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 26 Nov 2021 19:05:19 +0100 Subject: [PATCH 41/58] Update frame/preimage/src/lib.rs --- frame/preimage/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index b6b8326e6e0a5..e153f0d4a8ada 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -265,8 +265,6 @@ impl Pallet { // // If `maybe_owner` is provided, we verify that it is the correct owner before clearing the // data. - // - // If `maybe_owner` is not provided, this function cannot return an error. fn do_unnote_preimage( hash: &T::Hash, maybe_check_owner: Option, From 44e35aa33929bcb09fc802f9d54fc0da69b7f0f0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Nov 2021 19:22:30 +0100 Subject: [PATCH 42/58] Fix try-runtime build --- frame/scheduler/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 212951b85017c..cf65a36bf6df1 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -668,7 +668,7 @@ impl Pallet { } #[cfg(feature = "try-runtime")] - pub fn post_migrate_to_v3() -> Result<(), &'static str> { + pub fn post_migrate_to_v3() -> Result<(), &'static str> { assert!(StorageVersion::::get() == Releases::V3); for k in Agenda::::iter_keys() { let _ = Agenda::::try_get(k)?; From 2085d9287ebc2e7a543f16e02468fe528403fb9e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Nov 2021 19:24:03 +0100 Subject: [PATCH 43/58] Fixes --- frame/scheduler/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index 9e66d72153995..4774cfe38704d 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -783,7 +783,7 @@ fn migration_to_v3_works() { ] ); - assert_eq!(StorageVersion::::get(), Releases::V2); + assert_eq!(StorageVersion::::get(), Releases::V3); }); } From 91cdb940ba95696ac9754ab3e8d98de72a4303f1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Nov 2021 19:31:37 +0100 Subject: [PATCH 44/58] Fixes --- frame/scheduler/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index cf65a36bf6df1..2e11df85eb702 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -671,7 +671,7 @@ impl Pallet { pub fn post_migrate_to_v3() -> Result<(), &'static str> { assert!(StorageVersion::::get() == Releases::V3); for k in Agenda::::iter_keys() { - let _ = Agenda::::try_get(k)?; + let _ = Agenda::::try_get(k).map_err(|()| "Invalid item in Agenda")?; } Ok(()) } From 6c7f6fb7692e915987ae356703d95cda33529c84 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 8 Dec 2021 10:45:19 +0100 Subject: [PATCH 45/58] Update frame/support/src/traits/tokens/currency.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/support/src/traits/tokens/currency.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index 8280994f20d8b..9fdb08b8bd6e9 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -200,6 +200,7 @@ pub trait Currency { ) -> SignedImbalance; } +#[cfg(feature = "std")] impl Currency for () { type Balance = u32; type PositiveImbalance = (); From 207aadc10def138ac7e056e7a06152164db19ad3 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 8 Dec 2021 10:45:38 +0100 Subject: [PATCH 46/58] Update frame/support/src/traits/tokens/currency/reservable.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/support/src/traits/tokens/currency/reservable.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/support/src/traits/tokens/currency/reservable.rs b/frame/support/src/traits/tokens/currency/reservable.rs index 9717ba25608ad..e2313a9d2550d 100644 --- a/frame/support/src/traits/tokens/currency/reservable.rs +++ b/frame/support/src/traits/tokens/currency/reservable.rs @@ -81,6 +81,7 @@ pub trait ReservableCurrency: Currency { ) -> Result; } +#[cfg(feature = "std")] impl ReservableCurrency for () { fn can_reserve(_: &AccountId, _: Self::Balance) -> bool { true From f49ee8392a458c4896e569ff164cfe125f3b4f2a Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 8 Dec 2021 10:46:16 +0100 Subject: [PATCH 47/58] Update frame/support/src/traits/tokens/imbalance.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/support/src/traits/tokens/imbalance.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/support/src/traits/tokens/imbalance.rs b/frame/support/src/traits/tokens/imbalance.rs index 60efb67324ac9..eaa18be58f617 100644 --- a/frame/support/src/traits/tokens/imbalance.rs +++ b/frame/support/src/traits/tokens/imbalance.rs @@ -178,6 +178,7 @@ pub trait Imbalance: Sized + TryDrop + Default { fn peek(&self) -> Balance; } +#[cfg(feature = "std")] impl Imbalance for () { type Opposite = (); fn zero() -> Self { From 12b65c479efe1e4fe76b8ec0df44bc868332d466 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 8 Dec 2021 11:00:53 +0100 Subject: [PATCH 48/58] Update frame/preimage/src/mock.rs Co-authored-by: Guillaume Thiolliere --- frame/preimage/src/mock.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index c67f34e71445c..7393042999cfc 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -40,9 +40,9 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Preimage: pallet_preimage::{Pallet, Call, Storage, Event}, + System: frame_system, + Balances: pallet_balances, + Preimage: pallet_preimage, } ); From d62d001fba0d2f60adb0ec14005c0c665a31c00e Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 8 Dec 2021 11:01:23 +0100 Subject: [PATCH 49/58] Update frame/scheduler/src/lib.rs Co-authored-by: Guillaume Thiolliere --- frame/scheduler/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 2e11df85eb702..cbf329bea5d22 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -362,7 +362,7 @@ pub mod pallet { let call = match s.call.as_value().cloned() { Some(c) => c, None => { - // Preimage not available - postpone until next block. + // Preimage not available - postpone until some block. total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); if let Some(delay) = T::NoPreimagePostponement::get() { let until = now.saturating_add(delay); From 0cec31815f6b0d6a2e9f34c83a5655bec2257683 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 8 Dec 2021 11:05:38 +0100 Subject: [PATCH 50/58] Update frame/preimage/src/lib.rs --- frame/preimage/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index e153f0d4a8ada..bfa1ce5263360 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -219,7 +219,7 @@ impl Pallet { (Some(RequestStatus::Unrequested(..)), _) => Err(Error::::AlreadyNoted)?, (None, None) => { StatusFor::::insert(hash, RequestStatus::Unrequested(None)); - true + false }, (None, Some(depositor)) => { let length = preimage.len() as u32; From 05411a940717f839db544f1d960507f1b9b0a570 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 8 Dec 2021 11:18:35 +0100 Subject: [PATCH 51/58] Fixes --- frame/scheduler/src/mock.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 3f014e47d8911..2f37c722b2ee7 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -22,10 +22,10 @@ use super::*; use crate as scheduler; use frame_support::{ ord_parameter_types, parameter_types, - traits::{Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, + traits::{EnsureOneOf, Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, weights::constants::RocksDbWeight, }; -use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; +use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -174,7 +174,7 @@ impl Config for Test { type PalletsOrigin = OriginCaller; type Call = Call; type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; + type ScheduleOrigin = EnsureOneOf, EnsureSignedBy>; type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; From 54faaa3fcc332ff7595dec4beb5503c0eda6f0a8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Dec 2021 13:21:18 +0100 Subject: [PATCH 52/58] Fixes --- frame/scheduler/src/lib.rs | 2 +- frame/support/src/traits/schedule.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 636b761d7fb81..b4ee2575e23d0 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -320,7 +320,7 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - StorageVersion::::put(Releases::V2); + StorageVersion::::put(Releases::V3); } } diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 3bbc4672bc63d..1cedb96cb14bb 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -49,8 +49,7 @@ pub const HARD_DEADLINE: Priority = 63; /// The lowest priority. Most stuff should be around here. pub const LOWEST_PRIORITY: Priority = 255; -/// Type representing a call. Can be either the `Call` value itself or the hash of the encoded -/// `Call`. +/// Type representing an encodable value or the hash of the encoding of such a value. #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum MaybeHashed { /// The value itself. From bbed33c877ac6d352d9224afc143317910a484bc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Dec 2021 13:21:24 +0100 Subject: [PATCH 53/58] Formatting --- frame/scheduler/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 2f37c722b2ee7..33d026f27b226 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -22,7 +22,7 @@ use super::*; use crate as scheduler; use frame_support::{ ord_parameter_types, parameter_types, - traits::{EnsureOneOf, Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, + traits::{Contains, EnsureOneOf, EqualPrivilegeOnly, OnFinalize, OnInitialize}, weights::constants::RocksDbWeight, }; use frame_system::{EnsureRoot, EnsureSignedBy}; From 051250d67f3ed90eb45f02c992cf1a297a4babb7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Dec 2021 14:01:47 +0100 Subject: [PATCH 54/58] Fixes --- frame/scheduler/src/mock.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 33d026f27b226..535e91937e4dc 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -144,6 +144,7 @@ impl system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl logger::Config for Test { type Event = Event; From f087866c5f71e50c2545c9e675d92543bcedb41f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Dec 2021 14:24:50 +0100 Subject: [PATCH 55/58] Fixes --- frame/preimage/src/mock.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index 7393042999cfc..601f72547237b 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -75,6 +75,7 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { From 01a457e4a7ae382caaf1feb878ec26e8ca8db749 Mon Sep 17 00:00:00 2001 From: Parity Bot Date: Fri, 10 Dec 2021 02:19:33 +0000 Subject: [PATCH 56/58] cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_scheduler --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/scheduler/src/weights.rs --template=./.maintain/frame-weight-template.hbs --- frame/scheduler/src/weights.rs | 195 +++++++++++++++++---------------- 1 file changed, 98 insertions(+), 97 deletions(-) diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index ae2aa388153e3..3c2ed47110b66 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -18,29 +18,22 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-11-26, STEPS: `4000`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-12-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// ../../../target/release/substrate +// target/release/substrate // benchmark -// --chain -// dev -// --steps -// 4000 -// --repeat -// 1 -// --pallet -// pallet_scheduler -// --extrinsic -// * -// --raw +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_scheduler +// --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --output -// ../../../frame/scheduler/src/weights.rs -// --template -// ../../../.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --output=./frame/scheduler/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -75,9 +68,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (17_856_000 as Weight) - // Standard Error: 249_000 - .saturating_add((23_577_000 as Weight).saturating_mul(s as Weight)) + (8_183_000 as Weight) + // Standard Error: 36_000 + .saturating_add((34_670_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -88,9 +81,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (13_722_000 as Weight) - // Standard Error: 163_000 - .saturating_add((18_304_000 as Weight).saturating_mul(s as Weight)) + (11_520_000 as Weight) + // Standard Error: 30_000 + .saturating_add((26_386_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -100,9 +93,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 795_000 - .saturating_add((21_728_000 as Weight).saturating_mul(s as Weight)) + (8_222_000 as Weight) + // Standard Error: 33_000 + .saturating_add((28_925_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -112,9 +105,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (24_527_000 as Weight) - // Standard Error: 145_000 - .saturating_add((16_666_000 as Weight).saturating_mul(s as Weight)) + (11_610_000 as Weight) + // Standard Error: 26_000 + .saturating_add((23_857_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -124,9 +117,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (5_145_000 as Weight) - // Standard Error: 695_000 - .saturating_add((8_015_000 as Weight).saturating_mul(s as Weight)) + (11_067_000 as Weight) + // Standard Error: 15_000 + .saturating_add((11_728_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -135,9 +128,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (34_707_000 as Weight) - // Standard Error: 508_000 - .saturating_add((3_312_000 as Weight).saturating_mul(s as Weight)) + (13_045_000 as Weight) + // Standard Error: 5_000 + .saturating_add((6_378_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(2 as Weight)) @@ -145,9 +138,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (25_378_000 as Weight) - // Standard Error: 296_000 - .saturating_add((11_234_000 as Weight).saturating_mul(s as Weight)) + (13_496_000 as Weight) + // Standard Error: 27_000 + .saturating_add((17_932_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -155,9 +148,9 @@ impl WeightInfo for SubstrateWeight { } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (15_518_000 as Weight) - // Standard Error: 94_000 - .saturating_add((7_771_000 as Weight).saturating_mul(s as Weight)) + (17_074_000 as Weight) + // Standard Error: 16_000 + .saturating_add((11_982_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) @@ -166,49 +159,53 @@ impl WeightInfo for SubstrateWeight { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (19_202_000 as Weight) - // Standard Error: 93_000 - .saturating_add((5_889_000 as Weight).saturating_mul(s as Weight)) + (18_730_000 as Weight) + // Standard Error: 10_000 + .saturating_add((9_909_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (17_143_000 as Weight) - // Standard Error: 76_000 - .saturating_add((4_554_000 as Weight).saturating_mul(s as Weight)) + (17_844_000 as Weight) + // Standard Error: 9_000 + .saturating_add((7_719_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) - fn schedule(_s: u32, ) -> Weight { - (19_500_000 as Weight) + fn schedule(s: u32, ) -> Weight { + (23_361_000 as Weight) + // Standard Error: 1_000 + .saturating_add((82_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (20_152_000 as Weight) - // Standard Error: 42_000 - .saturating_add((460_000 as Weight).saturating_mul(s as Weight)) + (22_359_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_219_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) - fn schedule_named(_s: u32, ) -> Weight { - (25_941_000 as Weight) + fn schedule_named(s: u32, ) -> Weight { + (28_499_000 as Weight) + // Standard Error: 1_000 + .saturating_add((98_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (21_413_000 as Weight) - // Standard Error: 32_000 - .saturating_add((429_000 as Weight).saturating_mul(s as Weight)) + (24_995_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_223_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } @@ -221,9 +218,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - (17_856_000 as Weight) - // Standard Error: 249_000 - .saturating_add((23_577_000 as Weight).saturating_mul(s as Weight)) + (8_183_000 as Weight) + // Standard Error: 36_000 + .saturating_add((34_670_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -234,9 +231,9 @@ impl WeightInfo for () { // Storage: Preimage StatusFor (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_resolved(s: u32, ) -> Weight { - (13_722_000 as Weight) - // Standard Error: 163_000 - .saturating_add((18_304_000 as Weight).saturating_mul(s as Weight)) + (11_520_000 as Weight) + // Standard Error: 30_000 + .saturating_add((26_386_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -246,9 +243,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 795_000 - .saturating_add((21_728_000 as Weight).saturating_mul(s as Weight)) + (8_222_000 as Weight) + // Standard Error: 33_000 + .saturating_add((28_925_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -258,9 +255,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) fn on_initialize_resolved(s: u32, ) -> Weight { - (24_527_000 as Weight) - // Standard Error: 145_000 - .saturating_add((16_666_000 as Weight).saturating_mul(s as Weight)) + (11_610_000 as Weight) + // Standard Error: 26_000 + .saturating_add((23_857_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -270,9 +267,9 @@ impl WeightInfo for () { // Storage: Preimage PreimageFor (r:1 w:0) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named_aborted(s: u32, ) -> Weight { - (5_145_000 as Weight) - // Standard Error: 695_000 - .saturating_add((8_015_000 as Weight).saturating_mul(s as Weight)) + (11_067_000 as Weight) + // Standard Error: 15_000 + .saturating_add((11_728_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -281,9 +278,9 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Preimage PreimageFor (r:1 w:0) fn on_initialize_aborted(s: u32, ) -> Weight { - (34_707_000 as Weight) - // Standard Error: 508_000 - .saturating_add((3_312_000 as Weight).saturating_mul(s as Weight)) + (13_045_000 as Weight) + // Standard Error: 5_000 + .saturating_add((6_378_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) @@ -291,9 +288,9 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_periodic_named(s: u32, ) -> Weight { - (25_378_000 as Weight) - // Standard Error: 296_000 - .saturating_add((11_234_000 as Weight).saturating_mul(s as Weight)) + (13_496_000 as Weight) + // Standard Error: 27_000 + .saturating_add((17_932_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -301,9 +298,9 @@ impl WeightInfo for () { } // Storage: Scheduler Agenda (r:2 w:2) fn on_initialize_periodic(s: u32, ) -> Weight { - (15_518_000 as Weight) - // Standard Error: 94_000 - .saturating_add((7_771_000 as Weight).saturating_mul(s as Weight)) + (17_074_000 as Weight) + // Standard Error: 16_000 + .saturating_add((11_982_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) @@ -312,49 +309,53 @@ impl WeightInfo for () { // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn on_initialize_named(s: u32, ) -> Weight { - (19_202_000 as Weight) - // Standard Error: 93_000 - .saturating_add((5_889_000 as Weight).saturating_mul(s as Weight)) + (18_730_000 as Weight) + // Standard Error: 10_000 + .saturating_add((9_909_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } // Storage: Scheduler Agenda (r:1 w:1) fn on_initialize(s: u32, ) -> Weight { - (17_143_000 as Weight) - // Standard Error: 76_000 - .saturating_add((4_554_000 as Weight).saturating_mul(s as Weight)) + (17_844_000 as Weight) + // Standard Error: 9_000 + .saturating_add((7_719_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) - fn schedule(_s: u32, ) -> Weight { - (19_500_000 as Weight) + fn schedule(s: u32, ) -> Weight { + (23_361_000 as Weight) + // Standard Error: 1_000 + .saturating_add((82_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) fn cancel(s: u32, ) -> Weight { - (20_152_000 as Weight) - // Standard Error: 42_000 - .saturating_add((460_000 as Weight).saturating_mul(s as Weight)) + (22_359_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_219_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) - fn schedule_named(_s: u32, ) -> Weight { - (25_941_000 as Weight) + fn schedule_named(s: u32, ) -> Weight { + (28_499_000 as Weight) + // Standard Error: 1_000 + .saturating_add((98_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) fn cancel_named(s: u32, ) -> Weight { - (21_413_000 as Weight) - // Standard Error: 32_000 - .saturating_add((429_000 as Weight).saturating_mul(s as Weight)) + (24_995_000 as Weight) + // Standard Error: 2_000 + .saturating_add((1_223_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } From 2f8cc41289f570bdc325cd92e8533dca763965a7 Mon Sep 17 00:00:00 2001 From: Parity Bot Date: Fri, 10 Dec 2021 02:24:49 +0000 Subject: [PATCH 57/58] cargo run --quiet --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_preimage --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/preimage/src/weights.rs --template=./.maintain/frame-weight-template.hbs --- frame/preimage/src/weights.rs | 79 ++++++++++++++++------------------- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index f5fc74d1b1b50..406ca99bfb791 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -18,29 +18,22 @@ //! Autogenerated weights for pallet_preimage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-11-25, STEPS: `10`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-12-10, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// ../../../target/release/substrate +// target/release/substrate // benchmark -// --chain -// dev -// --steps -// 10 -// --repeat -// 10 -// --pallet -// pallet_preimage -// --extrinsic -// * -// --raw +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_preimage +// --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --output -// ../../../frame/preimage/src/weights.rs -// --template -// ../../../.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --output=./frame/preimage/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -73,16 +66,16 @@ impl WeightInfo for SubstrateWeight { fn note_preimage(s: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_requested_preimage(s: u32, ) -> Weight { - (10_356_000 as Weight) + (0 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -91,65 +84,65 @@ impl WeightInfo for SubstrateWeight { fn note_no_deposit_preimage(s: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (33_000_000 as Weight) + (60_560_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (19_000_000 as Weight) + (37_575_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (29_000_000 as Weight) + (56_868_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (18_000_000 as Weight) + (37_058_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (13_000_000 as Weight) + (21_500_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (4_000_000 as Weight) + (7_798_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (20_000_000 as Weight) + (37_771_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (14_000_000 as Weight) + (22_913_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (4_000_000 as Weight) + (7_608_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } @@ -162,16 +155,16 @@ impl WeightInfo for () { fn note_preimage(s: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:0) fn note_requested_preimage(s: u32, ) -> Weight { - (10_356_000 as Weight) + (0 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } @@ -180,65 +173,65 @@ impl WeightInfo for () { fn note_no_deposit_preimage(s: u32, ) -> Weight { (0 as Weight) // Standard Error: 0 - .saturating_add((1_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - (33_000_000 as Weight) + (60_560_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - (19_000_000 as Weight) + (37_575_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - (29_000_000 as Weight) + (56_868_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - (18_000_000 as Weight) + (37_058_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - (13_000_000 as Weight) + (21_500_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - (4_000_000 as Weight) + (7_798_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - (20_000_000 as Weight) + (37_771_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - (14_000_000 as Weight) + (22_913_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - (4_000_000 as Weight) + (7_608_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } From 582a473382abebef3bd813ce825e4accd25c2b1a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Dec 2021 15:21:13 +0100 Subject: [PATCH 58/58] Fixes --- frame/preimage/Cargo.toml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index b9571bbff77f6..b60c3fa854871 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -13,17 +13,16 @@ readme = "README.md" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } scale-info = { version = "1.0", default-features = false, features = ["derive"] } -sp-std = { version = "4.0.0-dev", default-features = false, path = "../../primitives/std" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "4.0.0-dev", default-features = false, path = "../../primitives/io" } -sp-core = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../primitives/core" } +sp-core = { version = "4.1.0-dev", default-features = false, optional = true, path = "../../primitives/core" } sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../primitives/runtime" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] -sp-core = { version = "4.0.0-dev", path = "../../primitives/core", default-features = false } - +sp-core = { version = "4.1.0-dev", path = "../../primitives/core", default-features = false } pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features]