auto_id_domain_runtime/
lib.rs

1#![feature(variant_count)]
2#![cfg_attr(not(feature = "std"), no_std)]
3// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
4#![recursion_limit = "256"]
5
6// Make the WASM binary available.
7#[cfg(feature = "std")]
8include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
9
10extern crate alloc;
11
12mod weights;
13
14use alloc::borrow::Cow;
15#[cfg(not(feature = "std"))]
16use alloc::format;
17use core::mem;
18use domain_runtime_primitives::opaque::Header;
19use domain_runtime_primitives::{
20    AccountId, Address, CheckExtrinsicsValidityError, DecodeExtrinsicError, ERR_BALANCE_OVERFLOW,
21    HoldIdentifier, SLOT_DURATION, Signature, TargetBlockFullness,
22};
23pub use domain_runtime_primitives::{
24    Balance, BlockNumber, EXISTENTIAL_DEPOSIT, Hash, MAX_OUTGOING_MESSAGES, Nonce, block_weights,
25    maximum_block_length, opaque,
26};
27use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo};
28use frame_support::genesis_builder_helper::{build_state, get_preset};
29use frame_support::pallet_prelude::TypeInfo;
30use frame_support::traits::fungible::Credit;
31use frame_support::traits::{
32    ConstU16, ConstU32, ConstU64, Everything, Imbalance, IsInherent, OnUnbalanced, VariantCount,
33};
34use frame_support::weights::constants::ParityDbWeight;
35use frame_support::weights::{ConstantMultiplier, Weight};
36use frame_support::{construct_runtime, parameter_types};
37use frame_system::limits::{BlockLength, BlockWeights};
38use pallet_block_fees::fees::OnChargeDomainTransaction;
39use pallet_transporter::EndpointHandler;
40use parity_scale_codec::{Decode, DecodeLimit, Encode, MaxEncodedLen};
41use sp_api::impl_runtime_apis;
42use sp_core::crypto::KeyTypeId;
43use sp_core::{Get, OpaqueMetadata};
44use sp_domains::{ChannelId, DomainAllowlistUpdates, DomainId, Transfers};
45use sp_messenger::endpoint::{Endpoint, EndpointHandler as EndpointHandlerT, EndpointId};
46use sp_messenger::messages::{
47    BlockMessagesQuery, BlockMessagesWithStorageKey, ChainId, ChannelStateWithNonce,
48    CrossDomainMessage, MessageId, MessageKey, MessagesWithStorageKey, Nonce as XdmNonce,
49};
50use sp_messenger::{ChannelNonce, XdmId};
51use sp_messenger_host_functions::{StorageKeyRequest, get_storage_key};
52use sp_mmr_primitives::EncodableOpaqueLeaf;
53use sp_runtime::generic::{Era, ExtrinsicFormat, Preamble};
54use sp_runtime::traits::{
55    AccountIdLookup, BlakeTwo256, Checkable, DispatchTransaction, Keccak256, NumberFor, One,
56    TransactionExtension, ValidateUnsigned, Zero,
57};
58use sp_runtime::transaction_validity::{
59    InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
60};
61use sp_runtime::type_with_default::TypeWithDefault;
62use sp_runtime::{ApplyExtrinsicResult, Digest, ExtrinsicInclusionMode, generic, impl_opaque_keys};
63pub use sp_runtime::{MultiAddress, Perbill, Permill};
64use sp_std::collections::btree_map::BTreeMap;
65use sp_std::collections::btree_set::BTreeSet;
66use sp_std::marker::PhantomData;
67use sp_std::prelude::*;
68use sp_subspace_mmr::domain_mmr_runtime_interface::{
69    is_consensus_block_finalized, verify_mmr_proof,
70};
71use sp_subspace_mmr::{ConsensusChainMmrLeafProof, MmrLeaf};
72use sp_version::RuntimeVersion;
73use static_assertions::const_assert;
74use subspace_runtime_primitives::utility::DefaultNonceProvider;
75use subspace_runtime_primitives::{
76    AI3, BlockHashFor, BlockNumber as ConsensusBlockNumber, DomainEventSegmentSize, ExtrinsicFor,
77    Hash as ConsensusBlockHash, HeaderFor, MAX_CALL_RECURSION_DEPTH, Moment, SHANNON,
78    SlowAdjustingFeeUpdate, XdmAdjustedWeightToFee, XdmFeeMultipler,
79};
80
81/// Block type as expected by this runtime.
82pub type Block = generic::Block<Header, UncheckedExtrinsic>;
83
84/// A Block signed with a Justification
85pub type SignedBlock = generic::SignedBlock<Block>;
86
87/// BlockId type as expected by this runtime.
88pub type BlockId = generic::BlockId<Block>;
89
90/// The SignedExtension to the basic transaction logic.
91pub type SignedExtra = (
92    frame_system::CheckNonZeroSender<Runtime>,
93    frame_system::CheckSpecVersion<Runtime>,
94    frame_system::CheckTxVersion<Runtime>,
95    frame_system::CheckGenesis<Runtime>,
96    frame_system::CheckMortality<Runtime>,
97    frame_system::CheckNonce<Runtime>,
98    domain_check_weight::CheckWeight<Runtime>,
99    pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
100    pallet_messenger::extensions::MessengerExtension<Runtime>,
101);
102
103/// The Custom SignedExtension used for pre_dispatch checks for bundle extrinsic verification
104pub type CustomSignedExtra = (
105    frame_system::CheckNonZeroSender<Runtime>,
106    frame_system::CheckSpecVersion<Runtime>,
107    frame_system::CheckTxVersion<Runtime>,
108    frame_system::CheckGenesis<Runtime>,
109    frame_system::CheckMortality<Runtime>,
110    frame_system::CheckNonce<Runtime>,
111    domain_check_weight::CheckWeight<Runtime>,
112    pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
113    pallet_messenger::extensions::MessengerTrustedMmrExtension<Runtime>,
114);
115
116/// Unchecked extrinsic type as expected by this runtime.
117pub type UncheckedExtrinsic =
118    generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
119
120/// Extrinsic type that has already been checked.
121pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, RuntimeCall, SignedExtra>;
122
123/// Executive: handles dispatch to the various modules.
124pub type Executive = domain_pallet_executive::Executive<
125    Runtime,
126    frame_system::ChainContext<Runtime>,
127    Runtime,
128    AllPalletsWithSystem,
129>;
130
131impl_opaque_keys! {
132    pub struct SessionKeys {
133        /// Primarily used for adding the operator signing key into the Keystore.
134        pub operator: sp_domains::OperatorKey,
135    }
136}
137
138#[sp_version::runtime_version]
139pub const VERSION: RuntimeVersion = RuntimeVersion {
140    spec_name: Cow::Borrowed("subspace-auto-id-domain"),
141    impl_name: Cow::Borrowed("subspace-auto-id-domain"),
142    authoring_version: 0,
143    // The spec version can be different on Taurus and Mainnet
144    spec_version: 0,
145    impl_version: 0,
146    apis: RUNTIME_API_VERSIONS,
147    transaction_version: 0,
148    system_version: 2,
149};
150
151parameter_types! {
152    pub const Version: RuntimeVersion = VERSION;
153    pub const BlockHashCount: BlockNumber = 2400;
154    pub RuntimeBlockLength: BlockLength = maximum_block_length();
155    pub RuntimeBlockWeights: BlockWeights = block_weights();
156}
157
158impl frame_system::Config for Runtime {
159    /// The identifier used to distinguish between accounts.
160    type AccountId = AccountId;
161    /// The aggregated dispatch type that is available for extrinsics.
162    type RuntimeCall = RuntimeCall;
163    /// The aggregated `RuntimeTask` type.
164    type RuntimeTask = RuntimeTask;
165    /// The lookup mechanism to get account ID from whatever is passed in dispatchers.
166    type Lookup = AccountIdLookup<AccountId, ()>;
167    /// The type for storing how many extrinsics an account has signed.
168    type Nonce = TypeWithDefault<Nonce, DefaultNonceProvider<System, Nonce>>;
169    /// The type for hashing blocks and tries.
170    type Hash = Hash;
171    /// The hashing algorithm used.
172    type Hashing = BlakeTwo256;
173    /// The block type.
174    type Block = Block;
175    /// The ubiquitous event type.
176    type RuntimeEvent = RuntimeEvent;
177    /// The ubiquitous origin type.
178    type RuntimeOrigin = RuntimeOrigin;
179    /// Maximum number of block number to block hash mappings to keep (oldest pruned first).
180    type BlockHashCount = BlockHashCount;
181    /// Runtime version.
182    type Version = Version;
183    /// Converts a module to an index of this module in the runtime.
184    type PalletInfo = PalletInfo;
185    /// The data to be stored in an account.
186    type AccountData = pallet_balances::AccountData<Balance>;
187    /// What to do if a new account is created.
188    type OnNewAccount = ();
189    /// What to do if an account is fully reaped from the system.
190    type OnKilledAccount = ();
191    /// The weight of database operations that the runtime can invoke.
192    type DbWeight = ParityDbWeight;
193    /// The basic call filter to use in dispatchable.
194    type BaseCallFilter = Everything;
195    /// Weight information for the extrinsics of this pallet.
196    type SystemWeightInfo = weights::frame_system::WeightInfo<Runtime>;
197    /// Block & extrinsics weights: base values and limits.
198    type BlockWeights = RuntimeBlockWeights;
199    /// The maximum length of a block (in bytes).
200    type BlockLength = RuntimeBlockLength;
201    type SS58Prefix = ConstU16<6094>;
202    /// The action to take on a Runtime Upgrade
203    type OnSetCode = ();
204    type SingleBlockMigrations = ();
205    type MultiBlockMigrator = ();
206    type PreInherents = ();
207    type PostInherents = ();
208    type PostTransactions = ();
209    type MaxConsumers = ConstU32<16>;
210    type ExtensionsWeightInfo = frame_system::ExtensionsWeight<Runtime>;
211    type EventSegmentSize = DomainEventSegmentSize;
212}
213
214impl pallet_timestamp::Config for Runtime {
215    /// A timestamp: milliseconds since the unix epoch.
216    type Moment = Moment;
217    type OnTimestampSet = ();
218    type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
219    type WeightInfo = weights::pallet_timestamp::WeightInfo<Runtime>;
220}
221
222parameter_types! {
223    pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT;
224    pub const MaxLocks: u32 = 50;
225    pub const MaxReserves: u32 = 50;
226}
227
228/// `DustRemovalHandler` used to collect all the AI3 dust left when the account is reaped.
229pub struct DustRemovalHandler;
230
231impl OnUnbalanced<Credit<AccountId, Balances>> for DustRemovalHandler {
232    fn on_nonzero_unbalanced(dusted_amount: Credit<AccountId, Balances>) {
233        BlockFees::note_burned_balance(dusted_amount.peek());
234    }
235}
236
237impl pallet_balances::Config for Runtime {
238    type RuntimeFreezeReason = RuntimeFreezeReason;
239    type MaxLocks = MaxLocks;
240    /// The type for recording an account's balance.
241    type Balance = Balance;
242    /// The ubiquitous event type.
243    type RuntimeEvent = RuntimeEvent;
244    type DustRemoval = DustRemovalHandler;
245    type ExistentialDeposit = ExistentialDeposit;
246    type AccountStore = System;
247    type WeightInfo = weights::pallet_balances::WeightInfo<Runtime>;
248    type MaxReserves = MaxReserves;
249    type ReserveIdentifier = [u8; 8];
250    type FreezeIdentifier = ();
251    type MaxFreezes = ();
252    type RuntimeHoldReason = HoldIdentifierWrapper;
253    type DoneSlashHandler = ();
254}
255
256parameter_types! {
257    pub const OperationalFeeMultiplier: u8 = 5;
258    pub const DomainChainByteFee: Balance = 1;
259    pub TransactionWeightFee: Balance = 100_000 * SHANNON;
260}
261
262impl pallet_block_fees::Config for Runtime {
263    type Balance = Balance;
264    type DomainChainByteFee = DomainChainByteFee;
265}
266
267pub struct FinalDomainTransactionByteFee;
268
269impl Get<Balance> for FinalDomainTransactionByteFee {
270    fn get() -> Balance {
271        BlockFees::final_domain_transaction_byte_fee()
272    }
273}
274
275impl pallet_transaction_payment::Config for Runtime {
276    type RuntimeEvent = RuntimeEvent;
277    type OnChargeTransaction = OnChargeDomainTransaction<Balances>;
278    type WeightToFee = ConstantMultiplier<Balance, TransactionWeightFee>;
279    type LengthToFee = ConstantMultiplier<Balance, FinalDomainTransactionByteFee>;
280    type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Runtime, TargetBlockFullness>;
281    type OperationalFeeMultiplier = OperationalFeeMultiplier;
282    type WeightInfo = weights::pallet_transaction_payment::WeightInfo<Runtime>;
283}
284
285impl pallet_auto_id::Config for Runtime {
286    type RuntimeEvent = RuntimeEvent;
287    type Time = Timestamp;
288    type Weights = weights::pallet_auto_id::WeightInfo<Runtime>;
289}
290
291pub struct ExtrinsicStorageFees;
292
293impl domain_pallet_executive::ExtrinsicStorageFees<Runtime> for ExtrinsicStorageFees {
294    fn extract_signer(xt: UncheckedExtrinsic) -> (Option<AccountId>, DispatchInfo) {
295        let dispatch_info = xt.get_dispatch_info();
296        let lookup = frame_system::ChainContext::<Runtime>::default();
297        let maybe_signer = extract_signer_inner(&xt, &lookup).and_then(|res| res.ok());
298        (maybe_signer, dispatch_info)
299    }
300
301    fn on_storage_fees_charged(
302        charged_fees: Balance,
303        tx_size: u32,
304    ) -> Result<(), TransactionValidityError> {
305        let consensus_storage_fee = BlockFees::consensus_chain_byte_fee()
306            .checked_mul(Balance::from(tx_size))
307            .ok_or(InvalidTransaction::Custom(ERR_BALANCE_OVERFLOW))?;
308
309        let (paid_consensus_storage_fee, paid_domain_fee) = if charged_fees <= consensus_storage_fee
310        {
311            (charged_fees, Zero::zero())
312        } else {
313            (consensus_storage_fee, charged_fees - consensus_storage_fee)
314        };
315
316        BlockFees::note_consensus_storage_fee(paid_consensus_storage_fee);
317        BlockFees::note_domain_execution_fee(paid_domain_fee);
318        Ok(())
319    }
320}
321
322impl domain_pallet_executive::Config for Runtime {
323    type RuntimeEvent = RuntimeEvent;
324    type WeightInfo = weights::domain_pallet_executive::WeightInfo<Runtime>;
325    type Currency = Balances;
326    type LengthToFee = <Runtime as pallet_transaction_payment::Config>::LengthToFee;
327    type ExtrinsicStorageFees = ExtrinsicStorageFees;
328}
329
330parameter_types! {
331    pub SelfChainId: ChainId = SelfDomainId::self_domain_id().into();
332}
333
334pub struct OnXDMRewards;
335
336impl sp_messenger::OnXDMRewards<Balance> for OnXDMRewards {
337    fn on_xdm_rewards(rewards: Balance) {
338        BlockFees::note_domain_execution_fee(rewards)
339    }
340    fn on_chain_protocol_fees(chain_id: ChainId, fees: Balance) {
341        // note the chain rewards
342        BlockFees::note_chain_rewards(chain_id, fees);
343    }
344}
345
346type MmrHash = <Keccak256 as sp_runtime::traits::Hash>::Output;
347
348pub struct MmrProofVerifier;
349
350impl sp_subspace_mmr::MmrProofVerifier<MmrHash, NumberFor<Block>, Hash> for MmrProofVerifier {
351    fn verify_proof_and_extract_leaf(
352        mmr_leaf_proof: ConsensusChainMmrLeafProof<NumberFor<Block>, Hash, MmrHash>,
353    ) -> Option<MmrLeaf<ConsensusBlockNumber, ConsensusBlockHash>> {
354        let ConsensusChainMmrLeafProof {
355            consensus_block_number,
356            opaque_mmr_leaf: opaque_leaf,
357            proof,
358            ..
359        } = mmr_leaf_proof;
360
361        if !is_consensus_block_finalized(consensus_block_number) {
362            return None;
363        }
364
365        let leaf: MmrLeaf<ConsensusBlockNumber, ConsensusBlockHash> =
366            opaque_leaf.into_opaque_leaf().try_decode()?;
367
368        verify_mmr_proof(vec![EncodableOpaqueLeaf::from_leaf(&leaf)], proof.encode())
369            .then_some(leaf)
370    }
371}
372
373pub struct StorageKeys;
374
375impl sp_messenger::StorageKeys for StorageKeys {
376    fn confirmed_domain_block_storage_key(domain_id: DomainId) -> Option<Vec<u8>> {
377        get_storage_key(StorageKeyRequest::ConfirmedDomainBlockStorageKey(domain_id))
378    }
379
380    fn outbox_storage_key(chain_id: ChainId, message_key: MessageKey) -> Option<Vec<u8>> {
381        get_storage_key(StorageKeyRequest::OutboxStorageKey {
382            chain_id,
383            message_key,
384        })
385    }
386
387    fn inbox_responses_storage_key(chain_id: ChainId, message_key: MessageKey) -> Option<Vec<u8>> {
388        get_storage_key(StorageKeyRequest::InboxResponseStorageKey {
389            chain_id,
390            message_key,
391        })
392    }
393}
394
395/// Hold identifier for balances for this runtime.
396#[derive(
397    PartialEq, Eq, Clone, Encode, Decode, TypeInfo, MaxEncodedLen, Ord, PartialOrd, Copy, Debug,
398)]
399pub struct HoldIdentifierWrapper(HoldIdentifier);
400
401impl VariantCount for HoldIdentifierWrapper {
402    const VARIANT_COUNT: u32 = mem::variant_count::<HoldIdentifier>() as u32;
403}
404
405impl pallet_messenger::HoldIdentifier<Runtime> for HoldIdentifierWrapper {
406    fn messenger_channel() -> Self {
407        Self(HoldIdentifier::MessengerChannel)
408    }
409}
410
411parameter_types! {
412    pub const ChannelReserveFee: Balance = 100 * AI3;
413    pub const ChannelInitReservePortion: Perbill = Perbill::from_percent(20);
414    pub const MaxOutgoingMessages: u32 = MAX_OUTGOING_MESSAGES;
415}
416
417// ensure the max outgoing messages is not 0.
418const_assert!(MaxOutgoingMessages::get() >= 1);
419
420impl pallet_messenger::Config for Runtime {
421    type RuntimeEvent = RuntimeEvent;
422    type SelfChainId = SelfChainId;
423
424    fn get_endpoint_handler(endpoint: &Endpoint) -> Option<Box<dyn EndpointHandlerT<MessageId>>> {
425        if endpoint == &Endpoint::Id(TransporterEndpointId::get()) {
426            Some(Box::new(EndpointHandler(PhantomData::<Runtime>)))
427        } else {
428            None
429        }
430    }
431
432    type Currency = Balances;
433    type WeightInfo = weights::pallet_messenger::WeightInfo<Runtime>;
434    type WeightToFee = ConstantMultiplier<Balance, TransactionWeightFee>;
435    type AdjustedWeightToFee = XdmAdjustedWeightToFee<Runtime>;
436    type FeeMultiplier = XdmFeeMultipler;
437    type OnXDMRewards = OnXDMRewards;
438    type MmrHash = MmrHash;
439    type MmrProofVerifier = MmrProofVerifier;
440    #[cfg(feature = "runtime-benchmarks")]
441    type StorageKeys = sp_messenger::BenchmarkStorageKeys;
442    #[cfg(not(feature = "runtime-benchmarks"))]
443    type StorageKeys = StorageKeys;
444    type DomainOwner = ();
445    type HoldIdentifier = HoldIdentifierWrapper;
446    type ChannelReserveFee = ChannelReserveFee;
447    type ChannelInitReservePortion = ChannelInitReservePortion;
448    type DomainRegistration = ();
449    type MaxOutgoingMessages = MaxOutgoingMessages;
450    type MessengerOrigin = pallet_messenger::EnsureMessengerOrigin;
451    type NoteChainTransfer = Transporter;
452    type ExtensionWeightInfo = pallet_messenger::extensions::weights::SubstrateWeight<
453        Runtime,
454        weights::pallet_messenger_from_consensus_extension::WeightInfo<Runtime>,
455        weights::pallet_messenger_between_domains_extension::WeightInfo<Runtime>,
456    >;
457}
458
459impl<C> frame_system::offchain::CreateTransactionBase<C> for Runtime
460where
461    RuntimeCall: From<C>,
462{
463    type Extrinsic = UncheckedExtrinsic;
464    type RuntimeCall = RuntimeCall;
465}
466
467parameter_types! {
468    pub const TransporterEndpointId: EndpointId = 1;
469    pub const MinimumTransfer: Balance = AI3;
470}
471
472impl pallet_transporter::Config for Runtime {
473    type RuntimeEvent = RuntimeEvent;
474    type SelfChainId = SelfChainId;
475    type SelfEndpointId = TransporterEndpointId;
476    type Currency = Balances;
477    type Sender = Messenger;
478    type AccountIdConverter = domain_runtime_primitives::AccountIdConverter;
479    type WeightInfo = weights::pallet_transporter::WeightInfo<Runtime>;
480    type SkipBalanceTransferChecks = ();
481    type MinimumTransfer = MinimumTransfer;
482}
483
484impl pallet_domain_id::Config for Runtime {}
485
486pub struct IntoRuntimeCall;
487
488impl sp_domain_sudo::IntoRuntimeCall<RuntimeCall> for IntoRuntimeCall {
489    fn runtime_call(call: Vec<u8>) -> RuntimeCall {
490        UncheckedExtrinsic::decode(&mut call.as_slice())
491            .expect("must always be a valid extrinsic as checked by consensus chain; qed")
492            .function
493    }
494}
495
496impl pallet_domain_sudo::Config for Runtime {
497    type RuntimeEvent = RuntimeEvent;
498    type RuntimeCall = RuntimeCall;
499    type IntoRuntimeCall = IntoRuntimeCall;
500}
501
502impl pallet_utility::Config for Runtime {
503    type RuntimeEvent = RuntimeEvent;
504    type RuntimeCall = RuntimeCall;
505    type PalletsOrigin = OriginCaller;
506    type WeightInfo = weights::pallet_utility::WeightInfo<Runtime>;
507}
508
509// Create the runtime by composing the FRAME pallets that were previously configured.
510//
511// NOTE: Currently domain runtime does not naturally support the pallets with inherent extrinsics.
512construct_runtime!(
513    pub struct Runtime {
514        // System support stuff.
515        System: frame_system = 0,
516        // Note: Ensure index of the timestamp matches with the index of timestamp on Consensus
517        //  so that consensus can construct encoded extrinsic that matches with Domain encoded
518        //  extrinsic.
519        Timestamp: pallet_timestamp = 1,
520        ExecutivePallet: domain_pallet_executive = 2,
521        Utility: pallet_utility = 8,
522
523        // monetary stuff
524        Balances: pallet_balances = 20,
525        TransactionPayment: pallet_transaction_payment = 21,
526
527        // AutoId
528        AutoId: pallet_auto_id = 40,
529
530        // messenger stuff
531        // Note: Indexes should match with indexes on other chains and domains
532        Messenger: pallet_messenger = 60,
533        Transporter: pallet_transporter = 61,
534
535        // domain instance stuff
536        SelfDomainId: pallet_domain_id = 90,
537        BlockFees: pallet_block_fees = 91,
538
539        // Sudo account
540        Sudo: pallet_domain_sudo = 100,
541    }
542);
543
544impl pallet_messenger::extensions::MaybeMessengerCall<Runtime> for RuntimeCall {
545    fn maybe_messenger_call(&self) -> Option<&pallet_messenger::Call<Runtime>> {
546        match self {
547            RuntimeCall::Messenger(call) => Some(call),
548            _ => None,
549        }
550    }
551}
552
553impl<C> subspace_runtime_primitives::CreateUnsigned<C> for Runtime
554where
555    RuntimeCall: From<C>,
556{
557    fn create_unsigned(call: Self::RuntimeCall) -> Self::Extrinsic {
558        create_unsigned_general_extrinsic(call)
559    }
560}
561
562fn create_unsigned_general_extrinsic(call: RuntimeCall) -> UncheckedExtrinsic {
563    let extra: SignedExtra = (
564        frame_system::CheckNonZeroSender::<Runtime>::new(),
565        frame_system::CheckSpecVersion::<Runtime>::new(),
566        frame_system::CheckTxVersion::<Runtime>::new(),
567        frame_system::CheckGenesis::<Runtime>::new(),
568        frame_system::CheckMortality::<Runtime>::from(generic::Era::Immortal),
569        // for unsigned extrinsic, nonce check will be skipped
570        // so set a default value
571        frame_system::CheckNonce::<Runtime>::from(0u32.into()),
572        domain_check_weight::CheckWeight::<Runtime>::new(),
573        // for unsigned extrinsic, transaction fee check will be skipped
574        // so set a default value
575        pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(0u128),
576        pallet_messenger::extensions::MessengerExtension::<Runtime>::new(),
577    );
578
579    UncheckedExtrinsic::new_transaction(call, extra)
580}
581
582fn is_xdm_mmr_proof_valid(ext: &ExtrinsicFor<Block>) -> Option<bool> {
583    match &ext.function {
584        RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })
585        | RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
586            let ConsensusChainMmrLeafProof {
587                consensus_block_number,
588                opaque_mmr_leaf,
589                proof,
590                ..
591            } = msg.proof.consensus_mmr_proof();
592
593            if !is_consensus_block_finalized(consensus_block_number) {
594                return Some(false);
595            }
596
597            Some(verify_mmr_proof(vec![opaque_mmr_leaf], proof.encode()))
598        }
599        _ => None,
600    }
601}
602
603/// Returns `true` if this is a validly encoded Sudo call.
604fn is_valid_sudo_call(encoded_ext: Vec<u8>) -> bool {
605    UncheckedExtrinsic::decode_all_with_depth_limit(
606        MAX_CALL_RECURSION_DEPTH,
607        &mut encoded_ext.as_slice(),
608    )
609    .is_ok()
610}
611
612fn construct_sudo_call_extrinsic(encoded_ext: Vec<u8>) -> ExtrinsicFor<Block> {
613    let ext = UncheckedExtrinsic::decode(&mut encoded_ext.as_slice()).expect(
614        "must always be a valid extrinsic due to the check above and storage proof check; qed",
615    );
616    UncheckedExtrinsic::new_bare(
617        pallet_domain_sudo::Call::sudo {
618            call: Box::new(ext.function),
619        }
620        .into(),
621    )
622}
623
624fn extract_signer_inner<Lookup>(
625    ext: &UncheckedExtrinsic,
626    lookup: &Lookup,
627) -> Option<Result<AccountId, TransactionValidityError>>
628where
629    Lookup: sp_runtime::traits::Lookup<Source = Address, Target = AccountId>,
630{
631    match &ext.preamble {
632        Preamble::Bare(_) | Preamble::General(_, _) => None,
633        Preamble::Signed(signed, _, _) => Some(lookup.lookup(signed.clone()).map_err(|e| e.into())),
634    }
635}
636
637pub fn extract_signer(
638    extrinsics: Vec<UncheckedExtrinsic>,
639) -> Vec<(Option<opaque::AccountId>, UncheckedExtrinsic)> {
640    let lookup = frame_system::ChainContext::<Runtime>::default();
641
642    extrinsics
643        .into_iter()
644        .map(|extrinsic| {
645            let maybe_signer =
646                extract_signer_inner(&extrinsic, &lookup).and_then(|account_result| {
647                    account_result.ok().map(|account_id| account_id.encode())
648                });
649            (maybe_signer, extrinsic)
650        })
651        .collect()
652}
653
654fn extrinsic_era(extrinsic: &ExtrinsicFor<Block>) -> Option<Era> {
655    match &extrinsic.preamble {
656        Preamble::Bare(_) | Preamble::General(_, _) => None,
657        Preamble::Signed(_, _, extra) => Some(extra.4.0),
658    }
659}
660
661#[cfg(feature = "runtime-benchmarks")]
662mod benches {
663    frame_benchmarking::define_benchmarks!(
664        [frame_benchmarking, BaselineBench::<Runtime>]
665        [frame_system, SystemBench::<Runtime>]
666        [pallet_timestamp, Timestamp]
667        [domain_pallet_executive, ExecutivePallet]
668        [pallet_utility, Utility]
669        [pallet_balances, Balances]
670        [pallet_transaction_payment, TransactionPayment]
671        [pallet_auto_id, AutoId]
672        [pallet_messenger, Messenger]
673        [pallet_messenger_from_consensus_extension, MessengerFromConsensusExtensionBench::<Runtime>]
674        [pallet_messenger_between_domains_extension, MessengerBetweenDomainsExtensionBench::<Runtime>]
675        [pallet_transporter, Transporter]
676        // pallet_domain_id has no calls to benchmark
677        // pallet_block_fees only has inherent calls
678        // pallet_domain_sudo only has inherent calls
679    );
680}
681
682fn check_transaction_and_do_pre_dispatch_inner(
683    uxt: &ExtrinsicFor<Block>,
684) -> Result<(), TransactionValidityError> {
685    let lookup = frame_system::ChainContext::<Runtime>::default();
686
687    let xt = uxt.clone().check(&lookup)?;
688
689    let dispatch_info = xt.get_dispatch_info();
690
691    if dispatch_info.class == DispatchClass::Mandatory {
692        return Err(InvalidTransaction::MandatoryValidation.into());
693    }
694
695    let encoded_len = uxt.encoded_size();
696
697    // We invoke `pre_dispatch` in addition to `validate_transaction`(even though the validation is almost same)
698    // as that will add the side effect of SignedExtension in the storage buffer
699    // which would help to maintain context across multiple transaction validity check against same
700    // runtime instance.
701    match xt.format {
702        ExtrinsicFormat::General(extension_version, extra) => {
703            let custom_extra: CustomSignedExtra = (
704                extra.0,
705                extra.1,
706                extra.2,
707                extra.3,
708                extra.4,
709                extra.5,
710                extra.6.clone(),
711                extra.7,
712                pallet_messenger::extensions::MessengerTrustedMmrExtension::<Runtime>::new(),
713            );
714
715            let origin = RuntimeOrigin::none();
716            <CustomSignedExtra as DispatchTransaction<RuntimeCall>>::validate_and_prepare(
717                custom_extra,
718                origin,
719                &xt.function,
720                &dispatch_info,
721                encoded_len,
722                extension_version,
723            )
724            .map(|_| ())
725        }
726        // signed transaction
727        ExtrinsicFormat::Signed(account_id, extra) => {
728            let origin = RuntimeOrigin::signed(account_id);
729            <SignedExtra as DispatchTransaction<RuntimeCall>>::validate_and_prepare(
730                extra,
731                origin,
732                &xt.function,
733                &dispatch_info,
734                encoded_len,
735                // default extension version define here -
736                // https://github.com/paritytech/polkadot-sdk/blob/master/substrate/primitives/runtime/src/generic/checked_extrinsic.rs#L37
737                0,
738            )
739            .map(|_| ())
740        }
741        // unsigned transaction
742        ExtrinsicFormat::Bare => {
743            Runtime::pre_dispatch(&xt.function).map(|_| ())?;
744            <SignedExtra as TransactionExtension<RuntimeCall>>::bare_validate_and_prepare(
745                &xt.function,
746                &dispatch_info,
747                encoded_len,
748            )
749            .map(|_| ())
750        }
751    }
752}
753
754#[cfg(feature = "runtime-benchmarks")]
755impl frame_system_benchmarking::Config for Runtime {}
756
757#[cfg(feature = "runtime-benchmarks")]
758impl frame_benchmarking::baseline::Config for Runtime {}
759
760impl_runtime_apis! {
761    impl sp_api::Core<Block> for Runtime {
762        fn version() -> RuntimeVersion {
763            VERSION
764        }
765
766        fn execute_block(block: Block) {
767            Executive::execute_block(block)
768        }
769
770        fn initialize_block(header: &HeaderFor<Block>) -> ExtrinsicInclusionMode {
771            Executive::initialize_block(header)
772        }
773    }
774
775    impl sp_api::Metadata<Block> for Runtime {
776        fn metadata() -> OpaqueMetadata {
777            OpaqueMetadata::new(Runtime::metadata().into())
778        }
779
780        fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
781            Runtime::metadata_at_version(version)
782        }
783
784        fn metadata_versions() -> Vec<u32> {
785            Runtime::metadata_versions()
786        }
787    }
788
789    impl sp_block_builder::BlockBuilder<Block> for Runtime {
790        fn apply_extrinsic(extrinsic: ExtrinsicFor<Block>) -> ApplyExtrinsicResult {
791            Executive::apply_extrinsic(extrinsic)
792        }
793
794        fn finalize_block() -> HeaderFor<Block> {
795            Executive::finalize_block()
796        }
797
798        fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<ExtrinsicFor<Block>> {
799            data.create_extrinsics()
800        }
801
802        fn check_inherents(
803            block: Block,
804            data: sp_inherents::InherentData,
805        ) -> sp_inherents::CheckInherentsResult {
806            data.check_extrinsics(&block)
807        }
808    }
809
810    impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
811        fn validate_transaction(
812            source: TransactionSource,
813            tx: ExtrinsicFor<Block>,
814            block_hash: BlockHashFor<Block>,
815        ) -> TransactionValidity {
816            Executive::validate_transaction(source, tx, block_hash)
817        }
818    }
819
820    impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
821        fn offchain_worker(header: &HeaderFor<Block>) {
822            Executive::offchain_worker(header)
823        }
824    }
825
826    impl sp_session::SessionKeys<Block> for Runtime {
827        fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
828            SessionKeys::generate(seed)
829        }
830
831        fn decode_session_keys(
832            encoded: Vec<u8>,
833        ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
834            SessionKeys::decode_into_raw_public_keys(&encoded)
835        }
836    }
837
838    impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
839        fn account_nonce(account: AccountId) -> Nonce {
840            *System::account_nonce(account)
841        }
842    }
843
844    impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
845        fn query_info(
846            uxt: ExtrinsicFor<Block>,
847            len: u32,
848        ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
849            TransactionPayment::query_info(uxt, len)
850        }
851        fn query_fee_details(
852            uxt: ExtrinsicFor<Block>,
853            len: u32,
854        ) -> pallet_transaction_payment::FeeDetails<Balance> {
855            TransactionPayment::query_fee_details(uxt, len)
856        }
857        fn query_weight_to_fee(weight: Weight) -> Balance {
858            TransactionPayment::weight_to_fee(weight)
859        }
860        fn query_length_to_fee(length: u32) -> Balance {
861            TransactionPayment::length_to_fee(length)
862        }
863    }
864
865    impl sp_domains::core_api::DomainCoreApi<Block> for Runtime {
866        fn extract_signer(
867            extrinsics: Vec<ExtrinsicFor<Block>>,
868        ) -> Vec<(Option<opaque::AccountId>, ExtrinsicFor<Block>)> {
869            extract_signer(extrinsics)
870        }
871
872        fn is_within_tx_range(
873            extrinsic: &ExtrinsicFor<Block>,
874            bundle_vrf_hash: &subspace_core_primitives::U256,
875            tx_range: &subspace_core_primitives::U256
876        ) -> bool {
877            use subspace_core_primitives::U256;
878            use subspace_core_primitives::hashes::blake3_hash;
879
880            let lookup = frame_system::ChainContext::<Runtime>::default();
881            if let Some(signer) = extract_signer_inner(extrinsic, &lookup).and_then(|account_result| {
882                    account_result.ok().map(|account_id| account_id.encode())
883                }) {
884                // Check if the signer Id hash is within the tx range
885                let signer_id_hash = U256::from_be_bytes(*blake3_hash(&signer.encode()));
886                sp_domains::signer_in_tx_range(bundle_vrf_hash, &signer_id_hash, tx_range)
887            } else {
888                // Unsigned transactions are always in the range.
889                true
890            }
891        }
892
893        fn extract_signer_if_all_within_tx_range(
894            extrinsics: &Vec<ExtrinsicFor<Block>>,
895            bundle_vrf_hash: &subspace_core_primitives::U256,
896            tx_range: &subspace_core_primitives::U256
897        ) -> Result<Vec<Option<opaque::AccountId>> , u32> {
898            use subspace_core_primitives::U256;
899            use subspace_core_primitives::hashes::blake3_hash;
900
901            let mut signers = Vec::with_capacity(extrinsics.len());
902            let lookup = frame_system::ChainContext::<Runtime>::default();
903            for (index, extrinsic) in extrinsics.iter().enumerate() {
904                let maybe_signer = extract_signer_inner(extrinsic, &lookup).and_then(|account_result| {
905                    account_result.ok().map(|account_id| account_id.encode())
906                });
907                if let Some(signer) = &maybe_signer {
908                    // Check if the signer Id hash is within the tx range
909                    let signer_id_hash = U256::from_be_bytes(*blake3_hash(&signer.encode()));
910                    if !sp_domains::signer_in_tx_range(bundle_vrf_hash, &signer_id_hash, tx_range) {
911                        return Err(index as u32)
912                    }
913                }
914                signers.push(maybe_signer);
915            }
916
917            Ok(signers)
918        }
919
920        fn initialize_block_with_post_state_root(header: &HeaderFor<Block>) -> Vec<u8> {
921            Executive::initialize_block(header);
922            Executive::storage_root()
923        }
924
925        fn apply_extrinsic_with_post_state_root(extrinsic: ExtrinsicFor<Block>) -> Vec<u8> {
926            let _ = Executive::apply_extrinsic(extrinsic);
927            Executive::storage_root()
928        }
929
930        fn construct_set_code_extrinsic(code: Vec<u8>) -> Vec<u8> {
931            UncheckedExtrinsic::new_bare(
932                domain_pallet_executive::Call::set_code {
933                    code
934                }.into()
935            ).encode()
936        }
937
938        fn construct_timestamp_extrinsic(moment: Moment) -> ExtrinsicFor<Block> {
939            UncheckedExtrinsic::new_bare(
940                pallet_timestamp::Call::set{ now: moment }.into()
941            )
942        }
943
944        fn is_inherent_extrinsic(extrinsic: &ExtrinsicFor<Block>) -> bool {
945            <Self as IsInherent<_>>::is_inherent(extrinsic)
946        }
947
948        fn find_first_inherent_extrinsic(extrinsics: &Vec<ExtrinsicFor<Block>>) -> Option<u32> {
949            for (index, extrinsic) in extrinsics.iter().enumerate() {
950                if <Self as IsInherent<_>>::is_inherent(extrinsic) {
951                    return Some(index as u32)
952                }
953            }
954            None
955        }
956
957        fn check_extrinsics_and_do_pre_dispatch(uxts: Vec<ExtrinsicFor<Block>>, block_number: BlockNumber,
958            block_hash: BlockHashFor<Block>) -> Result<(), CheckExtrinsicsValidityError> {
959            // Initializing block related storage required for validation
960            System::initialize(
961                &(block_number + BlockNumber::one()),
962                &block_hash,
963                &Default::default(),
964            );
965
966            for (extrinsic_index, uxt) in uxts.iter().enumerate() {
967                check_transaction_and_do_pre_dispatch_inner(uxt).map_err(|e| {
968                    CheckExtrinsicsValidityError {
969                        extrinsic_index: extrinsic_index as u32,
970                        transaction_validity_error: e
971                    }
972                })?;
973            }
974
975            Ok(())
976        }
977
978        fn decode_extrinsic(
979            opaque_extrinsic: sp_runtime::OpaqueExtrinsic,
980        ) -> Result<ExtrinsicFor<Block>, DecodeExtrinsicError> {
981            let encoded = opaque_extrinsic.encode();
982
983            UncheckedExtrinsic::decode_all_with_depth_limit(
984                MAX_CALL_RECURSION_DEPTH,
985                &mut encoded.as_slice(),
986            ).map_err(|err| DecodeExtrinsicError(format!("{err}")))
987        }
988
989        fn decode_extrinsics_prefix(
990            opaque_extrinsics: Vec<sp_runtime::OpaqueExtrinsic>,
991        ) -> Vec<ExtrinsicFor<Block>> {
992            let mut extrinsics = Vec::with_capacity(opaque_extrinsics.len());
993            for opaque_ext in opaque_extrinsics {
994                match UncheckedExtrinsic::decode_all_with_depth_limit(
995                    MAX_CALL_RECURSION_DEPTH,
996                    &mut opaque_ext.encode().as_slice(),
997                ) {
998                    Ok(tx) => extrinsics.push(tx),
999                    Err(_) => return extrinsics,
1000                }
1001            }
1002            extrinsics
1003        }
1004
1005        fn extrinsic_era(
1006          extrinsic: &ExtrinsicFor<Block>
1007        ) -> Option<Era> {
1008            extrinsic_era(extrinsic)
1009        }
1010
1011        fn extrinsic_weight(ext: &ExtrinsicFor<Block>) -> Weight {
1012            let len = ext.encoded_size() as u64;
1013            let info = ext.get_dispatch_info();
1014            info.call_weight.saturating_add(info.extension_weight)
1015                .saturating_add(<Runtime as frame_system::Config>::BlockWeights::get().get(info.class).base_extrinsic)
1016                .saturating_add(Weight::from_parts(0, len))
1017        }
1018
1019        fn extrinsics_weight(extrinsics: &Vec<ExtrinsicFor<Block>>) -> Weight {
1020            let mut total_weight = Weight::zero();
1021            for ext in extrinsics {
1022                let ext_weight = {
1023                    let len = ext.encoded_size() as u64;
1024                    let info = ext.get_dispatch_info();
1025                    info.call_weight.saturating_add(info.extension_weight)
1026                        .saturating_add(<Runtime as frame_system::Config>::BlockWeights::get().get(info.class).base_extrinsic)
1027                        .saturating_add(Weight::from_parts(0, len))
1028                };
1029                total_weight = total_weight.saturating_add(ext_weight);
1030            }
1031            total_weight
1032        }
1033
1034        fn block_fees() -> sp_domains::BlockFees<Balance> {
1035            BlockFees::collected_block_fees()
1036        }
1037
1038        fn block_digest() -> Digest {
1039            System::digest()
1040        }
1041
1042        fn block_weight() -> Weight {
1043            System::block_weight().total()
1044        }
1045
1046        fn construct_consensus_chain_byte_fee_extrinsic(transaction_byte_fee: Balance) -> ExtrinsicFor<Block> {
1047            UncheckedExtrinsic::new_bare(
1048                pallet_block_fees::Call::set_next_consensus_chain_byte_fee { transaction_byte_fee }.into()
1049            )
1050        }
1051
1052        fn construct_domain_update_chain_allowlist_extrinsic(updates: DomainAllowlistUpdates) -> ExtrinsicFor<Block> {
1053             UncheckedExtrinsic::new_bare(
1054                pallet_messenger::Call::update_domain_allowlist{ updates }.into()
1055            )
1056        }
1057
1058        fn transfers() -> Transfers<Balance> {
1059            Transporter::chain_transfers()
1060        }
1061
1062        fn transfers_storage_key() -> Vec<u8> {
1063            Transporter::transfers_storage_key()
1064        }
1065
1066        fn block_fees_storage_key() -> Vec<u8> {
1067            BlockFees::block_fees_storage_key()
1068        }
1069    }
1070
1071    impl sp_messenger::MessengerApi<Block, ConsensusBlockNumber, ConsensusBlockHash> for Runtime {
1072        fn is_xdm_mmr_proof_valid(
1073            extrinsic: &ExtrinsicFor<Block>,
1074        ) -> Option<bool> {
1075            is_xdm_mmr_proof_valid(extrinsic)
1076        }
1077
1078        fn extract_xdm_mmr_proof(ext: &ExtrinsicFor<Block>) -> Option<ConsensusChainMmrLeafProof<ConsensusBlockNumber, ConsensusBlockHash, sp_core::H256>> {
1079            match &ext.function {
1080                RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })
1081                | RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1082                    Some(msg.proof.consensus_mmr_proof())
1083                }
1084                _ => None,
1085            }
1086        }
1087
1088        fn batch_extract_xdm_mmr_proof(extrinsics: &Vec<ExtrinsicFor<Block>>) -> BTreeMap<u32, ConsensusChainMmrLeafProof<ConsensusBlockNumber, ConsensusBlockHash, sp_core::H256>> {
1089            let mut mmr_proofs = BTreeMap::new();
1090            for (index, ext) in extrinsics.iter().enumerate() {
1091                match &ext.function {
1092                    RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })
1093                    | RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1094                        mmr_proofs.insert(index as u32, msg.proof.consensus_mmr_proof());
1095                    }
1096                    _ => {},
1097                }
1098            }
1099            mmr_proofs
1100        }
1101
1102        fn confirmed_domain_block_storage_key(_domain_id: DomainId) -> Vec<u8> {
1103            // invalid call from Domain runtime
1104            vec![]
1105        }
1106
1107        fn outbox_storage_key(message_key: MessageKey) -> Vec<u8> {
1108            Messenger::outbox_storage_key(message_key)
1109        }
1110
1111        fn inbox_response_storage_key(message_key: MessageKey) -> Vec<u8> {
1112            Messenger::inbox_response_storage_key(message_key)
1113        }
1114
1115        fn domain_chains_allowlist_update(_domain_id: DomainId) -> Option<DomainAllowlistUpdates>{
1116            // not valid call on domains
1117            None
1118        }
1119
1120        fn xdm_id(ext: &ExtrinsicFor<Block>) -> Option<XdmId> {
1121            match &ext.function {
1122                RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })=> {
1123                    Some(XdmId::RelayMessage((msg.src_chain_id, msg.channel_id, msg.nonce)))
1124                }
1125                RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1126                    Some(XdmId::RelayResponseMessage((msg.src_chain_id, msg.channel_id, msg.nonce)))
1127                }
1128                _ => None,
1129            }
1130        }
1131
1132        fn channel_nonce(chain_id: ChainId, channel_id: ChannelId) -> Option<ChannelNonce> {
1133            Messenger::channel_nonce(chain_id, channel_id)
1134        }
1135    }
1136
1137    impl sp_messenger::RelayerApi<Block, BlockNumber, ConsensusBlockNumber, ConsensusBlockHash> for Runtime {
1138        fn block_messages() -> BlockMessagesWithStorageKey {
1139            BlockMessagesWithStorageKey::default()
1140        }
1141
1142        fn outbox_message_unsigned(msg: CrossDomainMessage<NumberFor<Block>, BlockHashFor<Block>, BlockHashFor<Block>>) -> Option<ExtrinsicFor<Block>> {
1143            Messenger::outbox_message_unsigned(msg)
1144        }
1145
1146        fn inbox_response_message_unsigned(msg: CrossDomainMessage<NumberFor<Block>, BlockHashFor<Block>, BlockHashFor<Block>>) -> Option<ExtrinsicFor<Block>> {
1147            Messenger::inbox_response_message_unsigned(msg)
1148        }
1149
1150        fn should_relay_outbox_message(_: ChainId, _: MessageId) -> bool {
1151            false
1152        }
1153
1154        fn should_relay_inbox_message_response(_: ChainId, _: MessageId) -> bool {
1155            false
1156        }
1157
1158        fn updated_channels() -> BTreeSet<(ChainId, ChannelId)> {
1159            Messenger::updated_channels()
1160        }
1161
1162        fn channel_storage_key(chain_id: ChainId, channel_id: ChannelId) -> Vec<u8> {
1163            Messenger::channel_storage_key(chain_id, channel_id)
1164        }
1165
1166        fn open_channels() -> BTreeSet<(ChainId, ChannelId)> {
1167            Messenger::open_channels()
1168        }
1169
1170        fn block_messages_with_query(query: BlockMessagesQuery) -> MessagesWithStorageKey {
1171            Messenger::get_block_messages(query)
1172        }
1173
1174        fn channels_and_state() -> Vec<(ChainId, ChannelId, ChannelStateWithNonce)> {
1175            Messenger::channels_and_states()
1176        }
1177
1178        fn first_outbox_message_nonce_to_relay(dst_chain_id: ChainId, channel_id: ChannelId, from_nonce: XdmNonce) -> Option<XdmNonce> {
1179            Messenger::first_outbox_message_nonce_to_relay(dst_chain_id, channel_id, from_nonce)
1180        }
1181
1182        fn first_inbox_message_response_nonce_to_relay(dst_chain_id: ChainId, channel_id: ChannelId, from_nonce: XdmNonce) -> Option<XdmNonce> {
1183            Messenger::first_inbox_message_response_nonce_to_relay(dst_chain_id, channel_id, from_nonce)
1184        }
1185    }
1186
1187    impl sp_domain_sudo::DomainSudoApi<Block> for Runtime {
1188        fn is_valid_sudo_call(extrinsic: Vec<u8>) -> bool {
1189            is_valid_sudo_call(extrinsic)
1190        }
1191
1192        fn construct_domain_sudo_extrinsic(inner: Vec<u8>) -> ExtrinsicFor<Block> {
1193            construct_sudo_call_extrinsic(inner)
1194        }
1195    }
1196
1197    impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
1198        fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
1199            build_state::<RuntimeGenesisConfig>(config)
1200        }
1201
1202        fn get_preset(_id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
1203            // By passing `None` the upstream `get_preset` will return the default value of `RuntimeGenesisConfig`
1204            get_preset::<RuntimeGenesisConfig>(&None, |_| None)
1205        }
1206
1207        fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
1208            vec![]
1209        }
1210    }
1211
1212    #[cfg(feature = "runtime-benchmarks")]
1213    impl frame_benchmarking::Benchmark<Block> for Runtime {
1214        fn benchmark_metadata(extra: bool) -> (
1215            Vec<frame_benchmarking::BenchmarkList>,
1216            Vec<frame_support::traits::StorageInfo>,
1217        ) {
1218            use frame_benchmarking::{baseline, Benchmarking, BenchmarkList};
1219            use frame_support::traits::StorageInfoTrait;
1220            use frame_system_benchmarking::Pallet as SystemBench;
1221            use baseline::Pallet as BaselineBench;
1222            use pallet_messenger::extensions::benchmarking_from_consensus::Pallet as MessengerFromConsensusExtensionBench;
1223            use pallet_messenger::extensions::benchmarking_between_domains::Pallet as MessengerBetweenDomainsExtensionBench;
1224
1225            let mut list = Vec::<BenchmarkList>::new();
1226
1227            list_benchmarks!(list, extra);
1228
1229            let storage_info = AllPalletsWithSystem::storage_info();
1230
1231            (list, storage_info)
1232        }
1233
1234        fn dispatch_benchmark(
1235            config: frame_benchmarking::BenchmarkConfig
1236        ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, alloc::string::String> {
1237            use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch};
1238            use sp_storage::TrackedStorageKey;
1239            use frame_system_benchmarking::Pallet as SystemBench;
1240            use frame_support::traits::WhitelistedStorageKeys;
1241            use baseline::Pallet as BaselineBench;
1242            use pallet_messenger::extensions::benchmarking_from_consensus::Pallet as MessengerFromConsensusExtensionBench;
1243            use pallet_messenger::extensions::benchmarking_between_domains::Pallet as MessengerBetweenDomainsExtensionBench;
1244
1245            let whitelist: Vec<TrackedStorageKey> = AllPalletsWithSystem::whitelisted_storage_keys();
1246
1247            let mut batches = Vec::<BenchmarkBatch>::new();
1248            let params = (&config, &whitelist);
1249
1250            add_benchmarks!(params, batches);
1251
1252            if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
1253            Ok(batches)
1254        }
1255    }
1256}
1257
1258#[cfg(test)]
1259mod tests {
1260    use crate::{Runtime, RuntimeBlockWeights as BlockWeights};
1261    use subspace_runtime_primitives::tests_utils::FeeMultiplierUtils;
1262
1263    #[test]
1264    fn multiplier_can_grow_from_zero() {
1265        FeeMultiplierUtils::<Runtime, BlockWeights>::multiplier_can_grow_from_zero()
1266    }
1267}