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