diff --git a/bin/node-template/pallets/template/src/mock.rs b/bin/node-template/pallets/template/src/mock.rs index 2ea81ffb45626..6e295de3ce092 100644 --- a/bin/node-template/pallets/template/src/mock.rs +++ b/bin/node-template/pallets/template/src/mock.rs @@ -42,6 +42,7 @@ impl system::Trait for Test { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl Trait for Test { type Event = (); diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 0414759a5ad86..a0039a4efddfe 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -167,6 +167,8 @@ impl system::Trait for Runtime { type OnKilledAccount = (); /// The data to be stored in an account. type AccountData = balances::AccountData; + // This is the central place where all calls are dispatched from. + type RootDispatcher = system::Module; } impl aura::Trait for Runtime { @@ -219,6 +221,7 @@ impl transaction_payment::Trait for Runtime { impl sudo::Trait for Runtime { type Event = Event; type Call = Call; + type Dispatcher = ::RootDispatcher; } /// Used for the module template in `./template.rs` diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 58728a507bce2..4c6c2e4659bd6 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -143,6 +143,7 @@ impl frame_system::Trait for Runtime { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = frame_system::Module; } parameter_types! { @@ -160,6 +161,7 @@ impl pallet_utility::Trait for Runtime { type MultisigDepositBase = MultisigDepositBase; type MultisigDepositFactor = MultisigDepositFactor; type MaxSignatories = MaxSignatories; + type Dispatcher = ::RootDispatcher; } parameter_types! { @@ -341,6 +343,7 @@ impl pallet_democracy::Trait for Runtime { type CooloffPeriod = CooloffPeriod; type PreimageByteDeposit = PreimageByteDeposit; type Slash = Treasury; + type Dispatcher = ::RootDispatcher; } parameter_types! { @@ -353,6 +356,7 @@ impl pallet_collective::Trait for Runtime { type Proposal = Call; type Event = Event; type MotionDuration = CouncilMotionDuration; + type Dispatcher = ::RootDispatcher; } parameter_types! { @@ -388,6 +392,7 @@ impl pallet_collective::Trait for Runtime { type Proposal = Call; type Event = Event; type MotionDuration = TechnicalMotionDuration; + type Dispatcher = ::RootDispatcher; } impl pallet_membership::Trait for Runtime { @@ -447,6 +452,7 @@ impl pallet_contracts::Trait for Runtime { type Event = Event; type DetermineContractAddress = pallet_contracts::SimpleAddressDeterminer; type ComputeDispatchFee = pallet_contracts::DefaultDispatchFeeComputor; + type Dispatcher = ::RootDispatcher; type TrieIdGenerator = pallet_contracts::TrieIdFromParentCounter; type GasPayment = (); type RentPayment = (); @@ -469,6 +475,7 @@ impl pallet_contracts::Trait for Runtime { impl pallet_sudo::Trait for Runtime { type Event = Event; type Call = Call; + type Dispatcher = ::RootDispatcher; } /// A runtime transaction submitter. @@ -586,6 +593,7 @@ impl pallet_recovery::Trait for Runtime { type FriendDepositFactor = FriendDepositFactor; type MaxFriends = MaxFriends; type RecoveryDeposit = RecoveryDeposit; + type Dispatcher = ::RootDispatcher; } parameter_types! { diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 838d21a46244b..6419c0e6b4107 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -296,6 +296,7 @@ mod tests { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl Trait for Test { type Event = (); diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index 05a161ee49c3d..a934d1fcbb59c 100644 --- a/frame/aura/src/mock.rs +++ b/frame/aura/src/mock.rs @@ -64,6 +64,7 @@ impl frame_system::Trait for Test { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl pallet_timestamp::Trait for Test { diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index 8ee4931e488c3..d6cdd688306c0 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -160,6 +160,7 @@ mod tests { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl_outer_origin! { diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index d3c1bf752aeb8..ec2a8cd5b8be4 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -434,6 +434,7 @@ mod tests { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 2ec083728e82c..1e9c96a14b06b 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -67,6 +67,7 @@ impl frame_system::Trait for Test { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl_opaque_keys! { diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index b83530d6352eb..8addb642bdf9e 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -853,6 +853,7 @@ impl, I: Instance> frame_system::Trait for ElevatedTrait { type OnNewAccount = T::OnNewAccount; type OnKilledAccount = T::OnKilledAccount; type AccountData = T::AccountData; + type RootDispatcher = (); } impl, I: Instance> Trait for ElevatedTrait { type Balance = T::Balance; diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index 3a5c2178f88cd..bb45e0733613d 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -68,6 +68,7 @@ impl frame_system::Trait for Test { type AccountData = super::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { pub const TransactionBaseFee: u64 = 0; diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index 861c1972127a0..af181cc959311 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -68,6 +68,7 @@ impl frame_system::Trait for Test { type AccountData = super::AccountData; type OnNewAccount = (); type OnKilledAccount = Module; + type RootDispatcher = (); } parameter_types! { pub const TransactionBaseFee: u64 = 0; diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index a18048d305337..f860ab832a98f 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -23,7 +23,7 @@ mod utils; pub use utils::*; #[doc(hidden)] pub use sp_io::storage::root as storage_root; -pub use sp_runtime::traits::Dispatchable; +pub use sp_runtime::{SimpleDispatcher, traits::{Dispatchable, Dispatcher}}; /// Construct pallet benchmarks for weighing dispatchables. /// @@ -158,7 +158,7 @@ macro_rules! benchmarks_iter { ) => { $crate::benchmarks_iter! { { $( $common )* } ( $( $names )* ) $name { $( $code )* }: { - as $crate::Dispatchable>::dispatch(Call::::$dispatch($($arg),*), $origin.into())?; + <$crate::SimpleDispatcher as $crate::Dispatcher<_, _>>::dispatch(Call::::$dispatch($($arg),*), $origin.into()).result?; } $( $rest )* } }; diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index 4327476c4a6c7..8d44caeb87aeb 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -73,6 +73,7 @@ impl frame_system::Trait for Test { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl Trait for Test { diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 0f5a16ed7ae9a..f86ef2d446a87 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -39,7 +39,7 @@ use sp_std::{prelude::*, result}; use sp_core::u32_trait::Value as U32; use sp_runtime::RuntimeDebug; -use sp_runtime::traits::{Hash, EnsureOrigin}; +use sp_runtime::traits::{Hash, EnsureOrigin, Dispatcher}; use frame_support::weights::SimpleDispatchInfo; use frame_support::{ dispatch::{Dispatchable, Parameter}, codec::{Encode, Decode}, @@ -69,6 +69,9 @@ pub trait Trait: frame_system::Trait { /// The time-out for council motions. type MotionDuration: Get; + + /// The means of dispatching the calls to the runtime. + type Dispatcher: Dispatcher<>::Proposal, >::Origin>; } /// Origin for the collective module. @@ -203,7 +206,7 @@ decl_module! { ensure!(Self::is_member(&who), Error::::NotMember); let proposal_hash = T::Hashing::hash_of(&proposal); - let ok = proposal.dispatch(RawOrigin::Member(who).into()).is_ok(); + let ok = T::Dispatcher::dispatch(*proposal, RawOrigin::Member(who).into()).is_ok(); Self::deposit_event(RawEvent::MemberExecuted(proposal_hash, ok)); } @@ -222,7 +225,7 @@ decl_module! { if threshold < 2 { let seats = Self::members().len() as MemberCount; - let ok = proposal.dispatch(RawOrigin::Members(1, seats).into()).is_ok(); + let ok = T::Dispatcher::dispatch(*proposal, RawOrigin::Members(1, seats).into()).is_ok(); Self::deposit_event(RawEvent::Executed(proposal_hash, ok)); } else { let index = Self::proposal_count(); @@ -360,7 +363,7 @@ impl, I: Instance> Module { // execute motion, assuming it exists. if let Some(p) = ProposalOf::::take(&proposal) { let origin = RawOrigin::Members(voting.threshold, seats).into(); - let ok = p.dispatch(origin).is_ok(); + let ok = T::Dispatcher::dispatch(p, origin).is_ok(); Self::deposit_event(RawEvent::Executed(proposal, ok)); } } else { @@ -537,18 +540,21 @@ mod tests { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl Trait for Test { type Origin = Origin; type Proposal = Call; type Event = Event; type MotionDuration = MotionDuration; + type Dispatcher = sp_runtime::SimpleDispatcher; } impl Trait for Test { type Origin = Origin; type Proposal = Call; type Event = Event; type MotionDuration = MotionDuration; + type Dispatcher = sp_runtime::SimpleDispatcher; } pub type Block = sp_runtime::generic::Block; diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index eeaa35a53d278..66bf1d45d0d91 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -113,7 +113,9 @@ use sp_std::{prelude::*, marker::PhantomData, fmt::Debug}; use codec::{Codec, Encode, Decode}; use sp_io::hashing::blake2_256; use sp_runtime::{ - traits::{Hash, StaticLookup, Zero, MaybeSerializeDeserialize, Member, SignedExtension}, + traits::{ + Hash, StaticLookup, Zero, MaybeSerializeDeserialize, Member, SignedExtension, Dispatcher, + }, transaction_validity::{ ValidTransaction, InvalidTransaction, TransactionValidity, TransactionValidityError, }, @@ -366,6 +368,9 @@ pub trait Trait: frame_system::Trait { /// trie id generator type TrieIdGenerator: TrieIdGenerator; + /// The means of dispatching the calls to the runtime. + type Dispatcher: Dispatcher<::Call, Self::Origin>; + /// Handler for the unbalanced reduction when making a gas payment. type GasPayment: OnUnbalanced>; @@ -763,7 +768,7 @@ impl Module { origin: who, call, } => { - let result = call.dispatch(RawOrigin::Signed(who.clone()).into()); + let result = T::Dispatcher::dispatch(call, RawOrigin::Signed(who.clone()).into()).result; Self::deposit_event(RawEvent::Dispatched(who, result.is_ok())); } RestoreTo { diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 3f01096b88397..5997fa7d36684 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -118,6 +118,7 @@ impl frame_system::Trait for Test { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = Contracts; + type RootDispatcher = (); } impl pallet_balances::Trait for Test { type Balance = u64; @@ -174,6 +175,7 @@ impl Trait for Test { type MaxDepth = MaxDepth; type MaxValueSize = MaxValueSize; type BlockGasLimit = BlockGasLimit; + type Dispatcher = sp_runtime::SimpleDispatcher; } type Balances = pallet_balances::Module; diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 32371c8a3a945..1c40dcdf1ef09 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -165,7 +165,10 @@ use sp_std::prelude::*; use sp_runtime::{ - DispatchResult, DispatchError, traits::{Zero, EnsureOrigin, Hash, Dispatchable, Saturating}, + DispatchResult, DispatchError, traits::{ + Zero, EnsureOrigin, Hash, Dispatchable, Dispatcher, Saturating + }, + }; use codec::{Ref, Decode}; use frame_support::{ @@ -270,6 +273,9 @@ pub trait Trait: frame_system::Trait + Sized { /// Handler for the unbalanced reduction when slashing a preimage deposit. type Slash: OnUnbalanced>; + + /// The means of dispatching the proposals. + type Dispatcher: Dispatcher; } decl_storage! { @@ -1539,7 +1545,11 @@ impl Module { let _ = T::Currency::unreserve(&who, amount); Self::deposit_event(RawEvent::PreimageUsed(proposal_hash, who, amount)); - let ok = proposal.dispatch(frame_system::RawOrigin::Root.into()).is_ok(); + let ok = T::Dispatcher::dispatch( + proposal, + frame_system::RawOrigin::Root.into() + ) + .is_ok(); Self::deposit_event(RawEvent::Executed(index, ok)); Ok(()) @@ -1663,4 +1673,4 @@ impl Module { } Ok(()) } -} +} \ No newline at end of file diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index f2544470aa722..8646d024391aa 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -87,6 +87,7 @@ impl frame_system::Trait for Test { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { pub const ExistentialDeposit: u64 = 1; @@ -152,6 +153,7 @@ impl super::Trait for Test { type Slash = (); type InstantOrigin = EnsureSignedBy; type InstantAllowed = InstantAllowed; + type Dispatcher = sp_runtime::SimpleDispatcher; } fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index d74fb4bdcd944..6dc186a5bbb3c 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -863,6 +863,7 @@ mod tests { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { diff --git a/frame/elections/src/mock.rs b/frame/elections/src/mock.rs index b82e73d512aa6..ae12a075545ff 100644 --- a/frame/elections/src/mock.rs +++ b/frame/elections/src/mock.rs @@ -57,6 +57,7 @@ impl frame_system::Trait for Test { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { diff --git a/frame/example-offchain-worker/src/tests.rs b/frame/example-offchain-worker/src/tests.rs index f64503b0a92a8..e65b4bd0aa10f 100644 --- a/frame/example-offchain-worker/src/tests.rs +++ b/frame/example-offchain-worker/src/tests.rs @@ -68,6 +68,7 @@ impl frame_system::Trait for Test { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } type Extrinsic = TestXt, ()>; diff --git a/frame/example/src/lib.rs b/frame/example/src/lib.rs index d6036b3af85c5..45f3f9bb49134 100644 --- a/frame/example/src/lib.rs +++ b/frame/example/src/lib.rs @@ -733,6 +733,7 @@ mod tests { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index 1b3867cf6e01d..0e7e9b2385eec 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -121,7 +121,11 @@ where GetDispatchInfo, CallOf: Dispatchable, OriginOf: From>, - UnsignedValidator: ValidateUnsigned>, + UnsignedValidator: ValidateUnsigned>, + System::RootDispatcher: traits::RootDispatcher< + CallOf, + OriginOf + >, { fn execute_block(block: Block) { Executive::::execute_block(block); @@ -147,7 +151,11 @@ where GetDispatchInfo, CallOf: Dispatchable, OriginOf: From>, - UnsignedValidator: ValidateUnsigned>, + UnsignedValidator: ValidateUnsigned>, + System::RootDispatcher: traits::RootDispatcher< + CallOf, + OriginOf + >, { /// Start the execution of a particular block. pub fn initialize_block(header: &System::Header) { @@ -312,7 +320,10 @@ where // Decode parameters and dispatch let dispatch_info = xt.get_dispatch_info(); - let r = Applyable::apply::(xt, dispatch_info, encoded_len)?; + let r = Applyable::apply::(xt, + dispatch_info, + encoded_len + )?; >::note_applied_extrinsic(&r, encoded_len as u32, dispatch_info); @@ -485,6 +496,7 @@ mod tests { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = System; } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/finality-tracker/src/lib.rs b/frame/finality-tracker/src/lib.rs index c7d5ad30d9a88..e09f5b26dcc72 100644 --- a/frame/finality-tracker/src/lib.rs +++ b/frame/finality-tracker/src/lib.rs @@ -264,6 +264,7 @@ mod tests { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { pub const WindowSize: u64 = 11; @@ -326,9 +327,9 @@ mod tests { &Default::default(), Default::default(), ); - assert_ok!(FinalityTracker::dispatch( - Call::final_hint(i-1), + assert_ok!(FinalityTracker::final_hint( Origin::NONE, + i - 1, )); FinalityTracker::on_finalize(i); let hdr = System::finalize(); diff --git a/frame/generic-asset/src/lib.rs b/frame/generic-asset/src/lib.rs index 3cb48ad18ae36..de9ddaab172df 100644 --- a/frame/generic-asset/src/lib.rs +++ b/frame/generic-asset/src/lib.rs @@ -1125,6 +1125,7 @@ impl frame_system::Trait for ElevatedTrait { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl Trait for ElevatedTrait { type Balance = T::Balance; diff --git a/frame/generic-asset/src/mock.rs b/frame/generic-asset/src/mock.rs index 8db140d90c666..24976973a43de 100644 --- a/frame/generic-asset/src/mock.rs +++ b/frame/generic-asset/src/mock.rs @@ -65,6 +65,7 @@ impl frame_system::Trait for Test { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl Trait for Test { diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 8b94becd5aa6a..4db989d553e89 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -68,6 +68,7 @@ impl frame_system::Trait for Test { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } mod grandpa { diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 4cbd8c7a2b574..d6a59eedc6d8f 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -938,6 +938,7 @@ mod tests { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 78b6409d543eb..7b9098eb12aa4 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -121,6 +121,7 @@ impl frame_system::Trait for Runtime { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { diff --git a/frame/indices/src/mock.rs b/frame/indices/src/mock.rs index 355b3cc792c94..7a826308c693b 100644 --- a/frame/indices/src/mock.rs +++ b/frame/indices/src/mock.rs @@ -68,6 +68,7 @@ impl frame_system::Trait for Test { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 129f3c4003bdd..b28e86b0d0aed 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -323,6 +323,7 @@ mod tests { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } ord_parameter_types! { pub const One: u64 = 1; diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index 2ab1789d395d3..cab1743050c2d 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -288,6 +288,7 @@ mod tests { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index a003ad69157fc..82d018b2dd4b4 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -92,6 +92,7 @@ impl frame_system::Trait for Runtime { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl Trait for Runtime { diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index 0ded7dd6b0c64..5f59bd115d43f 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -194,6 +194,7 @@ mod tests { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } type System = frame_system::Module; diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index d7f5127ee3fc4..3e2f2a0a484d6 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -152,7 +152,7 @@ use sp_std::prelude::*; use sp_runtime::{ - traits::{Dispatchable, SaturatedConversion, CheckedAdd, CheckedMul}, + traits::{Dispatchable, Dispatcher, SaturatedConversion, CheckedAdd, CheckedMul}, DispatchResult }; use codec::{Encode, Decode}; @@ -205,6 +205,9 @@ pub trait Trait: frame_system::Trait { /// `sizeof(BlockNumber, Balance + T * AccountId)` bytes. Where T is a configurable /// threshold. type RecoveryDeposit: Get>; + + /// The means of dispatching the calls. + type Dispatcher: Dispatcher<::Call, Self::Origin>; } /// An active recovery process. @@ -347,7 +350,7 @@ decl_module! { // Check `who` is allowed to make a call on behalf of `account` let target = Self::proxy(&who).ok_or(Error::::NotAllowed)?; ensure!(&target == &account, Error::::NotAllowed); - call.dispatch(frame_system::RawOrigin::Signed(account).into()) + T::Dispatcher::dispatch(*call, frame_system::RawOrigin::Signed(account).into()).result } /// Allow ROOT to bypass the recovery process and set an a rescuer account diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index a5b7731c2286a..bbf7b37860cda 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -81,6 +81,7 @@ impl frame_system::Trait for Test { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { @@ -110,6 +111,7 @@ impl Trait for Test { type FriendDepositFactor = FriendDepositFactor; type MaxFriends = MaxFriends; type RecoveryDeposit = RecoveryDeposit; + type Dispatcher = sp_runtime::SimpleDispatcher; } pub type Recovery = Module; diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index a28b7891370ea..d36bae60bccea 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -73,6 +73,7 @@ impl frame_system::Trait for Test { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl pallet_balances::Trait for Test { diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index 9d64285b900f8..25cba578d7212 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -181,6 +181,7 @@ impl frame_system::Trait for Test { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl pallet_timestamp::Trait for Test { diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index 158f139df5673..7f1ab4c8210a4 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -80,6 +80,7 @@ impl frame_system::Trait for Test { type OnNewAccount = (); type OnKilledAccount = (); type AccountData = pallet_balances::AccountData; + type RootDispatcher = (); } impl pallet_balances::Trait for Test { diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 8754751629731..2260124601bce 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -140,6 +140,7 @@ impl frame_system::Trait for Test { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl pallet_balances::Trait for Test { type Balance = Balance; diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index 8ee09ba223ab1..53749d8cfa7a1 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -86,7 +86,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use sp_std::prelude::*; -use sp_runtime::{traits::{StaticLookup, Dispatchable}, DispatchError}; +use sp_runtime::{traits::{StaticLookup, Dispatchable, Dispatcher}, DispatchError}; use frame_support::{ Parameter, decl_module, decl_event, decl_storage, decl_error, ensure, @@ -100,6 +100,9 @@ pub trait Trait: frame_system::Trait { /// A sudo-able call. type Call: Parameter + Dispatchable + GetDispatchInfo; + + /// The means of dispatching the calls. + type Dispatcher: Dispatcher<::Call, Self::Origin>; } decl_module! { @@ -129,7 +132,7 @@ decl_module! { let sender = ensure_signed(origin)?; ensure!(sender == Self::key(), Error::::RequireSudo); - let res = match call.dispatch(frame_system::RawOrigin::Root.into()) { + let res = match T::Dispatcher::dispatch(*call, frame_system::RawOrigin::Root.into()).result { Ok(_) => true, Err(e) => { let e: DispatchError = e.into(); @@ -187,7 +190,7 @@ decl_module! { let who = T::Lookup::lookup(who)?; - let res = match call.dispatch(frame_system::RawOrigin::Signed(who).into()) { + let res = match T::Dispatcher::dispatch(*call, frame_system::RawOrigin::Signed(who).into()).result { Ok(_) => true, Err(e) => { let e: DispatchError = e.into(); diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index a9c48097ad64a..527835b0ada74 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -1587,7 +1587,10 @@ macro_rules! decl_module { { type Trait = $trait_instance; type Origin = $origin_type; - fn dispatch(self, _origin: Self::Origin) -> $crate::sp_runtime::DispatchResult { + fn dispatch(self, + _origin: Self::Origin, + _token: $crate::sp_runtime::traits::Unconstructable<$crate::sp_runtime::traits::DispatchableToken> + ) -> $crate::sp_runtime::DispatchResult { match self { $( $call_type::$fn_name( $( $param_name ),* ) => { @@ -1614,9 +1617,10 @@ macro_rules! decl_module { #[doc(hidden)] pub fn dispatch>( d: D, - origin: D::Origin + origin: D::Origin, + token: $crate::sp_runtime::traits::Unconstructable<$crate::sp_runtime::traits::DispatchableToken> ) -> $crate::sp_runtime::DispatchResult { - d.dispatch(origin) + d.dispatch(origin, token) } } $crate::__dispatch_impl_metadata! { @@ -1716,12 +1720,14 @@ macro_rules! impl_outer_dispatch { fn dispatch( self, origin: $origin, + token: $crate::sp_runtime::traits::Unconstructable<$crate::sp_runtime::traits::DispatchableToken>, ) -> $crate::sp_runtime::DispatchResult { $crate::impl_outer_dispatch! { @DISPATCH_MATCH self $call_type origin + token {} 0; $( $camelcase ),* @@ -1751,6 +1757,7 @@ macro_rules! impl_outer_dispatch { $self:ident $call_type:ident $origin:ident + $token:ident { $( $generated:tt )* } $index:expr; $name:ident @@ -1761,9 +1768,10 @@ macro_rules! impl_outer_dispatch { $self $call_type $origin + $token { $( $generated )* - $call_type::$name(call) => call.dispatch($origin), + $call_type::$name(call) => call.dispatch($origin, $token), } $index + 1; $( $rest ),* @@ -1773,6 +1781,7 @@ macro_rules! impl_outer_dispatch { $self:ident $call_type:ident $origin:ident + $token:ident { $( $generated:tt )* } $index:expr; ) => { diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index 90a4ad1d34de8..e235bcff8bfc3 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -79,6 +79,7 @@ impl system::Trait for Runtime { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl module::Trait for Runtime { diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 138a151427698..8c7b097291977 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -108,6 +108,7 @@ use sp_runtime::{ self, CheckEqual, AtLeast32Bit, Zero, SignedExtension, Lookup, LookupError, SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, BadOrigin, SaturatedConversion, MaybeSerialize, MaybeSerializeDeserialize, MaybeMallocSizeOf, StaticLookup, One, Bounded, + Dispatchable, RootDispatcher, }, }; @@ -221,6 +222,14 @@ pub trait Trait: 'static + Eq + Clone { /// /// All resources should be cleaned up associated with the given account. type OnKilledAccount: OnKilledAccount; + + /// The central instance that dispatches all calls. + /// + /// For `Dispatchable` calls it is usually the responsiblity of the frame_system + /// module to function as the root `RootDispatcher`. In order to customize the + /// dispatch process for a specific module the `Dispatcher` trait can be implemented + /// and supplied to to the respective `Trait`. + type RootDispatcher: RootDispatcher; } pub type DigestOf = generic::Digest<::Hash>; @@ -1044,6 +1053,23 @@ impl Module { } } +impl sp_runtime::traits::RootDispatcher for Module where + T::Call: Dispatchable, +{ + type Data = (); + + fn dispatch( + dispatchable: T::Call, + origin: ::Origin, + token: sp_runtime::traits::Unconstructable, + ) -> sp_runtime::DispatcherResult { + sp_runtime::DispatcherResult { + data: (), + result: Self::raw_dispatch(dispatchable, origin, token), + } + } +} + /// Event handler which calls on_created_account when it happens. pub struct CallOnCreatedAccount(PhantomData); impl Happened for CallOnCreatedAccount { @@ -1577,6 +1603,7 @@ mod tests { type AccountData = u32; type OnNewAccount = (); type OnKilledAccount = RecordKilled; + type RootDispatcher = (); } impl From> for u16 { diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index 2a37dfdddb62a..10ac2517e3dfb 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -280,6 +280,7 @@ mod tests { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { pub const MinimumPeriod: u64 = 5; @@ -296,7 +297,7 @@ mod tests { let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); TestExternalities::new(t).execute_with(|| { Timestamp::set_timestamp(42); - assert_ok!(Timestamp::dispatch(Call::set(69), Origin::NONE)); + assert_ok!(Timestamp::set(Origin::NONE, 69)); assert_eq!(Timestamp::now(), 69); }); } @@ -307,8 +308,8 @@ mod tests { let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); TestExternalities::new(t).execute_with(|| { Timestamp::set_timestamp(42); - assert_ok!(Timestamp::dispatch(Call::set(69), Origin::NONE)); - let _ = Timestamp::dispatch(Call::set(70), Origin::NONE); + assert_ok!(Timestamp::set(Origin::NONE, 69)); + let _ = Timestamp::set(Origin::NONE, 70); }); } @@ -318,7 +319,7 @@ mod tests { let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); TestExternalities::new(t).execute_with(|| { Timestamp::set_timestamp(42); - let _ = Timestamp::dispatch(Call::set(46), Origin::NONE); + let _ = Timestamp::set(Origin::NONE, 46); }); } } diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index a9da3830614cc..869e16c16850c 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -312,6 +312,7 @@ mod tests { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index d7562d0767bc0..6ff459daf5573 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -725,4 +725,4 @@ impl OnUnbalanced> for Module { Self::deposit_event(RawEvent::Deposit(numeric_amount)); } -} +} \ No newline at end of file diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index a5acb2efe5ab4..899b2c8b5a3ed 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -41,6 +41,7 @@ impl frame_system::Trait for Test { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { pub const ExistentialDeposit: u64 = 1; diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 0b60532c3dd23..f058a0147d41f 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -70,7 +70,7 @@ use frame_support::{traits::{Get, ReservableCurrency, Currency}, weights::{GetDispatchInfo, DispatchClass,FunctionOf}, }; use frame_system::{self as system, ensure_signed}; -use sp_runtime::{DispatchError, DispatchResult, traits::Dispatchable}; +use sp_runtime::{DispatchError, DispatchResult, traits::{Dispatchable, Dispatcher}}; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -98,6 +98,9 @@ pub trait Trait: frame_system::Trait { /// The maximum amount of signatories allowed in the multisig. type MaxSignatories: Get; + + /// The dispatcher of calls/proposals. + type Dispatcher: Dispatcher<::Call, Self::Origin>; } /// A global extrinsic index, formed as the extrinsic index within a block, together with that @@ -241,7 +244,7 @@ decl_module! { )] fn batch(origin, calls: Vec<::Call>) { for (index, call) in calls.into_iter().enumerate() { - let result = call.dispatch(origin.clone()); + let result = T::Dispatcher::dispatch(call, origin.clone()).result; if let Err(e) = result { Self::deposit_event(Event::::BatchInterrupted(index as u32, e)); return Ok(()); @@ -265,7 +268,7 @@ decl_module! { fn as_sub(origin, index: u16, call: Box<::Call>) -> DispatchResult { let who = ensure_signed(origin)?; let pseudonym = Self::sub_account_id(who, index); - call.dispatch(frame_system::RawOrigin::Signed(pseudonym).into()) + T::Dispatcher::dispatch(*call, frame_system::RawOrigin::Signed(pseudonym).into()).result } /// Register approval for a dispatch to be made from a deterministic composite account if @@ -351,7 +354,11 @@ decl_module! { } } - let result = call.dispatch(frame_system::RawOrigin::Signed(id.clone()).into()); + let result = + T::Dispatcher::dispatch( + *call, + frame_system::RawOrigin::Signed(id.clone()).into() + ).result; let _ = T::Currency::unreserve(&m.depositor, m.deposit); >::remove(&id, call_hash); Self::deposit_event(RawEvent::MultisigExecuted(who, timepoint, id, result)); @@ -369,7 +376,7 @@ decl_module! { }); Self::deposit_event(RawEvent::NewMultisig(who, id)); } else { - return call.dispatch(frame_system::RawOrigin::Signed(id).into()) + return T::Dispatcher::dispatch(*call, frame_system::RawOrigin::Signed(id).into()).result; } } Ok(()) @@ -625,6 +632,7 @@ mod tests { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } parameter_types! { pub const ExistentialDeposit: u64 = 1; @@ -648,6 +656,7 @@ mod tests { type MultisigDepositBase = MultisigDepositBase; type MultisigDepositFactor = MultisigDepositFactor; type MaxSignatories = MaxSignatories; + type Dispatcher = sp_runtime::SimpleDispatcher; } type System = frame_system::Module; type Balances = pallet_balances::Module; diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 94a70b7ef132f..459022e6d4fc0 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -387,6 +387,7 @@ mod tests { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl pallet_balances::Trait for Test { type Balance = u64; diff --git a/primitives/runtime/src/generic/checked_extrinsic.rs b/primitives/runtime/src/generic/checked_extrinsic.rs index 25a8274354ae2..547eef529c982 100644 --- a/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/primitives/runtime/src/generic/checked_extrinsic.rs @@ -17,10 +17,8 @@ //! Generic implementation of an extrinsic that has passed the verification //! stage. -use crate::traits::{ - self, Member, MaybeDisplay, SignedExtension, Dispatchable, -}; use crate::traits::ValidateUnsigned; +use crate::traits::{self, Dispatchable, Dispatcher, MaybeDisplay, Member, SignedExtension}; use crate::transaction_validity::TransactionValidity; /// Definition of something that the external world might want to say; its @@ -62,21 +60,44 @@ where } } - fn apply>( + fn apply( self, info: Self::DispatchInfo, len: usize, - ) -> crate::ApplyExtrinsicResult { - let (maybe_who, pre) = if let Some((id, extra)) = self.signed { - let pre = Extra::pre_dispatch(extra, &id, &self.function, info.clone(), len)?; - (Some(id), pre) - } else { - let pre = Extra::pre_dispatch_unsigned(&self.function, info.clone(), len)?; - U::pre_dispatch(&self.function)?; - (None, pre) - }; - let res = self.function.dispatch(Origin::from(maybe_who)); - Extra::post_dispatch(pre, info.clone(), len); - Ok(res.map_err(Into::into)) + ) -> crate::ApplyExtrinsicResult where + V: ValidateUnsigned, + D: Dispatcher, + { + apply::(self.function, self.signed, info, len) } } + +/// Apply a call together with its signature (if any). +/// +/// This function is exposed in order for test code to make use of it. Production +/// code may use the `Applyable` implementation of `CheckedExtrinsic`. +pub fn apply( + call: Call, + signature: Option<(AccountId, Extra)>, + info: Info, + len: usize, +) -> crate::ApplyExtrinsicResult where + Origin: From>, + Call: Member + Dispatchable, + AccountId: Member + MaybeDisplay, + Info: Clone, + Extra: SignedExtension, + V: ValidateUnsigned, + D: Dispatcher, +{ + let (maybe_who, pre) = if let Some((who, extra)) = signature { + let pre = Extra::pre_dispatch(extra, &who, &call, info.clone(), len)?; + (Some(who), pre) + } else { + let pre = Extra::pre_dispatch_unsigned(&call, info.clone(), len)?; + (None, pre) + }; + let result = D::dispatch(call, maybe_who.into()); + Extra::post_dispatch(pre, info.clone(), len); + Ok(result.result.into()) +} diff --git a/primitives/runtime/src/generic/mod.rs b/primitives/runtime/src/generic/mod.rs index 5e9928ba1909a..3003cfda75968 100644 --- a/primitives/runtime/src/generic/mod.rs +++ b/primitives/runtime/src/generic/mod.rs @@ -35,6 +35,7 @@ pub use self::block::{Block, SignedBlock, BlockId}; pub use self::digest::{ Digest, DigestItem, DigestItemRef, OpaqueDigestItemId, ChangesTrieSignal, }; +pub use checked_extrinsic::apply as apply_checked; use crate::codec::Encode; use sp_std::prelude::*; diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 632deb13cbb45..ff0b452e13a90 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -434,6 +434,22 @@ impl traits::Printable for DispatchError { } } +/// This type describes the result of a module function call which is called through +/// a dispatcher. A dispatcher can return data even when the dispatch failed. +pub struct DispatcherResult { + /// Additional data that is added by the dispatcher. + pub data: Data, + /// The dispatch result from the actual `Dispatchable::dispatch`. + pub result: DispatchResult, +} + +impl DispatcherResult { + /// Convenience function to avoid drilling down to the result for this common operation. + pub fn is_ok(&self) -> bool { + self.result.is_ok() + } +} + /// This type specifies the outcome of dispatching a call to a module. /// /// In case of failure an error specific to the module is returned. @@ -685,6 +701,27 @@ pub fn print(print: impl traits::Printable) { print.print(); } +/// A simple dispatcher that dispatches a `Dispatchable` and nothing else. +pub struct SimpleDispatcher; + +impl traits::RootDispatcher for SimpleDispatcher where + D: traits::Dispatchable +{ + type Data = (); + + fn dispatch( + dispatchable: D, + origin: O, + token: traits::Unconstructable + ) -> DispatcherResult + { + DispatcherResult { + data: (), + result: Self::raw_dispatch(dispatchable, origin, token), + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/primitives/runtime/src/testing.rs b/primitives/runtime/src/testing.rs index 2439070054211..4a3910148e278 100644 --- a/primitives/runtime/src/testing.rs +++ b/primitives/runtime/src/testing.rs @@ -21,9 +21,8 @@ use std::{fmt::Debug, ops::Deref, fmt, cell::RefCell}; use crate::codec::{Codec, Encode, Decode}; use crate::traits::{ self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, - SignedExtension, Dispatchable, + SignedExtension, Dispatchable, Dispatcher, Member, ValidateUnsigned, }; -use crate::traits::ValidateUnsigned; use crate::{generic, KeyTypeId, ApplyExtrinsicResult}; pub use sp_core::{H256, sr25519}; use sp_core::{crypto::{CryptoType, Dummy, key_types, Public}, U256}; @@ -346,8 +345,8 @@ impl traits::Extrinsic for TestXt } impl Applyable for TestXt where - Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug + Dispatchable, - Extra: SignedExtension, + Call: Member + Dispatchable, + Extra: SignedExtension, Origin: From>, Info: Clone, { @@ -365,19 +364,11 @@ impl Applyable for TestXt where /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, /// index and sender. - fn apply>( + fn apply, D: Dispatcher>( self, info: Self::DispatchInfo, len: usize, ) -> ApplyExtrinsicResult { - let maybe_who = if let Some((who, extra)) = self.signature { - Extra::pre_dispatch(extra, &who, &self.call, info, len)?; - Some(who) - } else { - Extra::pre_dispatch_unsigned(&self.call, info, len)?; - None - }; - - Ok(self.call.dispatch(maybe_who.into()).map_err(Into::into)) + generic::apply_checked::(self.call, self.signature, info, len) } } diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 81b7733319bf8..663bdab1f2b11 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -31,6 +31,7 @@ use crate::transaction_validity::{ ValidTransaction, TransactionValidity, TransactionValidityError, UnknownTransaction, }; use crate::generic::{Digest, DigestItem}; +use crate::DispatcherResult; pub use sp_arithmetic::traits::{ AtLeast32Bit, UniqueSaturatedInto, UniqueSaturatedFrom, Saturating, SaturatedConversion, Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, @@ -681,7 +682,10 @@ pub trait Dispatchable { /// ... type Trait; /// Actually dispatch this call and result the result of it. - fn dispatch(self, origin: Self::Origin) -> crate::DispatchResult; + fn dispatch(self, + origin: Self::Origin, + token: Unconstructable + ) -> crate::DispatchResult; } /// Means by which a transaction may be extended. This type embodies both the data and the logic @@ -902,11 +906,193 @@ pub trait Applyable: Sized + Send + Sync { /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, /// index and sender. - fn apply>( + fn apply( self, info: Self::DispatchInfo, len: usize, - ) -> crate::ApplyExtrinsicResult; + ) -> crate::ApplyExtrinsicResult where + Self::Call: Dispatchable, + V: ValidateUnsigned, + D: Dispatcher::Origin>; +} + +/// Marker trait that marks types as something that can be used as a token. +pub trait UnconstructableToken {} + +/// Token used by `Dispatcher` and `RootDispatcher`. +pub struct DispatcherToken; + +/// Token used by `Dispatchable`. +pub struct DispatchableToken; + +impl UnconstructableToken for DispatcherToken {} +impl UnconstructableToken for DispatchableToken {} + + +/// A type that is unconstructable by anyone but the runtime::traits Module. +/// +/// Its purpose is to prevent calling certain functions from outside of this module. +pub struct Unconstructable { + _unconstructable: PhantomData, +} + +impl Unconstructable { + fn new() -> Self { + Self { + _unconstructable: PhantomData, + } + } +} + +impl Clone for Unconstructable { + fn clone(&self) -> Self { + Self::new() + } +} + +impl Copy for Unconstructable {} + +/// A type that is responsible for customizing dispatching of a `Dispatchable`. +/// +/// In order to provide a custom dispatcher this type should be implemented and then +/// and then used by calling `dispatch` with a `Dispatchable`. +pub trait Dispatcher { + /// In any runtime there is only one `RootDispatcher` that is usually implemented + /// by some central type. It must be specified here in order for the default + /// implementation of `dispatch` to delegate the dispatch to it. + type RootDispatcher: RootDispatcher; + + /// The type of a value that can be used to pass information from `pre_dispatch` + /// to `post_dispatch`. + type Pre; + + /// The type of a value that is returned from `post_dispatch` and passed through + /// by `dispatch` to the caller. It can be used to return information to the caller + /// in addition to the `DispatchResult`. + type Post; + + /// This is called before a dispatch and can be used to do bookkeeping or even filter + /// dispatches. By returning an `Err` for the `result` the dispatch is skipped and + /// and `post_dispatch` is passed `None` as `dispatch_data`. The `data` return value + /// is passed through as `pre` to `post_dispatch`. The `token` prevents this function + /// from being called by anyone else than the default `dispatch` implementation. + /// Implementers of this function can and should ignore it. + fn pre_dispatch( + dispatchable: &D, + origin: &O, + token: Unconstructable, + ) -> DispatcherResult; + + /// Called after a call was dispatched or skipped. It is passed the result of the + /// dispatch and the return `data ` of `pre_dispatch`. The token serves the same + /// purpose as for `pre_dispatch`. + fn post_dispatch( + pre: Self::Pre, + dispatch_data: Option<>::Data>, + dispatch_result: &crate::DispatchResult, + token: Unconstructable, + ) -> Self::Post; + + /// Dispatches a `Dispatchable`. It takes care of calling the pre and post dispatch + /// hooks and delegates to the `RootDipatcher` for the actual dispatch. + /// It should not be overriden and neither it can be as a custom implementation + /// cannot construct the required tokens to call the hooks. + fn dispatch(dispatchable: D, origin: O) -> DispatcherResult { + let token = Unconstructable::new(); + let pre = Self::pre_dispatch(&dispatchable, &origin, token); + let result = match pre.result { + Ok(_) => { + let result = >::dispatch( + dispatchable, + origin, + token, + ); + (Some(result.data), result.result) + }, + Err(err) => (None, Err(err)), + }; + DispatcherResult { + data: Self::post_dispatch(pre.data, result.0, &result.1, token), + result: result.1, + } + } +} + +/// The type that does the actual dispatch of a `Dispatchable`. +/// +/// There is usually only one `RootDispatcher` implementation per runtime. It is the only +/// type that will call `Dispatchable::dispatch`. Customizing the global dispatch logic +/// is done by implementing `RootDispatcher`. Customizing the dispatch logic +/// for only one specific part of the runtime is done by implementing `Dispatcher`. +pub trait RootDispatcher { + /// Additional information that can be returned from `dispatch`. + type Data; + + /// Helper function that allows implementers of this trait to call + /// `Dispatchable::dispatch` from their `dispatch` implementation. + /// There is usually no need to override this function. + fn raw_dispatch( + dispatchable: D, + origin: O, + _: Unconstructable, + ) -> crate::DispatchResult + where + D: Dispatchable, + { + dispatchable.dispatch(origin, Unconstructable::new()) + } + + /// Implement your custom dispatch logic here. + /// + /// Use `Self::raw_dspatch` in order to do the actual dispatch as direct call + /// of `Dispatchable::dispatch` is prevent by a token. This function should be called + /// through a `Dispatcher::Dispatch`. Direct call is prevented by the use of a + /// `DispatcherToken`. There is a blanket impl that implements `Dispatcher` for + /// every `RootDispatcher`. Therefore calling this function is just a matter + /// of selecting the correct `dispatch` function by not passing the token. + fn dispatch( + dispatchable: D, + origin: O, + token: Unconstructable + ) -> DispatcherResult; +} + +impl RootDispatcher for () { + type Data = (); + + fn dispatch(_: D, _: O, _: Unconstructable) -> DispatcherResult { + panic!("Using the dummy dispatcher for actual dispatch is a programming error.") + } +} + +impl Dispatcher for T where + T: RootDispatcher, +{ + type RootDispatcher = T; + type Pre = (); + type Post = T::Data; + + fn pre_dispatch( + _: &D, + _: &O, + _: Unconstructable + ) -> DispatcherResult { + DispatcherResult { + data: (), + result: Ok(()), + } + } + + fn post_dispatch( + _: Self::Pre, + data: Option, + _: &crate::DispatchResult, + _: Unconstructable + ) -> Self::Post { + data.expect( + "This `Dispatcher` impl does not filter any dispatches in `pre_dispatch`. + This means `data` is always `Some`. qed.") + } } /// A marker trait for something that knows the type of the runtime block. diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 59955cce48693..86820b947ad81 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -393,6 +393,7 @@ impl frame_system::Trait for Runtime { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); + type RootDispatcher = (); } impl pallet_timestamp::Trait for Runtime {