1#![cfg_attr(not(feature = "std"), no_std)]
26
27#[cfg(feature = "runtime-benchmarks")]
28mod benchmarking;
29#[cfg(test)]
30mod mock;
31#[cfg(test)]
32mod tests;
33pub mod weights;
34
35#[cfg(not(feature = "std"))]
36extern crate alloc;
37
38use frame_support::defensive_assert;
39use frame_support::dispatch::{
40 DispatchClass, DispatchErrorWithPostInfo, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo,
41};
42use frame_support::storage::with_storage_layer;
43use frame_support::traits::fungible::{Inspect, Mutate};
44use frame_support::traits::tokens::{Fortitude, Precision, Preservation};
45use frame_support::traits::{
46 BeforeAllRuntimeMigrations, EnsureInherentsAreFirst, ExecuteBlock, Get, OffchainWorker,
47 OnFinalize, OnIdle, OnInitialize, OnPoll, OnRuntimeUpgrade, PostTransactions,
48};
49use frame_support::weights::{Weight, WeightToFee};
50use frame_system::pallet_prelude::*;
51pub use pallet::*;
52use parity_scale_codec::{Codec, Encode};
53use sp_runtime::traits::{
54 Applyable, Block as BlockT, CheckEqual, Checkable, Dispatchable, Header, NumberFor, One,
55 ValidateUnsigned, Zero,
56};
57use sp_runtime::transaction_validity::{
58 InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
59};
60use sp_runtime::{ApplyExtrinsicResult, DispatchError, ExtrinsicInclusionMode};
61use sp_std::marker::PhantomData;
62use sp_std::prelude::*;
63
64pub type CheckedOf<E, C> = <E as Checkable<C>>::Checked;
65pub type CallOf<E, C> = <CheckedOf<E, C> as Applyable>::Call;
66pub type OriginOf<E, C> = <CallOf<E, C> as Dispatchable>::RuntimeOrigin;
67
68pub trait ExtrinsicStorageFees<T: Config> {
70 fn extract_signer(xt: ExtrinsicOf<T>) -> (Option<AccountIdOf<T>>, DispatchInfo);
72 fn on_storage_fees_charged(
74 charged_fees: BalanceOf<T>,
75 tx_size: u32,
76 ) -> Result<(), TransactionValidityError>;
77}
78
79type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
80type BalanceOf<T> = <<T as Config>::Currency as Inspect<AccountIdOf<T>>>::Balance;
81type ExtrinsicOf<T> = <BlockOf<T> as BlockT>::Extrinsic;
82type BlockOf<T> = <T as frame_system::Config>::Block;
83type BlockHashOf<T> = <BlockOf<T> as BlockT>::Hash;
84
85#[frame_support::pallet]
88mod pallet {
89 use crate::weights::WeightInfo;
90 use crate::{BalanceOf, ExtrinsicStorageFees};
91 #[cfg(not(feature = "std"))]
92 use alloc::vec::Vec;
93 use frame_support::pallet_prelude::*;
94 use frame_support::traits::fungible::Mutate;
95 use frame_support::weights::WeightToFee;
96 use frame_system::pallet_prelude::*;
97 use frame_system::SetCode;
98 use sp_executive::{InherentError, InherentType, INHERENT_IDENTIFIER};
99
100 #[pallet::config]
101 pub trait Config: frame_system::Config {
102 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
103 type WeightInfo: WeightInfo;
104 type Currency: Mutate<Self::AccountId>;
105 type LengthToFee: WeightToFee<Balance = BalanceOf<Self>>;
106 type ExtrinsicStorageFees: ExtrinsicStorageFees<Self>;
107 }
108
109 #[pallet::pallet]
110 #[pallet::without_storage_info]
111 pub struct Pallet<T>(_);
112
113 #[pallet::call]
114 impl<T: Config> Pallet<T> {
115 #[pallet::call_index(0)]
118 #[pallet::weight((T::WeightInfo::set_code(), DispatchClass::Mandatory))]
119 pub fn set_code(origin: OriginFor<T>, code: Vec<u8>) -> DispatchResult {
120 ensure_none(origin)?;
121 <frame_system::pallet::Pallet<T>>::can_set_code(&code)?;
122 <T as frame_system::Config>::OnSetCode::set_code(code)?;
123 Ok(())
124 }
125 }
126
127 #[pallet::inherent]
128 impl<T: Config> ProvideInherent for Pallet<T> {
129 type Call = Call<T>;
130 type Error = InherentError;
131 const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
132
133 fn create_inherent(data: &InherentData) -> Option<Self::Call> {
134 let inherent_data = data
135 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
136 .expect("Executive inherent data not correctly encoded")
137 .expect("Executive inherent data must be provided");
138
139 inherent_data.maybe_code.map(|code| Call::set_code { code })
140 }
141
142 fn is_inherent_required(data: &InherentData) -> Result<Option<Self::Error>, Self::Error> {
143 let inherent_data = data
144 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
145 .expect("Executive inherent data not correctly encoded")
146 .expect("Executive inherent data must be provided");
147
148 Ok(if inherent_data.maybe_code.is_none() {
149 None
150 } else {
151 Some(InherentError::MissingRuntimeCode)
152 })
153 }
154
155 fn check_inherent(call: &Self::Call, data: &InherentData) -> Result<(), Self::Error> {
156 let inherent_data = data
157 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
158 .expect("Executive inherent data not correctly encoded")
159 .expect("Executive inherent data must be provided");
160
161 if let Some(provided_code) = inherent_data.maybe_code {
162 if let Call::set_code { code } = call {
163 if code != &provided_code {
164 return Err(InherentError::IncorrectRuntimeCode);
165 }
166 }
167 } else {
168 return Err(InherentError::MissingRuntimeCode);
169 }
170
171 Ok(())
172 }
173
174 fn is_inherent(call: &Self::Call) -> bool {
175 matches!(call, Call::set_code { .. })
176 }
177 }
178
179 #[pallet::event]
180 pub enum Event<T: Config> {}
181
182 #[pallet::hooks]
183 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
184 fn on_initialize(_block_number: BlockNumberFor<T>) -> Weight {
185 Weight::from_parts(1, 0)
187 }
188 }
189}
190
191pub struct Executive<
196 ExecutiveConfig,
197 Context,
198 UnsignedValidator,
199 AllPalletsWithSystem,
200 OnRuntimeUpgrade = (),
201>(
202 PhantomData<(
203 ExecutiveConfig,
204 Context,
205 UnsignedValidator,
206 AllPalletsWithSystem,
207 OnRuntimeUpgrade,
208 )>,
209);
210
211impl<
212 ExecutiveConfig: Config + frame_system::Config + EnsureInherentsAreFirst<BlockOf<ExecutiveConfig>>,
213 Context: Default,
214 UnsignedValidator,
215 AllPalletsWithSystem: OnRuntimeUpgrade
216 + BeforeAllRuntimeMigrations
217 + OnInitialize<BlockNumberFor<ExecutiveConfig>>
218 + OnIdle<BlockNumberFor<ExecutiveConfig>>
219 + OnFinalize<BlockNumberFor<ExecutiveConfig>>
220 + OffchainWorker<BlockNumberFor<ExecutiveConfig>>
221 + OnPoll<BlockNumberFor<ExecutiveConfig>>,
222 COnRuntimeUpgrade: OnRuntimeUpgrade,
223 > ExecuteBlock<BlockOf<ExecutiveConfig>>
224 for Executive<
225 ExecutiveConfig,
226 Context,
227 UnsignedValidator,
228 AllPalletsWithSystem,
229 COnRuntimeUpgrade,
230 >
231where
232 ExtrinsicOf<ExecutiveConfig>: Checkable<Context> + Codec,
233 CheckedOf<ExtrinsicOf<ExecutiveConfig>, Context>: Applyable + GetDispatchInfo,
234 CallOf<ExtrinsicOf<ExecutiveConfig>, Context>:
235 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
236 OriginOf<ExtrinsicOf<ExecutiveConfig>, Context>: From<Option<AccountIdOf<ExecutiveConfig>>>,
237 UnsignedValidator: ValidateUnsigned<Call = CallOf<ExtrinsicOf<ExecutiveConfig>, Context>>,
238{
239 fn execute_block(block: BlockOf<ExecutiveConfig>) {
240 Executive::<
241 ExecutiveConfig,
242 Context,
243 UnsignedValidator,
244 AllPalletsWithSystem,
245 COnRuntimeUpgrade,
246 >::execute_block(block);
247 }
248}
249
250impl<
251 ExecutiveConfig: Config + frame_system::Config + EnsureInherentsAreFirst<BlockOf<ExecutiveConfig>>,
252 Context: Default,
253 UnsignedValidator,
254 AllPalletsWithSystem: OnRuntimeUpgrade
255 + BeforeAllRuntimeMigrations
256 + OnInitialize<BlockNumberFor<ExecutiveConfig>>
257 + OnIdle<BlockNumberFor<ExecutiveConfig>>
258 + OnFinalize<BlockNumberFor<ExecutiveConfig>>
259 + OffchainWorker<BlockNumberFor<ExecutiveConfig>>
260 + OnPoll<BlockNumberFor<ExecutiveConfig>>,
261 COnRuntimeUpgrade: OnRuntimeUpgrade,
262 >
263 Executive<ExecutiveConfig, Context, UnsignedValidator, AllPalletsWithSystem, COnRuntimeUpgrade>
264where
265 ExtrinsicOf<ExecutiveConfig>: Checkable<Context> + Codec,
266 CheckedOf<ExtrinsicOf<ExecutiveConfig>, Context>: Applyable + GetDispatchInfo,
267 CallOf<ExtrinsicOf<ExecutiveConfig>, Context>:
268 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
269 OriginOf<ExtrinsicOf<ExecutiveConfig>, Context>: From<Option<AccountIdOf<ExecutiveConfig>>>,
270 UnsignedValidator: ValidateUnsigned<Call = CallOf<ExtrinsicOf<ExecutiveConfig>, Context>>,
271{
272 pub fn storage_root() -> Vec<u8> {
274 let version = <ExecutiveConfig as frame_system::Config>::Version::get().state_version();
275 sp_io::storage::root(version)
276 }
277
278 pub fn execute_on_runtime_upgrade() -> Weight {
280 frame_executive::Executive::<
281 ExecutiveConfig,
282 BlockOf<ExecutiveConfig>,
283 Context,
284 UnsignedValidator,
285 AllPalletsWithSystem,
286 COnRuntimeUpgrade,
287 >::execute_on_runtime_upgrade()
288 }
289
290 pub fn initialize_block(header: &HeaderFor<ExecutiveConfig>) -> ExtrinsicInclusionMode {
294 frame_executive::Executive::<
295 ExecutiveConfig,
296 BlockOf<ExecutiveConfig>,
297 Context,
298 UnsignedValidator,
299 AllPalletsWithSystem,
300 COnRuntimeUpgrade,
301 >::initialize_block(header)
302 }
303
304 fn initial_checks(block: &BlockOf<ExecutiveConfig>) -> u32 {
306 sp_tracing::enter_span!(sp_tracing::Level::TRACE, "initial_checks");
307 let header = block.header();
308
309 let n = *header.number();
311 assert!(
312 n > BlockNumberFor::<ExecutiveConfig>::zero()
313 && <frame_system::Pallet<ExecutiveConfig>>::block_hash(
314 n - BlockNumberFor::<ExecutiveConfig>::one()
315 ) == *header.parent_hash(),
316 "Parent hash should be valid.",
317 );
318
319 match ExecutiveConfig::ensure_inherents_are_first(block) {
320 Ok(num) => num,
321 Err(i) => panic!("Invalid inherent position for extrinsic at index {}", i),
322 }
323 }
324
325 pub fn execute_block(block: BlockOf<ExecutiveConfig>) {
330 sp_io::init_tracing();
331 sp_tracing::within_span! {
332 sp_tracing::info_span!("execute_block", ?block);
333 let mode = Self::initialize_block(block.header());
335 let num_inherents = Self::initial_checks(&block) as usize;
336 let (header, extrinsics) = block.deconstruct();
337 let num_extrinsics = extrinsics.len();
338
339 if mode == ExtrinsicInclusionMode::OnlyInherents && num_extrinsics > num_inherents {
340 panic!("Only inherents are allowed in this block")
342 }
343
344 Self::apply_extrinsics(extrinsics.into_iter());
345
346 if !<frame_system::Pallet<ExecutiveConfig>>::inherents_applied() {
348 defensive_assert!(num_inherents == num_extrinsics);
349 frame_executive::Executive::<
350 ExecutiveConfig,
351 BlockOf<ExecutiveConfig>,
352 Context,
353 UnsignedValidator,
354 AllPalletsWithSystem,
355 COnRuntimeUpgrade,
356 >::inherents_applied();
357 }
358
359 <frame_system::Pallet<ExecutiveConfig>>::note_finished_extrinsics();
360 <ExecutiveConfig as frame_system::Config>::PostTransactions::post_transactions();
361
362 Self::idle_and_finalize_hook(*header.number());
363 Self::final_checks(&header);
364 }
365 }
366
367 fn apply_extrinsics(extrinsics: impl Iterator<Item = ExtrinsicOf<ExecutiveConfig>>) {
369 extrinsics.into_iter().for_each(|e| {
370 if let Err(e) = Self::apply_extrinsic(e) {
371 let err: &'static str = e.into();
372 panic!("{}", err)
373 }
374 });
375 }
376
377 pub fn finalize_block() -> HeaderFor<ExecutiveConfig> {
379 frame_executive::Executive::<
380 ExecutiveConfig,
381 BlockOf<ExecutiveConfig>,
382 Context,
383 UnsignedValidator,
384 AllPalletsWithSystem,
385 COnRuntimeUpgrade,
386 >::finalize_block()
387 }
388
389 fn idle_and_finalize_hook(block_number: NumberFor<BlockOf<ExecutiveConfig>>) {
391 let weight = <frame_system::Pallet<ExecutiveConfig>>::block_weight();
392 let max_weight = <<ExecutiveConfig as frame_system::Config>::BlockWeights as frame_support::traits::Get<_>>::get().max_block;
393 let remaining_weight = max_weight.saturating_sub(weight.total());
394
395 if remaining_weight.all_gt(Weight::zero()) {
396 let used_weight = AllPalletsWithSystem::on_idle(block_number, remaining_weight);
397 <frame_system::Pallet<ExecutiveConfig>>::register_extra_weight_unchecked(
398 used_weight,
399 DispatchClass::Mandatory,
400 );
401 }
402
403 AllPalletsWithSystem::on_finalize(block_number);
404 }
405
406 pub fn apply_extrinsic(uxt: ExtrinsicOf<ExecutiveConfig>) -> ApplyExtrinsicResult {
410 let res = with_storage_layer(|| {
412 frame_executive::Executive::<
413 ExecutiveConfig,
414 BlockOf<ExecutiveConfig>,
415 Context,
416 UnsignedValidator,
417 AllPalletsWithSystem,
418 COnRuntimeUpgrade,
419 >::apply_extrinsic(uxt.clone())
420 .map_err(|err| DispatchError::Other(err.into()))
421 });
422
423 match res {
435 Ok(dispatch_outcome) => Ok(dispatch_outcome),
436 Err(err) => {
437 let encoded = uxt.encode();
438 let (maybe_signer, dispatch_info) =
439 ExecutiveConfig::ExtrinsicStorageFees::extract_signer(uxt);
440 if dispatch_info.class == DispatchClass::Mandatory {
443 return Err(TransactionValidityError::Invalid(
444 InvalidTransaction::MandatoryValidation,
445 ));
446 }
447
448 if let Some(signer) = maybe_signer {
450 let storage_fees = ExecutiveConfig::LengthToFee::weight_to_fee(
451 &Weight::from_parts(encoded.len() as u64, 0),
452 );
453
454 let maybe_charged_fees = ExecutiveConfig::Currency::burn_from(
457 &signer,
458 storage_fees,
459 Preservation::Expendable,
460 Precision::BestEffort,
461 Fortitude::Force,
462 );
463
464 if let Ok(charged_fees) = maybe_charged_fees {
465 ExecutiveConfig::ExtrinsicStorageFees::on_storage_fees_charged(
466 charged_fees,
467 encoded.len() as u32,
468 )?;
469 }
470 }
471
472 <frame_system::Pallet<ExecutiveConfig>>::note_extrinsic(encoded);
474
475 let r = Err(DispatchErrorWithPostInfo {
478 post_info: PostDispatchInfo {
479 actual_weight: None,
480 pays_fee: Pays::No,
481 },
482 error: err,
483 });
484
485 <frame_system::Pallet<ExecutiveConfig>>::note_applied_extrinsic(&r, dispatch_info);
486 Ok(Err(err))
487 }
488 }
489 }
490
491 fn final_checks(header: &HeaderFor<ExecutiveConfig>) {
493 sp_tracing::enter_span!(sp_tracing::Level::TRACE, "final_checks");
494 let new_header = <frame_system::Pallet<ExecutiveConfig>>::finalize();
496
497 assert_eq!(
499 header.digest().logs().len(),
500 new_header.digest().logs().len(),
501 "Number of digest items must match that calculated."
502 );
503 let items_zip = header
504 .digest()
505 .logs()
506 .iter()
507 .zip(new_header.digest().logs().iter());
508 for (header_item, computed_item) in items_zip {
509 header_item.check_equal(computed_item);
510 assert_eq!(
511 header_item, computed_item,
512 "Digest item must match that calculated."
513 );
514 }
515
516 let storage_root = new_header.state_root();
518 header.state_root().check_equal(storage_root);
519 assert!(
520 header.state_root() == storage_root,
521 "Storage root must match that calculated."
522 );
523
524 assert!(
525 header.extrinsics_root() == new_header.extrinsics_root(),
526 "Transaction trie root must be valid.",
527 );
528 }
529
530 pub fn validate_transaction(
532 source: TransactionSource,
533 uxt: ExtrinsicOf<ExecutiveConfig>,
534 block_hash: BlockHashOf<ExecutiveConfig>,
535 ) -> TransactionValidity {
536 frame_executive::Executive::<
537 ExecutiveConfig,
538 BlockOf<ExecutiveConfig>,
539 Context,
540 UnsignedValidator,
541 AllPalletsWithSystem,
542 COnRuntimeUpgrade,
543 >::validate_transaction(source, uxt, block_hash)
544 }
545
546 pub fn offchain_worker(header: &HeaderFor<ExecutiveConfig>) {
548 frame_executive::Executive::<
549 ExecutiveConfig,
550 BlockOf<ExecutiveConfig>,
551 Context,
552 UnsignedValidator,
553 AllPalletsWithSystem,
554 COnRuntimeUpgrade,
555 >::offchain_worker(header)
556 }
557}