From b587267ca701b1da5d5a8201294692a305ece8f6 Mon Sep 17 00:00:00 2001 From: str-mv Date: Thu, 24 Feb 2022 07:35:17 +0000 Subject: [PATCH] Scheduler sponsoring balance reserve --- --- a/pallets/scheduler/src/lib.rs +++ b/pallets/scheduler/src/lib.rs @@ -78,6 +78,9 @@ use up_sponsorship::SponsorshipHandler; use scale_info::TypeInfo; use sp_core::H160; +use frame_support::traits::NamedReservableCurrency; + +type ScheduledId = [u8; MAX_TASK_ID_LENGTH_IN_BYTES as usize]; /// Our pallet's configuration trait. All our types and constants go in here. If the /// pallet is dependent on specific other pallets, then their configuration traits @@ -97,6 +100,8 @@ /// The caller origin, overarching type of all pallets origins. type PalletsOrigin: From> + Codec + TypeInfo + Clone + Eq; + type Currency: NamedReservableCurrency; + /// The aggregated call type. type Call: Parameter + Dispatchable::Origin> @@ -129,6 +134,19 @@ /// The type that encodes information that can be passed from pre_dispatch to post-dispatch. type Pre: Default + Codec + Clone + TypeInfo; + fn reserve_balance( + id: ScheduledId, + sponsor: ::AccountId, + call: ::Call, + count: u32, + ) -> Result<(), DispatchError>; + + fn pay_for_call( + id: ScheduledId, + sponsor: ::AccountId, + call: ::Call, + ) -> Result; + /// Resolve the call dispatch, including any post-dispatch operations. fn dispatch_call( pre_dispatch: Self::Pre, @@ -164,7 +182,7 @@ #[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo)] pub struct Scheduled { /// The unique identity for this task, if there is one. - maybe_id: Option>, + maybe_id: Option, /// This task's priority. priority: schedule::Priority, /// The call to be dispatched. @@ -197,7 +215,7 @@ >>>; /// Lookup from identity to the block number and index of the task. - Lookup: map hasher(twox_64_concat) Vec => Option>; + Lookup: map hasher(twox_64_concat) ScheduledId => Option>; } } @@ -208,7 +226,7 @@ /// Canceled some task. \[when, index\] Canceled(BlockNumber, u32), /// Dispatched some task. \[task, id, result\] - Dispatched(TaskAddress, Option>, DispatchResult), + Dispatched(TaskAddress, Option, DispatchResult), } ); @@ -285,7 +303,7 @@ /// # #[weight = ::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get())] fn schedule_named(origin, - id: Vec, + id: ScheduledId, when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, @@ -309,7 +327,7 @@ /// - Will use base weight of 100 which should be good for up to 30 scheduled calls /// # #[weight = ::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get())] - fn cancel_named(origin, id: Vec) { + fn cancel_named(origin, id: ScheduledId) { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::Origin::from(origin); Self::do_cancel_named(Some(origin.caller().clone()), id)?; @@ -341,7 +359,7 @@ /// # #[weight = ::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get())] fn schedule_named_after(origin, - id: Vec, + id: ScheduledId, after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, @@ -410,6 +428,24 @@ Some((order, index, *cumulative_weight, s)) }) .filter_map(|(order, index, cumulative_weight, mut s)| { + + // if call have id and periodic, it was be reserved + if s.maybe_id.is_some() && s.maybe_periodic.is_some() + { + let sender = ensure_signed( + <::Origin as From>::from(s.origin.clone()).into(), + ) + .unwrap_or_default(); + let who_will_pay = T::SponsorshipHandler::get_sponsor(&sender, &s.call.clone()) + .unwrap_or(sender.clone()); + + T::CallExecutor::pay_for_call( + s.maybe_id.unwrap(), + who_will_pay.clone(), + s.call.clone(), + ); + } + // We allow a scheduled call if: // - It's priority is `HARD_DEADLINE` // - It does not push the weight past the limit @@ -419,7 +455,7 @@ let r = T::CallExecutor::dispatch_call(s.pre_dispatch.clone(), s.call.clone()); if let Err(_) = r { - log::warn!( + log::info!( target: "runtime::scheduler", "Warning: Scheduler has failed to execute a post-dispatch transaction. \ This block might have become invalid.", @@ -486,7 +522,7 @@ } fn do_schedule( - maybe_id: Option>, + maybe_id: Option, when: DispatchTime, maybe_periodic: Option>, priority: schedule::Priority, @@ -519,11 +555,24 @@ .map(|(p, c)| (p, cmp::min(c, PERIODIC_CALLS_LIMIT) - 1)); if let Some(periodic) = maybe_periodic { - for _i in 0..=periodic.1 { + + // reserve balance for periodic execution + if maybe_id.is_some() + { + let sender = ensure_signed( + <::Origin as From>::from(origin.clone()).into(), + ) + .unwrap_or_default(); + let who_will_pay = T::SponsorshipHandler::get_sponsor(&sender, &call.clone()) + .unwrap_or(sender.clone()); + T::CallExecutor::reserve_balance(maybe_id.unwrap(), who_will_pay.clone(), call.clone(), periodic.1); + } + + //for _i in 0..=periodic.1 { // displace to runtime and count the total required fee, then deduct. find a way to use OnChargePayment // send constants and priority to runtime for fee computation, too. should create constants here or just declare them in runtime? // roadblock - they will return on post_dispatch -- oh! tips? - } + //} } let s = Some(Scheduled { @@ -623,7 +672,7 @@ } fn do_schedule_named( - id: Vec, + id: ScheduledId, when: DispatchTime, maybe_periodic: Option>, priority: schedule::Priority, @@ -652,7 +701,7 @@ Ok(address) } - fn do_cancel_named(origin: Option, id: Vec) -> DispatchResult { + fn do_cancel_named(origin: Option, id: ScheduledId) -> DispatchResult { Lookup::::try_mutate_exists(id, |lookup| -> DispatchResult { if let Some((when, index)) = lookup.take() { let i = index as usize; @@ -684,7 +733,7 @@ } fn do_reschedule_named( - id: Vec, + id: ScheduledId, new_time: DispatchTime, ) -> Result, DispatchError> { let new_time = Self::resolve_time(new_time)?; @@ -765,22 +814,27 @@ origin: T::PalletsOrigin, call: ::Call, ) -> Result { - Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call).map_err(|_| ()) + + let inner_id: ScheduledId = id.try_into().unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]); + Self::do_schedule_named(inner_id, when, maybe_periodic, priority, origin, call).map_err(|_| ()) } fn cancel_named(id: Vec) -> Result<(), ()> { - Self::do_cancel_named(None, id).map_err(|_| ()) + let inner_id: ScheduledId = id.try_into().unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]); + Self::do_cancel_named(None, inner_id).map_err(|_| ()) } fn reschedule_named( id: Vec, when: DispatchTime, ) -> Result { - Self::do_reschedule_named(id, when) + let inner_id: ScheduledId = id.try_into().unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]); + Self::do_reschedule_named(inner_id, when) } fn next_dispatch_time(id: Vec) -> Result { - Lookup::::get(id) + let inner_id: ScheduledId = id.try_into().unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]); + Lookup::::get(inner_id) .and_then(|(when, index)| Agenda::::get(when).get(index as usize).map(|_| when)) .ok_or(()) } --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -393,12 +393,13 @@ // pub const ExistentialDeposit: u128 = 500; pub const ExistentialDeposit: u128 = 0; pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; } impl pallet_balances::Config for Runtime { type MaxLocks = MaxLocks; - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 16]; /// The type for recording an account's balance. type Balance = Balance; /// The ubiquitous event type. @@ -818,6 +819,9 @@ fee: Option, } + +use frame_support::traits::NamedReservableCurrency; + pub struct SchedulerPaymentExecutor; impl DispatchCall for SchedulerPaymentExecutor @@ -865,6 +869,54 @@ Ok(res) } + fn reserve_balance( + id: [u8; 16], + sponsor: ::AccountId, + call: ::Call, + count: u32, + ) -> Result<(), DispatchError> + { + let dispatch_info = call.get_dispatch_info(); + let fee_charger = ChargeTransactionPayment::new( + 0 + ); + let pre = match fee_charger.pre_dispatch(&sponsor.clone().into(), &call.into(), &dispatch_info, 0) { + Ok(p) => p, + Err(_) => fail!("failed to get pre dispatch info") + }; + + let count: u128 = count.into(); + let total_fee: u128 = pre.2.map(|imbalance| imbalance.peek()).unwrap() * count; + >::reserve_named( + &id, + &(sponsor.into()), + total_fee) + } + + fn pay_for_call( + id: [u8; 16], + sponsor: ::AccountId, + call: ::Call, + ) + -> Result + { + let dispatch_info = call.get_dispatch_info(); + let fee_charger = ChargeTransactionPayment::new( + 0 + ); + let pre = match fee_charger.pre_dispatch(&sponsor.clone().into(), &call.into(), &dispatch_info, 0) { + Ok(p) => p, + Err(_) => fail!("failed to get pre dispatch info") + }; + + let single_fee: u128 = pre.2.map(|imbalance| imbalance.peek()).unwrap(); + + Ok(>::unreserve_named( + &id, + &(sponsor.into()), + single_fee)) + } + fn pre_dispatch( signer: ::AccountId, call: ::Call, @@ -893,6 +945,7 @@ impl pallet_unq_scheduler::Config for Runtime { type Event = Event; type Origin = Origin; + type Currency = Balances; type PalletsOrigin = OriginCaller; type Call = Call; type MaximumWeight = MaximumSchedulerWeight; -- gitstuff