Skip to main content

subspace_runtime/
lib.rs

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