subspace_test_runtime/
lib.rs

1// Copyright (C) 2021 Subspace Labs, Inc.
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17#![cfg_attr(not(feature = "std"), no_std)]
18#![feature(variant_count)]
19// `generic_const_exprs` is an incomplete feature
20#![allow(incomplete_features)]
21// TODO: This feature is not actually used in this crate, but is added as a workaround for
22//  https://github.com/rust-lang/rust/issues/133199
23#![feature(generic_const_exprs)]
24// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
25#![recursion_limit = "256"]
26// TODO: remove when upstream issue is fixed
27#![allow(
28    non_camel_case_types,
29    reason = "https://github.com/rust-lang/rust-analyzer/issues/16514"
30)]
31
32extern crate alloc;
33
34// Make the WASM binary available.
35#[cfg(feature = "std")]
36include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
37
38use alloc::borrow::Cow;
39use core::mem;
40use core::num::NonZeroU64;
41use domain_runtime_primitives::opaque::Header as DomainHeader;
42use domain_runtime_primitives::{
43    AccountIdConverter, BlockNumber as DomainNumber, EthereumAccountId, Hash as DomainHash,
44    MAX_OUTGOING_MESSAGES,
45};
46use frame_support::genesis_builder_helper::{build_state, get_preset};
47use frame_support::inherent::ProvideInherent;
48use frame_support::traits::fungible::Inspect;
49use frame_support::traits::tokens::WithdrawConsequence;
50use frame_support::traits::{
51    ConstU8, ConstU16, ConstU32, ConstU64, ConstU128, Currency, Everything, ExistenceRequirement,
52    Get, Imbalance, Time, VariantCount, WithdrawReasons,
53};
54use frame_support::weights::constants::{ParityDbWeight, WEIGHT_REF_TIME_PER_SECOND};
55use frame_support::weights::{ConstantMultiplier, Weight};
56use frame_support::{PalletId, construct_runtime, parameter_types};
57use frame_system::limits::{BlockLength, BlockWeights};
58use frame_system::pallet_prelude::RuntimeCallFor;
59use pallet_balances::NegativeImbalance;
60pub use pallet_rewards::RewardPoint;
61pub use pallet_subspace::{AllowAuthoringBy, EnableRewardsAt};
62use pallet_transporter::EndpointHandler;
63use parity_scale_codec::{Compact, CompactLen, Decode, Encode, MaxEncodedLen};
64use scale_info::TypeInfo;
65use sp_api::impl_runtime_apis;
66use sp_consensus_slots::{Slot, SlotDuration};
67use sp_consensus_subspace::{ChainConstants, PotParameters, SignedVote, SolutionRanges, Vote};
68use sp_core::crypto::KeyTypeId;
69use sp_core::{H256, OpaqueMetadata};
70use sp_domains::bundle_producer_election::BundleProducerElectionParams;
71use sp_domains::{
72    DOMAIN_STORAGE_FEE_MULTIPLIER, DomainAllowlistUpdates, DomainId, DomainInstanceData,
73    ExecutionReceiptFor, INITIAL_DOMAIN_TX_RANGE, OpaqueBundle, OpaqueBundles, OperatorId,
74    OperatorPublicKey, PermissionedActionAllowedBy,
75};
76use sp_domains_fraud_proof::fraud_proof::FraudProof;
77use sp_domains_fraud_proof::storage_proof::{
78    FraudProofStorageKeyProvider, FraudProofStorageKeyRequest,
79};
80use sp_messenger::endpoint::{Endpoint, EndpointHandler as EndpointHandlerT, EndpointId};
81use sp_messenger::messages::{
82    BlockMessagesQuery, BlockMessagesWithStorageKey, ChainId, ChannelId, ChannelStateWithNonce,
83    CrossDomainMessage, MessageId, MessageKey, MessagesWithStorageKey, Nonce as XdmNonce,
84};
85use sp_messenger::{ChannelNonce, XdmId};
86use sp_messenger_host_functions::{StorageKeyRequest, get_storage_key};
87use sp_mmr_primitives::EncodableOpaqueLeaf;
88use sp_runtime::traits::{
89    AccountIdConversion, AccountIdLookup, BlakeTwo256, ConstBool, DispatchInfoOf, Keccak256,
90    NumberFor, PostDispatchInfoOf, Zero,
91};
92use sp_runtime::transaction_validity::{
93    InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
94};
95use sp_runtime::type_with_default::TypeWithDefault;
96use sp_runtime::{AccountId32, ApplyExtrinsicResult, ExtrinsicInclusionMode, Perbill, generic};
97use sp_std::collections::btree_map::BTreeMap;
98use sp_std::collections::btree_set::BTreeSet;
99use sp_std::marker::PhantomData;
100use sp_std::prelude::*;
101use sp_subspace_mmr::ConsensusChainMmrLeafProof;
102use sp_version::RuntimeVersion;
103use static_assertions::const_assert;
104use subspace_core_primitives::objects::{BlockObject, BlockObjectMapping};
105use subspace_core_primitives::pieces::Piece;
106use subspace_core_primitives::segments::{
107    HistorySize, SegmentCommitment, SegmentHeader, SegmentIndex,
108};
109use subspace_core_primitives::solutions::SolutionRange;
110use subspace_core_primitives::{PublicKey, Randomness, SlotNumber, U256, hashes};
111pub use subspace_runtime_primitives::extension::BalanceTransferCheckExtension;
112use subspace_runtime_primitives::extension::{BalanceTransferChecks, MaybeBalancesCall};
113use subspace_runtime_primitives::utility::{
114    DefaultNonceProvider, MaybeMultisigCall, MaybeNestedCall, MaybeUtilityCall,
115};
116use subspace_runtime_primitives::{
117    AI3, AccountId, Balance, BlockHashFor, BlockNumber, ConsensusEventSegmentSize, ExtrinsicFor,
118    FindBlockRewardAddress, Hash, HeaderFor, HoldIdentifier, MAX_BLOCK_LENGTH,
119    MAX_CALL_RECURSION_DEPTH, MIN_REPLICATION_FACTOR, Moment, Nonce, SHANNON, Signature,
120    SlowAdjustingFeeUpdate, TargetBlockFullness, XdmAdjustedWeightToFee, XdmFeeMultipler,
121};
122use subspace_test_primitives::DOMAINS_BLOCK_PRUNING_DEPTH;
123
124sp_runtime::impl_opaque_keys! {
125    pub struct SessionKeys {
126    }
127}
128
129// Smaller value for testing purposes
130const MAX_PIECES_IN_SECTOR: u16 = 32;
131
132// To learn more about runtime versioning and what each of the following value means:
133//   https://substrate.dev/docs/en/knowledgebase/runtime/upgrades#runtime-versioning
134#[sp_version::runtime_version]
135pub const VERSION: RuntimeVersion = RuntimeVersion {
136    spec_name: Cow::Borrowed("subspace"),
137    impl_name: Cow::Borrowed("subspace"),
138    authoring_version: 1,
139    // The version of the runtime specification. A full node will not attempt to use its native
140    //   runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`,
141    //   `spec_version`, and `authoring_version` are the same between Wasm and native.
142    // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
143    //   the compatible custom types.
144    spec_version: 100,
145    impl_version: 1,
146    apis: RUNTIME_API_VERSIONS,
147    transaction_version: 1,
148    system_version: 2,
149};
150
151// TODO: Many of below constants should probably be updatable but currently they are not
152
153/// Expected block time in milliseconds.
154///
155/// Since Subspace is probabilistic this is the average expected block time that
156/// we are targeting. Blocks will be produced at a minimum duration defined
157/// by `SLOT_DURATION`, but some slots will not be allocated to any
158/// farmer and hence no block will be produced. We expect to have this
159/// block time on average following the defined slot duration and the value
160/// of `c` configured for Subspace (where `1 - c` represents the probability of
161/// a slot being empty).
162/// This value is only used indirectly to define the unit constants below
163/// that are expressed in blocks. The rest of the code should use
164/// `SLOT_DURATION` instead (like the Timestamp pallet for calculating the
165/// minimum period).
166///
167/// Based on:
168/// <https://research.web3.foundation/en/latest/polkadot/block-production/Babe.html#-6.-practical-results>
169pub const MILLISECS_PER_BLOCK: u64 = 2000;
170
171// NOTE: Currently it is not possible to change the slot duration after the chain has started.
172//       Attempting to do so will brick block production.
173pub const SLOT_DURATION: u64 = 2000;
174
175/// 1 in 6 slots (on average, not counting collisions) will have a block.
176/// Must match ratio between block and slot duration in constants above.
177const SLOT_PROBABILITY: (u64, u64) = (1, 1);
178/// Number of slots between slot arrival and when corresponding block can be produced.
179const BLOCK_AUTHORING_DELAY: SlotNumber = 2;
180
181/// Interval, in blocks, between blockchain entropy injection into proof of time chain.
182const POT_ENTROPY_INJECTION_INTERVAL: BlockNumber = 5;
183
184/// Interval, in entropy injection intervals, where to take entropy for injection from.
185const POT_ENTROPY_INJECTION_LOOKBACK_DEPTH: u8 = 2;
186
187/// Delay after block, in slots, when entropy injection takes effect.
188const POT_ENTROPY_INJECTION_DELAY: SlotNumber = 4;
189
190// Entropy injection interval must be bigger than injection delay or else we may end up in a
191// situation where we'll need to do more than one injection at the same slot
192const_assert!(POT_ENTROPY_INJECTION_INTERVAL as u64 > POT_ENTROPY_INJECTION_DELAY);
193// Entropy injection delay must be bigger than block authoring delay or else we may include
194// invalid future proofs in parent block, +1 ensures we do not have unnecessary reorgs that will
195// inevitably happen otherwise
196const_assert!(POT_ENTROPY_INJECTION_DELAY > BLOCK_AUTHORING_DELAY + 1);
197
198/// Era duration in blocks.
199const ERA_DURATION_IN_BLOCKS: BlockNumber = 2016;
200
201/// Any solution range is valid in the test environment.
202const INITIAL_SOLUTION_RANGE: SolutionRange = SolutionRange::MAX;
203
204/// A ratio of `Normal` dispatch class within block, for `BlockWeight` and `BlockLength`.
205const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
206
207/// The block weight for 2 seconds of compute
208const BLOCK_WEIGHT_FOR_2_SEC: Weight =
209    Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX);
210
211parameter_types! {
212    pub const Version: RuntimeVersion = VERSION;
213    pub const BlockHashCount: BlockNumber = 250;
214    /// We allow for 2 seconds of compute with a 6 second average block time.
215    pub SubspaceBlockWeights: BlockWeights = BlockWeights::with_sensible_defaults(BLOCK_WEIGHT_FOR_2_SEC, NORMAL_DISPATCH_RATIO);
216    /// We allow for 3.75 MiB for `Normal` extrinsic with 5 MiB maximum block length.
217    pub SubspaceBlockLength: BlockLength = BlockLength::max_with_normal_ratio(MAX_BLOCK_LENGTH, NORMAL_DISPATCH_RATIO);
218}
219
220pub type SS58Prefix = ConstU16<6094>;
221
222// Configure FRAME pallets to include in runtime.
223
224impl frame_system::Config for Runtime {
225    /// The basic call filter to use in dispatchable.
226    ///
227    /// `Everything` is used here as we use the signed extension
228    /// `DisablePallets` as the actual call filter.
229    type BaseCallFilter = Everything;
230    /// Block & extrinsics weights: base values and limits.
231    type BlockWeights = SubspaceBlockWeights;
232    /// The maximum length of a block (in bytes).
233    type BlockLength = SubspaceBlockLength;
234    /// The identifier used to distinguish between accounts.
235    type AccountId = AccountId;
236    /// The aggregated dispatch type that is available for extrinsics.
237    type RuntimeCall = RuntimeCall;
238    /// The aggregated `RuntimeTask` type.
239    type RuntimeTask = RuntimeTask;
240    /// The lookup mechanism to get account ID from whatever is passed in dispatchers.
241    type Lookup = AccountIdLookup<AccountId, ()>;
242    /// The type for storing how many extrinsics an account has signed.
243    type Nonce = TypeWithDefault<Nonce, DefaultNonceProvider<System, Nonce>>;
244    /// The type for hashing blocks and tries.
245    type Hash = Hash;
246    /// The hashing algorithm used.
247    type Hashing = BlakeTwo256;
248    /// The block type.
249    type Block = Block;
250    /// The ubiquitous event type.
251    type RuntimeEvent = RuntimeEvent;
252    /// The ubiquitous origin type.
253    type RuntimeOrigin = RuntimeOrigin;
254    /// Maximum number of block number to block hash mappings to keep (oldest pruned first).
255    type BlockHashCount = BlockHashCount;
256    /// The weight of database operations that the runtime can invoke.
257    type DbWeight = ParityDbWeight;
258    /// Version of the runtime.
259    type Version = Version;
260    /// Converts a module to the index of the module in `construct_runtime!`.
261    ///
262    /// This type is being generated by `construct_runtime!`.
263    type PalletInfo = PalletInfo;
264    /// What to do if a new account is created.
265    type OnNewAccount = ();
266    /// What to do if an account is fully reaped from the system.
267    type OnKilledAccount = ();
268    /// The data to be stored in an account.
269    type AccountData = pallet_balances::AccountData<Balance>;
270    /// Weight information for the extrinsics of this pallet.
271    type SystemWeightInfo = frame_system::weights::SubstrateWeight<Runtime>;
272    /// This is used as an identifier of the chain.
273    type SS58Prefix = SS58Prefix;
274    /// The set code logic, just the default since we're not a parachain.
275    type OnSetCode = ();
276    type SingleBlockMigrations = ();
277    type MultiBlockMigrator = ();
278    type PreInherents = ();
279    type PostInherents = ();
280    type PostTransactions = ();
281    type MaxConsumers = ConstU32<16>;
282    type ExtensionsWeightInfo = frame_system::ExtensionsWeight<Runtime>;
283    type EventSegmentSize = ConsensusEventSegmentSize;
284}
285
286parameter_types! {
287    pub const BlockAuthoringDelay: SlotNumber = BLOCK_AUTHORING_DELAY;
288    pub const PotEntropyInjectionInterval: BlockNumber = POT_ENTROPY_INJECTION_INTERVAL;
289    pub const PotEntropyInjectionLookbackDepth: u8 = POT_ENTROPY_INJECTION_LOOKBACK_DEPTH;
290    pub const PotEntropyInjectionDelay: SlotNumber = POT_ENTROPY_INJECTION_DELAY;
291    pub const EraDuration: BlockNumber = ERA_DURATION_IN_BLOCKS;
292    pub const SlotProbability: (u64, u64) = SLOT_PROBABILITY;
293    pub const ShouldAdjustSolutionRange: bool = false;
294    pub const ExpectedVotesPerBlock: u32 = 9;
295    pub const ConfirmationDepthK: u32 = 5;
296    pub const RecentSegments: HistorySize = HistorySize::new(NonZeroU64::new(5).unwrap());
297    pub const RecentHistoryFraction: (HistorySize, HistorySize) = (
298        HistorySize::new(NonZeroU64::new(1).unwrap()),
299        HistorySize::new(NonZeroU64::new(10).unwrap()),
300    );
301    pub const MinSectorLifetime: HistorySize = HistorySize::new(NonZeroU64::new(4).unwrap());
302    pub const BlockSlotCount: u32 = 6;
303    pub TransactionWeightFee: Balance = 100_000 * SHANNON;
304}
305
306impl pallet_subspace::Config for Runtime {
307    type RuntimeEvent = RuntimeEvent;
308    type SubspaceOrigin = pallet_subspace::EnsureSubspaceOrigin;
309    type BlockAuthoringDelay = BlockAuthoringDelay;
310    type PotEntropyInjectionInterval = PotEntropyInjectionInterval;
311    type PotEntropyInjectionLookbackDepth = PotEntropyInjectionLookbackDepth;
312    type PotEntropyInjectionDelay = PotEntropyInjectionDelay;
313    type EraDuration = EraDuration;
314    type InitialSolutionRange = ConstU64<INITIAL_SOLUTION_RANGE>;
315    type SlotProbability = SlotProbability;
316    type ConfirmationDepthK = ConfirmationDepthK;
317    type RecentSegments = RecentSegments;
318    type RecentHistoryFraction = RecentHistoryFraction;
319    type MinSectorLifetime = MinSectorLifetime;
320    type ExpectedVotesPerBlock = ExpectedVotesPerBlock;
321    type MaxPiecesInSector = ConstU16<{ MAX_PIECES_IN_SECTOR }>;
322    type ShouldAdjustSolutionRange = ShouldAdjustSolutionRange;
323    type EraChangeTrigger = pallet_subspace::NormalEraChange;
324    type WeightInfo = pallet_subspace::weights::SubstrateWeight<Runtime>;
325    type BlockSlotCount = BlockSlotCount;
326    type ExtensionWeightInfo = pallet_subspace::extensions::weights::SubstrateWeight<Runtime>;
327}
328
329impl pallet_timestamp::Config for Runtime {
330    /// A timestamp: milliseconds since the unix epoch.
331    type Moment = Moment;
332    type OnTimestampSet = ();
333    type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
334    type WeightInfo = pallet_timestamp::weights::SubstrateWeight<Runtime>;
335}
336
337#[derive(
338    PartialEq, Eq, Clone, Encode, Decode, TypeInfo, MaxEncodedLen, Ord, PartialOrd, Copy, Debug,
339)]
340pub struct HoldIdentifierWrapper(HoldIdentifier);
341
342impl pallet_domains::HoldIdentifier<Runtime> for HoldIdentifierWrapper {
343    fn staking_staked() -> Self {
344        Self(HoldIdentifier::DomainStaking)
345    }
346
347    fn domain_instantiation_id() -> Self {
348        Self(HoldIdentifier::DomainInstantiation)
349    }
350
351    fn storage_fund_withdrawal() -> Self {
352        Self(HoldIdentifier::DomainStorageFund)
353    }
354}
355
356impl pallet_messenger::HoldIdentifier<Runtime> for HoldIdentifierWrapper {
357    fn messenger_channel() -> Self {
358        Self(HoldIdentifier::MessengerChannel)
359    }
360}
361
362impl VariantCount for HoldIdentifierWrapper {
363    const VARIANT_COUNT: u32 = mem::variant_count::<HoldIdentifier>() as u32;
364}
365
366impl pallet_balances::Config for Runtime {
367    type RuntimeFreezeReason = RuntimeFreezeReason;
368    type MaxLocks = ConstU32<50>;
369    type MaxReserves = ();
370    type ReserveIdentifier = [u8; 8];
371    /// The type for recording an account's balance.
372    type Balance = Balance;
373    /// The ubiquitous event type.
374    type RuntimeEvent = RuntimeEvent;
375    type DustRemoval = ();
376    type ExistentialDeposit = ConstU128<{ 10_000_000_000_000 * SHANNON }>;
377    type AccountStore = System;
378    type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;
379    type FreezeIdentifier = ();
380    type MaxFreezes = ();
381    type RuntimeHoldReason = HoldIdentifierWrapper;
382    type DoneSlashHandler = ();
383}
384
385pub struct CreditSupply;
386
387impl Get<Balance> for CreditSupply {
388    fn get() -> Balance {
389        Balances::total_issuance()
390    }
391}
392
393pub struct TotalSpacePledged;
394
395impl Get<u128> for TotalSpacePledged {
396    fn get() -> u128 {
397        // Operations reordered to avoid data loss, but essentially are:
398        // u64::MAX * SlotProbability / (solution_range / PIECE_SIZE)
399        u128::from(u64::MAX)
400            .saturating_mul(Piece::SIZE as u128)
401            .saturating_mul(u128::from(SlotProbability::get().0))
402            / u128::from(Subspace::solution_ranges().current)
403            / u128::from(SlotProbability::get().1)
404    }
405}
406
407pub struct BlockchainHistorySize;
408
409impl Get<u128> for BlockchainHistorySize {
410    fn get() -> u128 {
411        u128::from(Subspace::archived_history_size())
412    }
413}
414
415impl pallet_transaction_fees::Config for Runtime {
416    type RuntimeEvent = RuntimeEvent;
417    type MinReplicationFactor = ConstU16<MIN_REPLICATION_FACTOR>;
418    type CreditSupply = CreditSupply;
419    type TotalSpacePledged = TotalSpacePledged;
420    type BlockchainHistorySize = BlockchainHistorySize;
421    type Currency = Balances;
422    type FindBlockRewardAddress = Subspace;
423    type DynamicCostOfStorage = ConstBool<false>;
424    type WeightInfo = pallet_transaction_fees::weights::SubstrateWeight<Runtime>;
425}
426
427pub struct TransactionByteFee;
428
429impl Get<Balance> for TransactionByteFee {
430    fn get() -> Balance {
431        TransactionFees::transaction_byte_fee()
432    }
433}
434
435pub struct LiquidityInfo {
436    storage_fee: Balance,
437    imbalance: NegativeImbalance<Runtime>,
438}
439
440/// Implementation of [`pallet_transaction_payment::OnChargeTransaction`] that charges transaction
441/// fees and distributes storage/compute fees and tip separately.
442pub struct OnChargeTransaction;
443
444impl pallet_transaction_payment::OnChargeTransaction<Runtime> for OnChargeTransaction {
445    type LiquidityInfo = Option<LiquidityInfo>;
446    type Balance = Balance;
447
448    fn withdraw_fee(
449        who: &AccountId,
450        call: &RuntimeCall,
451        _info: &DispatchInfoOf<RuntimeCall>,
452        fee: Self::Balance,
453        tip: Self::Balance,
454    ) -> Result<Self::LiquidityInfo, TransactionValidityError> {
455        if fee.is_zero() {
456            return Ok(None);
457        }
458
459        let withdraw_reason = if tip.is_zero() {
460            WithdrawReasons::TRANSACTION_PAYMENT
461        } else {
462            WithdrawReasons::TRANSACTION_PAYMENT | WithdrawReasons::TIP
463        };
464
465        let withdraw_result =
466            Balances::withdraw(who, fee, withdraw_reason, ExistenceRequirement::KeepAlive);
467        let imbalance = withdraw_result.map_err(|_error| InvalidTransaction::Payment)?;
468
469        // Separate storage fee while we have access to the call data structure to calculate it.
470        let storage_fee = TransactionByteFee::get()
471            * Balance::try_from(call.encoded_size())
472                .expect("Size of the call never exceeds balance units; qed");
473
474        Ok(Some(LiquidityInfo {
475            storage_fee,
476            imbalance,
477        }))
478    }
479
480    fn correct_and_deposit_fee(
481        who: &AccountId,
482        _dispatch_info: &DispatchInfoOf<RuntimeCall>,
483        _post_info: &PostDispatchInfoOf<RuntimeCall>,
484        corrected_fee: Self::Balance,
485        tip: Self::Balance,
486        liquidity_info: Self::LiquidityInfo,
487    ) -> Result<(), TransactionValidityError> {
488        if let Some(LiquidityInfo {
489            storage_fee,
490            imbalance,
491        }) = liquidity_info
492        {
493            // Calculate how much refund we should return
494            let refund_amount = imbalance.peek().saturating_sub(corrected_fee);
495            // Refund to the account that paid the fees. If this fails, the account might have
496            // dropped below the existential balance. In that case we don't refund anything.
497            let refund_imbalance = Balances::deposit_into_existing(who, refund_amount)
498                .unwrap_or_else(|_| <Balances as Currency<AccountId>>::PositiveImbalance::zero());
499            // Merge the imbalance caused by paying the fees and refunding parts of it again.
500            let adjusted_paid = imbalance
501                .offset(refund_imbalance)
502                .same()
503                .map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?;
504
505            // Split the tip from the total fee that ended up being paid.
506            let (tip, fee) = adjusted_paid.split(tip);
507            // Split paid storage and compute fees so that they can be distributed separately.
508            let (paid_storage_fee, paid_compute_fee) = fee.split(storage_fee);
509
510            TransactionFees::note_transaction_fees(
511                paid_storage_fee.peek(),
512                paid_compute_fee.peek(),
513                tip.peek(),
514            );
515        }
516        Ok(())
517    }
518
519    fn can_withdraw_fee(
520        who: &AccountId,
521        _call: &RuntimeCall,
522        _dispatch_info: &DispatchInfoOf<RuntimeCall>,
523        fee: Self::Balance,
524        _tip: Self::Balance,
525    ) -> Result<(), TransactionValidityError> {
526        if fee.is_zero() {
527            return Ok(());
528        }
529
530        match Balances::can_withdraw(who, fee) {
531            WithdrawConsequence::Success => Ok(()),
532            _ => Err(InvalidTransaction::Payment.into()),
533        }
534    }
535}
536
537impl pallet_transaction_payment::Config for Runtime {
538    type RuntimeEvent = RuntimeEvent;
539    type OnChargeTransaction = OnChargeTransaction;
540    type OperationalFeeMultiplier = ConstU8<5>;
541    type WeightToFee = ConstantMultiplier<Balance, TransactionWeightFee>;
542    type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
543    type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Runtime, TargetBlockFullness>;
544    type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight<Runtime>;
545}
546
547impl pallet_utility::Config for Runtime {
548    type RuntimeEvent = RuntimeEvent;
549    type RuntimeCall = RuntimeCall;
550    type PalletsOrigin = OriginCaller;
551    type WeightInfo = pallet_utility::weights::SubstrateWeight<Runtime>;
552}
553
554impl MaybeBalancesCall<Runtime> for RuntimeCall {
555    fn maybe_balance_call(&self) -> Option<&pallet_balances::Call<Runtime>> {
556        match self {
557            RuntimeCall::Balances(call) => Some(call),
558            _ => None,
559        }
560    }
561}
562
563impl BalanceTransferChecks for Runtime {
564    fn is_balance_transferable() -> bool {
565        RuntimeConfigs::enable_balance_transfers()
566    }
567}
568
569impl MaybeMultisigCall<Runtime> for RuntimeCall {
570    /// If this call is a `pallet_multisig::Call<Runtime>` call, returns the inner call.
571    fn maybe_multisig_call(&self) -> Option<&pallet_multisig::Call<Runtime>> {
572        match self {
573            RuntimeCall::Multisig(call) => Some(call),
574            _ => None,
575        }
576    }
577}
578
579impl MaybeUtilityCall<Runtime> for RuntimeCall {
580    /// If this call is a `pallet_utility::Call<Runtime>` call, returns the inner call.
581    fn maybe_utility_call(&self) -> Option<&pallet_utility::Call<Runtime>> {
582        match self {
583            RuntimeCall::Utility(call) => Some(call),
584            _ => None,
585        }
586    }
587}
588
589impl MaybeNestedCall<Runtime> for RuntimeCall {
590    /// If this call is a nested runtime call, returns the inner call(s).
591    ///
592    /// Ignored calls (such as `pallet_utility::Call::__Ignore`) should be yielded themsevles, but
593    /// their contents should not be yielded.
594    fn maybe_nested_call(&self) -> Option<Vec<&RuntimeCallFor<Runtime>>> {
595        // We currently ignore privileged calls, because privileged users can already change
596        // runtime code. This includes sudo, collective, and scheduler nested `RuntimeCall`s,
597        // and democracy nested `BoundedCall`s.
598
599        // It is ok to return early, because each call can only belong to one pallet.
600        let calls = self.maybe_nested_utility_calls();
601        if calls.is_some() {
602            return calls;
603        }
604
605        let calls = self.maybe_nested_multisig_calls();
606        if calls.is_some() {
607            return calls;
608        }
609
610        None
611    }
612}
613
614impl pallet_sudo::Config for Runtime {
615    type RuntimeEvent = RuntimeEvent;
616    type RuntimeCall = RuntimeCall;
617    type WeightInfo = pallet_sudo::weights::SubstrateWeight<Runtime>;
618}
619
620parameter_types! {
621    pub SelfChainId: ChainId = ChainId::Consensus;
622}
623
624pub struct MmrProofVerifier;
625
626impl sp_subspace_mmr::MmrProofVerifier<mmr::Hash, NumberFor<Block>, Hash> for MmrProofVerifier {
627    fn verify_proof_and_extract_leaf(
628        mmr_leaf_proof: ConsensusChainMmrLeafProof<NumberFor<Block>, Hash, mmr::Hash>,
629    ) -> Option<mmr::Leaf> {
630        let mmr_root = SubspaceMmr::mmr_root_hash(mmr_leaf_proof.consensus_block_number)?;
631        Self::verify_proof_stateless(mmr_root, mmr_leaf_proof)
632    }
633
634    fn verify_proof_stateless(
635        mmr_root: mmr::Hash,
636        mmr_leaf_proof: ConsensusChainMmrLeafProof<NumberFor<Block>, Hash, mmr::Hash>,
637    ) -> Option<mmr::Leaf> {
638        let ConsensusChainMmrLeafProof {
639            opaque_mmr_leaf,
640            proof,
641            ..
642        } = mmr_leaf_proof;
643
644        pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(
645            mmr_root,
646            vec![mmr::DataOrHash::Data(
647                EncodableOpaqueLeaf(opaque_mmr_leaf.0.clone()).into_opaque_leaf(),
648            )],
649            proof,
650        )
651        .ok()?;
652
653        let leaf: mmr::Leaf = opaque_mmr_leaf.into_opaque_leaf().try_decode()?;
654
655        Some(leaf)
656    }
657}
658
659pub struct StorageKeys;
660
661impl sp_messenger::StorageKeys for StorageKeys {
662    fn confirmed_domain_block_storage_key(domain_id: DomainId) -> Option<Vec<u8>> {
663        Some(Domains::confirmed_domain_block_storage_key(domain_id))
664    }
665
666    fn outbox_storage_key(chain_id: ChainId, message_key: MessageKey) -> Option<Vec<u8>> {
667        get_storage_key(StorageKeyRequest::OutboxStorageKey {
668            chain_id,
669            message_key,
670        })
671    }
672
673    fn inbox_responses_storage_key(chain_id: ChainId, message_key: MessageKey) -> Option<Vec<u8>> {
674        get_storage_key(StorageKeyRequest::InboxResponseStorageKey {
675            chain_id,
676            message_key,
677        })
678    }
679}
680
681pub struct DomainRegistration;
682impl sp_messenger::DomainRegistration for DomainRegistration {
683    fn is_domain_registered(domain_id: DomainId) -> bool {
684        Domains::is_domain_registered(domain_id)
685    }
686}
687
688parameter_types! {
689    pub const ChannelReserveFee: Balance = AI3;
690    pub const ChannelInitReservePortion: Perbill = Perbill::from_percent(20);
691    pub const MaxOutgoingMessages: u32 = MAX_OUTGOING_MESSAGES;
692}
693
694// ensure the max outgoing messages is not 0.
695const_assert!(MaxOutgoingMessages::get() >= 1);
696
697pub struct OnXDMRewards;
698
699impl sp_messenger::OnXDMRewards<Balance> for OnXDMRewards {
700    fn on_xdm_rewards(reward: Balance) {
701        if let Some(block_author) = Subspace::find_block_reward_address() {
702            let _ = Balances::deposit_creating(&block_author, reward);
703        }
704    }
705
706    fn on_chain_protocol_fees(chain_id: ChainId, fees: Balance) {
707        // on consensus chain, reward the domain operators
708        // balance is already on this consensus runtime
709        if let ChainId::Domain(domain_id) = chain_id {
710            Domains::reward_domain_operators(domain_id, fees)
711        }
712    }
713}
714
715impl pallet_messenger::Config for Runtime {
716    type RuntimeEvent = RuntimeEvent;
717    type SelfChainId = SelfChainId;
718
719    fn get_endpoint_handler(endpoint: &Endpoint) -> Option<Box<dyn EndpointHandlerT<MessageId>>> {
720        if endpoint == &Endpoint::Id(TransporterEndpointId::get()) {
721            Some(Box::new(EndpointHandler(PhantomData::<Runtime>)))
722        } else {
723            None
724        }
725    }
726
727    type Currency = Balances;
728    type WeightInfo = pallet_messenger::weights::SubstrateWeight<Runtime>;
729    type WeightToFee = ConstantMultiplier<Balance, TransactionWeightFee>;
730    type AdjustedWeightToFee = XdmAdjustedWeightToFee<Runtime>;
731    type FeeMultiplier = XdmFeeMultipler;
732    type OnXDMRewards = OnXDMRewards;
733    type MmrHash = mmr::Hash;
734    type MmrProofVerifier = MmrProofVerifier;
735    type StorageKeys = StorageKeys;
736    type DomainOwner = Domains;
737    type HoldIdentifier = HoldIdentifierWrapper;
738    type ChannelReserveFee = ChannelReserveFee;
739    type ChannelInitReservePortion = ChannelInitReservePortion;
740    type DomainRegistration = DomainRegistration;
741    type MaxOutgoingMessages = MaxOutgoingMessages;
742    type MessengerOrigin = pallet_messenger::EnsureMessengerOrigin;
743    type NoteChainTransfer = Transporter;
744    type ExtensionWeightInfo = pallet_messenger::extensions::weights::SubstrateWeight<Runtime>;
745}
746
747impl<C> frame_system::offchain::CreateTransactionBase<C> for Runtime
748where
749    RuntimeCall: From<C>,
750{
751    type Extrinsic = UncheckedExtrinsic;
752    type RuntimeCall = RuntimeCall;
753}
754
755impl<C> subspace_runtime_primitives::CreateUnsigned<C> for Runtime
756where
757    RuntimeCall: From<C>,
758{
759    fn create_unsigned(call: Self::RuntimeCall) -> Self::Extrinsic {
760        create_unsigned_general_extrinsic(call)
761    }
762}
763
764parameter_types! {
765    pub const TransporterEndpointId: EndpointId = 1;
766    pub const MinimumTransfer: Balance = 1;
767}
768
769impl pallet_transporter::Config for Runtime {
770    type RuntimeEvent = RuntimeEvent;
771    type SelfChainId = SelfChainId;
772    type SelfEndpointId = TransporterEndpointId;
773    type Currency = Balances;
774    type Sender = Messenger;
775    type AccountIdConverter = AccountIdConverter;
776    type WeightInfo = pallet_transporter::weights::SubstrateWeight<Runtime>;
777    type SkipBalanceTransferChecks = ();
778    type MinimumTransfer = MinimumTransfer;
779}
780
781parameter_types! {
782    pub const MaximumReceiptDrift: BlockNumber = 2;
783    pub const InitialDomainTxRange: u64 = INITIAL_DOMAIN_TX_RANGE;
784    pub const DomainTxRangeAdjustmentInterval: u64 = 100;
785    pub const MinOperatorStake: Balance = 100 * AI3;
786    pub const MinNominatorStake: Balance = AI3;
787    /// Use the consensus chain's `Normal` extrinsics block size limit as the domain block size limit
788    pub MaxDomainBlockSize: u32 = NORMAL_DISPATCH_RATIO * MAX_BLOCK_LENGTH;
789    /// Use the consensus chain's `Normal` extrinsics block weight limit as the domain block weight limit
790    pub MaxDomainBlockWeight: Weight = NORMAL_DISPATCH_RATIO * BLOCK_WEIGHT_FOR_2_SEC;
791    pub const DomainInstantiationDeposit: Balance = 100 * AI3;
792    pub const MaxDomainNameLength: u32 = 32;
793    pub const BlockTreePruningDepth: u32 = DOMAINS_BLOCK_PRUNING_DEPTH;
794    pub const StakeWithdrawalLockingPeriod: BlockNumber = 20;
795    pub const StakeEpochDuration: DomainNumber = 5;
796    pub TreasuryAccount: AccountId = PalletId(*b"treasury").into_account_truncating();
797    pub const MaxPendingStakingOperation: u32 = 512;
798    pub const DomainsPalletId: PalletId = PalletId(*b"domains_");
799    pub const MaxInitialDomainAccounts: u32 = 20;
800    pub const MinInitialDomainAccountBalance: Balance = AI3;
801    pub const BundleLongevity: u32 = 5;
802    pub const WithdrawalLimit: u32 = 32;
803}
804
805// `BlockSlotCount` must at least keep the slot for the current and the parent block, it also need to
806// keep enough block slot for bundle validation
807const_assert!(BlockSlotCount::get() >= 2 && BlockSlotCount::get() > BundleLongevity::get());
808
809// `BlockHashCount` must greater than `BlockSlotCount` because we need to use the block number found
810// with `BlockSlotCount` to get the block hash.
811const_assert!(BlockHashCount::get() > BlockSlotCount::get());
812
813// Minimum operator stake must be >= minimum nominator stake since operator is also a nominator.
814const_assert!(MinOperatorStake::get() >= MinNominatorStake::get());
815
816pub struct BlockSlot;
817
818impl pallet_domains::BlockSlot<Runtime> for BlockSlot {
819    fn future_slot(block_number: BlockNumber) -> Option<Slot> {
820        let block_slots = Subspace::block_slots();
821        block_slots
822            .get(&block_number)
823            .map(|slot| *slot + Slot::from(BlockAuthoringDelay::get()))
824    }
825
826    fn slot_produced_after(to_check: Slot) -> Option<BlockNumber> {
827        let block_slots = Subspace::block_slots();
828        for (block_number, slot) in block_slots.into_iter().rev() {
829            if to_check > slot {
830                return Some(block_number);
831            }
832        }
833        None
834    }
835}
836
837pub struct OnChainRewards;
838
839impl sp_domains::OnChainRewards<Balance> for OnChainRewards {
840    fn on_chain_rewards(chain_id: ChainId, reward: Balance) {
841        match chain_id {
842            ChainId::Consensus => {
843                if let Some(block_author) = Subspace::find_block_reward_address() {
844                    let _ = Balances::deposit_creating(&block_author, reward);
845                }
846            }
847            ChainId::Domain(domain_id) => Domains::reward_domain_operators(domain_id, reward),
848        }
849    }
850}
851
852impl pallet_domains::Config for Runtime {
853    type RuntimeEvent = RuntimeEvent;
854    type DomainOrigin = pallet_domains::EnsureDomainOrigin;
855    type DomainHash = DomainHash;
856    type Balance = Balance;
857    type DomainHeader = DomainHeader;
858    type ConfirmationDepthK = ConfirmationDepthK;
859    type Currency = Balances;
860    type Share = Balance;
861    type HoldIdentifier = HoldIdentifierWrapper;
862    type BlockTreePruningDepth = BlockTreePruningDepth;
863    type ConsensusSlotProbability = SlotProbability;
864    type MaxDomainBlockSize = MaxDomainBlockSize;
865    type MaxDomainBlockWeight = MaxDomainBlockWeight;
866    type MaxDomainNameLength = MaxDomainNameLength;
867    type DomainInstantiationDeposit = DomainInstantiationDeposit;
868    type WeightInfo = pallet_domains::weights::SubstrateWeight<Runtime>;
869    type InitialDomainTxRange = InitialDomainTxRange;
870    type DomainTxRangeAdjustmentInterval = DomainTxRangeAdjustmentInterval;
871    type MinOperatorStake = MinOperatorStake;
872    type MinNominatorStake = MinNominatorStake;
873    type StakeWithdrawalLockingPeriod = StakeWithdrawalLockingPeriod;
874    type StakeEpochDuration = StakeEpochDuration;
875    type TreasuryAccount = TreasuryAccount;
876    type MaxPendingStakingOperation = MaxPendingStakingOperation;
877    type Randomness = Subspace;
878    type PalletId = DomainsPalletId;
879    type StorageFee = TransactionFees;
880    type BlockTimestamp = pallet_timestamp::Pallet<Runtime>;
881    type BlockSlot = BlockSlot;
882    type DomainsTransfersTracker = Transporter;
883    type MaxInitialDomainAccounts = MaxInitialDomainAccounts;
884    type MinInitialDomainAccountBalance = MinInitialDomainAccountBalance;
885    type BundleLongevity = BundleLongevity;
886    type DomainBundleSubmitted = Messenger;
887    type OnDomainInstantiated = Messenger;
888    type MmrHash = mmr::Hash;
889    type MmrProofVerifier = MmrProofVerifier;
890    type FraudProofStorageKeyProvider = StorageKeyProvider;
891    type OnChainRewards = OnChainRewards;
892    type WithdrawalLimit = WithdrawalLimit;
893}
894
895parameter_types! {
896    pub const AvgBlockspaceUsageNumBlocks: BlockNumber = 100;
897    pub const ProposerTaxOnVotes: (u32, u32) = (1, 10);
898}
899
900impl pallet_rewards::Config for Runtime {
901    type RuntimeEvent = RuntimeEvent;
902    type Currency = Balances;
903    type AvgBlockspaceUsageNumBlocks = AvgBlockspaceUsageNumBlocks;
904    type TransactionByteFee = TransactionByteFee;
905    type MaxRewardPoints = ConstU32<20>;
906    type ProposerTaxOnVotes = ProposerTaxOnVotes;
907    type RewardsEnabled = Subspace;
908    type FindBlockRewardAddress = Subspace;
909    type FindVotingRewardAddresses = Subspace;
910    type WeightInfo = pallet_rewards::weights::SubstrateWeight<Runtime>;
911    type OnReward = ();
912}
913
914pub mod mmr {
915    use super::Runtime;
916    pub use pallet_mmr::primitives::*;
917
918    pub type Leaf = <<Runtime as pallet_mmr::Config>::LeafData as LeafDataProvider>::LeafData;
919    pub type Hashing = <Runtime as pallet_mmr::Config>::Hashing;
920    pub type Hash = <Hashing as sp_runtime::traits::Hash>::Output;
921}
922
923pub struct BlockHashProvider;
924
925impl pallet_mmr::BlockHashProvider<BlockNumber, Hash> for BlockHashProvider {
926    fn block_hash(block_number: BlockNumber) -> Hash {
927        sp_subspace_mmr::subspace_mmr_runtime_interface::consensus_block_hash(block_number)
928            .expect("Hash must exist for a given block number.")
929    }
930}
931
932impl pallet_mmr::Config for Runtime {
933    const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX;
934    type Hashing = Keccak256;
935    type LeafData = SubspaceMmr;
936    type OnNewRoot = SubspaceMmr;
937    type BlockHashProvider = BlockHashProvider;
938    type WeightInfo = ();
939    #[cfg(feature = "runtime-benchmarks")]
940    type BenchmarkHelper = ();
941}
942
943parameter_types! {
944    pub const MmrRootHashCount: u32 = 15;
945}
946
947impl pallet_subspace_mmr::Config for Runtime {
948    type MmrRootHash = mmr::Hash;
949    type MmrRootHashCount = MmrRootHashCount;
950}
951
952impl pallet_runtime_configs::Config for Runtime {
953    type WeightInfo = pallet_runtime_configs::weights::SubstrateWeight<Runtime>;
954}
955
956impl pallet_domains::extensions::DomainsCheck for Runtime {
957    fn is_domains_enabled() -> bool {
958        RuntimeConfigs::enable_domains()
959    }
960}
961
962parameter_types! {
963    pub const MaxSignatories: u32 = 100;
964}
965
966macro_rules! deposit {
967    ($name:ident, $item_fee:expr, $items:expr, $bytes:expr) => {
968        pub struct $name;
969
970        impl Get<Balance> for $name {
971            fn get() -> Balance {
972                $item_fee.saturating_mul($items.into()).saturating_add(
973                    TransactionFees::transaction_byte_fee().saturating_mul($bytes.into()),
974                )
975            }
976        }
977    };
978}
979
980// One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes.
981// Each multisig costs 20 AI3 + bytes_of_storge * TransactionByteFee
982deposit!(DepositBaseFee, 20 * AI3, 1u32, 88u32);
983
984// Additional storage item size of 32 bytes.
985deposit!(DepositFactor, 0u128, 0u32, 32u32);
986
987impl pallet_multisig::Config for Runtime {
988    type RuntimeEvent = RuntimeEvent;
989    type RuntimeCall = RuntimeCall;
990    type Currency = Balances;
991    type DepositBase = DepositBaseFee;
992    type DepositFactor = DepositFactor;
993    type MaxSignatories = MaxSignatories;
994    type WeightInfo = pallet_multisig::weights::SubstrateWeight<Runtime>;
995}
996
997construct_runtime!(
998    pub struct Runtime {
999        System: frame_system = 0,
1000        Timestamp: pallet_timestamp = 1,
1001
1002        Subspace: pallet_subspace = 2,
1003        Rewards: pallet_rewards = 9,
1004
1005        Balances: pallet_balances = 4,
1006        TransactionFees: pallet_transaction_fees = 12,
1007        TransactionPayment: pallet_transaction_payment = 5,
1008        Utility: pallet_utility = 8,
1009
1010        Domains: pallet_domains = 11,
1011        RuntimeConfigs: pallet_runtime_configs = 14,
1012
1013        Mmr: pallet_mmr = 30,
1014        SubspaceMmr: pallet_subspace_mmr = 31,
1015
1016        // messenger stuff
1017        // Note: Indexes should match with indexes on other chains and domains
1018        Messenger: pallet_messenger exclude_parts { Inherent } = 60,
1019        Transporter: pallet_transporter = 61,
1020
1021        // Multisig
1022        Multisig: pallet_multisig = 90,
1023
1024        // Reserve some room for other pallets as we'll remove sudo pallet eventually.
1025        Sudo: pallet_sudo = 100,
1026    }
1027);
1028
1029/// The address format for describing accounts.
1030pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
1031/// Block header type as expected by this runtime.
1032pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
1033/// Block type as expected by this runtime.
1034pub type Block = generic::Block<Header, UncheckedExtrinsic>;
1035/// The SignedExtension to the basic transaction logic.
1036pub type SignedExtra = (
1037    frame_system::CheckNonZeroSender<Runtime>,
1038    frame_system::CheckSpecVersion<Runtime>,
1039    frame_system::CheckTxVersion<Runtime>,
1040    frame_system::CheckGenesis<Runtime>,
1041    frame_system::CheckMortality<Runtime>,
1042    frame_system::CheckNonce<Runtime>,
1043    frame_system::CheckWeight<Runtime>,
1044    pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
1045    BalanceTransferCheckExtension<Runtime>,
1046    pallet_subspace::extensions::SubspaceExtension<Runtime>,
1047    pallet_domains::extensions::DomainsExtension<Runtime>,
1048    pallet_messenger::extensions::MessengerExtension<Runtime>,
1049);
1050/// Unchecked extrinsic type as expected by this runtime.
1051pub type UncheckedExtrinsic =
1052    generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
1053/// Executive: handles dispatch to the various modules.
1054pub type Executive = frame_executive::Executive<
1055    Runtime,
1056    Block,
1057    frame_system::ChainContext<Runtime>,
1058    Runtime,
1059    AllPalletsWithSystem,
1060>;
1061/// The payload being signed in transactions.
1062pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
1063
1064impl pallet_subspace::extensions::MaybeSubspaceCall<Runtime> for RuntimeCall {
1065    fn maybe_subspace_call(&self) -> Option<&pallet_subspace::Call<Runtime>> {
1066        match self {
1067            RuntimeCall::Subspace(call) => Some(call),
1068            _ => None,
1069        }
1070    }
1071}
1072
1073impl pallet_domains::extensions::MaybeDomainsCall<Runtime> for RuntimeCall {
1074    fn maybe_domains_call(&self) -> Option<&pallet_domains::Call<Runtime>> {
1075        match self {
1076            RuntimeCall::Domains(call) => Some(call),
1077            _ => None,
1078        }
1079    }
1080}
1081
1082impl pallet_messenger::extensions::MaybeMessengerCall<Runtime> for RuntimeCall {
1083    fn maybe_messenger_call(&self) -> Option<&pallet_messenger::Call<Runtime>> {
1084        match self {
1085            RuntimeCall::Messenger(call) => Some(call),
1086            _ => None,
1087        }
1088    }
1089}
1090
1091fn extract_segment_headers(ext: &UncheckedExtrinsic) -> Option<Vec<SegmentHeader>> {
1092    match &ext.function {
1093        RuntimeCall::Subspace(pallet_subspace::Call::store_segment_headers { segment_headers }) => {
1094            Some(segment_headers.clone())
1095        }
1096        _ => None,
1097    }
1098}
1099
1100fn is_xdm_mmr_proof_valid(ext: &ExtrinsicFor<Block>) -> Option<bool> {
1101    match &ext.function {
1102        RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })
1103        | RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1104            let ConsensusChainMmrLeafProof {
1105                consensus_block_number,
1106                opaque_mmr_leaf,
1107                proof,
1108                ..
1109            } = msg.proof.consensus_mmr_proof();
1110
1111            let mmr_root = SubspaceMmr::mmr_root_hash(consensus_block_number)?;
1112
1113            Some(
1114                pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(
1115                    mmr_root,
1116                    vec![mmr::DataOrHash::Data(
1117                        EncodableOpaqueLeaf(opaque_mmr_leaf.0.clone()).into_opaque_leaf(),
1118                    )],
1119                    proof,
1120                )
1121                .is_ok(),
1122            )
1123        }
1124        _ => None,
1125    }
1126}
1127
1128// This code must be kept in sync with `crates/subspace-runtime/src/object_mapping.rs`.
1129fn extract_utility_block_object_mapping(
1130    mut base_offset: u32,
1131    objects: &mut Vec<BlockObject>,
1132    call: &pallet_utility::Call<Runtime>,
1133    mut recursion_depth_left: u16,
1134) {
1135    if recursion_depth_left == 0 {
1136        return;
1137    }
1138
1139    recursion_depth_left -= 1;
1140
1141    // Add enum variant to the base offset.
1142    base_offset += 1;
1143
1144    match call {
1145        pallet_utility::Call::batch { calls }
1146        | pallet_utility::Call::batch_all { calls }
1147        | pallet_utility::Call::force_batch { calls } => {
1148            base_offset += Compact::compact_len(&(calls.len() as u32)) as u32;
1149
1150            for call in calls {
1151                extract_call_block_object_mapping(base_offset, objects, call, recursion_depth_left);
1152
1153                base_offset += call.encoded_size() as u32;
1154            }
1155        }
1156        pallet_utility::Call::as_derivative { index, call } => {
1157            base_offset += index.encoded_size() as u32;
1158
1159            extract_call_block_object_mapping(
1160                base_offset,
1161                objects,
1162                call.as_ref(),
1163                recursion_depth_left,
1164            );
1165        }
1166        pallet_utility::Call::dispatch_as { as_origin, call } => {
1167            base_offset += as_origin.encoded_size() as u32;
1168
1169            extract_call_block_object_mapping(
1170                base_offset,
1171                objects,
1172                call.as_ref(),
1173                recursion_depth_left,
1174            );
1175        }
1176        pallet_utility::Call::with_weight { call, .. } => {
1177            extract_call_block_object_mapping(
1178                base_offset,
1179                objects,
1180                call.as_ref(),
1181                recursion_depth_left,
1182            );
1183        }
1184        pallet_utility::Call::__Ignore(_, _) => {
1185            // Ignore.
1186        }
1187    }
1188}
1189
1190fn extract_call_block_object_mapping(
1191    mut base_offset: u32,
1192    objects: &mut Vec<BlockObject>,
1193    call: &RuntimeCall,
1194    recursion_depth_left: u16,
1195) {
1196    // Add RuntimeCall enum variant to the base offset.
1197    base_offset += 1;
1198
1199    match call {
1200        // Extract the actual object mappings.
1201        RuntimeCall::System(frame_system::Call::remark { remark }) => {
1202            objects.push(BlockObject {
1203                hash: hashes::blake3_hash(remark),
1204                // Add frame_system::Call enum variant to the base offset.
1205                offset: base_offset + 1,
1206            });
1207        }
1208        RuntimeCall::System(frame_system::Call::remark_with_event { remark }) => {
1209            objects.push(BlockObject {
1210                hash: hashes::blake3_hash(remark),
1211                // Add frame_system::Call enum variant to the base offset.
1212                offset: base_offset + 1,
1213            });
1214        }
1215
1216        // Recursively extract object mappings for the call.
1217        RuntimeCall::Utility(call) => {
1218            extract_utility_block_object_mapping(base_offset, objects, call, recursion_depth_left)
1219        }
1220        // Other calls don't contain object mappings.
1221        _ => {}
1222    }
1223}
1224
1225fn extract_block_object_mapping(block: Block) -> BlockObjectMapping {
1226    let mut block_object_mapping = BlockObjectMapping::default();
1227    let mut base_offset =
1228        block.header.encoded_size() + Compact::compact_len(&(block.extrinsics.len() as u32));
1229    for extrinsic in block.extrinsics {
1230        let preamble_size = extrinsic.preamble.encoded_size();
1231        // Extrinsic starts with vector length followed by preamble and
1232        // `function` encoding.
1233        let base_extrinsic_offset = base_offset
1234            + Compact::compact_len(&((preamble_size + extrinsic.function.encoded_size()) as u32))
1235            + preamble_size;
1236
1237        extract_call_block_object_mapping(
1238            base_extrinsic_offset as u32,
1239            block_object_mapping.objects_mut(),
1240            &extrinsic.function,
1241            MAX_CALL_RECURSION_DEPTH as u16,
1242        );
1243
1244        base_offset += extrinsic.encoded_size();
1245    }
1246
1247    block_object_mapping
1248}
1249
1250fn extract_successful_bundles(
1251    domain_id: DomainId,
1252    extrinsics: Vec<UncheckedExtrinsic>,
1253) -> OpaqueBundles<Block, DomainHeader, Balance> {
1254    let successful_bundles = Domains::successful_bundles(domain_id);
1255    extrinsics
1256        .into_iter()
1257        .filter_map(|uxt| match uxt.function {
1258            RuntimeCall::Domains(pallet_domains::Call::submit_bundle { opaque_bundle })
1259                if opaque_bundle.domain_id() == domain_id
1260                    && successful_bundles.contains(&opaque_bundle.hash()) =>
1261            {
1262                Some(opaque_bundle)
1263            }
1264            _ => None,
1265        })
1266        .collect()
1267}
1268
1269fn create_unsigned_general_extrinsic(call: RuntimeCall) -> UncheckedExtrinsic {
1270    let extra: SignedExtra = (
1271        frame_system::CheckNonZeroSender::<Runtime>::new(),
1272        frame_system::CheckSpecVersion::<Runtime>::new(),
1273        frame_system::CheckTxVersion::<Runtime>::new(),
1274        frame_system::CheckGenesis::<Runtime>::new(),
1275        frame_system::CheckMortality::<Runtime>::from(generic::Era::Immortal),
1276        // for unsigned extrinsic, nonce check will be skipped
1277        // so set a default value
1278        frame_system::CheckNonce::<Runtime>::from(0u32.into()),
1279        frame_system::CheckWeight::<Runtime>::new(),
1280        // for unsigned extrinsic, transaction fee check will be skipped
1281        // so set a default value
1282        pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(0u128),
1283        BalanceTransferCheckExtension::<Runtime>::default(),
1284        pallet_subspace::extensions::SubspaceExtension::<Runtime>::new(),
1285        pallet_domains::extensions::DomainsExtension::<Runtime>::new(),
1286        pallet_messenger::extensions::MessengerExtension::<Runtime>::new(),
1287    );
1288
1289    UncheckedExtrinsic::new_transaction(call, extra)
1290}
1291
1292struct RewardAddress([u8; 32]);
1293
1294impl From<PublicKey> for RewardAddress {
1295    #[inline]
1296    fn from(public_key: PublicKey) -> Self {
1297        Self(*public_key)
1298    }
1299}
1300
1301impl From<RewardAddress> for AccountId32 {
1302    #[inline]
1303    fn from(reward_address: RewardAddress) -> Self {
1304        reward_address.0.into()
1305    }
1306}
1307
1308pub struct StorageKeyProvider;
1309impl FraudProofStorageKeyProvider<NumberFor<Block>> for StorageKeyProvider {
1310    fn storage_key(req: FraudProofStorageKeyRequest<NumberFor<Block>>) -> Vec<u8> {
1311        match req {
1312            FraudProofStorageKeyRequest::InvalidInherentExtrinsicData => {
1313                pallet_domains::BlockInherentExtrinsicData::<Runtime>::hashed_key().to_vec()
1314            }
1315            FraudProofStorageKeyRequest::SuccessfulBundles(domain_id) => {
1316                pallet_domains::SuccessfulBundles::<Runtime>::hashed_key_for(domain_id)
1317            }
1318            FraudProofStorageKeyRequest::DomainAllowlistUpdates(domain_id) => {
1319                Messenger::domain_allow_list_update_storage_key(domain_id)
1320            }
1321            FraudProofStorageKeyRequest::DomainRuntimeUpgrades => {
1322                pallet_domains::DomainRuntimeUpgrades::<Runtime>::hashed_key().to_vec()
1323            }
1324            FraudProofStorageKeyRequest::RuntimeRegistry(runtime_id) => {
1325                pallet_domains::RuntimeRegistry::<Runtime>::hashed_key_for(runtime_id)
1326            }
1327            FraudProofStorageKeyRequest::DomainSudoCall(domain_id) => {
1328                pallet_domains::DomainSudoCalls::<Runtime>::hashed_key_for(domain_id)
1329            }
1330            FraudProofStorageKeyRequest::EvmDomainContractCreationAllowedByCall(domain_id) => {
1331                pallet_domains::EvmDomainContractCreationAllowedByCalls::<Runtime>::hashed_key_for(
1332                    domain_id,
1333                )
1334            }
1335            FraudProofStorageKeyRequest::MmrRoot(block_number) => {
1336                pallet_subspace_mmr::MmrRootHashes::<Runtime>::hashed_key_for(block_number)
1337            }
1338        }
1339    }
1340}
1341
1342impl_runtime_apis! {
1343    impl sp_api::Core<Block> for Runtime {
1344        fn version() -> RuntimeVersion {
1345            VERSION
1346        }
1347
1348        fn execute_block(block: Block) {
1349            Executive::execute_block(block);
1350        }
1351
1352        fn initialize_block(header: &HeaderFor<Block>) -> ExtrinsicInclusionMode {
1353            Executive::initialize_block(header)
1354        }
1355    }
1356
1357    impl sp_api::Metadata<Block> for Runtime {
1358        fn metadata() -> OpaqueMetadata {
1359            OpaqueMetadata::new(Runtime::metadata().into())
1360        }
1361
1362        fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
1363            Runtime::metadata_at_version(version)
1364        }
1365
1366        fn metadata_versions() -> Vec<u32> {
1367            Runtime::metadata_versions()
1368        }
1369    }
1370
1371    impl sp_block_builder::BlockBuilder<Block> for Runtime {
1372        fn apply_extrinsic(extrinsic: ExtrinsicFor<Block>) -> ApplyExtrinsicResult {
1373            Executive::apply_extrinsic(extrinsic)
1374        }
1375
1376        fn finalize_block() -> HeaderFor<Block> {
1377            Executive::finalize_block()
1378        }
1379
1380        fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<ExtrinsicFor<Block>> {
1381            data.create_extrinsics()
1382        }
1383
1384        fn check_inherents(
1385            block: Block,
1386            data: sp_inherents::InherentData,
1387        ) -> sp_inherents::CheckInherentsResult {
1388            data.check_extrinsics(&block)
1389        }
1390    }
1391
1392    impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
1393        fn validate_transaction(
1394            source: TransactionSource,
1395            tx: ExtrinsicFor<Block>,
1396            block_hash: BlockHashFor<Block>,
1397        ) -> TransactionValidity {
1398            Executive::validate_transaction(source, tx, block_hash)
1399        }
1400    }
1401
1402    impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
1403        fn offchain_worker(header: &HeaderFor<Block>) {
1404            Executive::offchain_worker(header)
1405        }
1406    }
1407
1408    impl sp_objects::ObjectsApi<Block> for Runtime {
1409        fn extract_block_object_mapping(block: Block) -> BlockObjectMapping {
1410            extract_block_object_mapping(block)
1411        }
1412    }
1413
1414    impl sp_consensus_subspace::SubspaceApi<Block, PublicKey> for Runtime {
1415        fn pot_parameters() -> PotParameters {
1416            Subspace::pot_parameters()
1417        }
1418
1419        fn solution_ranges() -> SolutionRanges {
1420            Subspace::solution_ranges()
1421        }
1422
1423        fn submit_vote_extrinsic(
1424            signed_vote: SignedVote<NumberFor<Block>, BlockHashFor<Block>, PublicKey>,
1425        ) {
1426            let SignedVote { vote, signature } = signed_vote;
1427            let Vote::V0 {
1428                height,
1429                parent_hash,
1430                slot,
1431                solution,
1432                proof_of_time,
1433                future_proof_of_time,
1434            } = vote;
1435
1436            Subspace::submit_vote(SignedVote {
1437                vote: Vote::V0 {
1438                    height,
1439                    parent_hash,
1440                    slot,
1441                    solution: solution.into_reward_address_format::<RewardAddress, AccountId32>(),
1442                    proof_of_time,
1443                    future_proof_of_time,
1444                },
1445                signature,
1446            })
1447        }
1448
1449        fn history_size() -> HistorySize {
1450            <pallet_subspace::Pallet<Runtime>>::history_size()
1451        }
1452
1453        fn max_pieces_in_sector() -> u16 {
1454            MAX_PIECES_IN_SECTOR
1455        }
1456
1457        fn segment_commitment(segment_index: SegmentIndex) -> Option<SegmentCommitment> {
1458            Subspace::segment_commitment(segment_index)
1459        }
1460
1461        fn extract_segment_headers(ext: &ExtrinsicFor<Block>) -> Option<Vec<SegmentHeader >> {
1462            extract_segment_headers(ext)
1463        }
1464
1465        fn is_inherent(ext: &ExtrinsicFor<Block>) -> bool {
1466            match &ext.function {
1467                RuntimeCall::Subspace(call) => Subspace::is_inherent(call),
1468                RuntimeCall::Timestamp(call) => Timestamp::is_inherent(call),
1469                _ => false,
1470            }
1471        }
1472
1473        fn root_plot_public_key() -> Option<PublicKey> {
1474            Subspace::root_plot_public_key()
1475        }
1476
1477        fn should_adjust_solution_range() -> bool {
1478            Subspace::should_adjust_solution_range()
1479        }
1480
1481        fn chain_constants() -> ChainConstants {
1482            ChainConstants::V0 {
1483                confirmation_depth_k: ConfirmationDepthK::get(),
1484                block_authoring_delay: Slot::from(BlockAuthoringDelay::get()),
1485                era_duration: EraDuration::get(),
1486                slot_probability: SlotProbability::get(),
1487                slot_duration: SlotDuration::from_millis(SLOT_DURATION),
1488                recent_segments: RecentSegments::get(),
1489                recent_history_fraction: RecentHistoryFraction::get(),
1490                min_sector_lifetime: MinSectorLifetime::get(),
1491            }
1492        }
1493    }
1494
1495    impl sp_domains::DomainsApi<Block, DomainHeader> for Runtime {
1496        fn submit_bundle_unsigned(
1497            opaque_bundle: OpaqueBundle<NumberFor<Block>, BlockHashFor<Block>, DomainHeader, Balance>,
1498        ) {
1499            Domains::submit_bundle_unsigned(opaque_bundle)
1500        }
1501
1502        fn submit_receipt_unsigned(
1503            singleton_receipt: sp_domains::SealedSingletonReceipt<NumberFor<Block>, BlockHashFor<Block>, DomainHeader, Balance>,
1504        ) {
1505            Domains::submit_receipt_unsigned(singleton_receipt)
1506        }
1507
1508        fn extract_successful_bundles(
1509            domain_id: DomainId,
1510            extrinsics: Vec<ExtrinsicFor<Block>>,
1511        ) -> OpaqueBundles<Block, DomainHeader, Balance> {
1512            extract_successful_bundles(domain_id, extrinsics)
1513        }
1514
1515        fn extrinsics_shuffling_seed() -> Randomness {
1516            Randomness::from(Domains::extrinsics_shuffling_seed().to_fixed_bytes())
1517        }
1518
1519        fn domain_runtime_code(domain_id: DomainId) -> Option<Vec<u8>> {
1520            Domains::domain_runtime_code(domain_id)
1521        }
1522
1523        fn runtime_id(domain_id: DomainId) -> Option<sp_domains::RuntimeId> {
1524            Domains::runtime_id(domain_id)
1525        }
1526
1527        fn runtime_upgrades() -> Vec<sp_domains::RuntimeId> {
1528            Domains::runtime_upgrades()
1529        }
1530
1531        fn domain_instance_data(domain_id: DomainId) -> Option<(DomainInstanceData, NumberFor<Block>)> {
1532            Domains::domain_instance_data(domain_id)
1533        }
1534
1535        fn domain_timestamp() -> Moment {
1536            Domains::timestamp()
1537        }
1538
1539        fn timestamp() -> Moment {
1540            Timestamp::now()
1541        }
1542
1543        fn consensus_transaction_byte_fee() -> Balance {
1544            Domains::consensus_transaction_byte_fee()
1545        }
1546
1547        fn consensus_chain_byte_fee() -> Balance {
1548            DOMAIN_STORAGE_FEE_MULTIPLIER * TransactionFees::transaction_byte_fee()
1549        }
1550
1551        fn domain_tx_range(_: DomainId) -> U256 {
1552            U256::MAX
1553        }
1554
1555        fn genesis_state_root(domain_id: DomainId) -> Option<H256> {
1556            Domains::genesis_state_root(domain_id)
1557        }
1558
1559        fn head_receipt_number(domain_id: DomainId) -> DomainNumber {
1560            Domains::head_receipt_number(domain_id)
1561        }
1562
1563        fn oldest_unconfirmed_receipt_number(domain_id: DomainId) -> Option<DomainNumber> {
1564            Domains::oldest_unconfirmed_receipt_number(domain_id)
1565        }
1566
1567        fn domain_bundle_limit(domain_id: DomainId) -> Option<sp_domains::DomainBundleLimit> {
1568            Domains::domain_bundle_limit(domain_id).ok().flatten()
1569        }
1570
1571        fn non_empty_er_exists(domain_id: DomainId) -> bool {
1572            Domains::non_empty_er_exists(domain_id)
1573        }
1574
1575        fn domain_best_number(domain_id: DomainId) -> Option<DomainNumber> {
1576            Domains::domain_best_number(domain_id).ok()
1577        }
1578
1579        fn execution_receipt(receipt_hash: DomainHash) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>> {
1580            Domains::execution_receipt(receipt_hash)
1581        }
1582
1583        fn domain_operators(domain_id: DomainId) -> Option<(BTreeMap<OperatorId, Balance>, Vec<OperatorId>)> {
1584            Domains::domain_staking_summary(domain_id).map(|summary| {
1585                let next_operators = summary.next_operators.into_iter().collect();
1586                (summary.current_operators, next_operators)
1587            })
1588        }
1589
1590        fn receipt_hash(domain_id: DomainId, domain_number: DomainNumber) -> Option<DomainHash> {
1591            Domains::receipt_hash(domain_id, domain_number)
1592        }
1593
1594        fn latest_confirmed_domain_block(domain_id: DomainId) -> Option<(DomainNumber, DomainHash)>{
1595            Domains::latest_confirmed_domain_block(domain_id)
1596        }
1597
1598        fn is_bad_er_pending_to_prune(domain_id: DomainId, receipt_hash: DomainHash) -> bool {
1599            Domains::execution_receipt(receipt_hash).map(
1600                |er| Domains::is_bad_er_pending_to_prune(domain_id, er.domain_block_number)
1601            )
1602            .unwrap_or(false)
1603        }
1604
1605        fn storage_fund_account_balance(operator_id: OperatorId) -> Balance {
1606            Domains::storage_fund_account_balance(operator_id)
1607        }
1608
1609        fn is_domain_runtime_upgraded_since(domain_id: DomainId, at: NumberFor<Block>) -> Option<bool> {
1610            Domains::is_domain_runtime_upgraded_since(domain_id, at)
1611        }
1612
1613        fn domain_sudo_call(domain_id: DomainId) -> Option<Vec<u8>> {
1614            Domains::domain_sudo_call(domain_id)
1615        }
1616
1617        fn evm_domain_contract_creation_allowed_by_call(domain_id: DomainId) -> Option<PermissionedActionAllowedBy<EthereumAccountId>> {
1618            Domains::evm_domain_contract_creation_allowed_by_call(domain_id)
1619        }
1620
1621        fn last_confirmed_domain_block_receipt(domain_id: DomainId) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>{
1622            Domains::latest_confirmed_domain_execution_receipt(domain_id)
1623        }
1624    }
1625
1626    impl sp_domains::BundleProducerElectionApi<Block, Balance> for Runtime {
1627        fn bundle_producer_election_params(domain_id: DomainId) -> Option<BundleProducerElectionParams<Balance>> {
1628            Domains::bundle_producer_election_params(domain_id)
1629        }
1630
1631        fn operator(operator_id: OperatorId) -> Option<(OperatorPublicKey, Balance)> {
1632            Domains::operator(operator_id)
1633        }
1634    }
1635
1636    impl sp_session::SessionKeys<Block> for Runtime {
1637        fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
1638            SessionKeys::generate(seed)
1639        }
1640
1641        fn decode_session_keys(
1642            encoded: Vec<u8>,
1643        ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
1644            SessionKeys::decode_into_raw_public_keys(&encoded)
1645        }
1646    }
1647
1648    impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
1649        fn account_nonce(account: AccountId) -> Nonce {
1650            *System::account_nonce(account)
1651        }
1652    }
1653
1654    impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
1655        fn query_info(
1656            uxt: ExtrinsicFor<Block>,
1657            len: u32,
1658        ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
1659            TransactionPayment::query_info(uxt, len)
1660        }
1661        fn query_fee_details(
1662            uxt: ExtrinsicFor<Block>,
1663            len: u32,
1664        ) -> pallet_transaction_payment::FeeDetails<Balance> {
1665            TransactionPayment::query_fee_details(uxt, len)
1666        }
1667        fn query_weight_to_fee(weight: Weight) -> Balance {
1668            TransactionPayment::weight_to_fee(weight)
1669        }
1670        fn query_length_to_fee(length: u32) -> Balance {
1671            TransactionPayment::length_to_fee(length)
1672        }
1673    }
1674
1675    impl sp_messenger::MessengerApi<Block, BlockNumber, BlockHashFor<Block>> for Runtime {
1676        fn is_xdm_mmr_proof_valid(
1677            extrinsic: &ExtrinsicFor<Block>
1678        ) -> Option<bool> {
1679            is_xdm_mmr_proof_valid(extrinsic)
1680        }
1681
1682        fn extract_xdm_mmr_proof(ext: &ExtrinsicFor<Block>) -> Option<ConsensusChainMmrLeafProof<BlockNumber, BlockHashFor<Block>, sp_core::H256>> {
1683            match &ext.function {
1684                RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })
1685                | RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1686                    Some(msg.proof.consensus_mmr_proof())
1687                }
1688                _ => None,
1689            }
1690        }
1691
1692        fn batch_extract_xdm_mmr_proof(extrinsics: &Vec<ExtrinsicFor<Block>>) -> BTreeMap<u32, ConsensusChainMmrLeafProof<BlockNumber, BlockHashFor<Block>, sp_core::H256>> {
1693            let mut mmr_proofs = BTreeMap::new();
1694            for (index, ext) in extrinsics.iter().enumerate() {
1695                match &ext.function {
1696                    RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })
1697                    | RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1698                        mmr_proofs.insert(index as u32, msg.proof.consensus_mmr_proof());
1699                    }
1700                    _ => {},
1701                }
1702            }
1703            mmr_proofs
1704        }
1705
1706        fn confirmed_domain_block_storage_key(domain_id: DomainId) -> Vec<u8> {
1707            Domains::confirmed_domain_block_storage_key(domain_id)
1708        }
1709
1710        fn outbox_storage_key(message_key: MessageKey) -> Vec<u8> {
1711            Messenger::outbox_storage_key(message_key)
1712        }
1713
1714        fn inbox_response_storage_key(message_key: MessageKey) -> Vec<u8> {
1715            Messenger::inbox_response_storage_key(message_key)
1716        }
1717
1718        fn domain_chains_allowlist_update(domain_id: DomainId) -> Option<DomainAllowlistUpdates>{
1719            Messenger::domain_chains_allowlist_update(domain_id)
1720        }
1721
1722        fn xdm_id(ext: &ExtrinsicFor<Block>) -> Option<XdmId> {
1723            match &ext.function {
1724                RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })=> {
1725                    Some(XdmId::RelayMessage((msg.src_chain_id, msg.channel_id, msg.nonce)))
1726                }
1727                RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1728                    Some(XdmId::RelayResponseMessage((msg.src_chain_id, msg.channel_id, msg.nonce)))
1729                }
1730                _ => None,
1731            }
1732        }
1733
1734        fn channel_nonce(chain_id: ChainId, channel_id: ChannelId) -> Option<ChannelNonce> {
1735            Messenger::channel_nonce(chain_id, channel_id)
1736        }
1737    }
1738
1739    impl sp_messenger::RelayerApi<Block, BlockNumber, BlockNumber, BlockHashFor<Block>> for Runtime {
1740        fn block_messages() -> BlockMessagesWithStorageKey {
1741            BlockMessagesWithStorageKey::default()
1742        }
1743
1744        fn outbox_message_unsigned(msg: CrossDomainMessage<NumberFor<Block>, BlockHashFor<Block>, BlockHashFor<Block>>) -> Option<ExtrinsicFor<Block>> {
1745            Messenger::outbox_message_unsigned(msg)
1746        }
1747
1748        fn inbox_response_message_unsigned(msg: CrossDomainMessage<NumberFor<Block>, BlockHashFor<Block>, BlockHashFor<Block>>) -> Option<ExtrinsicFor<Block>> {
1749            Messenger::inbox_response_message_unsigned(msg)
1750        }
1751
1752        fn should_relay_outbox_message(_: ChainId, _: MessageId) -> bool {
1753            false
1754        }
1755
1756        fn should_relay_inbox_message_response(_: ChainId, _: MessageId) -> bool {
1757            false
1758        }
1759
1760        fn updated_channels() -> BTreeSet<(ChainId, ChannelId)> {
1761            Messenger::updated_channels()
1762        }
1763
1764        fn channel_storage_key(chain_id: ChainId, channel_id: ChannelId) -> Vec<u8> {
1765            Messenger::channel_storage_key(chain_id, channel_id)
1766        }
1767
1768        fn open_channels() -> BTreeSet<(ChainId, ChannelId)> {
1769            Messenger::open_channels()
1770        }
1771
1772        fn block_messages_with_query(query: BlockMessagesQuery) -> MessagesWithStorageKey {
1773            Messenger::get_block_messages(query)
1774        }
1775
1776        fn channels_and_state() -> Vec<(ChainId, ChannelId, ChannelStateWithNonce)> {
1777            Messenger::channels_and_states()
1778        }
1779
1780        fn first_outbox_message_nonce_to_relay(dst_chain_id: ChainId, channel_id: ChannelId, from_nonce: XdmNonce) -> Option<XdmNonce> {
1781            Messenger::first_outbox_message_nonce_to_relay(dst_chain_id, channel_id, from_nonce)
1782        }
1783
1784        fn first_inbox_message_response_nonce_to_relay(dst_chain_id: ChainId, channel_id: ChannelId, from_nonce: XdmNonce) -> Option<XdmNonce> {
1785            Messenger::first_inbox_message_response_nonce_to_relay(dst_chain_id, channel_id, from_nonce)
1786        }
1787    }
1788
1789    impl sp_domains_fraud_proof::FraudProofApi<Block, DomainHeader> for Runtime {
1790        fn submit_fraud_proof_unsigned(fraud_proof: FraudProof<NumberFor<Block>, BlockHashFor<Block>, DomainHeader, H256>) {
1791            Domains::submit_fraud_proof_unsigned(fraud_proof)
1792        }
1793
1794        fn fraud_proof_storage_key(req: FraudProofStorageKeyRequest<NumberFor<Block>>) -> Vec<u8> {
1795            <StorageKeyProvider as FraudProofStorageKeyProvider<NumberFor<Block>>>::storage_key(req)
1796        }
1797    }
1798
1799    impl mmr::MmrApi<Block, mmr::Hash, BlockNumber> for Runtime {
1800        fn mmr_root() -> Result<mmr::Hash, mmr::Error> {
1801            Ok(Mmr::mmr_root())
1802        }
1803
1804        fn mmr_leaf_count() -> Result<mmr::LeafIndex, mmr::Error> {
1805            Ok(Mmr::mmr_leaves())
1806        }
1807
1808        fn generate_proof(
1809            block_numbers: Vec<BlockNumber>,
1810            best_known_block_number: Option<BlockNumber>,
1811        ) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::LeafProof<mmr::Hash>), mmr::Error> {
1812            Mmr::generate_proof(block_numbers, best_known_block_number).map(
1813                |(leaves, proof)| {
1814                    (
1815                        leaves
1816                            .into_iter()
1817                            .map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf))
1818                            .collect(),
1819                        proof,
1820                    )
1821                },
1822            )
1823        }
1824
1825        fn verify_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::LeafProof<mmr::Hash>)
1826            -> Result<(), mmr::Error>
1827        {
1828            let leaves = leaves.into_iter().map(|leaf|
1829                leaf.into_opaque_leaf()
1830                .try_decode()
1831                .ok_or(mmr::Error::Verify)).collect::<Result<Vec<mmr::Leaf>, mmr::Error>>()?;
1832            Mmr::verify_leaves(leaves, proof)
1833        }
1834
1835        fn verify_proof_stateless(
1836            root: mmr::Hash,
1837            leaves: Vec<mmr::EncodableOpaqueLeaf>,
1838            proof: mmr::LeafProof<mmr::Hash>
1839        ) -> Result<(), mmr::Error> {
1840            let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect();
1841            pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(root, nodes, proof)
1842        }
1843    }
1844
1845    impl subspace_test_primitives::OnchainStateApi<Block, AccountId, Balance> for Runtime {
1846        fn free_balance(account_id: AccountId) -> Balance {
1847            Balances::free_balance(account_id)
1848        }
1849
1850        fn get_open_channel_for_chain(dst_chain_id: ChainId) -> Option<ChannelId> {
1851            Messenger::get_open_channel_for_chain(dst_chain_id)
1852        }
1853
1854        fn verify_proof_and_extract_leaf(mmr_leaf_proof: ConsensusChainMmrLeafProof<NumberFor<Block>, BlockHashFor<Block>, H256>) -> Option<mmr::Leaf> {
1855            <MmrProofVerifier as sp_subspace_mmr::MmrProofVerifier<_, _, _,>>::verify_proof_and_extract_leaf(mmr_leaf_proof)
1856        }
1857
1858        fn domain_balance(domain_id: DomainId) -> Balance {
1859            Transporter::domain_balances(domain_id)
1860        }
1861    }
1862
1863    impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
1864        fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
1865            build_state::<RuntimeGenesisConfig>(config)
1866        }
1867
1868        fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
1869            get_preset::<RuntimeGenesisConfig>(id, |_| None)
1870        }
1871
1872        fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
1873            vec![]
1874        }
1875    }
1876}
1877
1878#[cfg(test)]
1879mod tests {
1880    use crate::Runtime;
1881    use pallet_domains::bundle_storage_fund::AccountType;
1882    use sp_domains::OperatorId;
1883    use sp_runtime::traits::AccountIdConversion;
1884
1885    #[test]
1886    fn test_bundle_storage_fund_account_uniqueness() {
1887        let _: <Runtime as frame_system::Config>::AccountId = <Runtime as pallet_domains::Config>::PalletId::get()
1888            .try_into_sub_account((AccountType::StorageFund, OperatorId::MAX))
1889            .expect(
1890                "The `AccountId` type must be large enough to fit the seed of the bundle storage fund account",
1891            );
1892    }
1893}