domain_pallet_executive/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! # Domain Executive Module
19//!
20//! This module is derived from frame_executive with some custom modifications for
21//! including the failed extrinsic during `pre/post_dispatch` in the block and
22//! collecting the intermediate storage roots in the block execution required for
23//! the fraud proof of decoupled execution in Subspace.
24
25#![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
69/// Trait trait used to charge the extrinsic storage.
70pub trait ExtrinsicStorageFees<T: Config> {
71    /// Extracts signer from given extrinsic and its dispatch info.
72    fn extract_signer(xt: ExtrinsicOf<T>) -> (Option<AccountIdOf<T>>, DispatchInfo);
73    /// Hook to note operator rewards for charged storage fees.
74    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        /// Sets new runtime code after doing necessary checks.
115        /// Same as frame_system::Call::set_code but without root origin.
116        #[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
189/// Same semantics with `frame_executive::Executive`.
190///
191/// One extra generic parameter:
192/// - `ExecutiveConfig`: Something that implements `domain_pallet_executive::Config`.
193pub 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    /// Returns the latest storage root.
270    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    /// Wrapped `frame_executive::Executive::execute_on_runtime_upgrade`.
276    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    /// Wrapped `frame_executive::Executive::initialize_block`.
288    ///
289    /// Note the storage root in the end.
290    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    // TODO: https://github.com/paritytech/substrate/issues/10711
302    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        // Check that `parent_hash` is correct.
307        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    /// Wrapped `frame_executive::Executive::execute_block`.
323    ///
324    /// The purpose is to use our custom [`Executive::apply_extrinsic`] and
325    /// the [`Executive::finalize_block`] logic.
326    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            // Execute `on_runtime_upgrade` and `on_initialize`.
331            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                // Invalid block
338                panic!("Only inherents are allowed in this block")
339            }
340
341            Self::apply_extrinsics(extrinsics.into_iter());
342
343            // In this case there were no transactions to trigger this state transition:
344            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    /// Wrapped `frame_executive::Executive::apply_extrinsics`.
365    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    /// Wrapped `frame_executive::Executive::finalize_block`.
375    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    /// Wrapped `frame_executive::Executive::on_idle_hook` and `frame_executive::Executive::on_finalize_hook`
387    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    /// Wrapped `frame_executive::Executive::apply_extrinsic`.
404    ///
405    /// Note the storage root in the beginning.
406    pub fn apply_extrinsic(uxt: ExtrinsicOf<ExecutiveConfig>) -> ApplyExtrinsicResult {
407        // apply the extrinsic within another transaction so that changes can be reverted.
408        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        // apply extrinsic failed with transaction validity error
421        // this could happen for following scenarios
422        // - Bad extrinsic Signature
423        //      This extrinsic will be ignored by the operators during the bundle check
424        //      and marks such bundle as Invalid.
425        // - Extrinsic execution failed
426        //      There are multiple scenarios why this can happen
427        //      - Inherent extrinsic failed. If this happens, we should fail to apply extrinsic
428        //      - Pre and Post dispatch fails. Check the test `test_domain_block_builder_include_ext_with_failed_predispatch`
429        //        why this could happen. If it fail due to this, then we revert the inner storage changes
430        //        but still include extrinsic so that we can clear inconsistency between block body and trace roots.
431        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 this is mandatory extrinsic, then transaction should not execute
438                // we should fail here.
439                if dispatch_info.class == DispatchClass::Mandatory {
440                    return Err(TransactionValidityError::Invalid(
441                        InvalidTransaction::MandatoryValidation,
442                    ));
443                }
444
445                // charge signer for extrinsic storage
446                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                    // best effort to charge the fees to signer.
452                    // if signer does not have enough balance, we continue
453                    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                // note the extrinsic into system storage
470                <frame_system::Pallet<ExecutiveConfig>>::note_extrinsic(encoded);
471
472                // note extrinsic applied. it pays no fees since there was no execution.
473                // we also set the weight to zero since there was no execution done.
474                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    // TODO: https://github.com/paritytech/substrate/issues/10711
489    fn final_checks(header: &HeaderFor<ExecutiveConfig>) {
490        sp_tracing::enter_span!(sp_tracing::Level::TRACE, "final_checks");
491        // remove temporaries
492        let new_header = <frame_system::Pallet<ExecutiveConfig>>::finalize();
493
494        // check digest
495        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        // check storage root.
514        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    /// Wrapped `frame_executive::Executive::validate_transaction`.
528    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    /// Wrapped `frame_executive::Executive::offchain_worker`.
544    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}