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