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