Skip to main content

subspace_runtime/
lib.rs

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