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