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_executive::OnInitializeWithWeightRegistration;
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, ExecuteBlock, Get, IsInherent, OffchainWorker, OnFinalize, OnIdle,
47 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, LazyBlock, NumberFor,
55 One, 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::*;
63pub use weights::WeightInfo;
64
65pub type CheckedOf<E, C> = <E as Checkable<C>>::Checked;
66pub type CallOf<E, C> = <CheckedOf<E, C> as Applyable>::Call;
67pub type OriginOf<E, C> = <CallOf<E, C> as Dispatchable>::RuntimeOrigin;
68
69pub trait ExtrinsicStorageFees<T: Config> {
71 fn extract_signer(xt: ExtrinsicOf<T>) -> (Option<AccountIdOf<T>>, DispatchInfo);
73 fn on_storage_fees_charged(
75 charged_fees: BalanceOf<T>,
76 tx_size: u32,
77 ) -> Result<(), TransactionValidityError>;
78}
79
80type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
81type BalanceOf<T> = <<T as Config>::Currency as Inspect<AccountIdOf<T>>>::Balance;
82type ExtrinsicOf<T> = <BlockOf<T> as BlockT>::Extrinsic;
83type BlockOf<T> = <T as frame_system::Config>::Block;
84type BlockHashOf<T> = <BlockOf<T> as BlockT>::Hash;
85
86#[frame_support::pallet]
87mod pallet {
88 use crate::weights::WeightInfo;
89 use crate::{BalanceOf, ExtrinsicStorageFees};
90 #[cfg(not(feature = "std"))]
91 use alloc::vec::Vec;
92 use frame_support::pallet_prelude::*;
93 use frame_support::traits::fungible::Mutate;
94 use frame_support::weights::WeightToFee;
95 use frame_system::SetCode;
96 use frame_system::pallet_prelude::*;
97 use sp_executive::{INHERENT_IDENTIFIER, InherentError, InherentType};
98
99 #[pallet::config]
100 pub trait Config: frame_system::Config<RuntimeEvent: From<Event<Self>>> {
101 type WeightInfo: WeightInfo;
102 type Currency: Mutate<Self::AccountId>;
103 type LengthToFee: WeightToFee<Balance = BalanceOf<Self>>;
104 type ExtrinsicStorageFees: ExtrinsicStorageFees<Self>;
105 }
106
107 #[pallet::pallet]
108 #[pallet::without_storage_info]
109 pub struct Pallet<T>(_);
110
111 #[pallet::call]
112 impl<T: Config> Pallet<T> {
113 #[pallet::call_index(0)]
116 #[pallet::weight((T::WeightInfo::set_code(), DispatchClass::Mandatory))]
117 pub fn set_code(origin: OriginFor<T>, code: Vec<u8>) -> DispatchResult {
118 ensure_none(origin)?;
119 <frame_system::pallet::Pallet<T>>::can_set_code(&code, false).into_result()?;
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 && code != &provided_code
164 {
165 return Err(InherentError::IncorrectRuntimeCode);
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::zero()
186 }
187 }
188}
189
190pub struct Executive<
195 ExecutiveConfig,
196 Context,
197 UnsignedValidator,
198 AllPalletsWithSystem,
199 OnRuntimeUpgrade = (),
200>(
201 PhantomData<(
202 ExecutiveConfig,
203 Context,
204 UnsignedValidator,
205 AllPalletsWithSystem,
206 OnRuntimeUpgrade,
207 )>,
208);
209
210impl<
211 ExecutiveConfig: Config + frame_system::Config + IsInherent<ExtrinsicOf<ExecutiveConfig>>,
212 Context: Default,
213 UnsignedValidator,
214 AllPalletsWithSystem: OnRuntimeUpgrade
215 + BeforeAllRuntimeMigrations
216 + OnInitializeWithWeightRegistration<ExecutiveConfig>
217 + OnIdle<BlockNumberFor<ExecutiveConfig>>
218 + OnFinalize<BlockNumberFor<ExecutiveConfig>>
219 + OffchainWorker<BlockNumberFor<ExecutiveConfig>>
220 + OnPoll<BlockNumberFor<ExecutiveConfig>>,
221 COnRuntimeUpgrade: OnRuntimeUpgrade,
222> ExecuteBlock<BlockOf<ExecutiveConfig>>
223 for Executive<
224 ExecutiveConfig,
225 Context,
226 UnsignedValidator,
227 AllPalletsWithSystem,
228 COnRuntimeUpgrade,
229 >
230where
231 ExtrinsicOf<ExecutiveConfig>: Checkable<Context> + Codec,
232 CheckedOf<ExtrinsicOf<ExecutiveConfig>, Context>: Applyable + GetDispatchInfo,
233 CallOf<ExtrinsicOf<ExecutiveConfig>, Context>:
234 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
235 OriginOf<ExtrinsicOf<ExecutiveConfig>, Context>: From<Option<AccountIdOf<ExecutiveConfig>>>,
236 UnsignedValidator: ValidateUnsigned<Call = CallOf<ExtrinsicOf<ExecutiveConfig>, Context>>,
237{
238 fn execute_block(block: <BlockOf<ExecutiveConfig> as BlockT>::LazyBlock) {
239 Executive::<
240 ExecutiveConfig,
241 Context,
242 UnsignedValidator,
243 AllPalletsWithSystem,
244 COnRuntimeUpgrade,
245 >::execute_block(block);
246 }
247}
248
249impl<
250 ExecutiveConfig: Config + frame_system::Config + IsInherent<ExtrinsicOf<ExecutiveConfig>>,
251 Context: Default,
252 UnsignedValidator,
253 AllPalletsWithSystem: OnRuntimeUpgrade
254 + BeforeAllRuntimeMigrations
255 + OnInitializeWithWeightRegistration<ExecutiveConfig>
256 + OnIdle<BlockNumberFor<ExecutiveConfig>>
257 + OnFinalize<BlockNumberFor<ExecutiveConfig>>
258 + OffchainWorker<BlockNumberFor<ExecutiveConfig>>
259 + OnPoll<BlockNumberFor<ExecutiveConfig>>,
260 COnRuntimeUpgrade: OnRuntimeUpgrade,
261> Executive<ExecutiveConfig, Context, UnsignedValidator, AllPalletsWithSystem, COnRuntimeUpgrade>
262where
263 ExtrinsicOf<ExecutiveConfig>: Checkable<Context> + Codec,
264 CheckedOf<ExtrinsicOf<ExecutiveConfig>, Context>: Applyable + GetDispatchInfo,
265 CallOf<ExtrinsicOf<ExecutiveConfig>, Context>:
266 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
267 OriginOf<ExtrinsicOf<ExecutiveConfig>, Context>: From<Option<AccountIdOf<ExecutiveConfig>>>,
268 UnsignedValidator: ValidateUnsigned<Call = CallOf<ExtrinsicOf<ExecutiveConfig>, Context>>,
269{
270 pub fn storage_root() -> Vec<u8> {
272 let version = <ExecutiveConfig as frame_system::Config>::Version::get().state_version();
273 sp_io::storage::root(version)
274 }
275
276 pub fn execute_on_runtime_upgrade() -> Weight {
278 frame_executive::Executive::<
279 ExecutiveConfig,
280 BlockOf<ExecutiveConfig>,
281 Context,
282 UnsignedValidator,
283 AllPalletsWithSystem,
284 COnRuntimeUpgrade,
285 >::execute_on_runtime_upgrade()
286 }
287
288 pub fn initialize_block(header: &HeaderFor<ExecutiveConfig>) -> ExtrinsicInclusionMode {
292 frame_executive::Executive::<
293 ExecutiveConfig,
294 BlockOf<ExecutiveConfig>,
295 Context,
296 UnsignedValidator,
297 AllPalletsWithSystem,
298 COnRuntimeUpgrade,
299 >::initialize_block(header)
300 }
301
302 fn initial_checks(header: &HeaderFor<ExecutiveConfig>) {
305 sp_tracing::enter_span!(sp_tracing::Level::TRACE, "initial_checks");
306
307 let n = *header.number();
309 assert!(
310 n > BlockNumberFor::<ExecutiveConfig>::zero()
311 && <frame_system::Pallet<ExecutiveConfig>>::block_hash(
312 n - BlockNumberFor::<ExecutiveConfig>::one()
313 ) == *header.parent_hash(),
314 "Parent hash should be valid.",
315 );
316 }
317
318 pub fn execute_block(block: <BlockOf<ExecutiveConfig> as BlockT>::LazyBlock) {
326 sp_io::init_tracing();
327 sp_tracing::within_span! {
328 sp_tracing::info_span!("execute_block", ?block);
329 let mode = Self::initialize_block(block.header());
331 Self::initial_checks(block.header());
332
333 let extrinsics = block.extrinsics();
334 Self::apply_extrinsics(mode, extrinsics);
335
336 if !<frame_system::Pallet<ExecutiveConfig>>::inherents_applied() {
338 frame_executive::Executive::<
339 ExecutiveConfig,
340 BlockOf<ExecutiveConfig>,
341 Context,
342 UnsignedValidator,
343 AllPalletsWithSystem,
344 COnRuntimeUpgrade,
345 >::inherents_applied();
346 }
347
348 <frame_system::Pallet<ExecutiveConfig>>::note_finished_extrinsics();
349 <ExecutiveConfig as frame_system::Config>::PostTransactions::post_transactions();
350
351 let header = block.header();
352 Self::on_idle_hook(*header.number());
353 Self::on_finalize_hook(*header.number());
354 Self::final_checks(header);
355 }
356 }
357
358 fn apply_extrinsics(
361 mode: ExtrinsicInclusionMode,
362 extrinsics: impl Iterator<
363 Item = Result<ExtrinsicOf<ExecutiveConfig>, parity_scale_codec::Error>,
364 >,
365 ) {
366 let mut first_non_inherent_idx = 0;
367 for (idx, maybe_uxt) in extrinsics.into_iter().enumerate() {
368 let uxt = maybe_uxt
369 .unwrap_or_else(|err| panic!("Failed to decode extrinsic at index {idx}: {err}"));
370 let is_inherent = ExecutiveConfig::is_inherent(&uxt);
371 if is_inherent {
372 if first_non_inherent_idx != idx {
373 panic!("Invalid inherent position for extrinsic at index {idx}");
374 }
375 first_non_inherent_idx += 1;
376 } else if mode == ExtrinsicInclusionMode::OnlyInherents {
377 panic!("Only inherents are allowed in this block")
378 }
379
380 if let Err(e) = Self::apply_extrinsic(uxt) {
381 let err: &'static str = e.into();
382 panic!("{}", err)
383 }
384 }
385 }
386
387 pub fn finalize_block() -> HeaderFor<ExecutiveConfig> {
389 frame_executive::Executive::<
390 ExecutiveConfig,
391 BlockOf<ExecutiveConfig>,
392 Context,
393 UnsignedValidator,
394 AllPalletsWithSystem,
395 COnRuntimeUpgrade,
396 >::finalize_block()
397 }
398
399 fn on_idle_hook(block_number: NumberFor<BlockOf<ExecutiveConfig>>) {
401 let weight = <frame_system::Pallet<ExecutiveConfig>>::block_weight();
402 let max_weight = <<ExecutiveConfig as frame_system::Config>::BlockWeights as frame_support::traits::Get<_>>::get().max_block;
403 let remaining_weight = max_weight.saturating_sub(weight.total());
404
405 if remaining_weight.all_gt(Weight::zero()) {
406 let used_weight = AllPalletsWithSystem::on_idle(block_number, remaining_weight);
407 <frame_system::Pallet<ExecutiveConfig>>::register_extra_weight_unchecked(
408 used_weight,
409 DispatchClass::Mandatory,
410 );
411 }
412 }
413
414 fn on_finalize_hook(block_number: NumberFor<BlockOf<ExecutiveConfig>>) {
416 AllPalletsWithSystem::on_finalize(block_number);
417 }
418
419 pub fn apply_extrinsic(uxt: ExtrinsicOf<ExecutiveConfig>) -> ApplyExtrinsicResult {
423 let res = with_storage_layer(|| {
425 frame_executive::Executive::<
426 ExecutiveConfig,
427 BlockOf<ExecutiveConfig>,
428 Context,
429 UnsignedValidator,
430 AllPalletsWithSystem,
431 COnRuntimeUpgrade,
432 >::apply_extrinsic(uxt.clone())
433 .map_err(|err| DispatchError::Other(err.into()))
434 });
435
436 match res {
448 Ok(dispatch_outcome) => Ok(dispatch_outcome),
449 Err(err) => {
450 let encoded = uxt.encode();
451 let (maybe_signer, dispatch_info) =
452 ExecutiveConfig::ExtrinsicStorageFees::extract_signer(uxt);
453 if dispatch_info.class == DispatchClass::Mandatory {
456 return Err(TransactionValidityError::Invalid(
457 InvalidTransaction::MandatoryValidation,
458 ));
459 }
460
461 if let Some(signer) = maybe_signer {
463 let storage_fees = ExecutiveConfig::LengthToFee::weight_to_fee(
464 &Weight::from_parts(encoded.len() as u64, 0),
465 );
466
467 let maybe_charged_fees = ExecutiveConfig::Currency::burn_from(
470 &signer,
471 storage_fees,
472 Preservation::Expendable,
473 Precision::BestEffort,
474 Fortitude::Force,
475 );
476
477 if let Ok(charged_fees) = maybe_charged_fees {
478 ExecutiveConfig::ExtrinsicStorageFees::on_storage_fees_charged(
479 charged_fees,
480 encoded.len() as u32,
481 )?;
482 }
483 }
484
485 <frame_system::Pallet<ExecutiveConfig>>::note_extrinsic(encoded);
487
488 let r = Err(DispatchErrorWithPostInfo {
491 post_info: PostDispatchInfo {
492 actual_weight: None,
493 pays_fee: Pays::No,
494 },
495 error: err,
496 });
497
498 <frame_system::Pallet<ExecutiveConfig>>::note_applied_extrinsic(&r, dispatch_info);
499 Ok(Err(err))
500 }
501 }
502 }
503
504 fn final_checks(header: &HeaderFor<ExecutiveConfig>) {
506 sp_tracing::enter_span!(sp_tracing::Level::TRACE, "final_checks");
507 let new_header = <frame_system::Pallet<ExecutiveConfig>>::finalize();
509
510 assert_eq!(
512 header.digest().logs().len(),
513 new_header.digest().logs().len(),
514 "Number of digest items must match that calculated."
515 );
516 let items_zip = header
517 .digest()
518 .logs()
519 .iter()
520 .zip(new_header.digest().logs().iter());
521 for (header_item, computed_item) in items_zip {
522 header_item.check_equal(computed_item);
523 assert_eq!(
524 header_item, computed_item,
525 "Digest item must match that calculated."
526 );
527 }
528
529 let storage_root = new_header.state_root();
531 header.state_root().check_equal(storage_root);
532 assert!(
533 header.state_root() == storage_root,
534 "Storage root must match that calculated."
535 );
536
537 assert!(
538 header.extrinsics_root() == new_header.extrinsics_root(),
539 "Transaction trie root must be valid.",
540 );
541 }
542
543 pub fn validate_transaction(
545 source: TransactionSource,
546 uxt: ExtrinsicOf<ExecutiveConfig>,
547 block_hash: BlockHashOf<ExecutiveConfig>,
548 ) -> TransactionValidity {
549 frame_executive::Executive::<
550 ExecutiveConfig,
551 BlockOf<ExecutiveConfig>,
552 Context,
553 UnsignedValidator,
554 AllPalletsWithSystem,
555 COnRuntimeUpgrade,
556 >::validate_transaction(source, uxt, block_hash)
557 }
558
559 pub fn offchain_worker(header: &HeaderFor<ExecutiveConfig>) {
561 frame_executive::Executive::<
562 ExecutiveConfig,
563 BlockOf<ExecutiveConfig>,
564 Context,
565 UnsignedValidator,
566 AllPalletsWithSystem,
567 COnRuntimeUpgrade,
568 >::offchain_worker(header)
569 }
570}