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::*;
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 {
101 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
102 type WeightInfo: WeightInfo;
103 type Currency: Mutate<Self::AccountId>;
104 type LengthToFee: WeightToFee<Balance = BalanceOf<Self>>;
105 type ExtrinsicStorageFees: ExtrinsicStorageFees<Self>;
106 }
107
108 #[pallet::pallet]
109 #[pallet::without_storage_info]
110 pub struct Pallet<T>(_);
111
112 #[pallet::call]
113 impl<T: Config> Pallet<T> {
114 #[pallet::call_index(0)]
117 #[pallet::weight((T::WeightInfo::set_code(), DispatchClass::Mandatory))]
118 pub fn set_code(origin: OriginFor<T>, code: Vec<u8>) -> DispatchResult {
119 ensure_none(origin)?;
120 <frame_system::pallet::Pallet<T>>::can_set_code(&code)?;
121 <T as frame_system::Config>::OnSetCode::set_code(code)?;
122 Ok(())
123 }
124 }
125
126 #[pallet::inherent]
127 impl<T: Config> ProvideInherent for Pallet<T> {
128 type Call = Call<T>;
129 type Error = InherentError;
130 const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
131
132 fn create_inherent(data: &InherentData) -> Option<Self::Call> {
133 let inherent_data = data
134 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
135 .expect("Executive inherent data not correctly encoded")
136 .expect("Executive inherent data must be provided");
137
138 inherent_data.maybe_code.map(|code| Call::set_code { code })
139 }
140
141 fn is_inherent_required(data: &InherentData) -> Result<Option<Self::Error>, Self::Error> {
142 let inherent_data = data
143 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
144 .expect("Executive inherent data not correctly encoded")
145 .expect("Executive inherent data must be provided");
146
147 Ok(if inherent_data.maybe_code.is_none() {
148 None
149 } else {
150 Some(InherentError::MissingRuntimeCode)
151 })
152 }
153
154 fn check_inherent(call: &Self::Call, data: &InherentData) -> Result<(), Self::Error> {
155 let inherent_data = data
156 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
157 .expect("Executive inherent data not correctly encoded")
158 .expect("Executive inherent data must be provided");
159
160 if let Some(provided_code) = inherent_data.maybe_code {
161 if let Call::set_code { code } = call
162 && code != &provided_code
163 {
164 return Err(InherentError::IncorrectRuntimeCode);
165 }
166 } else {
167 return Err(InherentError::MissingRuntimeCode);
168 }
169
170 Ok(())
171 }
172
173 fn is_inherent(call: &Self::Call) -> bool {
174 matches!(call, Call::set_code { .. })
175 }
176 }
177
178 #[pallet::event]
179 pub enum Event<T: Config> {}
180
181 #[pallet::hooks]
182 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
183 fn on_initialize(_block_number: BlockNumberFor<T>) -> Weight {
184 Weight::zero()
185 }
186 }
187}
188
189pub struct Executive<
194 ExecutiveConfig,
195 Context,
196 UnsignedValidator,
197 AllPalletsWithSystem,
198 OnRuntimeUpgrade = (),
199>(
200 PhantomData<(
201 ExecutiveConfig,
202 Context,
203 UnsignedValidator,
204 AllPalletsWithSystem,
205 OnRuntimeUpgrade,
206 )>,
207);
208
209impl<
210 ExecutiveConfig: Config + frame_system::Config + EnsureInherentsAreFirst<BlockOf<ExecutiveConfig>>,
211 Context: Default,
212 UnsignedValidator,
213 AllPalletsWithSystem: OnRuntimeUpgrade
214 + BeforeAllRuntimeMigrations
215 + OnInitialize<BlockNumberFor<ExecutiveConfig>>
216 + OnIdle<BlockNumberFor<ExecutiveConfig>>
217 + OnFinalize<BlockNumberFor<ExecutiveConfig>>
218 + OffchainWorker<BlockNumberFor<ExecutiveConfig>>
219 + OnPoll<BlockNumberFor<ExecutiveConfig>>,
220 COnRuntimeUpgrade: OnRuntimeUpgrade,
221> ExecuteBlock<BlockOf<ExecutiveConfig>>
222 for Executive<
223 ExecutiveConfig,
224 Context,
225 UnsignedValidator,
226 AllPalletsWithSystem,
227 COnRuntimeUpgrade,
228 >
229where
230 ExtrinsicOf<ExecutiveConfig>: Checkable<Context> + Codec,
231 CheckedOf<ExtrinsicOf<ExecutiveConfig>, Context>: Applyable + GetDispatchInfo,
232 CallOf<ExtrinsicOf<ExecutiveConfig>, Context>:
233 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
234 OriginOf<ExtrinsicOf<ExecutiveConfig>, Context>: From<Option<AccountIdOf<ExecutiveConfig>>>,
235 UnsignedValidator: ValidateUnsigned<Call = CallOf<ExtrinsicOf<ExecutiveConfig>, Context>>,
236{
237 fn execute_block(block: BlockOf<ExecutiveConfig>) {
238 Executive::<
239 ExecutiveConfig,
240 Context,
241 UnsignedValidator,
242 AllPalletsWithSystem,
243 COnRuntimeUpgrade,
244 >::execute_block(block);
245 }
246}
247
248impl<
249 ExecutiveConfig: Config + frame_system::Config + EnsureInherentsAreFirst<BlockOf<ExecutiveConfig>>,
250 Context: Default,
251 UnsignedValidator,
252 AllPalletsWithSystem: OnRuntimeUpgrade
253 + BeforeAllRuntimeMigrations
254 + OnInitialize<BlockNumberFor<ExecutiveConfig>>
255 + OnIdle<BlockNumberFor<ExecutiveConfig>>
256 + OnFinalize<BlockNumberFor<ExecutiveConfig>>
257 + OffchainWorker<BlockNumberFor<ExecutiveConfig>>
258 + OnPoll<BlockNumberFor<ExecutiveConfig>>,
259 COnRuntimeUpgrade: OnRuntimeUpgrade,
260> Executive<ExecutiveConfig, Context, UnsignedValidator, AllPalletsWithSystem, COnRuntimeUpgrade>
261where
262 ExtrinsicOf<ExecutiveConfig>: Checkable<Context> + Codec,
263 CheckedOf<ExtrinsicOf<ExecutiveConfig>, Context>: Applyable + GetDispatchInfo,
264 CallOf<ExtrinsicOf<ExecutiveConfig>, Context>:
265 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
266 OriginOf<ExtrinsicOf<ExecutiveConfig>, Context>: From<Option<AccountIdOf<ExecutiveConfig>>>,
267 UnsignedValidator: ValidateUnsigned<Call = CallOf<ExtrinsicOf<ExecutiveConfig>, Context>>,
268{
269 pub fn storage_root() -> Vec<u8> {
271 let version = <ExecutiveConfig as frame_system::Config>::Version::get().state_version();
272 sp_io::storage::root(version)
273 }
274
275 pub fn execute_on_runtime_upgrade() -> Weight {
277 frame_executive::Executive::<
278 ExecutiveConfig,
279 BlockOf<ExecutiveConfig>,
280 Context,
281 UnsignedValidator,
282 AllPalletsWithSystem,
283 COnRuntimeUpgrade,
284 >::execute_on_runtime_upgrade()
285 }
286
287 pub fn initialize_block(header: &HeaderFor<ExecutiveConfig>) -> ExtrinsicInclusionMode {
291 frame_executive::Executive::<
292 ExecutiveConfig,
293 BlockOf<ExecutiveConfig>,
294 Context,
295 UnsignedValidator,
296 AllPalletsWithSystem,
297 COnRuntimeUpgrade,
298 >::initialize_block(header)
299 }
300
301 fn initial_checks(block: &BlockOf<ExecutiveConfig>) -> u32 {
303 sp_tracing::enter_span!(sp_tracing::Level::TRACE, "initial_checks");
304 let header = block.header();
305
306 let n = *header.number();
308 assert!(
309 n > BlockNumberFor::<ExecutiveConfig>::zero()
310 && <frame_system::Pallet<ExecutiveConfig>>::block_hash(
311 n - BlockNumberFor::<ExecutiveConfig>::one()
312 ) == *header.parent_hash(),
313 "Parent hash should be valid.",
314 );
315
316 match ExecutiveConfig::ensure_inherents_are_first(block) {
317 Ok(num) => num,
318 Err(i) => panic!("Invalid inherent position for extrinsic at index {i}"),
319 }
320 }
321
322 pub fn execute_block(block: BlockOf<ExecutiveConfig>) {
327 sp_io::init_tracing();
328 sp_tracing::within_span! {
329 sp_tracing::info_span!("execute_block", ?block);
330 let mode = Self::initialize_block(block.header());
332 let num_inherents = Self::initial_checks(&block) as usize;
333 let (header, extrinsics) = block.deconstruct();
334 let num_extrinsics = extrinsics.len();
335
336 if mode == ExtrinsicInclusionMode::OnlyInherents && num_extrinsics > num_inherents {
337 panic!("Only inherents are allowed in this block")
339 }
340
341 Self::apply_extrinsics(extrinsics.into_iter());
342
343 if !<frame_system::Pallet<ExecutiveConfig>>::inherents_applied() {
345 defensive_assert!(num_inherents == num_extrinsics);
346 frame_executive::Executive::<
347 ExecutiveConfig,
348 BlockOf<ExecutiveConfig>,
349 Context,
350 UnsignedValidator,
351 AllPalletsWithSystem,
352 COnRuntimeUpgrade,
353 >::inherents_applied();
354 }
355
356 <frame_system::Pallet<ExecutiveConfig>>::note_finished_extrinsics();
357 <ExecutiveConfig as frame_system::Config>::PostTransactions::post_transactions();
358
359 Self::idle_and_finalize_hook(*header.number());
360 Self::final_checks(&header);
361 }
362 }
363
364 fn apply_extrinsics(extrinsics: impl Iterator<Item = ExtrinsicOf<ExecutiveConfig>>) {
366 extrinsics.into_iter().for_each(|e| {
367 if let Err(e) = Self::apply_extrinsic(e) {
368 let err: &'static str = e.into();
369 panic!("{}", err)
370 }
371 });
372 }
373
374 pub fn finalize_block() -> HeaderFor<ExecutiveConfig> {
376 frame_executive::Executive::<
377 ExecutiveConfig,
378 BlockOf<ExecutiveConfig>,
379 Context,
380 UnsignedValidator,
381 AllPalletsWithSystem,
382 COnRuntimeUpgrade,
383 >::finalize_block()
384 }
385
386 fn idle_and_finalize_hook(block_number: NumberFor<BlockOf<ExecutiveConfig>>) {
388 let weight = <frame_system::Pallet<ExecutiveConfig>>::block_weight();
389 let max_weight = <<ExecutiveConfig as frame_system::Config>::BlockWeights as frame_support::traits::Get<_>>::get().max_block;
390 let remaining_weight = max_weight.saturating_sub(weight.total());
391
392 if remaining_weight.all_gt(Weight::zero()) {
393 let used_weight = AllPalletsWithSystem::on_idle(block_number, remaining_weight);
394 <frame_system::Pallet<ExecutiveConfig>>::register_extra_weight_unchecked(
395 used_weight,
396 DispatchClass::Mandatory,
397 );
398 }
399
400 AllPalletsWithSystem::on_finalize(block_number);
401 }
402
403 pub fn apply_extrinsic(uxt: ExtrinsicOf<ExecutiveConfig>) -> ApplyExtrinsicResult {
407 let res = with_storage_layer(|| {
409 frame_executive::Executive::<
410 ExecutiveConfig,
411 BlockOf<ExecutiveConfig>,
412 Context,
413 UnsignedValidator,
414 AllPalletsWithSystem,
415 COnRuntimeUpgrade,
416 >::apply_extrinsic(uxt.clone())
417 .map_err(|err| DispatchError::Other(err.into()))
418 });
419
420 match res {
432 Ok(dispatch_outcome) => Ok(dispatch_outcome),
433 Err(err) => {
434 let encoded = uxt.encode();
435 let (maybe_signer, dispatch_info) =
436 ExecutiveConfig::ExtrinsicStorageFees::extract_signer(uxt);
437 if dispatch_info.class == DispatchClass::Mandatory {
440 return Err(TransactionValidityError::Invalid(
441 InvalidTransaction::MandatoryValidation,
442 ));
443 }
444
445 if let Some(signer) = maybe_signer {
447 let storage_fees = ExecutiveConfig::LengthToFee::weight_to_fee(
448 &Weight::from_parts(encoded.len() as u64, 0),
449 );
450
451 let maybe_charged_fees = ExecutiveConfig::Currency::burn_from(
454 &signer,
455 storage_fees,
456 Preservation::Expendable,
457 Precision::BestEffort,
458 Fortitude::Force,
459 );
460
461 if let Ok(charged_fees) = maybe_charged_fees {
462 ExecutiveConfig::ExtrinsicStorageFees::on_storage_fees_charged(
463 charged_fees,
464 encoded.len() as u32,
465 )?;
466 }
467 }
468
469 <frame_system::Pallet<ExecutiveConfig>>::note_extrinsic(encoded);
471
472 let r = Err(DispatchErrorWithPostInfo {
475 post_info: PostDispatchInfo {
476 actual_weight: None,
477 pays_fee: Pays::No,
478 },
479 error: err,
480 });
481
482 <frame_system::Pallet<ExecutiveConfig>>::note_applied_extrinsic(&r, dispatch_info);
483 Ok(Err(err))
484 }
485 }
486 }
487
488 fn final_checks(header: &HeaderFor<ExecutiveConfig>) {
490 sp_tracing::enter_span!(sp_tracing::Level::TRACE, "final_checks");
491 let new_header = <frame_system::Pallet<ExecutiveConfig>>::finalize();
493
494 assert_eq!(
496 header.digest().logs().len(),
497 new_header.digest().logs().len(),
498 "Number of digest items must match that calculated."
499 );
500 let items_zip = header
501 .digest()
502 .logs()
503 .iter()
504 .zip(new_header.digest().logs().iter());
505 for (header_item, computed_item) in items_zip {
506 header_item.check_equal(computed_item);
507 assert_eq!(
508 header_item, computed_item,
509 "Digest item must match that calculated."
510 );
511 }
512
513 let storage_root = new_header.state_root();
515 header.state_root().check_equal(storage_root);
516 assert!(
517 header.state_root() == storage_root,
518 "Storage root must match that calculated."
519 );
520
521 assert!(
522 header.extrinsics_root() == new_header.extrinsics_root(),
523 "Transaction trie root must be valid.",
524 );
525 }
526
527 pub fn validate_transaction(
529 source: TransactionSource,
530 uxt: ExtrinsicOf<ExecutiveConfig>,
531 block_hash: BlockHashOf<ExecutiveConfig>,
532 ) -> TransactionValidity {
533 frame_executive::Executive::<
534 ExecutiveConfig,
535 BlockOf<ExecutiveConfig>,
536 Context,
537 UnsignedValidator,
538 AllPalletsWithSystem,
539 COnRuntimeUpgrade,
540 >::validate_transaction(source, uxt, block_hash)
541 }
542
543 pub fn offchain_worker(header: &HeaderFor<ExecutiveConfig>) {
545 frame_executive::Executive::<
546 ExecutiveConfig,
547 BlockOf<ExecutiveConfig>,
548 Context,
549 UnsignedValidator,
550 AllPalletsWithSystem,
551 COnRuntimeUpgrade,
552 >::offchain_worker(header)
553 }
554}