git.delta.rocks / unique-network / refs/commits / 0f7bb4adb180

difftreelog

Merge pull request #341 from UniqueNetwork/feature/simple-scheduler

kozyrevdev2022-06-03parents: #93f5452 #9e5b125.patch.diff
in: master
Feature/simple scheduler

11 files changed

modifiedpallets/scheduler/Cargo.tomldiffbeforeafterboth
20sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" }21sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" }
21sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" }22sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" }
22sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" }23sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" }
24sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.22' }
23frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" }25frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" }
2426
25up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.22" }27up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.22" }
40 "up-sponsorship/std",42 "up-sponsorship/std",
41 "sp-io/std",43 "sp-io/std",
42 "sp-std/std",44 "sp-std/std",
45 "sp-core/std",
43 "log/std",46 "log/std",
44]47]
45runtime-benchmarks = [48runtime-benchmarks = [
modifiedpallets/scheduler/src/lib.rsdiffbeforeafterboth
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
2// This file is part of Unique Network.
3
4// Unique Network is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Unique Network is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
16
17// Original license
18// This file is part of Substrate.1// This file is part of Substrate.
192
20// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd.3// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
21// SPDX-License-Identifier: Apache-2.04// SPDX-License-Identifier: Apache-2.0
225
23// Licensed under the Apache License, Version 2.0 (the "License");6// Licensed under the Apache License, Version 2.0 (the "License");
32// See the License for the specific language governing permissions and15// See the License for the specific language governing permissions and
33// limitations under the License.16// limitations under the License.
3417
35//! # Scheduler18//! # Schedulerdo_reschedule
36//! A module for scheduling dispatches.
37//!19//!
38//! - [`Config`]20//! This Pallet exposes capabilities for scheduling dispatches to occur at a
39//! - [`Call`]
40//! - [`Module`]
41//!
42//! ## Overview
43//!
44//! This module exposes capabilities for scheduling dispatches to occur at a
45//! specified block number or at a specified period. These scheduled dispatches21//! specified block number or at a specified period. These scheduled dispatches
46//! may be named or anonymous and may be canceled.22//! may be named or anonymous and may be canceled.
47//!23//!
57//!33//!
58//! ### Dispatchable Functions34//! ### Dispatchable Functions
59//!35//!
60//! * `schedule` - schedule a dispatch, which may be periodic, to occur at a36//! * `schedule` - schedule a dispatch, which may be periodic, to occur at a specified block and
61//! specified block and with a specified priority.37//! with a specified priority.
62//! * `cancel` - cancel a scheduled dispatch, specified by block number and38//! * `cancel` - cancel a scheduled dispatch, specified by block number and index.
63//! index.
64//! * `schedule_named` - augments the `schedule` interface with an additional39//! * `schedule_named` - augments the `schedule` interface with an additional `Vec<u8>` parameter
65//! `Vec<u8>` parameter that can be used for identification.40//! that can be used for identification.
66//! * `cancel_named` - the named complement to the cancel function.41//! * `cancel_named` - the named complement to the cancel function.
6742
68// Ensure we're `no_std` when compiling for Wasm.43// Ensure we're `no_std` when compiling for Wasm.
69#![cfg_attr(not(feature = "std"), no_std)]44#![cfg_attr(not(feature = "std"), no_std)]
70#![allow(clippy::type_complexity, clippy::boxed_local, clippy::unused_unit)]
7145
46#[cfg(feature = "runtime-benchmarks")]
72mod benchmarking;47mod benchmarking;
48
73pub mod weights;49pub mod weights;
7450
75use sp_std::{prelude::*, marker::PhantomData, borrow::Borrow};51use sp_core::H160;
52use codec::{Codec, Decode, Encode};
76use codec::{Encode, Decode, Codec};53use frame_system::{self as system, ensure_signed};
54pub use pallet::*;
55use scale_info::TypeInfo;
77use sp_runtime::{56use sp_runtime::{
78 RuntimeDebug,57 traits::{BadOrigin, One, Saturating, Zero},
79 traits::{Zero, One, BadOrigin, Saturating},58 RuntimeDebug, DispatchErrorWithPostInfo,
80};59};
60use sp_std::{borrow::Borrow, cmp::Ordering, marker::PhantomData, prelude::*};
61
81use frame_support::{62use frame_support::{
82 decl_module, decl_storage, decl_event, decl_error,63 dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter},
83 dispatch::{Dispatchable, DispatchError, DispatchResult, Parameter},
84 traits::{64 traits::{
85 Get,65 schedule::{self, DispatchTime, MaybeHashed},
86 schedule::{self, DispatchTime},
87 OriginTrait, EnsureOrigin, IsType,66 NamedReservableCurrency, EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp,
67 StorageVersion,
88 },68 },
89 weights::{GetDispatchInfo, Weight},69 weights::{GetDispatchInfo, Weight},
90};70};
91use frame_system::{self as system, ensure_signed};71
92pub use weights::WeightInfo;72pub use weights::WeightInfo;
93use up_sponsorship::SponsorshipHandler;
94use scale_info::TypeInfo;
9573
96/// Our pallet's configuration trait. All our types and constants go in here. If the
97/// pallet is dependent on specific other pallets, then their configuration traits
98/// should be added to our implied traits list.
99///
100/// `system::Config` should always be included in our implied traits.
101/// //
102pub trait Config: system::Config {
103 /// The overarching event type.
104 type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;
105
106 /// The aggregated origin which the dispatch will take.
107 type Origin: OriginTrait<PalletsOrigin = Self::PalletsOrigin>
108 + From<Self::PalletsOrigin>
109 + IsType<<Self as system::Config>::Origin>;
110
111 /// The caller origin, overarching type of all pallets origins.
112 type PalletsOrigin: From<system::RawOrigin<Self::AccountId>> + Codec + TypeInfo + Clone + Eq;
113
114 /// The aggregated call type.
115 type Call: Parameter
116 + Dispatchable<Origin = <Self as Config>::Origin>
117 + GetDispatchInfo
118 + From<system::Call<Self>>;
119
120 /// The maximum weight that may be scheduled per block for any dispatchables of less priority
121 /// than `schedule::HARD_DEADLINE`.
122 type MaximumWeight: Get<Weight>;
123
124 /// Required origin to schedule or cancel calls.
125 type ScheduleOrigin: EnsureOrigin<<Self as system::Config>::Origin>;
126
127 /// The maximum number of scheduled calls in the queue for a single block.
128 /// Not strictly enforced, but used for weight estimation.
129 type MaxScheduledPerBlock: Get<u32>;
130
131 /// Sponsoring function
132 type SponsorshipHandler: SponsorshipHandler<Self::AccountId, <Self as Config>::Call>;
133
134 /// Weight information for extrinsics in this pallet.
135 type WeightInfo: WeightInfo;
136}
137
138// pub type SelfWeightInfo<T> = <T as system::Config>::WeightInfo;
139
140/// Just a simple index for naming period tasks.74/// Just a simple index for naming period tasks.
141pub type PeriodicIndex = u32;75pub type PeriodicIndex = u32;
142/// The location of a scheduled task that can be used to remove it.76/// The location of a scheduled task that can be used to remove it.
143pub type TaskAddress<BlockNumber> = (BlockNumber, u32);77pub type TaskAddress<BlockNumber> = (BlockNumber, u32);
78pub const MAX_TASK_ID_LENGTH_IN_BYTES: u8 = 16;
14479
145#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]80type ScheduledId = [u8; MAX_TASK_ID_LENGTH_IN_BYTES as usize];
146#[derive(Clone, RuntimeDebug, Encode, Decode)]
147struct ScheduledV1<Call, BlockNumber> {81pub type CallOrHashOf<T> = MaybeHashed<<T as Config>::Call, <T as frame_system::Config>::Hash>;
148 maybe_id: Option<Vec<u8>>,
149 priority: schedule::Priority,
150 call: Call,
151 maybe_periodic: Option<schedule::Period<BlockNumber>>,
152}
15382
154/// Information regarding an item to be executed in the future.83/// Information regarding an item to be executed in the future.
155#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]84#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]
156#[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo)]85#[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo)]
157pub struct ScheduledV2<Call, BlockNumber, PalletsOrigin, AccountId> {86pub struct ScheduledV3<Call, BlockNumber, PalletsOrigin, AccountId> {
158 /// The unique identity for this task, if there is one.87 /// The unique identity for this task, if there is one.
159 maybe_id: Option<Vec<u8>>,88 maybe_id: Option<ScheduledId>,
160 /// This task's priority.89 /// This task's priority.
161 priority: schedule::Priority,90 priority: schedule::Priority,
162 /// The call to be dispatched.91 /// The call to be dispatched.
168 _phantom: PhantomData<AccountId>,97 _phantom: PhantomData<AccountId>,
169}98}
17099
100pub type ScheduledV3Of<T> = ScheduledV3<
101 CallOrHashOf<T>,
102 <T as frame_system::Config>::BlockNumber,
103 <T as Config>::PalletsOrigin,
104 <T as frame_system::Config>::AccountId,
105>;
106
107pub type ScheduledOf<T> = ScheduledV3Of<T>;
108
171/// The current version of Scheduled struct.109/// The current version of Scheduled struct.
172pub type Scheduled<Call, BlockNumber, PalletsOrigin, AccountId> =110pub type Scheduled<Call, BlockNumber, PalletsOrigin, AccountId> =
173 ScheduledV2<Call, BlockNumber, PalletsOrigin, AccountId>;111 ScheduledV3<Call, BlockNumber, PalletsOrigin, AccountId>;
174112
175// A value placed in storage that represents the current version of the Scheduler storage.113#[cfg(feature = "runtime-benchmarks")]
176// This value is used by the `on_runtime_upgrade` logic to determine whether we run114mod preimage_provider {
177// storage migration logic.115 use frame_support::traits::PreimageRecipient;
178#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]116 pub trait PreimageProviderAndMaybeRecipient<H>: PreimageRecipient<H> {}
179enum Releases {117 impl<H, T: PreimageRecipient<H>> PreimageProviderAndMaybeRecipient<H> for T {}
180 V1,
181 V2,
182}118}
183119
184impl Default for Releases {120#[cfg(not(feature = "runtime-benchmarks"))]
121mod preimage_provider {
185 fn default() -> Self {122 use frame_support::traits::PreimageProvider;
123 pub trait PreimageProviderAndMaybeRecipient<H>: PreimageProvider<H> {}
186 Releases::V1124 impl<H, T: PreimageProvider<H>> PreimageProviderAndMaybeRecipient<H> for T {}
187 }
188}125}
189126
127pub use preimage_provider::PreimageProviderAndMaybeRecipient;
128
190#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]129pub(crate) trait MarginalWeightInfo: WeightInfo {
130 fn item(periodic: bool, named: bool, resolved: Option<bool>) -> Weight {
131 match (periodic, named, resolved) {
132 (_, false, None) => Self::on_initialize_aborted(2) - Self::on_initialize_aborted(1),
191pub struct CallSpec {133 (_, true, None) => {
192 module: u32,134 Self::on_initialize_named_aborted(2) - Self::on_initialize_named_aborted(1)
135 }
136 (false, false, Some(false)) => Self::on_initialize(2) - Self::on_initialize(1),
193 method: u32,137 (false, true, Some(false)) => {
138 Self::on_initialize_named(2) - Self::on_initialize_named(1)
139 }
140 (true, false, Some(false)) => {
141 Self::on_initialize_periodic(2) - Self::on_initialize_periodic(1)
142 }
143 (true, true, Some(false)) => {
144 Self::on_initialize_periodic_named(2) - Self::on_initialize_periodic_named(1)
145 }
146 (false, false, Some(true)) => {
147 Self::on_initialize_resolved(2) - Self::on_initialize_resolved(1)
148 }
149 (false, true, Some(true)) => {
150 Self::on_initialize_named_resolved(2) - Self::on_initialize_named_resolved(1)
151 }
152 (true, false, Some(true)) => {
153 Self::on_initialize_periodic_resolved(2) - Self::on_initialize_periodic_resolved(1)
154 }
155 (true, true, Some(true)) => {
156 Self::on_initialize_periodic_named_resolved(2)
157 - Self::on_initialize_periodic_named_resolved(1)
158 }
159 }
160 }
194}161}
162impl<T: WeightInfo> MarginalWeightInfo for T {}
195163
164#[frame_support::pallet]
196decl_storage! {165pub mod pallet {
197 trait Store for Module<T: Config> as Scheduler {166 use super::*;
167 use frame_support::{
198 /// Items to be executed, indexed by the block number that they should be executed on.168 dispatch::PostDispatchInfo,
199 pub Agenda: map hasher(twox_64_concat) T::BlockNumber169 pallet_prelude::*,
200 => Vec<Option<Scheduled<<T as Config>::Call, T::BlockNumber, T::PalletsOrigin, T::AccountId>>>;170 traits::{schedule::LookupError, PreimageProvider},
171 };
172 use frame_system::pallet_prelude::*;
201173
202 pub SpecAgenda: map hasher(twox_64_concat) T::BlockNumber174 /// The current storage version.
203 => Vec<Option<CallSpec>>;175 const STORAGE_VERSION: StorageVersion = StorageVersion::new(3);
204176
205 /// Lookup from identity to the block number and index of the task.177 #[pallet::pallet]
178 #[pallet::generate_store(pub(super) trait Store)]
206 Lookup: map hasher(twox_64_concat) Vec<u8> => Option<TaskAddress<T::BlockNumber>>;179 #[pallet::storage_version(STORAGE_VERSION)]
180 #[pallet::without_storage_info]
181 pub struct Pallet<T>(_);
207182
208 /// Storage version of the pallet.183 /// `system::Config` should always be included in our implied traits.
184 #[pallet::config]
185 pub trait Config: frame_system::Config {
186 /// The overarching event type.
187 type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
188
189 /// The aggregated origin which the dispatch will take.
190 type Origin: OriginTrait<PalletsOrigin = Self::PalletsOrigin>
191 + From<Self::PalletsOrigin>
192 + IsType<<Self as system::Config>::Origin>;
193
194 /// The caller origin, overarching type of all pallets origins.
195 type PalletsOrigin: From<system::RawOrigin<Self::AccountId>> + Codec + Clone + Eq + TypeInfo;
196
197 type Currency: NamedReservableCurrency<Self::AccountId, ReserveIdentifier = ScheduledId>;
198
199 /// The aggregated call type.
200 type Call: Parameter
201 + Dispatchable<Origin = <Self as Config>::Origin, PostInfo = PostDispatchInfo>
202 + GetDispatchInfo
203 + From<system::Call<Self>>;
204
205 /// The maximum weight that may be scheduled per block for any dispatchables of less
206 /// priority than `schedule::HARD_DEADLINE`.
207 #[pallet::constant]
208 type MaximumWeight: Get<Weight>;
209
210 /// Required origin to schedule or cancel calls.
211 type ScheduleOrigin: EnsureOrigin<<Self as system::Config>::Origin>;
212
213 /// Compare the privileges of origins.
209 ///214 ///
210 /// New networks start with last version.215 /// This will be used when canceling a task, to ensure that the origin that tries
216 /// to cancel has greater or equal privileges as the origin that created the scheduled task.
211 StorageVersion build(|_| Releases::V2): Releases;217 ///
218 /// For simplicity the [`EqualPrivilegeOnly`](frame_support::traits::EqualPrivilegeOnly) can
219 /// be used. This will only check if two given origins are equal.
220 type OriginPrivilegeCmp: PrivilegeCmp<Self::PalletsOrigin>;
221
222 /// The maximum number of scheduled calls in the queue for a single block.
223 /// Not strictly enforced, but used for weight estimation.
224 #[pallet::constant]
225 type MaxScheduledPerBlock: Get<u32>;
226
227 /// Weight information for extrinsics in this pallet.
228 type WeightInfo: WeightInfo;
229
230 /// The preimage provider with which we look up call hashes to get the call.
231 type PreimageProvider: PreimageProviderAndMaybeRecipient<Self::Hash>;
232
233 /// If `Some` then the number of blocks to postpone execution for when the item is delayed.
234 type NoPreimagePostponement: Get<Option<Self::BlockNumber>>;
235
236 /// Sponsoring function.
237 // type SponsorshipHandler: SponsorshipHandler<Self::AccountId, <Self as Config>::Call>;
238
239 /// The helper type used for custom transaction fee logic.
240 type CallExecutor: DispatchCall<Self, H160>;
212 }241 }
213}
214242
215decl_event!(243 /// A Scheduler-Runtime interface for finer payment handling.
216 pub enum Event<T> where <T as system::Config>::BlockNumber {244 pub trait DispatchCall<T: frame_system::Config + Config, SelfContainedSignedInfo> {
245 fn reserve_balance(
246 id: ScheduledId,
247 sponsor: <T as frame_system::Config>::AccountId,
217 /// Scheduled some task. \[when, index\]248 call: <T as Config>::Call,
249 count: u32,
250 ) -> Result<(), DispatchError>;
251
218 Scheduled(BlockNumber, u32),252 fn pay_for_call(
253 id: ScheduledId,
254 sponsor: <T as frame_system::Config>::AccountId,
255 call: <T as Config>::Call,
256 ) -> Result<u128, DispatchError>;
257
219 /// Canceled some task. \[when, index\]258 /// Resolve the call dispatch, including any post-dispatch operations.
220 Canceled(BlockNumber, u32),259 fn dispatch_call(
260 signer: T::AccountId,
221 /// Dispatched some task. \[task, id, result\]261 function: <T as Config>::Call,
262 ) -> Result<
222 Dispatched(TaskAddress<BlockNumber>, Option<Vec<u8>>, DispatchResult),263 Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,
264 TransactionValidityError,
265 >;
266
267 fn cancel_reserve(
268 id: ScheduledId,
269 sponsor: <T as frame_system::Config>::AccountId,
270 ) -> Result<u128, DispatchError>;
223 }271 }
224);
225272
226decl_error! {273 /// Items to be executed, indexed by the block number that they should be executed on.
227 pub enum Error for Module<T: Config> {274 #[pallet::storage]
275 pub type Agenda<T: Config> =
276 StorageMap<_, Twox64Concat, T::BlockNumber, Vec<Option<ScheduledV3Of<T>>>, ValueQuery>;
277
278 /// Lookup from identity to the block number and index of the task.
279 #[pallet::storage]
280 pub(crate) type Lookup<T: Config> =
281 StorageMap<_, Twox64Concat, ScheduledId, TaskAddress<T::BlockNumber>>;
282
283 /// Events type.
284 #[pallet::event]
285 #[pallet::generate_deposit(pub(super) fn deposit_event)]
286 pub enum Event<T: Config> {
287 /// Scheduled some task.
288 Scheduled { when: T::BlockNumber, index: u32 },
289 /// Canceled some task.
290 Canceled { when: T::BlockNumber, index: u32 },
291 /// Dispatched some task.
292 Dispatched {
293 task: TaskAddress<T::BlockNumber>,
294 id: Option<ScheduledId>,
295 result: DispatchResult,
296 },
297 /// The call for the provided hash was not found so the task has been aborted.
298 CallLookupFailed {
299 task: TaskAddress<T::BlockNumber>,
300 id: Option<ScheduledId>,
301 error: LookupError,
302 },
303 }
304
305 #[pallet::error]
306 pub enum Error<T> {
228 /// Failed to schedule a call307 /// Failed to schedule a call
229 FailedToSchedule,308 FailedToSchedule,
230 /// Cannot find the scheduled call.309 /// Cannot find the scheduled call.
234 /// Reschedule failed because it does not change scheduled time.313 /// Reschedule failed because it does not change scheduled time.
235 RescheduleNoChange,314 RescheduleNoChange,
236 }315 }
237}
238316
239decl_module! {
240 /// Scheduler module declaration.317 #[pallet::hooks]
241 pub struct Module<T: Config> for enum Call318 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
242 where319 /// Execute the scheduled calls
243 origin: <T as system::Config>::Origin320 fn on_initialize(now: T::BlockNumber) -> Weight {
244 {
245 type Error = Error<T>;321 let limit = T::MaximumWeight::get();
246 fn deposit_event() = default;
247322
323 let mut queued = Agenda::<T>::take(now)
324 .into_iter()
325 .enumerate()
326 .filter_map(|(index, s)| Some((index as u32, s?)))
327 .collect::<Vec<_>>();
248328
249 /// Anonymously schedule a task.329 if queued.len() as u32 > T::MaxScheduledPerBlock::get() {
250 ///
251 /// # <weight>
252 /// - S = Number of already scheduled calls
253 /// - Base Weight: 22.29 + .126 * S µs
254 /// - DB Weight:
255 /// - Read: Agenda
256 /// - Write: Agenda
257 /// - Will use base weight of 25 which should be good for up to 30 scheduled calls
258 /// # </weight>
259 #[weight = <T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get())]
260 fn schedule(origin,
261 when: T::BlockNumber,330 log::warn!(
262 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,331 target: "runtime::scheduler",
263 priority: schedule::Priority,
264 call: Box<<T as Config>::Call>,332 "Warning: This block has more items queued in Scheduler than \
265 )333 expected from the runtime configuration. An update might be needed."
266 {
267 let origin = <T as Config>::Origin::from(origin);
268 Self::do_schedule(DispatchTime::At(when), maybe_periodic, priority, origin.caller().clone(), *call)?;334 );
269 }335 }
270336
271 /// Cancel an anonymously scheduled task.337 queued.sort_by_key(|(_, s)| s.priority);
272 ///338
273 /// # <weight>339 let next = now + One::one();
274 /// - S = Number of already scheduled calls340
275 /// - Base Weight: 22.15 + 2.869 * S µs341 let mut total_weight: Weight = T::WeightInfo::on_initialize(0);
276 /// - DB Weight:342 for (order, (index, mut s)) in queued.into_iter().enumerate() {
277 /// - Read: Agenda343 let named = if let Some(ref id) = s.maybe_id {
278 /// - Write: Agenda, Lookup344 Lookup::<T>::remove(id);
279 /// - Will use base weight of 100 which should be good for up to 30 scheduled calls345 true
280 /// # </weight>346 } else {
281 #[weight = <T as Config>::WeightInfo::cancel(T::MaxScheduledPerBlock::get())]347 false
282 fn cancel(origin, when: T::BlockNumber, index: u32) {348 };
283 T::ScheduleOrigin::ensure_origin(origin.clone())?;349
284 let origin = <T as Config>::Origin::from(origin);350 let (call, maybe_completed) = s.call.resolved::<T::PreimageProvider>();
285 Self::do_cancel(Some(origin.caller().clone()), (when, index))?;351 s.call = call;
352
353 let resolved = if let Some(completed) = maybe_completed {
354 T::PreimageProvider::unrequest_preimage(&completed);
355 true
356 } else {
357 false
358 };
359 let call = match s.call.as_value().cloned() {
360 Some(c) => c,
361 None => {
362 // Preimage not available - postpone until some block.
363 total_weight.saturating_accrue(T::WeightInfo::item(false, named, None));
364 if let Some(delay) = T::NoPreimagePostponement::get() {
365 let until = now.saturating_add(delay);
366 if let Some(ref id) = s.maybe_id {
367 let index = Agenda::<T>::decode_len(until).unwrap_or(0);
368 Lookup::<T>::insert(id, (until, index as u32));
369 }
370 Agenda::<T>::append(until, Some(s));
371 }
372 continue;
373 }
374 };
375
376 let periodic = s.maybe_periodic.is_some();
377 let call_weight = call.get_dispatch_info().weight;
378 let mut item_weight = T::WeightInfo::item(periodic, named, Some(resolved));
379 let origin =
380 <<T as Config>::Origin as From<T::PalletsOrigin>>::from(s.origin.clone())
381 .into();
382 if ensure_signed(origin).is_ok() {
383 // Weights of Signed dispatches expect their signing account to be whitelisted.
384 item_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
385 }
386
387 // We allow a scheduled call if any is true:
388 // - It's priority is `HARD_DEADLINE`
389 // - It does not push the weight past the limit.
390 // - It is the first item in the schedule
391 let hard_deadline = s.priority <= schedule::HARD_DEADLINE;
392 let test_weight = total_weight
393 .saturating_add(call_weight)
394 .saturating_add(item_weight);
395 if !hard_deadline && order > 0 && test_weight > limit {
396 // Cannot be scheduled this block - postpone until next.
397 total_weight.saturating_accrue(T::WeightInfo::item(false, named, None));
398 if let Some(ref id) = s.maybe_id {
399 // NOTE: We could reasonably not do this (in which case there would be one
400 // block where the named and delayed item could not be referenced by name),
401 // but we will do it anyway since it should be mostly free in terms of
402 // weight and it is slightly cleaner.
403 let index = Agenda::<T>::decode_len(next).unwrap_or(0);
404 Lookup::<T>::insert(id, (next, index as u32));
405 }
406 Agenda::<T>::append(next, Some(s));
407 continue;
408 }
409
410 let sender = ensure_signed(
411 <<T as Config>::Origin as From<T::PalletsOrigin>>::from(s.origin.clone())
412 .into(),
413 )
414 .unwrap();
415
416 // // if call have id it was be reserved
417 // if s.maybe_id.is_some() {
418 // let _ = T::CallExecutor::pay_for_call(
419 // s.maybe_id.unwrap(),
420 // sender.clone(),
421 // call.clone(),
422 // );
423 // }
424
425 let r = T::CallExecutor::dispatch_call(sender, call.clone());
426
427 let mut actual_call_weight: Weight = item_weight;
428 let result: Result<_, DispatchError> = match r {
429 Ok(o) => match o {
430 Ok(di) => {
431 actual_call_weight = di.actual_weight.unwrap_or(item_weight);
432 Ok(())
433 }
434 Err(err) => Err(err.error),
435 },
436 Err(_) => {
437 log::error!(
438 target: "runtime::scheduler",
439 "Warning: Scheduler has failed to execute a post-dispatch transaction. \
440 This block might have become invalid.");
441 Err(DispatchError::CannotLookup)
442 } // todo possibly force a skip/return here, do something with the error
443 };
444
445 total_weight.saturating_accrue(item_weight);
446 total_weight.saturating_accrue(actual_call_weight);
447
448 Self::deposit_event(Event::Dispatched {
449 task: (now, index),
450 id: s.maybe_id.clone(),
451 result,
452 });
453
454 if let &Some((period, count)) = &s.maybe_periodic {
455 if count > 1 {
456 s.maybe_periodic = Some((period, count - 1));
457 } else {
458 s.maybe_periodic = None;
459 }
460 let wake = now + period;
461 // If scheduled is named, place its information in `Lookup`
462 if let Some(ref id) = s.maybe_id {
463 let wake_index = Agenda::<T>::decode_len(wake).unwrap_or(0);
464 Lookup::<T>::insert(id, (wake, wake_index as u32));
465 }
466 Agenda::<T>::append(wake, Some(s));
467 }
468 }
469 0
470 //total_weight
286 }471 }
472 }
287473
474 #[pallet::call]
475 impl<T: Config> Pallet<T> {
288 /// Schedule a named task.476 /// Schedule a named task.
289 ///477 #[pallet::weight(<T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))]
290 /// # <weight>
291 /// - S = Number of already scheduled calls
292 /// - Base Weight: 29.6 + .159 * S µs
293 /// - DB Weight:
294 /// - Read: Agenda, Lookup
295 /// - Write: Agenda, Lookup
296 /// - Will use base weight of 35 which should be good for more than 30 scheduled calls
297 /// # </weight>
298 #[weight = <T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get())]
299 fn schedule_named(origin,478 pub fn schedule_named(
479 origin: OriginFor<T>,
300 id: Vec<u8>,480 id: ScheduledId,
301 when: T::BlockNumber,481 when: T::BlockNumber,
302 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,482 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
303 priority: schedule::Priority,483 priority: schedule::Priority,
304 call: Box<<T as Config>::Call>,484 call: Box<CallOrHashOf<T>>,
305 ) {485 ) -> DispatchResult {
306 T::ScheduleOrigin::ensure_origin(origin.clone())?;486 T::ScheduleOrigin::ensure_origin(origin.clone())?;
307 let origin = <T as Config>::Origin::from(origin);487 let origin = <T as Config>::Origin::from(origin);
308 Self::do_schedule_named(488 Self::do_schedule_named(
309 id, DispatchTime::At(when), maybe_periodic, priority, origin.caller().clone(), *call489 id,
490 DispatchTime::At(when),
491 maybe_periodic,
492 priority,
493 origin.caller().clone(),
494 *call,
310 )?;495 )?;
496 Ok(())
311 }497 }
312498
313 /// Cancel a named scheduled task.499 /// Cancel a named scheduled task.
314 ///500 #[pallet::weight(<T as Config>::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))]
315 /// # <weight>
316 /// - S = Number of already scheduled calls
317 /// - Base Weight: 24.91 + 2.907 * S µs
318 /// - DB Weight:
319 /// - Read: Agenda, Lookup
320 /// - Write: Agenda, Lookup
321 /// - Will use base weight of 100 which should be good for up to 30 scheduled calls
322 /// # </weight>
323 #[weight = <T as Config>::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get())]
324 fn cancel_named(origin, id: Vec<u8>) {501 pub fn cancel_named(origin: OriginFor<T>, id: ScheduledId) -> DispatchResult {
325 T::ScheduleOrigin::ensure_origin(origin.clone())?;502 T::ScheduleOrigin::ensure_origin(origin.clone())?;
326 let origin = <T as Config>::Origin::from(origin);503 let origin = <T as Config>::Origin::from(origin);
327 Self::do_cancel_named(Some(origin.caller().clone()), id)?;504 Self::do_cancel_named(Some(origin.caller().clone()), id)?;
505 Ok(())
328 }506 }
329507
330 /// Anonymously schedule a task after a delay.
331 ///
332 /// # <weight>
333 /// Same as [`schedule`].
334 /// # </weight>
335 #[weight = <T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get())]
336 fn schedule_after(origin,
337 after: T::BlockNumber,
338 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
339 priority: schedule::Priority,
340 call: Box<<T as Config>::Call>,
341 ) {
342 T::ScheduleOrigin::ensure_origin(origin.clone())?;
343 let origin = <T as Config>::Origin::from(origin);
344 Self::do_schedule(
345 DispatchTime::After(after), maybe_periodic, priority, origin.caller().clone(), *call
346 )?;
347 }
348
349 /// Schedule a named task after a delay.508 /// Schedule a named task after a delay.
350 ///509 ///
351 /// # <weight>510 /// # <weight>
352 /// Same as [`schedule_named`].511 /// Same as [`schedule_named`](Self::schedule_named).
353 /// # </weight>512 /// # </weight>
354 #[weight = <T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get())]513 #[pallet::weight(<T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))]
355 fn schedule_named_after(origin,514 pub fn schedule_named_after(
515 origin: OriginFor<T>,
356 id: Vec<u8>,516 id: ScheduledId,
357 after: T::BlockNumber,517 after: T::BlockNumber,
358 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,518 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
359 priority: schedule::Priority,519 priority: schedule::Priority,
360 call: Box<<T as Config>::Call>,520 call: Box<CallOrHashOf<T>>,
361 ) {521 ) -> DispatchResult {
362 T::ScheduleOrigin::ensure_origin(origin.clone())?;522 T::ScheduleOrigin::ensure_origin(origin.clone())?;
363 let origin = <T as Config>::Origin::from(origin);523 let origin = <T as Config>::Origin::from(origin);
364 Self::do_schedule_named(524 Self::do_schedule_named(
365 id, DispatchTime::After(after), maybe_periodic, priority, origin.caller().clone(), *call525 id,
526 DispatchTime::After(after),
527 maybe_periodic,
528 priority,
529 origin.caller().clone(),
530 *call,
366 )?;531 )?;
532 Ok(())
367 }533 }
534 }
535}
368536
369 /// Execute the scheduled calls
370 ///
371 /// # <weight>537impl<T: Config> Pallet<T> {
372 /// - S = Number of already scheduled calls
373 /// - N = Named scheduled calls
374 /// - P = Periodic Calls
375 /// - Base Weight: 9.243 + 23.45 * S µs
376 /// - DB Weight:
377 /// - Read: Agenda + Lookup * N + Agenda(Future) * P
378 /// - Write: Agenda + Lookup * N + Agenda(future) * P
379 /// # </weight>
380 fn on_initialize(now: T::BlockNumber) -> Weight {
381 let limit = T::MaximumWeight::get();
382 let mut queued = Agenda::<T>::take(now).into_iter()
383 .enumerate()
384 .filter_map(|(index, s)| s.map(|inner| (index as u32, inner)))
385 .collect::<Vec<_>>();
386 if queued.len() as u32 > T::MaxScheduledPerBlock::get() {
387 log::warn!(538 #[cfg(feature = "try-runtime")]
388 target: "runtime::scheduler",
389 "Warning: This block has more items queued in Scheduler than \
390 expected from the runtime configuration. An update might be needed."
391 );
392 }539 pub fn pre_migrate_to_v3() -> Result<(), &'static str> {
393 queued.sort_by_key(|(_, s)| s.priority);
394 let base_weight: Weight = T::DbWeight::get().reads_writes(1, 2); // Agenda + Agenda(next)
395 let mut total_weight: Weight = 0;
396 queued.into_iter()
397 .enumerate()
398 .scan(base_weight, |cumulative_weight, (order, (index, s))| {
399 *cumulative_weight = cumulative_weight540 Ok(())
400 .saturating_add(s.call.get_dispatch_info().weight);541 }
401542
402 let origin = <<T as Config>::Origin as From<T::PalletsOrigin>>::from(543 #[cfg(feature = "try-runtime")]
403 s.origin.clone()544 pub fn post_migrate_to_v3() -> Result<(), &'static str> {
404 ).into();545 use frame_support::dispatch::GetStorageVersion;
405546
406 if ensure_signed(origin).is_ok() {547 assert!(Self::current_storage_version() == 3);
407 // AccountData for inner call origin accountdata.548 for k in Agenda::<T>::iter_keys() {
408 *cumulative_weight = cumulative_weight549 let _ = Agenda::<T>::try_get(k).map_err(|()| "Invalid item in Agenda")?;
409 .saturating_add(T::DbWeight::get().reads_writes(1, 1));
410 }
411
412 if s.maybe_id.is_some() {
413 // Remove/Modify Lookup
414 *cumulative_weight = cumulative_weight.saturating_add(T::DbWeight::get().writes(1));
415 }
416 if s.maybe_periodic.is_some() {
417 // Read/Write Agenda for future block
418 *cumulative_weight = cumulative_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));
419 }
420
421 Some((order, index, *cumulative_weight, s))
422 })
423 .filter_map(|(order, index, cumulative_weight, mut s)| {
424 // We allow a scheduled call if any is true:
425 // - It's priority is `HARD_DEADLINE`
426 // - It does not push the weight past the limit.
427 // - It is the first item in the schedule
428 if s.priority <= schedule::HARD_DEADLINE || cumulative_weight <= limit || order == 0 {
429
430 let origin = <<T as Config>::Origin as From<T::PalletsOrigin>>::from(
431 s.origin.clone()
432 ).into();
433 let sender = match ensure_signed(origin) {
434 Ok(v) => v,
435 // TODO: Support for unsigned extrinsics?
436 Err(_) => return Some(Some(s))
437 };
438 let who_will_pay = T::SponsorshipHandler::get_sponsor(&sender, &s.call).unwrap_or(sender);
439 let sponsor = T::PalletsOrigin::from(system::RawOrigin::Signed(who_will_pay));
440 let r = s.call.clone().dispatch(sponsor.into());
441 let maybe_id = s.maybe_id.clone();
442 if let Some((period, count)) = s.maybe_periodic {
443 if count > 1 {
444 s.maybe_periodic = Some((period, count - 1));
445 } else {
446 s.maybe_periodic = None;
447 }
448 let next = now + period;
449 // If scheduled is named, place it's information in `Lookup`
450 if let Some(ref id) = s.maybe_id {
451 let next_index = Agenda::<T>::decode_len(now + period).unwrap_or(0);
452 Lookup::<T>::insert(id, (next, next_index as u32));
453 }
454 Agenda::<T>::append(next, Some(s));
455 } else if let Some(ref id) = s.maybe_id {
456 Lookup::<T>::remove(id);
457 }
458 Self::deposit_event(RawEvent::Dispatched(
459 (now, index),
460 maybe_id,
461 r.map(|_| ()).map_err(|e| e.error)
462 ));
463 total_weight = cumulative_weight;
464 None
465 } else {
466 Some(Some(s))
467 }
468 })
469 .for_each(|unused| {
470 let next = now + One::one();
471 Agenda::<T>::append(next, unused);
472 });
473
474 total_weight
475 }550 }
551 Ok(())
476 }552 }
477}
478553
554 /// Helper to migrate scheduler when the pallet origin type has changed.
479impl<T: Config> Module<T> {555 pub fn migrate_origin<OldOrigin: Into<T::PalletsOrigin> + codec::Decode>() {
556 Agenda::<T>::translate::<
557 Vec<Option<Scheduled<CallOrHashOf<T>, T::BlockNumber, OldOrigin, T::AccountId>>>,
558 _,
559 >(|_, agenda| {
560 Some(
561 agenda
562 .into_iter()
563 .map(|schedule| {
564 schedule.map(|schedule| Scheduled {
565 maybe_id: schedule.maybe_id,
566 priority: schedule.priority,
567 call: schedule.call,
568 maybe_periodic: schedule.maybe_periodic,
569 origin: schedule.origin.into(),
570 _phantom: Default::default(),
571 })
572 })
573 .collect::<Vec<_>>(),
574 )
575 });
576 }
577
480 fn resolve_time(when: DispatchTime<T::BlockNumber>) -> Result<T::BlockNumber, DispatchError> {578 fn resolve_time(when: DispatchTime<T::BlockNumber>) -> Result<T::BlockNumber, DispatchError> {
481 let now = frame_system::Pallet::<T>::block_number();579 let now = frame_system::Pallet::<T>::block_number();
499 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,597 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
500 priority: schedule::Priority,598 priority: schedule::Priority,
501 origin: T::PalletsOrigin,599 origin: T::PalletsOrigin,
502 call: <T as Config>::Call,600 call: CallOrHashOf<T>,
503 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {601 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
504 let when = Self::resolve_time(when)?;602 let when = Self::resolve_time(when)?;
603 call.ensure_requested::<T::PreimageProvider>();
505604
506 // sanitize maybe_periodic605 // sanitize maybe_periodic
507 let maybe_periodic = maybe_periodic606 let maybe_periodic = maybe_periodic
518 });617 });
519 Agenda::<T>::append(when, s);618 Agenda::<T>::append(when, s);
520 let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;619 let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;
521 if index > T::MaxScheduledPerBlock::get() {620 Self::deposit_event(Event::Scheduled { when, index });
522 log::warn!(
523 target: "runtime::scheduler",
524 "Warning: There are more items queued in the Scheduler than \
525 expected from the runtime configuration. An update might be needed.",
526 );
527 }
528 Self::deposit_event(RawEvent::Scheduled(when, index));
529621
530 Ok((when, index))622 Ok((when, index))
531 }623 }
539 Ok(None),631 Ok(None),
540 |s| -> Result<Option<Scheduled<_, _, _, _>>, DispatchError> {632 |s| -> Result<Option<Scheduled<_, _, _, _>>, DispatchError> {
541 if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {633 if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {
542 if *o != s.origin {634 if matches!(
635 T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin),
636 Some(Ordering::Less) | None
637 ) {
543 return Err(BadOrigin.into());638 return Err(BadOrigin.into());
544 }639 }
545 };640 };
548 )643 )
549 })?;644 })?;
550 if let Some(s) = scheduled {645 if let Some(s) = scheduled {
646 s.call.ensure_unrequested::<T::PreimageProvider>();
551 if let Some(id) = s.maybe_id {647 if let Some(id) = s.maybe_id {
552 Lookup::<T>::remove(id);648 Lookup::<T>::remove(id);
553 }649 }
554 Self::deposit_event(RawEvent::Canceled(when, index));650 Self::deposit_event(Event::Canceled { when, index });
555 Ok(())651 Ok(())
556 } else {652 } else {
557 Err(Error::<T>::NotFound.into())653 Err(Error::<T>::NotFound)?
558 }654 }
559 }655 }
560656
576 })?;672 })?;
577673
578 let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;674 let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;
579 Self::deposit_event(RawEvent::Canceled(when, index));675 Self::deposit_event(Event::Canceled { when, index });
580 Self::deposit_event(RawEvent::Scheduled(new_time, new_index));676 Self::deposit_event(Event::Scheduled {
677 when: new_time,
678 index: new_index,
679 });
581680
582 Ok((new_time, new_index))681 Ok((new_time, new_index))
583 }682 }
584683
585 fn do_schedule_named(684 fn do_schedule_named(
586 id: Vec<u8>,685 id: ScheduledId,
587 when: DispatchTime<T::BlockNumber>,686 when: DispatchTime<T::BlockNumber>,
588 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,687 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
589 priority: schedule::Priority,688 priority: schedule::Priority,
590 origin: T::PalletsOrigin,689 origin: T::PalletsOrigin,
591 call: <T as Config>::Call,690 call: CallOrHashOf<T>,
592 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {691 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
593 // ensure id it is unique692 // ensure id it is unique
594 if Lookup::<T>::contains_key(&id) {693 if Lookup::<T>::contains_key(&id) {
595 return Err(Error::<T>::FailedToSchedule.into());694 return Err(Error::<T>::FailedToSchedule)?;
596 }695 }
597696
598 let when = Self::resolve_time(when)?;697 let when = Self::resolve_time(when)?;
599698
699 call.ensure_requested::<T::PreimageProvider>();
700
600 // sanitize maybe_periodic701 // sanitize maybe_periodic
601 let maybe_periodic = maybe_periodic702 let maybe_periodic = maybe_periodic
602 .filter(|p| p.1 > 1 && !p.0.is_zero())703 .filter(|p| p.1 > 1 && !p.0.is_zero())
606 let s = Scheduled {707 let s = Scheduled {
607 maybe_id: Some(id.clone()),708 maybe_id: Some(id.clone()),
608 priority,709 priority,
609 call,710 call: call.clone(),
610 maybe_periodic,711 maybe_periodic,
611 origin,712 origin: origin.clone(),
612 _phantom: Default::default(),713 _phantom: Default::default(),
613 };714 };
715
716 // reserve balance for periodic execution
717 // let sender =
718 // ensure_signed(<<T as Config>::Origin as From<T::PalletsOrigin>>::from(origin).into())?;
719 // let repeats = match maybe_periodic {
720 // Some(p) => p.1,
721 // None => 1,
722 // };
723 // let _ = T::CallExecutor::reserve_balance(
724 // id.clone(),
725 // sender,
726 // call.as_value().unwrap().clone(),
727 // repeats,
728 // );
729
614 Agenda::<T>::append(when, Some(s));730 Agenda::<T>::append(when, Some(s));
615 let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;731 let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;
616 if index > T::MaxScheduledPerBlock::get() {
617 log::warn!(
618 target: "runtime::scheduler",
619 "Warning: There are more items queued in the Scheduler than \
620 expected from the runtime configuration. An update might be needed.",
621 );
622 }
623 let address = (when, index);732 let address = (when, index);
624 Lookup::<T>::insert(&id, &address);733 Lookup::<T>::insert(&id, &address);
625 Self::deposit_event(RawEvent::Scheduled(when, index));734 Self::deposit_event(Event::Scheduled { when, index });
626735
627 Ok(address)736 Ok(address)
628 }737 }
629738
630 fn do_cancel_named(origin: Option<T::PalletsOrigin>, id: Vec<u8>) -> DispatchResult {739 fn do_cancel_named(origin: Option<T::PalletsOrigin>, id: ScheduledId) -> DispatchResult {
631 Lookup::<T>::try_mutate_exists(id, |lookup| -> DispatchResult {740 Lookup::<T>::try_mutate_exists(id, |lookup| -> DispatchResult {
632 if let Some((when, index)) = lookup.take() {741 if let Some((when, index)) = lookup.take() {
633 let i = index as usize;742 let i = index as usize;
634 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {743 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {
635 if let Some(s) = agenda.get_mut(i) {744 if let Some(s) = agenda.get_mut(i) {
636 if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {745 if let (Some(ref o), Some(ref s)) = (origin.clone(), s.borrow()) {
637 if *o != s.origin {746 if matches!(
747 T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin),
748 Some(Ordering::Less) | None
749 ) {
638 return Err(BadOrigin.into());750 return Err(BadOrigin.into());
639 }751 }
752 // release balance reserve
753 // let sender = ensure_signed(
754 // <<T as Config>::Origin as From<T::PalletsOrigin>>::from(
755 // origin.unwrap(),
756 // )
757 // .into(),
758 // )?;
759 // let _ = T::CallExecutor::cancel_reserve(id, sender);
760
761 s.call.ensure_unrequested::<T::PreimageProvider>();
640 }762 }
641 *s = None;763 *s = None;
642 }764 }
643 Ok(())765 Ok(())
644 })?;766 })?;
767
645 Self::deposit_event(RawEvent::Canceled(when, index));768 Self::deposit_event(Event::Canceled { when, index });
646 Ok(())769 Ok(())
647 } else {770 } else {
648 Err(Error::<T>::NotFound.into())771 Err(Error::<T>::NotFound)?
649 }772 }
650 })773 })
651 }774 }
652775
653 fn do_reschedule_named(776 fn do_reschedule_named(
654 id: Vec<u8>,777 id: ScheduledId,
655 new_time: DispatchTime<T::BlockNumber>,778 new_time: DispatchTime<T::BlockNumber>,
656 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {779 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
657 let new_time = Self::resolve_time(new_time)?;780 let new_time = Self::resolve_time(new_time)?;
674 })?;797 })?;
675798
676 let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;799 let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;
677 Self::deposit_event(RawEvent::Canceled(when, index));800 Self::deposit_event(Event::Canceled { when, index });
678 Self::deposit_event(RawEvent::Scheduled(new_time, new_index));801 Self::deposit_event(Event::Scheduled {
802 when: new_time,
803 index: new_index,
804 });
679805
680 *lookup = Some((new_time, new_index));806 *lookup = Some((new_time, new_index));
681807
685 }811 }
686}812}
687813
688#[cfg(test)]
689#[allow(clippy::from_over_into)]814impl<T: Config> schedule::v2::Anon<T::BlockNumber, <T as Config>::Call, T::PalletsOrigin>
690mod tests {815 for Pallet<T>
816{
691 use super::*;817 type Address = TaskAddress<T::BlockNumber>;
818 type Hash = T::Hash;
692819
693 use frame_support::{820 fn schedule(
694 ord_parameter_types, parameter_types,821 when: DispatchTime<T::BlockNumber>,
695 traits::{Contains, ConstU32, EnsureOneOf},
696 weights::constants::RocksDbWeight,822 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
697 };823 priority: schedule::Priority,
698 use sp_core::H256;
699 use sp_runtime::{824 origin: T::PalletsOrigin,
700 Perbill,
701 testing::Header,825 call: CallOrHashOf<T>,
702 traits::{BlakeTwo256, IdentityLookup},826 ) -> Result<Self::Address, DispatchError> {
703 };827 Self::do_schedule(when, maybe_periodic, priority, origin, call)
704 use frame_system::{EnsureRoot, EnsureSignedBy};828 }
705 use crate as scheduler;
706829
707 #[frame_support::pallet]830 fn cancel((when, index): Self::Address) -> Result<(), ()> {
708 pub mod logger {
709 use super::{OriginCaller, OriginTrait};831 Self::do_cancel(None, (when, index)).map_err(|_| ())
710 use frame_support::pallet_prelude::*;
711 use frame_system::pallet_prelude::*;
712 use std::cell::RefCell;832 }
713833
714 thread_local! {834 fn reschedule(
715 static LOG: RefCell<Vec<(OriginCaller, u32)>> = RefCell::new(Vec::new());835 address: Self::Address,
716 }836 when: DispatchTime<T::BlockNumber>,
717 pub fn log() -> Vec<(OriginCaller, u32)> {837 ) -> Result<Self::Address, DispatchError> {
718 LOG.with(|log| log.borrow().clone())838 Self::do_reschedule(address, when)
719 }839 }
720840
721 #[pallet::pallet]841 fn next_dispatch_time((when, index): Self::Address) -> Result<T::BlockNumber, ()> {
722 #[pallet::generate_store(pub(super) trait Store)]
723 pub struct Pallet<T>(PhantomData<T>);
724
725 #[pallet::hooks]
726 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
727
728 #[pallet::config]
729 pub trait Config: frame_system::Config {
730 type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
731 }
732
733 #[pallet::event]
734 #[pallet::generate_deposit(pub(super) fn deposit_event)]
735 pub enum Event<T: Config> {
736 Logged(u32, Weight),
737 }
738
739 #[pallet::call]
740 impl<T: Config> Pallet<T>
741 where
742 <T as frame_system::Config>::Origin: OriginTrait<PalletsOrigin = OriginCaller>,
743 {
744 #[pallet::weight(*weight)]842 Agenda::<T>::get(when)
745 pub fn log(origin: OriginFor<T>, i: u32, weight: Weight) -> DispatchResult {
746 Self::deposit_event(Event::Logged(i, weight));
747 LOG.with(|log| {843 .get(index as usize)
748 log.borrow_mut().push((origin.caller().clone(), i));
749 });844 .ok_or(())
750 Ok(())
751 }845 .map(|_| when)
752
753 #[pallet::weight(*weight)]
754 pub fn log_without_filter(
755 origin: OriginFor<T>,
756 i: u32,
757 weight: Weight,
758 ) -> DispatchResult {
759 Self::deposit_event(Event::Logged(i, weight));
760 LOG.with(|log| {
761 log.borrow_mut().push((origin.caller().clone(), i));
762 });
763 Ok(())
764 }
765 }
766 }846 }
847}
767848
768 type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;849impl<T: Config> schedule::v2::Named<T::BlockNumber, <T as Config>::Call, T::PalletsOrigin>
850 for Pallet<T>
851{
769 type Block = frame_system::mocking::MockBlock<Test>;852 type Address = TaskAddress<T::BlockNumber>;
853 type Hash = T::Hash;
770854
771 frame_support::construct_runtime!(855 fn schedule_named(
772 pub enum Test where856 id: Vec<u8>,
773 Block = Block,
774 NodeBlock = Block,857 when: DispatchTime<T::BlockNumber>,
775 UncheckedExtrinsic = UncheckedExtrinsic,858 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
776 {
777 System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
778 Logger: logger::{Pallet, Call, Event<T>},859 priority: schedule::Priority,
779 Scheduler: scheduler::{Pallet, Call, Storage, Event<T>},860 origin: T::PalletsOrigin,
861 call: CallOrHashOf<T>,
780 }862 ) -> Result<Self::Address, ()> {
781 );
782
783 // Scheduler must dispatch with root and no filter, this tests base filter is indeed not used.
784 pub struct BaseFilter;863 let inner_id: ScheduledId = id
785 impl Contains<Call> for BaseFilter {
786 fn contains(call: &Call) -> bool {864 .try_into()
787 !matches!(call, Call::Logger(logger::Call::log { .. }))865 .unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);
866 Self::do_schedule_named(inner_id, when, maybe_periodic, priority, origin, call)
788 }867 .map_err(|_| ())
789 }868 }
790869
791 parameter_types! {870 fn cancel_named(id: Vec<u8>) -> Result<(), ()> {
792 pub const BlockHashCount: u64 = 250;871 let inner_id: ScheduledId = id
793 pub BlockWeights: frame_system::limits::BlockWeights =872 .try_into()
873 .unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);
794 frame_system::limits::BlockWeights::simple_max(2_000_000_000_000);874 Self::do_cancel_named(None, inner_id).map_err(|_| ())
795 }875 }
796 impl system::Config for Test {876
797 type BaseCallFilter = BaseFilter;877 fn reschedule_named(
798 type BlockWeights = ();
799 type BlockLength = ();878 id: Vec<u8>,
800 type DbWeight = RocksDbWeight;879 when: DispatchTime<T::BlockNumber>,
801 type Origin = Origin;
802 type Call = Call;
803 type Index = u64;
804 type BlockNumber = u64;
805 type Hash = H256;880 ) -> Result<Self::Address, DispatchError> {
806 type Hashing = BlakeTwo256;
807 type AccountId = u64;
808 type Lookup = IdentityLookup<Self::AccountId>;
809 type Header = Header;
810 type Event = Event;881 let inner_id: ScheduledId = id
811 type BlockHashCount = BlockHashCount;
812 type Version = ();882 .try_into()
813 type PalletInfo = PalletInfo;
814 type AccountData = ();
815 type OnNewAccount = ();883 .unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);
816 type OnKilledAccount = ();
817 type SystemWeightInfo = ();
818 type SS58Prefix = ();884 Self::do_reschedule_named(inner_id, when)
819 type OnSetCode = ();
820 type MaxConsumers = ConstU32<16>;
821 }
822 impl logger::Config for Test {
823 type Event = Event;
824 }
825 parameter_types! {
826 pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block;
827 pub const MaxScheduledPerBlock: u32 = 10;
828 }
829 ord_parameter_types! {
830 pub const One: u64 = 1;
831 }885 }
832886
833 impl Config for Test {887 fn next_dispatch_time(id: Vec<u8>) -> Result<T::BlockNumber, ()> {
834 type Event = Event;
835 type Origin = Origin;888 let inner_id: ScheduledId = id
836 type PalletsOrigin = OriginCaller;
837 type Call = Call;889 .try_into()
838 type MaximumWeight = MaximumSchedulerWeight;890 .unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);
839 type ScheduleOrigin = EnsureOneOf<EnsureRoot<u64>, EnsureSignedBy<One, u64>>;891 Lookup::<T>::get(inner_id)
840 type MaxScheduledPerBlock = MaxScheduledPerBlock;892 .and_then(|(when, index)| Agenda::<T>::get(when).get(index as usize).map(|_| when))
841 type WeightInfo = ();
842 type SponsorshipHandler = ();893 .ok_or(())
843 }894 }
844}895}
845896
modifiedpallets/scheduler/src/weights.rsdiffbeforeafterboth
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
2// This file is part of Unique Network.
3
4// Unique Network is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Unique Network is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
16
17// Original license
18// This file is part of Substrate.1// This file is part of Substrate.
192
20// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.3// Copyright (C) 2022 Parity Technologies (UK) Ltd.
21// SPDX-License-Identifier: Apache-2.04// SPDX-License-Identifier: Apache-2.0
225
23// Licensed under the Apache License, Version 2.0 (the "License");6// Licensed under the Apache License, Version 2.0 (the "License");
32// See the License for the specific language governing permissions and15// See the License for the specific language governing permissions and
33// limitations under the License.16// limitations under the License.
3417
35//! Weights for pallet_scheduler18//! Autogenerated weights for pallet_scheduler
36//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.019//!
20//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
37//! DATE: 2020-10-27, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: [], HIGH RANGE: []21//! DATE: 2022-01-31, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
38//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 12822//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
3923
40// Executed Command:24// Executed Command:
41// target/release/substrate25// ./target/production/substrate
42// benchmark26// benchmark
43// --chain=dev27// --chain=dev
44// --steps=5028// --steps=50
49// --wasm-execution=compiled33// --wasm-execution=compiled
50// --heap-pages=409634// --heap-pages=4096
51// --output=./frame/scheduler/src/weights.rs35// --output=./frame/scheduler/src/weights.rs
52// --template=./.maintain/frame-weight-template.hbs36// --template=.maintain/frame-weight-template.hbs
37// --header=HEADER-APACHE2
38// --raw
5339
40#![cfg_attr(rustfmt, rustfmt_skip)]
54#![allow(unused_parens)]41#![allow(unused_parens)]
55#![allow(unused_imports)]42#![allow(unused_imports)]
5643
57use frame_support::{44use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
58 traits::Get,
59 weights::{Weight, constants::RocksDbWeight},
60};
61use sp_std::marker::PhantomData;45use sp_std::marker::PhantomData;
6246
63/// Weight functions needed for pallet_scheduler.47/// Weight functions needed for pallet_scheduler.
64pub trait WeightInfo {48pub trait WeightInfo {
65 fn schedule(s: u32) -> Weight;49 fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight;
50 fn on_initialize_named_resolved(s: u32, ) -> Weight;
51 fn on_initialize_periodic_resolved(s: u32, ) -> Weight;
52 fn on_initialize_resolved(s: u32, ) -> Weight;
53 fn on_initialize_named_aborted(s: u32, ) -> Weight;
54 fn on_initialize_aborted(s: u32, ) -> Weight;
55 fn on_initialize_periodic_named(s: u32, ) -> Weight;
56 fn on_initialize_periodic(s: u32, ) -> Weight;
57 fn on_initialize_named(s: u32, ) -> Weight;
58 fn on_initialize(s: u32, ) -> Weight;
59 fn schedule(s: u32, ) -> Weight;
66 fn cancel(s: u32) -> Weight;60 fn cancel(s: u32, ) -> Weight;
67 fn schedule_named(s: u32) -> Weight;61 fn schedule_named(s: u32, ) -> Weight;
68 fn cancel_named(s: u32) -> Weight;62 fn cancel_named(s: u32, ) -> Weight;
69}63}
7064
71/// Weights for pallet_scheduler using the Substrate node and recommended hardware.65/// Weights for pallet_scheduler using the Substrate node and recommended hardware.
72pub struct SubstrateWeight<T>(PhantomData<T>);66pub struct SubstrateWeight<T>(PhantomData<T>);
73impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {67impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
74 fn schedule(s: u32) -> Weight {68 // Storage: Scheduler Agenda (r:2 w:2)
69 // Storage: Preimage PreimageFor (r:1 w:1)
70 // Storage: Preimage StatusFor (r:1 w:1)
71 // Storage: Scheduler Lookup (r:0 w:1)
72 fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight {
75 35_029_000_u6473 (11_587_000 as Weight)
76 .saturating_add(77_000_u64.saturating_mul(s as Weight))74 // Standard Error: 17_000
75 .saturating_add((17_428_000 as Weight).saturating_mul(s as Weight))
77 .saturating_add(T::DbWeight::get().reads(1_u64))76 .saturating_add(T::DbWeight::get().reads(1 as Weight))
78 .saturating_add(T::DbWeight::get().writes(1_u64))77 .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight)))
78 .saturating_add(T::DbWeight::get().writes(1 as Weight))
79 .saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(s as Weight)))
79 }80 }
80 fn cancel(s: u32) -> Weight {81 // Storage: Scheduler Agenda (r:1 w:1)
82 // Storage: Preimage PreimageFor (r:1 w:1)
83 // Storage: Preimage StatusFor (r:1 w:1)
84 // Storage: Scheduler Lookup (r:0 w:1)
85 fn on_initialize_named_resolved(s: u32, ) -> Weight {
81 31_419_000_u6486 (8_965_000 as Weight)
82 .saturating_add(4_015_000_u64.saturating_mul(s as Weight))87 // Standard Error: 11_000
88 .saturating_add((13_410_000 as Weight).saturating_mul(s as Weight))
83 .saturating_add(T::DbWeight::get().reads(1_u64))89 .saturating_add(T::DbWeight::get().reads(1 as Weight))
84 .saturating_add(T::DbWeight::get().writes(2_u64))90 .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight)))
91 .saturating_add(T::DbWeight::get().writes(1 as Weight))
92 .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(s as Weight)))
85 }93 }
86 fn schedule_named(s: u32) -> Weight {94 // Storage: Scheduler Agenda (r:2 w:2)
95 // Storage: Preimage PreimageFor (r:1 w:1)
96 // Storage: Preimage StatusFor (r:1 w:1)
97 fn on_initialize_periodic_resolved(s: u32, ) -> Weight {
87 44_752_000_u6498 (8_654_000 as Weight)
88 .saturating_add(123_000_u64.saturating_mul(s as Weight))99 // Standard Error: 17_000
100 .saturating_add((14_990_000 as Weight).saturating_mul(s as Weight))
89 .saturating_add(T::DbWeight::get().reads(2_u64))101 .saturating_add(T::DbWeight::get().reads(1 as Weight))
90 .saturating_add(T::DbWeight::get().writes(2_u64))102 .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(s as Weight)))
103 .saturating_add(T::DbWeight::get().writes(1 as Weight))
104 .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(s as Weight)))
91 }105 }
92 fn cancel_named(s: u32) -> Weight {106 // Storage: Scheduler Agenda (r:1 w:1)
107 // Storage: Preimage PreimageFor (r:1 w:1)
108 // Storage: Preimage StatusFor (r:1 w:1)
109 fn on_initialize_resolved(s: u32, ) -> Weight {
93 35_712_000_u64110 (9_303_000 as Weight)
94 .saturating_add(4_008_000_u64.saturating_mul(s as Weight))111 // Standard Error: 10_000
112 .saturating_add((12_244_000 as Weight).saturating_mul(s as Weight))
95 .saturating_add(T::DbWeight::get().reads(2_u64))113 .saturating_add(T::DbWeight::get().reads(1 as Weight))
96 .saturating_add(T::DbWeight::get().writes(2_u64))114 .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(s as Weight)))
115 .saturating_add(T::DbWeight::get().writes(1 as Weight))
116 .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(s as Weight)))
97 }117 }
118 // Storage: Scheduler Agenda (r:2 w:2)
119 // Storage: Preimage PreimageFor (r:1 w:0)
120 // Storage: Scheduler Lookup (r:0 w:1)
121 fn on_initialize_named_aborted(s: u32, ) -> Weight {
122 (7_506_000 as Weight)
123 // Standard Error: 3_000
124 .saturating_add((5_208_000 as Weight).saturating_mul(s as Weight))
125 .saturating_add(T::DbWeight::get().reads(2 as Weight))
126 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight)))
127 .saturating_add(T::DbWeight::get().writes(2 as Weight))
128 .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight)))
129 }
130 // Storage: Scheduler Agenda (r:2 w:2)
131 // Storage: Preimage PreimageFor (r:1 w:0)
132 fn on_initialize_aborted(s: u32, ) -> Weight {
133 (8_046_000 as Weight)
134 // Standard Error: 3_000
135 .saturating_add((2_914_000 as Weight).saturating_mul(s as Weight))
136 .saturating_add(T::DbWeight::get().reads(2 as Weight))
137 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight)))
138 .saturating_add(T::DbWeight::get().writes(2 as Weight))
139 }
140 // Storage: Scheduler Agenda (r:2 w:2)
141 // Storage: Scheduler Lookup (r:0 w:1)
142 fn on_initialize_periodic_named(s: u32, ) -> Weight {
143 (13_704_000 as Weight)
144 // Standard Error: 4_000
145 .saturating_add((8_186_000 as Weight).saturating_mul(s as Weight))
146 .saturating_add(T::DbWeight::get().reads(1 as Weight))
147 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight)))
148 .saturating_add(T::DbWeight::get().writes(1 as Weight))
149 .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(s as Weight)))
150 }
151 // Storage: Scheduler Agenda (r:2 w:2)
152 fn on_initialize_periodic(s: u32, ) -> Weight {
153 (12_668_000 as Weight)
154 // Standard Error: 5_000
155 .saturating_add((5_868_000 as Weight).saturating_mul(s as Weight))
156 .saturating_add(T::DbWeight::get().reads(1 as Weight))
157 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight)))
158 .saturating_add(T::DbWeight::get().writes(1 as Weight))
159 .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight)))
160 }
161 // Storage: Scheduler Agenda (r:1 w:1)
162 // Storage: Scheduler Lookup (r:0 w:1)
163 fn on_initialize_named(s: u32, ) -> Weight {
164 (13_946_000 as Weight)
165 // Standard Error: 4_000
166 .saturating_add((4_367_000 as Weight).saturating_mul(s as Weight))
167 .saturating_add(T::DbWeight::get().reads(1 as Weight))
168 .saturating_add(T::DbWeight::get().writes(1 as Weight))
169 .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight)))
170 }
171 // Storage: Scheduler Agenda (r:1 w:1)
172 fn on_initialize(s: u32, ) -> Weight {
173 (13_151_000 as Weight)
174 // Standard Error: 4_000
175 .saturating_add((3_455_000 as Weight).saturating_mul(s as Weight))
176 .saturating_add(T::DbWeight::get().reads(1 as Weight))
177 .saturating_add(T::DbWeight::get().writes(1 as Weight))
178 }
179 // Storage: Scheduler Agenda (r:1 w:1)
180 fn schedule(s: u32, ) -> Weight {
181 (14_040_000 as Weight)
182 // Standard Error: 1_000
183 .saturating_add((89_000 as Weight).saturating_mul(s as Weight))
184 .saturating_add(T::DbWeight::get().reads(1 as Weight))
185 .saturating_add(T::DbWeight::get().writes(1 as Weight))
186 }
187 // Storage: Scheduler Agenda (r:1 w:1)
188 // Storage: Scheduler Lookup (r:0 w:1)
189 fn cancel(s: u32, ) -> Weight {
190 (14_376_000 as Weight)
191 // Standard Error: 1_000
192 .saturating_add((576_000 as Weight).saturating_mul(s as Weight))
193 .saturating_add(T::DbWeight::get().reads(1 as Weight))
194 .saturating_add(T::DbWeight::get().writes(2 as Weight))
195 }
196 // Storage: Scheduler Lookup (r:1 w:1)
197 // Storage: Scheduler Agenda (r:1 w:1)
198 fn schedule_named(s: u32, ) -> Weight {
199 (16_806_000 as Weight)
200 // Standard Error: 1_000
201 .saturating_add((102_000 as Weight).saturating_mul(s as Weight))
202 .saturating_add(T::DbWeight::get().reads(2 as Weight))
203 .saturating_add(T::DbWeight::get().writes(2 as Weight))
204 }
205 // Storage: Scheduler Lookup (r:1 w:1)
206 // Storage: Scheduler Agenda (r:1 w:1)
207 fn cancel_named(s: u32, ) -> Weight {
208 (15_852_000 as Weight)
209 // Standard Error: 2_000
210 .saturating_add((590_000 as Weight).saturating_mul(s as Weight))
211 .saturating_add(T::DbWeight::get().reads(2 as Weight))
212 .saturating_add(T::DbWeight::get().writes(2 as Weight))
213 }
98}214}
99215
100// For backwards compatibility and tests216// For backwards compatibility and tests
101impl WeightInfo for () {217impl WeightInfo for () {
102 fn schedule(s: u32) -> Weight {218 // Storage: Scheduler Agenda (r:2 w:2)
103 35_029_000_u64219 // Storage: Preimage PreimageFor (r:1 w:1)
104 .saturating_add(77_000_u64.saturating_mul(s as Weight))220 // Storage: Preimage StatusFor (r:1 w:1)
105 .saturating_add(RocksDbWeight::get().reads(1_u64))221 // Storage: Scheduler Lookup (r:0 w:1)
106 .saturating_add(RocksDbWeight::get().writes(1_u64))222 fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight {
223 (11_587_000 as Weight)
224 // Standard Error: 17_000
225 .saturating_add((17_428_000 as Weight).saturating_mul(s as Weight))
226 .saturating_add(RocksDbWeight::get().reads(1 as Weight))
227 .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight)))
228 .saturating_add(RocksDbWeight::get().writes(1 as Weight))
229 .saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(s as Weight)))
230 }
231 // Storage: Scheduler Agenda (r:1 w:1)
232 // Storage: Preimage PreimageFor (r:1 w:1)
233 // Storage: Preimage StatusFor (r:1 w:1)
234 // Storage: Scheduler Lookup (r:0 w:1)
235 fn on_initialize_named_resolved(s: u32, ) -> Weight {
236 (8_965_000 as Weight)
237 // Standard Error: 11_000
238 .saturating_add((13_410_000 as Weight).saturating_mul(s as Weight))
239 .saturating_add(RocksDbWeight::get().reads(1 as Weight))
240 .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight)))
241 .saturating_add(RocksDbWeight::get().writes(1 as Weight))
242 .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(s as Weight)))
243 }
244 // Storage: Scheduler Agenda (r:2 w:2)
245 // Storage: Preimage PreimageFor (r:1 w:1)
246 // Storage: Preimage StatusFor (r:1 w:1)
247 fn on_initialize_periodic_resolved(s: u32, ) -> Weight {
248 (8_654_000 as Weight)
249 // Standard Error: 17_000
250 .saturating_add((14_990_000 as Weight).saturating_mul(s as Weight))
251 .saturating_add(RocksDbWeight::get().reads(1 as Weight))
252 .saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(s as Weight)))
253 .saturating_add(RocksDbWeight::get().writes(1 as Weight))
254 .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(s as Weight)))
255 }
256 // Storage: Scheduler Agenda (r:1 w:1)
257 // Storage: Preimage PreimageFor (r:1 w:1)
258 // Storage: Preimage StatusFor (r:1 w:1)
259 fn on_initialize_resolved(s: u32, ) -> Weight {
260 (9_303_000 as Weight)
261 // Standard Error: 10_000
262 .saturating_add((12_244_000 as Weight).saturating_mul(s as Weight))
263 .saturating_add(RocksDbWeight::get().reads(1 as Weight))
264 .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(s as Weight)))
265 .saturating_add(RocksDbWeight::get().writes(1 as Weight))
266 .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(s as Weight)))
267 }
268 // Storage: Scheduler Agenda (r:2 w:2)
269 // Storage: Preimage PreimageFor (r:1 w:0)
270 // Storage: Scheduler Lookup (r:0 w:1)
271 fn on_initialize_named_aborted(s: u32, ) -> Weight {
272 (7_506_000 as Weight)
273 // Standard Error: 3_000
274 .saturating_add((5_208_000 as Weight).saturating_mul(s as Weight))
275 .saturating_add(RocksDbWeight::get().reads(2 as Weight))
276 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight)))
277 .saturating_add(RocksDbWeight::get().writes(2 as Weight))
278 .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight)))
279 }
280 // Storage: Scheduler Agenda (r:2 w:2)
281 // Storage: Preimage PreimageFor (r:1 w:0)
282 fn on_initialize_aborted(s: u32, ) -> Weight {
283 (8_046_000 as Weight)
284 // Standard Error: 3_000
285 .saturating_add((2_914_000 as Weight).saturating_mul(s as Weight))
286 .saturating_add(RocksDbWeight::get().reads(2 as Weight))
287 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight)))
288 .saturating_add(RocksDbWeight::get().writes(2 as Weight))
289 }
290 // Storage: Scheduler Agenda (r:2 w:2)
291 // Storage: Scheduler Lookup (r:0 w:1)
292 fn on_initialize_periodic_named(s: u32, ) -> Weight {
293 (13_704_000 as Weight)
294 // Standard Error: 4_000
295 .saturating_add((8_186_000 as Weight).saturating_mul(s as Weight))
296 .saturating_add(RocksDbWeight::get().reads(1 as Weight))
297 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight)))
298 .saturating_add(RocksDbWeight::get().writes(1 as Weight))
299 .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(s as Weight)))
300 }
301 // Storage: Scheduler Agenda (r:2 w:2)
302 fn on_initialize_periodic(s: u32, ) -> Weight {
303 (12_668_000 as Weight)
304 // Standard Error: 5_000
305 .saturating_add((5_868_000 as Weight).saturating_mul(s as Weight))
306 .saturating_add(RocksDbWeight::get().reads(1 as Weight))
307 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight)))
308 .saturating_add(RocksDbWeight::get().writes(1 as Weight))
309 .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight)))
310 }
311 // Storage: Scheduler Agenda (r:1 w:1)
312 // Storage: Scheduler Lookup (r:0 w:1)
313 fn on_initialize_named(s: u32, ) -> Weight {
314 (13_946_000 as Weight)
315 // Standard Error: 4_000
316 .saturating_add((4_367_000 as Weight).saturating_mul(s as Weight))
317 .saturating_add(RocksDbWeight::get().reads(1 as Weight))
318 .saturating_add(RocksDbWeight::get().writes(1 as Weight))
319 .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight)))
320 }
321 // Storage: Scheduler Agenda (r:1 w:1)
322 fn on_initialize(s: u32, ) -> Weight {
323 (13_151_000 as Weight)
324 // Standard Error: 4_000
325 .saturating_add((3_455_000 as Weight).saturating_mul(s as Weight))
326 .saturating_add(RocksDbWeight::get().reads(1 as Weight))
327 .saturating_add(RocksDbWeight::get().writes(1 as Weight))
328 }
329 // Storage: Scheduler Agenda (r:1 w:1)
330 fn schedule(s: u32, ) -> Weight {
331 (14_040_000 as Weight)
332 // Standard Error: 1_000
333 .saturating_add((89_000 as Weight).saturating_mul(s as Weight))
334 .saturating_add(RocksDbWeight::get().reads(1 as Weight))
335 .saturating_add(RocksDbWeight::get().writes(1 as Weight))
107 }336 }
108 fn cancel(s: u32) -> Weight {337 // Storage: Scheduler Agenda (r:1 w:1)
338 // Storage: Scheduler Lookup (r:0 w:1)
339 fn cancel(s: u32, ) -> Weight {
109 31_419_000_u64340 (14_376_000 as Weight)
110 .saturating_add(4_015_000_u64.saturating_mul(s as Weight))341 // Standard Error: 1_000
342 .saturating_add((576_000 as Weight).saturating_mul(s as Weight))
111 .saturating_add(RocksDbWeight::get().reads(1_u64))343 .saturating_add(RocksDbWeight::get().reads(1 as Weight))
112 .saturating_add(RocksDbWeight::get().writes(2_u64))344 .saturating_add(RocksDbWeight::get().writes(2 as Weight))
113 }345 }
114 fn schedule_named(s: u32) -> Weight {346 // Storage: Scheduler Lookup (r:1 w:1)
347 // Storage: Scheduler Agenda (r:1 w:1)
348 fn schedule_named(s: u32, ) -> Weight {
115 44_752_000_u64349 (16_806_000 as Weight)
116 .saturating_add(123_000_u64.saturating_mul(s as Weight))350 // Standard Error: 1_000
351 .saturating_add((102_000 as Weight).saturating_mul(s as Weight))
117 .saturating_add(RocksDbWeight::get().reads(2_u64))352 .saturating_add(RocksDbWeight::get().reads(2 as Weight))
118 .saturating_add(RocksDbWeight::get().writes(2_u64))353 .saturating_add(RocksDbWeight::get().writes(2 as Weight))
119 }354 }
120 fn cancel_named(s: u32) -> Weight {355 // Storage: Scheduler Lookup (r:1 w:1)
356 // Storage: Scheduler Agenda (r:1 w:1)
357 fn cancel_named(s: u32, ) -> Weight {
121 35_712_000_u64358 (15_852_000 as Weight)
122 .saturating_add(4_008_000_u64.saturating_mul(s as Weight))359 // Standard Error: 2_000
360 .saturating_add((590_000 as Weight).saturating_mul(s as Weight))
123 .saturating_add(RocksDbWeight::get().reads(2_u64))361 .saturating_add(RocksDbWeight::get().reads(2 as Weight))
124 .saturating_add(RocksDbWeight::get().writes(2_u64))362 .saturating_add(RocksDbWeight::get().writes(2 as Weight))
125 }363 }
126}364}
127365
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
28use sp_api::impl_runtime_apis;28use sp_api::impl_runtime_apis;
29use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};29use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};
30use sp_runtime::DispatchError;30use sp_runtime::DispatchError;
31use fp_self_contained::*;
32use sp_runtime::traits::{Member};
31// #[cfg(any(feature = "std", test))]33// #[cfg(any(feature = "std", test))]
32// pub use sp_runtime::BuildStorage;34// pub use sp_runtime::BuildStorage;
3335
59 traits::{61 traits::{
60 tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,62 tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,
61 Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,63 Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,
62 OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance,64 OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance, PrivilegeCmp,
63 },65 },
64 weights::{66 weights::{
65 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},67 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
66 DispatchClass, DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,68 DispatchClass, DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,
67 WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, ConstantMultiplier,69 WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, ConstantMultiplier,
68 },70 },
69};71};
72use pallet_unq_scheduler::DispatchCall;
70use up_data_structs::mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping};73use up_data_structs::{
71use up_data_structs::*;74 CollectionId, TokenId, TokenData, Property, PropertyKeyPermission, CollectionLimits,
75 CollectionStats, RpcCollection,
76 mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
77};
78
72// use pallet_contracts::weights::WeightInfo;79// use pallet_contracts::weights::WeightInfo;
73// #[cfg(any(feature = "std", test))]80// #[cfg(any(feature = "std", test))]
79 traits::{BaseArithmetic, Unsigned},86 traits::{BaseArithmetic, Unsigned},
80};87};
81use smallvec::smallvec;88use smallvec::smallvec;
89// use scale_info::TypeInfo;
82use codec::{Encode, Decode};90use codec::{Encode, Decode};
83use fp_rpc::TransactionStatus;91use fp_rpc::TransactionStatus;
84use sp_runtime::{92use sp_runtime::{
85 traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf, DispatchInfoOf, Saturating},93 traits::{
94 Applyable, BlockNumberProvider, Dispatchable, PostDispatchInfoOf, DispatchInfoOf,
95 Saturating, CheckedConversion,
96 },
97 generic::Era,
86 transaction_validity::TransactionValidityError,98 transaction_validity::TransactionValidityError,
87 SaturatedConversion,99 DispatchErrorWithPostInfo, SaturatedConversion,
88};100};
89101
90// pub use pallet_timestamp::Call as TimestampCall;102// pub use pallet_timestamp::Call as TimestampCall;
102 ParentIsPreset,114 ParentIsPreset,
103};115};
104use xcm_executor::{Config, XcmExecutor, Assets};116use xcm_executor::{Config, XcmExecutor, Assets};
105use sp_std::{marker::PhantomData};117use sp_std::{cmp::Ordering, marker::PhantomData};
106118
107use xcm::latest::{119use xcm::latest::{
108 // Xcm,120 // Xcm,
113};125};
114use xcm_executor::traits::{MatchesFungible, WeightTrader};126use xcm_executor::traits::{MatchesFungible, WeightTrader};
115//use xcm_executor::traits::MatchesFungible;127//use xcm_executor::traits::MatchesFungible;
116use sp_runtime::traits::CheckedConversion;
117128
118use unique_runtime_common::{129use unique_runtime_common::{
119 impl_common_runtime_apis,130 impl_common_runtime_apis,
406 // pub const ExistentialDeposit: u128 = 500;417 // pub const ExistentialDeposit: u128 = 500;
407 pub const ExistentialDeposit: u128 = 0;418 pub const ExistentialDeposit: u128 = 0;
408 pub const MaxLocks: u32 = 50;419 pub const MaxLocks: u32 = 50;
420 pub const MaxReserves: u32 = 50;
409}421}
410422
411impl pallet_balances::Config for Runtime {423impl pallet_balances::Config for Runtime {
412 type MaxLocks = MaxLocks;424 type MaxLocks = MaxLocks;
413 type MaxReserves = ();425 type MaxReserves = MaxReserves;
414 type ReserveIdentifier = [u8; 8];426 type ReserveIdentifier = [u8; 16];
415 /// The type for recording an account's balance.427 /// The type for recording an account's balance.
416 type Balance = Balance;428 type Balance = Balance;
417 /// The ubiquitous event type.429 /// The ubiquitous event type.
930 type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;942 type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
931}943}
932944
933// parameter_types! {945parameter_types! {
934// pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *946 pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *
935// RuntimeBlockWeights::get().max_block;947 RuntimeBlockWeights::get().max_block;
936// pub const MaxScheduledPerBlock: u32 = 50;948 pub const MaxScheduledPerBlock: u32 = 50;
937// }949}
950
951type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
952use frame_support::traits::NamedReservableCurrency;
953
954fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {
955 (
956 frame_system::CheckSpecVersion::<Runtime>::new(),
957 frame_system::CheckGenesis::<Runtime>::new(),
958 frame_system::CheckEra::<Runtime>::from(Era::Immortal),
959 frame_system::CheckNonce::<Runtime>::from(frame_system::Pallet::<Runtime>::account_nonce(
960 from,
961 )),
962 frame_system::CheckWeight::<Runtime>::new(),
963 // sponsoring transaction logic
964 // pallet_charge_transaction::ChargeTransactionPayment::<Runtime>::new(0),
965 )
966}
967
968pub struct SchedulerPaymentExecutor;
969impl<T: frame_system::Config + pallet_unq_scheduler::Config, SelfContainedSignedInfo>
970 DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor
971where
972 <T as frame_system::Config>::Call: Member
973 + Dispatchable<Origin = Origin, Info = DispatchInfo>
974 + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>
975 + GetDispatchInfo
976 + From<frame_system::Call<Runtime>>,
977 SelfContainedSignedInfo: Send + Sync + 'static,
978 Call: From<<T as frame_system::Config>::Call>
979 + From<<T as pallet_unq_scheduler::Config>::Call>
980 + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,
981 sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,
982{
983 fn dispatch_call(
984 signer: <T as frame_system::Config>::AccountId,
985 call: <T as pallet_unq_scheduler::Config>::Call,
986 ) -> Result<
987 Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,
988 TransactionValidityError,
989 > {
990 let dispatch_info = call.get_dispatch_info();
991 let extrinsic = fp_self_contained::CheckedExtrinsic::<
992 AccountId,
993 Call,
994 SignedExtraScheduler,
995 SelfContainedSignedInfo,
996 > {
997 signed:
998 CheckedSignature::<AccountId, SignedExtraScheduler, SelfContainedSignedInfo>::Signed(
999 signer.clone().into(),
1000 get_signed_extras(signer.into()),
1001 ),
1002 function: call.into(),
1003 };
1004
1005 extrinsic.apply::<Runtime>(&dispatch_info, 0)
1006 }
1007
1008 fn reserve_balance(
1009 id: [u8; 16],
1010 sponsor: <T as frame_system::Config>::AccountId,
1011 call: <T as pallet_unq_scheduler::Config>::Call,
1012 count: u32,
1013 ) -> Result<(), DispatchError> {
1014 let dispatch_info = call.get_dispatch_info();
1015 let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)
1016 .saturating_mul(count.into());
1017
1018 <Balances as NamedReservableCurrency<AccountId>>::reserve_named(
1019 &id,
1020 &(sponsor.into()),
1021 weight,
1022 )
1023 }
1024
1025 fn pay_for_call(
1026 id: [u8; 16],
1027 sponsor: <T as frame_system::Config>::AccountId,
1028 call: <T as pallet_unq_scheduler::Config>::Call,
1029 ) -> Result<u128, DispatchError> {
1030 let dispatch_info = call.get_dispatch_info();
1031 let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);
1032 Ok(
1033 <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
1034 &id,
1035 &(sponsor.into()),
1036 weight,
1037 ),
1038 )
1039 }
1040
1041 fn cancel_reserve(
1042 id: [u8; 16],
1043 sponsor: <T as frame_system::Config>::AccountId,
1044 ) -> Result<u128, DispatchError> {
1045 Ok(
1046 <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
1047 &id,
1048 &(sponsor.into()),
1049 u128::MAX,
1050 ),
1051 )
1052 }
1053}
1054
1055parameter_types! {
1056 pub const NoPreimagePostponement: Option<u32> = Some(10);
1057 pub const Preimage: Option<u32> = Some(10);
1058}
1059
1060/// Used the compare the privilege of an origin inside the scheduler.
1061pub struct OriginPrivilegeCmp;
1062
1063impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
1064 fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option<Ordering> {
1065 Some(Ordering::Equal)
1066 }
1067}
1068
1069impl pallet_unq_scheduler::Config for Runtime {
1070 type Event = Event;
1071 type Origin = Origin;
1072 type Currency = Balances;
1073 type PalletsOrigin = OriginCaller;
1074 type Call = Call;
1075 type MaximumWeight = MaximumSchedulerWeight;
1076 type ScheduleOrigin = EnsureSigned<AccountId>;
1077 type MaxScheduledPerBlock = MaxScheduledPerBlock;
1078 type WeightInfo = ();
1079 type CallExecutor = SchedulerPaymentExecutor;
1080 type OriginPrivilegeCmp = OriginPrivilegeCmp;
1081 type PreimageProvider = ();
1082 type NoPreimagePostponement = NoPreimagePostponement;
1083}
9381084
939type EvmSponsorshipHandler = (1085type EvmSponsorshipHandler = (
940 UniqueEthSponsorshipHandler<Runtime>,1086 UniqueEthSponsorshipHandler<Runtime>,
946 pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,1093 pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
947);1094);
948
949// impl pallet_unq_scheduler::Config for Runtime {
950// type Event = Event;
951// type Origin = Origin;
952// type PalletsOrigin = OriginCaller;
953// type Call = Call;
954// type MaximumWeight = MaximumSchedulerWeight;
955// type ScheduleOrigin = EnsureSigned<AccountId>;
956// type MaxScheduledPerBlock = MaxScheduledPerBlock;
957// type SponsorshipHandler = SponsorshipHandler;
958// type WeightInfo = ();
959// }
9601095
961impl pallet_evm_transaction_payment::Config for Runtime {1096impl pallet_evm_transaction_payment::Config for Runtime {
962 type EvmSponsorshipHandler = EvmSponsorshipHandler;1097 type EvmSponsorshipHandler = EvmSponsorshipHandler;
1020 // Unique Pallets1155 // Unique Pallets
1021 Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,1156 Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
1022 Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,1157 Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
1023 // Scheduler: pallet_unq_scheduler::{Pallet, Call, Storage, Event<T>} = 62,1158 Scheduler: pallet_unq_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
1024 // free = 631159 // free = 63
1025 Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,1160 Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,
1026 // ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,1161 // ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,
1087 frame_system::CheckEra<Runtime>,1222 frame_system::CheckEra<Runtime>,
1088 frame_system::CheckNonce<Runtime>,1223 frame_system::CheckNonce<Runtime>,
1089 frame_system::CheckWeight<Runtime>,1224 frame_system::CheckWeight<Runtime>,
1090 pallet_charge_transaction::ChargeTransactionPayment<Runtime>,1225 ChargeTransactionPayment,
1091 //pallet_contract_helpers::ContractHelpersExtension<Runtime>,1226 //pallet_contract_helpers::ContractHelpersExtension<Runtime>,
1092 pallet_ethereum::FakeTransactionFinalizer<Runtime>,1227 pallet_ethereum::FakeTransactionFinalizer<Runtime>,
1093);1228);
1229pub type SignedExtraScheduler = (
1230 frame_system::CheckSpecVersion<Runtime>,
1231 frame_system::CheckGenesis<Runtime>,
1232 frame_system::CheckEra<Runtime>,
1233 frame_system::CheckNonce<Runtime>,
1234 frame_system::CheckWeight<Runtime>,
1235);
1094/// Unchecked extrinsic type as expected by this runtime.1236/// Unchecked extrinsic type as expected by this runtime.
1095pub type UncheckedExtrinsic =1237pub type UncheckedExtrinsic =
1096 fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;1238 fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
modifiedruntime/quartz/src/lib.rsdiffbeforeafterboth
3333
34use sp_runtime::{34use sp_runtime::{
35 Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,35 Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,
36 traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, AccountIdConversion, Zero},36 traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, AccountIdConversion, Zero, Member},
37 transaction_validity::{TransactionSource, TransactionValidity},37 transaction_validity::{TransactionSource, TransactionValidity},
38 ApplyExtrinsicResult, RuntimeAppPublic,38 ApplyExtrinsicResult, RuntimeAppPublic,
39};39};
58 traits::{58 traits::{
59 tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,59 tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,
60 Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,60 Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,
61 OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance,61 OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance, PrivilegeCmp,
62 },62 },
63 weights::{63 weights::{
64 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},64 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
82use fp_rpc::TransactionStatus;82use fp_rpc::TransactionStatus;
83use sp_runtime::{83use sp_runtime::{
84 traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf, Saturating},84 traits::{
85 Applyable, BlockNumberProvider, Dispatchable, PostDispatchInfoOf, Saturating,
86 CheckedConversion,
87 },
88 generic::Era,
85 transaction_validity::TransactionValidityError,89 transaction_validity::TransactionValidityError,
86 SaturatedConversion,90 SaturatedConversion, DispatchErrorWithPostInfo,
87};91};
92
93use fp_self_contained::{SelfContainedCall, CheckedSignature};
8894
89// pub use pallet_timestamp::Call as TimestampCall;95// pub use pallet_timestamp::Call as TimestampCall;
90pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;96pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
9197
92// Polkadot imports98// Polkadot imports
93use pallet_xcm::XcmPassthrough;99use pallet_xcm::XcmPassthrough;
94use polkadot_parachain::primitives::Sibling;100use polkadot_parachain::primitives::Sibling;
95use up_data_structs::mapping::{CrossTokenAddressMapping, EvmTokenAddressMapping};101use up_data_structs::{
102 CollectionId, TokenId, TokenData, Property, PropertyKeyPermission, CollectionLimits,
103 CollectionStats, RpcCollection,
104 mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping}
105};
96use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};106use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};
97use xcm_builder::{107use xcm_builder::{
98 AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,108 AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
102 ParentIsPreset,112 ParentIsPreset,
103};113};
104use xcm_executor::{Config, XcmExecutor, Assets};114use xcm_executor::{Config, XcmExecutor, Assets};
105use sp_std::{marker::PhantomData};115use sp_std::{cmp::Ordering, marker::PhantomData};
116use pallet_unq_scheduler::DispatchCall;
106117
107use xcm::latest::{118use xcm::latest::{
108 // Xcm,119 // Xcm,
112 Error as XcmError,123 Error as XcmError,
113};124};
114use xcm_executor::traits::{MatchesFungible, WeightTrader};125use xcm_executor::traits::{MatchesFungible, WeightTrader};
115//use xcm_executor::traits::MatchesFungible;
116use sp_runtime::traits::CheckedConversion;
117126
118use unique_runtime_common::{127use unique_runtime_common::{
119 impl_common_runtime_apis,128 impl_common_runtime_apis,
390impl pallet_balances::Config for Runtime {399impl pallet_balances::Config for Runtime {
391 type MaxLocks = MaxLocks;400 type MaxLocks = MaxLocks;
392 type MaxReserves = ();401 type MaxReserves = ();
393 type ReserveIdentifier = [u8; 8];402 type ReserveIdentifier = [u8; 16];
394 /// The type for recording an account's balance.403 /// The type for recording an account's balance.
395 type Balance = Balance;404 type Balance = Balance;
396 /// The ubiquitous event type.405 /// The ubiquitous event type.
913 type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;922 type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
914}923}
915924
916// parameter_types! {925parameter_types! {
917// pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *926 pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *
918// RuntimeBlockWeights::get().max_block;927 RuntimeBlockWeights::get().max_block;
919// pub const MaxScheduledPerBlock: u32 = 50;928 pub const MaxScheduledPerBlock: u32 = 50;
920// }929}
921930
922type EvmSponsorshipHandler = (931type EvmSponsorshipHandler = (
923 UniqueEthSponsorshipHandler<Runtime>,932 UniqueEthSponsorshipHandler<Runtime>,
929 pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,938 pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
930);939);
931940
932// impl pallet_unq_scheduler::Config for Runtime {941parameter_types! {
933// type Event = Event;942 pub const NoPreimagePostponement: Option<u32> = Some(10);
934// type Origin = Origin;943 pub const Preimage: Option<u32> = Some(10);
935// type PalletsOrigin = OriginCaller;944}
936// type Call = Call;945
937// type MaximumWeight = MaximumSchedulerWeight;946/// Used the compare the privilege of an origin inside the scheduler.
938// type ScheduleOrigin = EnsureSigned<AccountId>;947pub struct OriginPrivilegeCmp;
939// type MaxScheduledPerBlock = MaxScheduledPerBlock;948impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
940// type SponsorshipHandler = SponsorshipHandler;949 fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option<Ordering> {
941// type WeightInfo = ();950 Some(Ordering::Equal)
942// }951 }
952}
953
954impl pallet_unq_scheduler::Config for Runtime {
955 type Event = Event;
956 type Origin = Origin;
957 type Currency = Balances;
958 type PalletsOrigin = OriginCaller;
959 type Call = Call;
960 type MaximumWeight = MaximumSchedulerWeight;
961 type ScheduleOrigin = EnsureSigned<AccountId>;
962 type MaxScheduledPerBlock = MaxScheduledPerBlock;
963 type WeightInfo = ();
964 type CallExecutor = SchedulerPaymentExecutor;
965 type OriginPrivilegeCmp = OriginPrivilegeCmp;
966 type PreimageProvider = ();
967 type NoPreimagePostponement = NoPreimagePostponement;
968}
943969
944impl pallet_evm_transaction_payment::Config for Runtime {970impl pallet_evm_transaction_payment::Config for Runtime {
945 type EvmSponsorshipHandler = EvmSponsorshipHandler;971 type EvmSponsorshipHandler = EvmSponsorshipHandler;
954// type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;980// type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
955// }981// }
982
983type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
984use frame_support::traits::NamedReservableCurrency;
985
986fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {
987 (
988 frame_system::CheckSpecVersion::<Runtime>::new(),
989 frame_system::CheckGenesis::<Runtime>::new(),
990 frame_system::CheckEra::<Runtime>::from(Era::Immortal),
991 frame_system::CheckNonce::<Runtime>::from(frame_system::Pallet::<Runtime>::account_nonce(
992 from,
993 )),
994 frame_system::CheckWeight::<Runtime>::new(),
995 // sponsoring transaction logic
996 // pallet_charge_transaction::ChargeTransactionPayment::<Runtime>::new(0),
997 )
998}
999
1000pub struct SchedulerPaymentExecutor;
1001impl<T: frame_system::Config + pallet_unq_scheduler::Config, SelfContainedSignedInfo>
1002 DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor
1003where
1004 <T as frame_system::Config>::Call: Member
1005 + Dispatchable<Origin = Origin, Info = DispatchInfo>
1006 + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>
1007 + GetDispatchInfo
1008 + From<frame_system::Call<Runtime>>,
1009 SelfContainedSignedInfo: Send + Sync + 'static,
1010 Call: From<<T as frame_system::Config>::Call>
1011 + From<<T as pallet_unq_scheduler::Config>::Call>
1012 + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,
1013 sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,
1014{
1015 fn dispatch_call(
1016 signer: <T as frame_system::Config>::AccountId,
1017 call: <T as pallet_unq_scheduler::Config>::Call,
1018 ) -> Result<
1019 Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,
1020 TransactionValidityError,
1021 > {
1022 let dispatch_info = call.get_dispatch_info();
1023 let extrinsic = fp_self_contained::CheckedExtrinsic::<
1024 AccountId,
1025 Call,
1026 SignedExtraScheduler,
1027 SelfContainedSignedInfo,
1028 > {
1029 signed:
1030 CheckedSignature::<AccountId, SignedExtraScheduler, SelfContainedSignedInfo>::Signed(
1031 signer.clone().into(),
1032 get_signed_extras(signer.into()),
1033 ),
1034 function: call.into(),
1035 };
1036
1037 extrinsic.apply::<Runtime>(&dispatch_info, 0)
1038 }
1039
1040 fn reserve_balance(
1041 id: [u8; 16],
1042 sponsor: <T as frame_system::Config>::AccountId,
1043 call: <T as pallet_unq_scheduler::Config>::Call,
1044 count: u32,
1045 ) -> Result<(), DispatchError> {
1046 let dispatch_info = call.get_dispatch_info();
1047 let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)
1048 .saturating_mul(count.into());
1049
1050 <Balances as NamedReservableCurrency<AccountId>>::reserve_named(
1051 &id,
1052 &(sponsor.into()),
1053 weight.into(),
1054 )
1055 }
1056
1057 fn pay_for_call(
1058 id: [u8; 16],
1059 sponsor: <T as frame_system::Config>::AccountId,
1060 call: <T as pallet_unq_scheduler::Config>::Call,
1061 ) -> Result<u128, DispatchError> {
1062 let dispatch_info = call.get_dispatch_info();
1063 let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);
1064 Ok(
1065 <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
1066 &id,
1067 &(sponsor.into()),
1068 weight.into(),
1069 ),
1070 )
1071 }
1072
1073 fn cancel_reserve(
1074 id: [u8; 16],
1075 sponsor: <T as frame_system::Config>::AccountId,
1076 ) -> Result<u128, DispatchError> {
1077 Ok(
1078 <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
1079 &id,
1080 &(sponsor.into()),
1081 u128::MAX,
1082 ),
1083 )
1084 }
1085}
9561086
957parameter_types! {1087parameter_types! {
958 // 0x842899ECF380553E8a4de75bF534cdf6fBF640491088 // 0x842899ECF380553E8a4de75bF534cdf6fBF64049
1003 // Unique Pallets1133 // Unique Pallets
1004 Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,1134 Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
1005 Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,1135 Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
1006 // Scheduler: pallet_unq_scheduler::{Pallet, Call, Storage, Event<T>} = 62,1136 Scheduler: pallet_unq_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
1007 // free = 631137 // free = 63
1008 Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,1138 Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,
1009 // ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,1139 // ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,
1074 pallet_ethereum::FakeTransactionFinalizer<Runtime>,1204 pallet_ethereum::FakeTransactionFinalizer<Runtime>,
1075);1205);
1206
1207pub type SignedExtraScheduler = (
1208 frame_system::CheckSpecVersion<Runtime>,
1209 frame_system::CheckGenesis<Runtime>,
1210 frame_system::CheckEra<Runtime>,
1211 frame_system::CheckNonce<Runtime>,
1212 frame_system::CheckWeight<Runtime>,
1213 // pallet_charge_transaction::ChargeTransactionPayment<Runtime>,
1214);
1076/// Unchecked extrinsic type as expected by this runtime.1215/// Unchecked extrinsic type as expected by this runtime.
1077pub type UncheckedExtrinsic =1216pub type UncheckedExtrinsic =
1078 fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;1217 fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
modifiedruntime/unique/src/lib.rsdiffbeforeafterboth
3333
34use sp_runtime::{34use sp_runtime::{
35 Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,35 Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,
36 generic::Era,
36 traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, AccountIdConversion, Zero},37 traits::{
38 Applyable, BlockNumberProvider, Dispatchable, PostDispatchInfoOf, Saturating,
39 CheckedConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, AccountIdConversion,
40 Zero, Member,
41 },
37 transaction_validity::{TransactionSource, TransactionValidity},42 transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError},
38 ApplyExtrinsicResult, RuntimeAppPublic,43 ApplyExtrinsicResult, RuntimeAppPublic, SaturatedConversion, DispatchErrorWithPostInfo,
39};44};
45
46use fp_self_contained::{SelfContainedCall, CheckedSignature};
47use sp_std::{cmp::Ordering, marker::PhantomData};
48use pallet_unq_scheduler::DispatchCall;
4049
41use sp_std::prelude::*;50use sp_std::prelude::*;
4251
59 traits::{68 traits::{
60 tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,69 tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,
61 Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,70 Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,
62 OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance,71 OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance, PrivilegeCmp,
63 },72 },
64 weights::{73 weights::{
65 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},74 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
86use smallvec::smallvec;95use smallvec::smallvec;
87use codec::{Encode, Decode};96use codec::{Encode, Decode};
88use fp_rpc::TransactionStatus;97use fp_rpc::TransactionStatus;
89use sp_runtime::{
90 traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf, Saturating},
91 transaction_validity::TransactionValidityError,
92 SaturatedConversion,
93};
9498
95// pub use pallet_timestamp::Call as TimestampCall;99// pub use pallet_timestamp::Call as TimestampCall;
96100
97// Polkadot imports101// Polkadot imports
98use pallet_xcm::XcmPassthrough;102use pallet_xcm::XcmPassthrough;
99use polkadot_parachain::primitives::Sibling;103use polkadot_parachain::primitives::Sibling;
100use up_data_structs::mapping::{CrossTokenAddressMapping, EvmTokenAddressMapping};104use up_data_structs::{
105 CollectionId, TokenId, TokenData, Property, PropertyKeyPermission, CollectionLimits,
106 CollectionStats, RpcCollection,
107 mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping}
108};
101use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};109use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};
102use xcm_builder::{110use xcm_builder::{
103 AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,111 AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
107 ParentIsPreset,115 ParentIsPreset,
108};116};
109use xcm_executor::{Config, XcmExecutor, Assets};117use xcm_executor::{Config, XcmExecutor, Assets};
110use sp_std::{marker::PhantomData};
111118
112use xcm::latest::{119use xcm::latest::{
113 // Xcm,120 // Xcm,
117 Error as XcmError,124 Error as XcmError,
118};125};
119use xcm_executor::traits::{MatchesFungible, WeightTrader};126use xcm_executor::traits::{MatchesFungible, WeightTrader};
120//use xcm_executor::traits::MatchesFungible;
121use sp_runtime::traits::CheckedConversion;127use sp_runtime::traits::CheckedConversion;
122128
123use unique_runtime_common::{129use unique_runtime_common::{
395impl pallet_balances::Config for Runtime {401impl pallet_balances::Config for Runtime {
396 type MaxLocks = MaxLocks;402 type MaxLocks = MaxLocks;
397 type MaxReserves = ();403 type MaxReserves = ();
398 type ReserveIdentifier = [u8; 8];404 type ReserveIdentifier = [u8; 16];
399 /// The type for recording an account's balance.405 /// The type for recording an account's balance.
400 type Balance = Balance;406 type Balance = Balance;
401 /// The ubiquitous event type.407 /// The ubiquitous event type.
918 type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;924 type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
919}925}
920926
921// parameter_types! {927parameter_types! {
922// pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *928 pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *
923// RuntimeBlockWeights::get().max_block;929 RuntimeBlockWeights::get().max_block;
924// pub const MaxScheduledPerBlock: u32 = 50;930 pub const MaxScheduledPerBlock: u32 = 50;
925// }931}
932
933parameter_types! {
934 pub const NoPreimagePostponement: Option<u32> = Some(10);
935 pub const Preimage: Option<u32> = Some(10);
936}
937
938/// Used the compare the privilege of an origin inside the scheduler.
939pub struct OriginPrivilegeCmp;
940impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
941 fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option<Ordering> {
942 Some(Ordering::Equal)
943 }
944}
945
946impl pallet_unq_scheduler::Config for Runtime {
947 type Event = Event;
948 type Origin = Origin;
949 type Currency = Balances;
950 type PalletsOrigin = OriginCaller;
951 type Call = Call;
952 type MaximumWeight = MaximumSchedulerWeight;
953 type ScheduleOrigin = EnsureSigned<AccountId>;
954 type MaxScheduledPerBlock = MaxScheduledPerBlock;
955 type WeightInfo = ();
956 type CallExecutor = SchedulerPaymentExecutor;
957 type OriginPrivilegeCmp = OriginPrivilegeCmp;
958 type PreimageProvider = ();
959 type NoPreimagePostponement = NoPreimagePostponement;
960}
961
962type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
963use frame_support::traits::NamedReservableCurrency;
964
965fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {
966 (
967 frame_system::CheckSpecVersion::<Runtime>::new(),
968 frame_system::CheckGenesis::<Runtime>::new(),
969 frame_system::CheckEra::<Runtime>::from(Era::Immortal),
970 frame_system::CheckNonce::<Runtime>::from(frame_system::Pallet::<Runtime>::account_nonce(
971 from,
972 )),
973 frame_system::CheckWeight::<Runtime>::new(),
974 // sponsoring transaction logic
975 // pallet_charge_transaction::ChargeTransactionPayment::<Runtime>::new(0),
976 )
977}
978
979pub struct SchedulerPaymentExecutor;
980impl<T: frame_system::Config + pallet_unq_scheduler::Config, SelfContainedSignedInfo>
981 DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor
982where
983 <T as frame_system::Config>::Call: Member
984 + Dispatchable<Origin = Origin, Info = DispatchInfo>
985 + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>
986 + GetDispatchInfo
987 + From<frame_system::Call<Runtime>>,
988 SelfContainedSignedInfo: Send + Sync + 'static,
989 Call: From<<T as frame_system::Config>::Call>
990 + From<<T as pallet_unq_scheduler::Config>::Call>
991 + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,
992 sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,
993{
994 fn dispatch_call(
995 signer: <T as frame_system::Config>::AccountId,
996 call: <T as pallet_unq_scheduler::Config>::Call,
997 ) -> Result<
998 Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,
999 TransactionValidityError,
1000 > {
1001 let dispatch_info = call.get_dispatch_info();
1002 let extrinsic = fp_self_contained::CheckedExtrinsic::<
1003 AccountId,
1004 Call,
1005 SignedExtraScheduler,
1006 SelfContainedSignedInfo,
1007 > {
1008 signed:
1009 CheckedSignature::<AccountId, SignedExtraScheduler, SelfContainedSignedInfo>::Signed(
1010 signer.clone().into(),
1011 get_signed_extras(signer.into()),
1012 ),
1013 function: call.into(),
1014 };
1015
1016 extrinsic.apply::<Runtime>(&dispatch_info, 0)
1017 }
1018
1019 fn reserve_balance(
1020 id: [u8; 16],
1021 sponsor: <T as frame_system::Config>::AccountId,
1022 call: <T as pallet_unq_scheduler::Config>::Call,
1023 count: u32,
1024 ) -> Result<(), DispatchError> {
1025 let dispatch_info = call.get_dispatch_info();
1026 let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)
1027 .saturating_mul(count.into());
1028
1029 <Balances as NamedReservableCurrency<AccountId>>::reserve_named(
1030 &id,
1031 &(sponsor.into()),
1032 weight.into(),
1033 )
1034 }
1035
1036 fn pay_for_call(
1037 id: [u8; 16],
1038 sponsor: <T as frame_system::Config>::AccountId,
1039 call: <T as pallet_unq_scheduler::Config>::Call,
1040 ) -> Result<u128, DispatchError> {
1041 let dispatch_info = call.get_dispatch_info();
1042 let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);
1043 Ok(
1044 <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
1045 &id,
1046 &(sponsor.into()),
1047 weight.into(),
1048 ),
1049 )
1050 }
1051
1052 fn cancel_reserve(
1053 id: [u8; 16],
1054 sponsor: <T as frame_system::Config>::AccountId,
1055 ) -> Result<u128, DispatchError> {
1056 Ok(
1057 <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
1058 &id,
1059 &(sponsor.into()),
1060 u128::MAX,
1061 ),
1062 )
1063 }
1064}
9261065
927type EvmSponsorshipHandler = (1066type EvmSponsorshipHandler = (
928 UniqueEthSponsorshipHandler<Runtime>,1067 UniqueEthSponsorshipHandler<Runtime>,
934 pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,1073 pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
935);1074);
936
937// impl pallet_unq_scheduler::Config for Runtime {
938// type Event = Event;
939// type Origin = Origin;
940// type PalletsOrigin = OriginCaller;
941// type Call = Call;
942// type MaximumWeight = MaximumSchedulerWeight;
943// type ScheduleOrigin = EnsureSigned<AccountId>;
944// type MaxScheduledPerBlock = MaxScheduledPerBlock;
945// type SponsorshipHandler = SponsorshipHandler;
946// type WeightInfo = ();
947// }
9481075
949impl pallet_evm_transaction_payment::Config for Runtime {1076impl pallet_evm_transaction_payment::Config for Runtime {
950 type EvmSponsorshipHandler = EvmSponsorshipHandler;1077 type EvmSponsorshipHandler = EvmSponsorshipHandler;
1008 // Unique Pallets1135 // Unique Pallets
1009 Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,1136 Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
1010 Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,1137 Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
1011 // Scheduler: pallet_unq_scheduler::{Pallet, Call, Storage, Event<T>} = 62,1138 Scheduler: pallet_unq_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
1012 // free = 631139 // free = 63
1013 Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,1140 Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,
1014 // ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,1141 // ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,
1078 //pallet_contract_helpers::ContractHelpersExtension<Runtime>,1205 //pallet_contract_helpers::ContractHelpersExtension<Runtime>,
1079 pallet_ethereum::FakeTransactionFinalizer<Runtime>,1206 pallet_ethereum::FakeTransactionFinalizer<Runtime>,
1080);1207);
1208pub type SignedExtraScheduler = (
1209 frame_system::CheckSpecVersion<Runtime>,
1210 frame_system::CheckGenesis<Runtime>,
1211 frame_system::CheckEra<Runtime>,
1212 frame_system::CheckNonce<Runtime>,
1213 frame_system::CheckWeight<Runtime>,
1214 // pallet_charge_transaction::ChargeTransactionPayment<Runtime>,
1215);
1081/// Unchecked extrinsic type as expected by this runtime.1216/// Unchecked extrinsic type as expected by this runtime.
1082pub type UncheckedExtrinsic =1217pub type UncheckedExtrinsic =
1083 fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;1218 fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
modifiedtests/package.jsondiffbeforeafterboth
68 "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",68 "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",
69 "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts",69 "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts",
70 "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",70 "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",
71 "testScheduler": "mocha --timeout 9999999 -r ts-node/register ./**/scheduler.test.ts",
72 "testSchedulingEVM": "mocha --timeout 9999999 -r ts-node/register ./**/eth/scheduling.test.ts",
71 "testXcmTransfer": "mocha --timeout 9999999 -r ts-node/register ./**/xcmTransfer.test.ts",73 "testXcmTransfer": "mocha --timeout 9999999 -r ts-node/register ./**/xcmTransfer.test.ts",
72 "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",74 "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",
73 "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",75 "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",
addedtests/src/eth/scheduling.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/pallet-presence.test.tsdiffbeforeafterboth
50 'unique',50 'unique',
51 'nonfungible',51 'nonfungible',
52 'refungible',52 'refungible',
53 //'scheduler',53 'scheduler',
54 'charging',54 'charging',
55];55];
5656
modifiedtests/src/scheduler.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import chai from 'chai';17import chai, {expect} from 'chai';
18import chaiAsPromised from 'chai-as-promised';18import chaiAsPromised from 'chai-as-promised';
19import privateKey from './substrate/privateKey';19import privateKey from './substrate/privateKey';
20import usingApi from './substrate/substrate-api';20import {
21 default as usingApi,
22 submitTransactionAsync,
23} from './substrate/substrate-api';
21import {24import {
22 createItemExpectSuccess,25 createItemExpectSuccess,
23 createCollectionExpectSuccess,26 createCollectionExpectSuccess,
24 scheduleTransferExpectSuccess,27 scheduleTransferExpectSuccess,
28 scheduleTransferAndWaitExpectSuccess,
25 setCollectionSponsorExpectSuccess,29 setCollectionSponsorExpectSuccess,
26 confirmSponsorshipExpectSuccess,30 confirmSponsorshipExpectSuccess,
31 findUnusedAddress,
32 UNIQUE,
33 enablePublicMintingExpectSuccess,
34 addToAllowListExpectSuccess,
35 waitNewBlocks,
36 normalizeAccountId,
37 getTokenOwner,
38 getGenericResult,
39 scheduleTransferFundsPeriodicExpectSuccess,
40 getFreeBalance,
41 confirmSponsorshipByKeyExpectSuccess,
42 scheduleExpectFailure,
27} from './util/helpers';43} from './util/helpers';
44import {IKeyringPair} from '@polkadot/types/types';
2845
29chai.use(chaiAsPromised);46chai.use(chaiAsPromised);
3047
31describe.skip('Integration Test scheduler base transaction', () => {48describe.skip('Scheduling token and balance transfers', () => {
49 let alice: IKeyringPair;
50 let bob: IKeyringPair;
51 let scheduledIdBase: string;
52 let scheduledIdSlider: number;
53
54 before(async() => {
55 await usingApi(async () => {
56 alice = privateKey('//Alice');
57 bob = privateKey('//Bob');
58 });
59
60 scheduledIdBase = '0x' + '0'.repeat(31);
61 scheduledIdSlider = 0;
62 });
63
64 // Loop scheduledId around 10. Unless there are concurrent tasks with long periods/repetitions, tests' tasks' ids shouldn't ovelap.
65 function makeScheduledId(): string {
66 return scheduledIdBase + ((scheduledIdSlider++) % 10);
67 }
68
32 it('User can transfer owned token with delay (scheduler)', async () => {69 it('Can schedule a transfer of an owned token with delay', async () => {
33 await usingApi(async () => {70 await usingApi(async () => {
34 const alice = privateKey('//Alice');
35 const bob = privateKey('//Bob');
36 // nft
37 const nftCollectionId = await createCollectionExpectSuccess();71 const nftCollectionId = await createCollectionExpectSuccess();
38 const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');72 const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
39 await setCollectionSponsorExpectSuccess(nftCollectionId, alice.address);73 await setCollectionSponsorExpectSuccess(nftCollectionId, alice.address);
40 await confirmSponsorshipExpectSuccess(nftCollectionId);74 await confirmSponsorshipExpectSuccess(nftCollectionId);
4175
42 await scheduleTransferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 1, 4);76 await scheduleTransferAndWaitExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 1, 4, makeScheduledId());
43 });77 });
44 });78 });
79
80 it('Can transfer funds periodically', async () => {
81 await usingApi(async () => {
82 const waitForBlocks = 4;
83 const period = 2;
84 await scheduleTransferFundsPeriodicExpectSuccess(1n * UNIQUE, alice, bob, waitForBlocks, makeScheduledId(), period, 2);
85 const bobsBalanceBefore = await getFreeBalance(bob);
86
87 // discounting already waited-for operations
88 await waitNewBlocks(waitForBlocks - 2);
89 const bobsBalanceAfterFirst = await getFreeBalance(bob);
90 expect(bobsBalanceAfterFirst > bobsBalanceBefore).to.be.true;
91
92 await waitNewBlocks(period);
93 const bobsBalanceAfterSecond = await getFreeBalance(bob);
94 expect(bobsBalanceAfterSecond > bobsBalanceAfterFirst).to.be.true;
95 });
96 });
97
98 it('Can sponsor scheduling a transaction', async () => {
99 const collectionId = await createCollectionExpectSuccess();
100 await setCollectionSponsorExpectSuccess(collectionId, bob.address);
101 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
102
103 await usingApi(async () => {
104 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
105
106 const bobBalanceBefore = await getFreeBalance(bob);
107 const waitForBlocks = 4;
108 // no need to wait to check, fees must be deducted on scheduling, immediately
109 await scheduleTransferExpectSuccess(collectionId, tokenId, alice, bob, 0, waitForBlocks, makeScheduledId());
110 const bobBalanceAfter = await getFreeBalance(bob);
111 // expect(aliceBalanceAfter == aliceBalanceBefore).to.be.true;
112 expect(bobBalanceAfter < bobBalanceBefore).to.be.true;
113 // wait for sequentiality matters
114 await waitNewBlocks(waitForBlocks - 1);
115 });
116 });
117
118 it('Schedules and dispatches a transaction even if the caller has no funds at the time of the dispatch', async () => {
119 await usingApi(async (api) => {
120 // Find an empty, unused account
121 const zeroBalance = await findUnusedAddress(api);
122
123 const collectionId = await createCollectionExpectSuccess();
124
125 // Add zeroBalance address to allow list
126 await enablePublicMintingExpectSuccess(alice, collectionId);
127 await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);
128
129 // Grace zeroBalance with money, enough to cover future transactions
130 const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);
131 await submitTransactionAsync(alice, balanceTx);
132
133 // Mint a fresh NFT
134 const tokenId = await createItemExpectSuccess(zeroBalance, collectionId, 'NFT');
135
136 // Schedule transfer of the NFT a few blocks ahead
137 const waitForBlocks = 5;
138 await scheduleTransferExpectSuccess(collectionId, tokenId, zeroBalance, alice, 1, waitForBlocks, makeScheduledId());
139
140 // Get rid of the account's funds before the scheduled transaction takes place
141 const balanceTx2 = api.tx.balances.transfer(alice.address, UNIQUE * 68n / 100n);
142 const events = await submitTransactionAsync(zeroBalance, balanceTx2);
143 expect(getGenericResult(events).success).to.be.true;
144 /*const emptyBalanceTx = api.tx.balances.setBalance(zeroBalance.address, 0, 0); // do not null reserved?
145 const sudoTx = api.tx.sudo.sudo(emptyBalanceTx as any);
146 const events = await submitTransactionAsync(alice, sudoTx);
147 expect(getGenericResult(events).success).to.be.true;*/
148
149 // Wait for a certain number of blocks, discarding the ones that already happened while accepting the late transactions
150 await waitNewBlocks(waitForBlocks - 3);
151
152 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(alice.address));
153 });
154 });
155
156 it('Sponsor going bankrupt does not impact a scheduled transaction', async () => {
157 const collectionId = await createCollectionExpectSuccess();
158
159 await usingApi(async (api) => {
160 const zeroBalance = await findUnusedAddress(api);
161 const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);
162 await submitTransactionAsync(alice, balanceTx);
163
164 await setCollectionSponsorExpectSuccess(collectionId, zeroBalance.address);
165 await confirmSponsorshipByKeyExpectSuccess(collectionId, zeroBalance);
166
167 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
168
169 const waitForBlocks = 5;
170 await scheduleTransferExpectSuccess(collectionId, tokenId, alice, zeroBalance, 1, waitForBlocks, makeScheduledId());
171
172 const emptyBalanceSponsorTx = api.tx.balances.setBalance(zeroBalance.address, 0, 0);
173 const sudoTx = api.tx.sudo.sudo(emptyBalanceSponsorTx as any);
174 const events = await submitTransactionAsync(alice, sudoTx);
175 expect(getGenericResult(events).success).to.be.true;
176
177 // Wait for a certain number of blocks, save for the ones that already happened while accepting the late transactions
178 await waitNewBlocks(waitForBlocks - 3);
179
180 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(zeroBalance.address));
181 });
182 });
183
184 it.skip('Exceeding sponsor rate limit without having enough funds prevents scheduling a periodic transaction', async () => {
185 const collectionId = await createCollectionExpectSuccess();
186 await setCollectionSponsorExpectSuccess(collectionId, bob.address);
187 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
188
189 await usingApi(async (api) => {
190 const zeroBalance = await findUnusedAddress(api);
191
192 await enablePublicMintingExpectSuccess(alice, collectionId);
193 await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);
194
195 const bobBalanceBefore = await getFreeBalance(bob);
196
197 const createData = {nft: {const_data: [], variable_data: []}};
198 const creationTx = api.tx.unique.createItem(collectionId, normalizeAccountId(zeroBalance), createData as any);
199
200 /*const badTransaction = async function () {
201 await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice);
202 };
203 await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');*/
204
205 await scheduleExpectFailure(creationTx, zeroBalance, 3, makeScheduledId(), 1, 3);
206
207 expect(await getFreeBalance(bob)).to.be.equal(bobBalanceBefore);
208 });
209 });
45});210});
46211
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
629 });629 });
630}630}
631
632export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed = '//Alice') {
633 await usingApi(async () => {
634 const sender = privateKey(senderSeed);
635 await confirmSponsorshipByKeyExpectSuccess(collectionId, sender);
636 });
637}
631638
632export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed = '//Alice') {639export async function confirmSponsorshipByKeyExpectSuccess(collectionId: number, sender: IKeyringPair) {
633 await usingApi(async (api) => {640 await usingApi(async (api) => {
634641
635 // Run the transaction642 // Run the transaction
636 const sender = privateKey(senderSeed);
637 const tx = api.tx.unique.confirmSponsorship(collectionId);643 const tx = api.tx.unique.confirmSponsorship(collectionId);
638 const events = await submitTransactionAsync(sender, tx);644 const events = await submitTransactionAsync(sender, tx);
639 const result = getGenericResult(events);645 const result = getGenericResult(events);
899}905}
900906
901/* eslint no-async-promise-executor: "off" */907/* eslint no-async-promise-executor: "off" */
902async function getBlockNumber(api: ApiPromise): Promise<number> {908export async function getBlockNumber(api: ApiPromise): Promise<number> {
903 return new Promise<number>(async (resolve) => {909 return new Promise<number>(async (resolve) => {
904 const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {910 const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {
905 unsubscribe();911 unsubscribe();
934 expect(result.success).to.be.true;940 expect(result.success).to.be.true;
935}941}
942
943export async function
944scheduleExpectSuccess(
945 operationTx: any,
946 sender: IKeyringPair,
947 blockSchedule: number,
948 scheduledId: string,
949 period = 1,
950 repetitions = 1,
951) {
952 await usingApi(async (api: ApiPromise) => {
953 const blockNumber: number | undefined = await getBlockNumber(api);
954 const expectedBlockNumber = blockNumber + blockSchedule;
955
956 expect(blockNumber).to.be.greaterThan(0);
957 const scheduleTx = api.tx.scheduler.scheduleNamed( // schedule
958 scheduledId,
959 expectedBlockNumber,
960 repetitions > 1 ? [period, repetitions] : null,
961 0,
962 {value: operationTx as any},
963 );
964
965 const events = await submitTransactionAsync(sender, scheduleTx);
966 expect(getGenericResult(events).success).to.be.true;
967 });
968}
969
970export async function
971scheduleExpectFailure(
972 operationTx: any,
973 sender: IKeyringPair,
974 blockSchedule: number,
975 scheduledId: string,
976 period = 1,
977 repetitions = 1,
978) {
979 await usingApi(async (api: ApiPromise) => {
980 const blockNumber: number | undefined = await getBlockNumber(api);
981 const expectedBlockNumber = blockNumber + blockSchedule;
982
983 expect(blockNumber).to.be.greaterThan(0);
984 const scheduleTx = api.tx.scheduler.scheduleNamed( // schedule
985 scheduledId,
986 expectedBlockNumber,
987 repetitions <= 1 ? null : [period, repetitions],
988 0,
989 {value: operationTx as any},
990 );
991
992 //const events =
993 await expect(submitTransactionExpectFailAsync(sender, scheduleTx)).to.be.rejected;
994 //expect(getGenericResult(events).success).to.be.false;
995 });
996}
936997
937export async function998export async function
938scheduleTransferExpectSuccess(999scheduleTransferAndWaitExpectSuccess(
939 collectionId: number,1000 collectionId: number,
940 tokenId: number,1001 tokenId: number,
941 sender: IKeyringPair,1002 sender: IKeyringPair,
942 recipient: IKeyringPair,1003 recipient: IKeyringPair,
943 value: number | bigint = 1,1004 value: number | bigint = 1,
944 blockSchedule: number,1005 blockSchedule: number,
1006 scheduledId: string,
945) {1007) {
946 await usingApi(async (api: ApiPromise) => {1008 await usingApi(async (api: ApiPromise) => {
947 const blockNumber: number | undefined = await getBlockNumber(api);
948 const expectedBlockNumber = blockNumber + blockSchedule;
949
950 expect(blockNumber).to.be.greaterThan(0);
951 const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);1009 await scheduleTransferExpectSuccess(collectionId, tokenId, sender, recipient, value, blockSchedule, scheduledId);
952 const scheduleTx = api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx as any);
953
954 await submitTransactionAsync(sender, scheduleTx);
9551010
956 const recipientBalanceBefore = (await api.query.system.account(recipient.address)).data.free.toBigInt();1011 const recipientBalanceBefore = (await api.query.system.account(recipient.address)).data.free.toBigInt();
957
958 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(sender.address));
9591012
960 // sleep for 4 blocks1013 // sleep for n + 1 blocks
961 await waitNewBlocks(blockSchedule + 1);1014 await waitNewBlocks(blockSchedule + 1);
9621015
963 const recipientBalanceAfter = (await api.query.system.account(recipient.address)).data.free.toBigInt();1016 const recipientBalanceAfter = (await api.query.system.account(recipient.address)).data.free.toBigInt();
967 });1020 });
968}1021}
9691022
1023export async function
1024scheduleTransferExpectSuccess(
1025 collectionId: number,
1026 tokenId: number,
1027 sender: IKeyringPair,
1028 recipient: IKeyringPair,
1029 value: number | bigint = 1,
1030 blockSchedule: number,
1031 scheduledId: string,
1032) {
1033 await usingApi(async (api: ApiPromise) => {
1034 const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);
1035
1036 await scheduleExpectSuccess(transferTx, sender, blockSchedule, scheduledId);
1037
1038 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(sender.address));
1039 });
1040}
1041
1042export async function
1043scheduleTransferFundsPeriodicExpectSuccess(
1044 amount: bigint,
1045 sender: IKeyringPair,
1046 recipient: IKeyringPair,
1047 blockSchedule: number,
1048 scheduledId: string,
1049 period: number,
1050 repetitions: number,
1051) {
1052 await usingApi(async (api: ApiPromise) => {
1053 const transferTx = api.tx.balances.transfer(recipient.address, amount);
1054
1055 const balanceBefore = await getFreeBalance(recipient);
1056
1057 await scheduleExpectSuccess(transferTx, sender, blockSchedule, scheduledId, period, repetitions);
1058
1059 expect(await getFreeBalance(recipient)).to.be.equal(balanceBefore);
1060 });
1061}
9701062
971export async function1063export async function
972transferExpectSuccess(1064transferExpectSuccess(