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