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