1#![cfg_attr(not(feature = "std"), no_std)]
26#![expect(clippy::clone_on_copy, reason = "Comes from Substrate")]
28
29#[cfg(feature = "runtime-benchmarks")]
30mod benchmarking;
31#[cfg(test)]
32mod mock;
33#[cfg(test)]
34mod tests;
35pub mod weights;
36
37#[cfg(not(feature = "std"))]
38extern crate alloc;
39
40use frame_executive::OnInitializeWithWeightRegistration;
41use frame_support::dispatch::{
42 DispatchClass, DispatchErrorWithPostInfo, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo,
43};
44use frame_support::storage::with_storage_layer;
45use frame_support::traits::fungible::{Inspect, Mutate};
46use frame_support::traits::tokens::{Fortitude, Precision, Preservation};
47use frame_support::traits::{
48 BeforeAllRuntimeMigrations, ExecuteBlock, Get, IsInherent, OffchainWorker, OnFinalize, OnIdle,
49 OnPoll, OnRuntimeUpgrade, PostTransactions,
50};
51use frame_support::weights::{Weight, WeightToFee};
52use frame_system::pallet_prelude::*;
53pub use pallet::*;
54use parity_scale_codec::{Codec, Encode};
55use sp_runtime::traits::{
56 Applyable, Block as BlockT, CheckEqual, Checkable, Dispatchable, Header, LazyBlock, NumberFor,
57 One, ValidateUnsigned, Zero,
58};
59use sp_runtime::transaction_validity::{
60 InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
61};
62use sp_runtime::{ApplyExtrinsicResult, DispatchError, ExtrinsicInclusionMode};
63use sp_std::marker::PhantomData;
64use sp_std::prelude::*;
65pub use weights::WeightInfo;
66
67pub type CheckedOf<E, C> = <E as Checkable<C>>::Checked;
68pub type CallOf<E, C> = <CheckedOf<E, C> as Applyable>::Call;
69pub type OriginOf<E, C> = <CallOf<E, C> as Dispatchable>::RuntimeOrigin;
70
71pub trait ExtrinsicStorageFees<T: Config> {
73 fn extract_signer(xt: ExtrinsicOf<T>) -> (Option<AccountIdOf<T>>, DispatchInfo);
75 fn on_storage_fees_charged(
77 charged_fees: BalanceOf<T>,
78 tx_size: u32,
79 ) -> Result<(), TransactionValidityError>;
80}
81
82type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
83type BalanceOf<T> = <<T as Config>::Currency as Inspect<AccountIdOf<T>>>::Balance;
84type ExtrinsicOf<T> = <BlockOf<T> as BlockT>::Extrinsic;
85type BlockOf<T> = <T as frame_system::Config>::Block;
86type BlockHashOf<T> = <BlockOf<T> as BlockT>::Hash;
87
88#[frame_support::pallet]
89mod pallet {
90 use crate::weights::WeightInfo;
91 use crate::{BalanceOf, ExtrinsicStorageFees};
92 #[cfg(not(feature = "std"))]
93 use alloc::vec::Vec;
94 use frame_support::pallet_prelude::*;
95 use frame_support::traits::fungible::Mutate;
96 use frame_support::weights::WeightToFee;
97 use frame_system::SetCode;
98 use frame_system::pallet_prelude::*;
99 use sp_executive::{INHERENT_IDENTIFIER, InherentError, InherentType};
100
101 #[pallet::config]
102 pub trait Config: frame_system::Config<RuntimeEvent: From<Event<Self>>> {
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, false).into_result()?;
124 <T as frame_system::Config>::OnSetCode::set_code(code)?;
125 Ok(())
126 }
127 }
128
129 #[pallet::inherent]
130 impl<T: Config> ProvideInherent for Pallet<T> {
131 type Call = Call<T>;
132 type Error = InherentError;
133 const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
134
135 fn create_inherent(data: &InherentData) -> Option<Self::Call> {
136 let inherent_data = data
137 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
138 .expect("Executive inherent data not correctly encoded")
139 .expect("Executive inherent data must be provided");
140
141 inherent_data.maybe_code.map(|code| Call::set_code { code })
142 }
143
144 fn is_inherent_required(data: &InherentData) -> Result<Option<Self::Error>, Self::Error> {
145 let inherent_data = data
146 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
147 .expect("Executive inherent data not correctly encoded")
148 .expect("Executive inherent data must be provided");
149
150 Ok(if inherent_data.maybe_code.is_none() {
151 None
152 } else {
153 Some(InherentError::MissingRuntimeCode)
154 })
155 }
156
157 fn check_inherent(call: &Self::Call, data: &InherentData) -> Result<(), Self::Error> {
158 let inherent_data = data
159 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
160 .expect("Executive inherent data not correctly encoded")
161 .expect("Executive inherent data must be provided");
162
163 if let Some(provided_code) = inherent_data.maybe_code {
164 if let Call::set_code { code } = call
165 && code != &provided_code
166 {
167 return Err(InherentError::IncorrectRuntimeCode);
168 }
169 } else {
170 return Err(InherentError::MissingRuntimeCode);
171 }
172
173 Ok(())
174 }
175
176 fn is_inherent(call: &Self::Call) -> bool {
177 matches!(call, Call::set_code { .. })
178 }
179 }
180
181 #[pallet::event]
182 pub enum Event<T: Config> {}
183
184 #[pallet::hooks]
185 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
186 fn on_initialize(_block_number: BlockNumberFor<T>) -> Weight {
187 Weight::zero()
188 }
189 }
190}
191
192pub struct Executive<
197 ExecutiveConfig,
198 Context,
199 UnsignedValidator,
200 AllPalletsWithSystem,
201 OnRuntimeUpgrade = (),
202>(
203 PhantomData<(
204 ExecutiveConfig,
205 Context,
206 UnsignedValidator,
207 AllPalletsWithSystem,
208 OnRuntimeUpgrade,
209 )>,
210);
211
212impl<
213 ExecutiveConfig: Config + frame_system::Config + IsInherent<ExtrinsicOf<ExecutiveConfig>>,
214 Context: Default,
215 UnsignedValidator,
216 AllPalletsWithSystem: OnRuntimeUpgrade
217 + BeforeAllRuntimeMigrations
218 + OnInitializeWithWeightRegistration<ExecutiveConfig>
219 + OnIdle<BlockNumberFor<ExecutiveConfig>>
220 + OnFinalize<BlockNumberFor<ExecutiveConfig>>
221 + OffchainWorker<BlockNumberFor<ExecutiveConfig>>
222 + OnPoll<BlockNumberFor<ExecutiveConfig>>,
223 COnRuntimeUpgrade: OnRuntimeUpgrade,
224> ExecuteBlock<BlockOf<ExecutiveConfig>>
225 for Executive<
226 ExecutiveConfig,
227 Context,
228 UnsignedValidator,
229 AllPalletsWithSystem,
230 COnRuntimeUpgrade,
231 >
232where
233 ExtrinsicOf<ExecutiveConfig>: Checkable<Context> + Codec,
234 CheckedOf<ExtrinsicOf<ExecutiveConfig>, Context>: Applyable + GetDispatchInfo,
235 CallOf<ExtrinsicOf<ExecutiveConfig>, Context>:
236 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
237 OriginOf<ExtrinsicOf<ExecutiveConfig>, Context>: From<Option<AccountIdOf<ExecutiveConfig>>>,
238 UnsignedValidator: ValidateUnsigned<Call = CallOf<ExtrinsicOf<ExecutiveConfig>, Context>>,
239{
240 fn execute_block(block: <BlockOf<ExecutiveConfig> as BlockT>::LazyBlock) {
241 Executive::<
242 ExecutiveConfig,
243 Context,
244 UnsignedValidator,
245 AllPalletsWithSystem,
246 COnRuntimeUpgrade,
247 >::execute_block(block);
248 }
249}
250
251impl<
252 ExecutiveConfig: Config + frame_system::Config + IsInherent<ExtrinsicOf<ExecutiveConfig>>,
253 Context: Default,
254 UnsignedValidator,
255 AllPalletsWithSystem: OnRuntimeUpgrade
256 + BeforeAllRuntimeMigrations
257 + OnInitializeWithWeightRegistration<ExecutiveConfig>
258 + OnIdle<BlockNumberFor<ExecutiveConfig>>
259 + OnFinalize<BlockNumberFor<ExecutiveConfig>>
260 + OffchainWorker<BlockNumberFor<ExecutiveConfig>>
261 + OnPoll<BlockNumberFor<ExecutiveConfig>>,
262 COnRuntimeUpgrade: OnRuntimeUpgrade,
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(header: &HeaderFor<ExecutiveConfig>) {
307 sp_tracing::enter_span!(sp_tracing::Level::TRACE, "initial_checks");
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
320 pub fn execute_block(block: <BlockOf<ExecutiveConfig> as BlockT>::LazyBlock) {
328 sp_io::init_tracing();
329 sp_tracing::within_span! {
330 sp_tracing::info_span!("execute_block", ?block);
331 let mode = Self::initialize_block(block.header());
333 Self::initial_checks(block.header());
334
335 let extrinsics = block.extrinsics();
336 Self::apply_extrinsics(mode, extrinsics);
337
338 if !<frame_system::Pallet<ExecutiveConfig>>::inherents_applied() {
340 frame_executive::Executive::<
341 ExecutiveConfig,
342 BlockOf<ExecutiveConfig>,
343 Context,
344 UnsignedValidator,
345 AllPalletsWithSystem,
346 COnRuntimeUpgrade,
347 >::inherents_applied();
348 }
349
350 <frame_system::Pallet<ExecutiveConfig>>::note_finished_extrinsics();
351 <ExecutiveConfig as frame_system::Config>::PostTransactions::post_transactions();
352
353 let header = block.header();
354 Self::on_idle_hook(*header.number());
355 Self::on_finalize_hook(*header.number());
356 Self::final_checks(header);
357 }
358 }
359
360 fn apply_extrinsics(
363 mode: ExtrinsicInclusionMode,
364 extrinsics: impl Iterator<
365 Item = Result<ExtrinsicOf<ExecutiveConfig>, parity_scale_codec::Error>,
366 >,
367 ) {
368 let mut first_non_inherent_idx = 0;
369 for (idx, maybe_uxt) in extrinsics.into_iter().enumerate() {
370 let uxt = maybe_uxt
371 .unwrap_or_else(|err| panic!("Failed to decode extrinsic at index {idx}: {err}"));
372 let is_inherent = ExecutiveConfig::is_inherent(&uxt);
373 if is_inherent {
374 if first_non_inherent_idx != idx {
375 panic!("Invalid inherent position for extrinsic at index {idx}");
376 }
377 first_non_inherent_idx += 1;
378 } else if mode == ExtrinsicInclusionMode::OnlyInherents {
379 panic!("Only inherents are allowed in this block")
380 }
381
382 if let Err(e) = Self::apply_extrinsic(uxt) {
383 let err: &'static str = e.into();
384 panic!("{}", err)
385 }
386 }
387 }
388
389 pub fn finalize_block() -> HeaderFor<ExecutiveConfig> {
391 frame_executive::Executive::<
392 ExecutiveConfig,
393 BlockOf<ExecutiveConfig>,
394 Context,
395 UnsignedValidator,
396 AllPalletsWithSystem,
397 COnRuntimeUpgrade,
398 >::finalize_block()
399 }
400
401 fn on_idle_hook(block_number: NumberFor<BlockOf<ExecutiveConfig>>) {
403 let weight = <frame_system::Pallet<ExecutiveConfig>>::block_weight();
404 let max_weight = <<ExecutiveConfig as frame_system::Config>::BlockWeights as frame_support::traits::Get<_>>::get().max_block;
405 let remaining_weight = max_weight.saturating_sub(weight.total());
406
407 if remaining_weight.all_gt(Weight::zero()) {
408 let used_weight = AllPalletsWithSystem::on_idle(block_number, remaining_weight);
409 <frame_system::Pallet<ExecutiveConfig>>::register_extra_weight_unchecked(
410 used_weight,
411 DispatchClass::Mandatory,
412 );
413 }
414 }
415
416 fn on_finalize_hook(block_number: NumberFor<BlockOf<ExecutiveConfig>>) {
418 AllPalletsWithSystem::on_finalize(block_number);
419 }
420
421 pub fn apply_extrinsic(uxt: ExtrinsicOf<ExecutiveConfig>) -> ApplyExtrinsicResult {
425 let res = with_storage_layer(|| {
427 frame_executive::Executive::<
428 ExecutiveConfig,
429 BlockOf<ExecutiveConfig>,
430 Context,
431 UnsignedValidator,
432 AllPalletsWithSystem,
433 COnRuntimeUpgrade,
434 >::apply_extrinsic(uxt.clone())
435 .map_err(|err| DispatchError::Other(err.into()))
436 });
437
438 match res {
450 Ok(dispatch_outcome) => Ok(dispatch_outcome),
451 Err(err) => {
452 let encoded = uxt.encode();
453 let (maybe_signer, dispatch_info) =
454 ExecutiveConfig::ExtrinsicStorageFees::extract_signer(uxt);
455 if dispatch_info.class == DispatchClass::Mandatory {
458 return Err(TransactionValidityError::Invalid(
459 InvalidTransaction::MandatoryValidation,
460 ));
461 }
462
463 if let Some(signer) = maybe_signer {
465 let storage_fees = ExecutiveConfig::LengthToFee::weight_to_fee(
466 &Weight::from_parts(encoded.len() as u64, 0),
467 );
468
469 let maybe_charged_fees = ExecutiveConfig::Currency::burn_from(
472 &signer,
473 storage_fees,
474 Preservation::Expendable,
475 Precision::BestEffort,
476 Fortitude::Force,
477 );
478
479 if let Ok(charged_fees) = maybe_charged_fees {
480 ExecutiveConfig::ExtrinsicStorageFees::on_storage_fees_charged(
481 charged_fees,
482 encoded.len() as u32,
483 )?;
484 }
485 }
486
487 <frame_system::Pallet<ExecutiveConfig>>::note_extrinsic(encoded);
489
490 let r = Err(DispatchErrorWithPostInfo {
493 post_info: PostDispatchInfo {
494 actual_weight: None,
495 pays_fee: Pays::No,
496 },
497 error: err,
498 });
499
500 <frame_system::Pallet<ExecutiveConfig>>::note_applied_extrinsic(&r, dispatch_info);
501 Ok(Err(err))
502 }
503 }
504 }
505
506 fn final_checks(header: &HeaderFor<ExecutiveConfig>) {
508 sp_tracing::enter_span!(sp_tracing::Level::TRACE, "final_checks");
509 let new_header = <frame_system::Pallet<ExecutiveConfig>>::finalize();
511
512 assert_eq!(
514 header.digest().logs().len(),
515 new_header.digest().logs().len(),
516 "Number of digest items must match that calculated."
517 );
518 let items_zip = header
519 .digest()
520 .logs()
521 .iter()
522 .zip(new_header.digest().logs().iter());
523 for (header_item, computed_item) in items_zip {
524 header_item.check_equal(computed_item);
525 assert_eq!(
526 header_item, computed_item,
527 "Digest item must match that calculated."
528 );
529 }
530
531 let storage_root = new_header.state_root();
533 header.state_root().check_equal(storage_root);
534 assert!(
535 header.state_root() == storage_root,
536 "Storage root must match that calculated."
537 );
538
539 assert!(
540 header.extrinsics_root() == new_header.extrinsics_root(),
541 "Transaction trie root must be valid.",
542 );
543 }
544
545 pub fn validate_transaction(
547 source: TransactionSource,
548 uxt: ExtrinsicOf<ExecutiveConfig>,
549 block_hash: BlockHashOf<ExecutiveConfig>,
550 ) -> TransactionValidity {
551 frame_executive::Executive::<
552 ExecutiveConfig,
553 BlockOf<ExecutiveConfig>,
554 Context,
555 UnsignedValidator,
556 AllPalletsWithSystem,
557 COnRuntimeUpgrade,
558 >::validate_transaction(source, uxt, block_hash)
559 }
560
561 pub fn offchain_worker(header: &HeaderFor<ExecutiveConfig>) {
563 frame_executive::Executive::<
564 ExecutiveConfig,
565 BlockOf<ExecutiveConfig>,
566 Context,
567 UnsignedValidator,
568 AllPalletsWithSystem,
569 COnRuntimeUpgrade,
570 >::offchain_worker(header)
571 }
572}