1#![cfg_attr(not(feature = "std"), no_std)]
18#![feature(variant_count)]
19#![allow(incomplete_features)]
21#![feature(generic_const_exprs)]
24#![recursion_limit = "256"]
26#![allow(
28 non_camel_case_types,
29 reason = "https://github.com/rust-lang/rust-analyzer/issues/16514"
30)]
31
32extern crate alloc;
33
34#[cfg(feature = "std")]
36include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
37
38use alloc::borrow::Cow;
39use core::mem;
40use core::num::NonZeroU64;
41use domain_runtime_primitives::opaque::Header as DomainHeader;
42use domain_runtime_primitives::{
43 AccountIdConverter, BlockNumber as DomainNumber, EthereumAccountId, Hash as DomainHash,
44 MAX_OUTGOING_MESSAGES,
45};
46use frame_support::genesis_builder_helper::{build_state, get_preset};
47use frame_support::inherent::ProvideInherent;
48use frame_support::traits::fungible::Inspect;
49use frame_support::traits::tokens::WithdrawConsequence;
50use frame_support::traits::{
51 ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, Currency, Everything, ExistenceRequirement,
52 Get, Imbalance, Time, VariantCount, WithdrawReasons,
53};
54use frame_support::weights::constants::{ParityDbWeight, WEIGHT_REF_TIME_PER_SECOND};
55use frame_support::weights::{ConstantMultiplier, Weight};
56use frame_support::{construct_runtime, parameter_types, PalletId};
57use frame_system::limits::{BlockLength, BlockWeights};
58use frame_system::pallet_prelude::{OriginFor, RuntimeCallFor};
59use pallet_balances::NegativeImbalance;
60pub use pallet_rewards::RewardPoint;
61pub use pallet_subspace::{AllowAuthoringBy, EnableRewardsAt};
62use pallet_transporter::EndpointHandler;
63use parity_scale_codec::{Compact, CompactLen, Decode, Encode, MaxEncodedLen};
64use scale_info::TypeInfo;
65use sp_api::impl_runtime_apis;
66use sp_consensus_slots::{Slot, SlotDuration};
67use sp_consensus_subspace::{ChainConstants, PotParameters, SignedVote, SolutionRanges, Vote};
68use sp_core::crypto::KeyTypeId;
69use sp_core::{OpaqueMetadata, H256};
70use sp_domains::bundle_producer_election::BundleProducerElectionParams;
71use sp_domains::{
72 DomainAllowlistUpdates, DomainId, DomainInstanceData, ExecutionReceiptFor, OpaqueBundle,
73 OpaqueBundles, OperatorId, OperatorPublicKey, OperatorRewardSource,
74 PermissionedActionAllowedBy, DOMAIN_STORAGE_FEE_MULTIPLIER, INITIAL_DOMAIN_TX_RANGE,
75};
76use sp_domains_fraud_proof::fraud_proof::FraudProof;
77use sp_domains_fraud_proof::storage_proof::{
78 FraudProofStorageKeyProvider, FraudProofStorageKeyRequest,
79};
80use sp_messenger::endpoint::{Endpoint, EndpointHandler as EndpointHandlerT, EndpointId};
81use sp_messenger::messages::{
82 BlockMessagesQuery, BlockMessagesWithStorageKey, ChainId, ChannelId, ChannelStateWithNonce,
83 CrossDomainMessage, MessageId, MessageKey, MessagesWithStorageKey, Nonce as XdmNonce,
84};
85use sp_messenger::{ChannelNonce, XdmId};
86use sp_messenger_host_functions::{get_storage_key, StorageKeyRequest};
87use sp_mmr_primitives::EncodableOpaqueLeaf;
88use sp_runtime::traits::{
89 AccountIdConversion, AccountIdLookup, AsSystemOriginSigner, BlakeTwo256, ConstBool,
90 DispatchInfoOf, Keccak256, NumberFor, PostDispatchInfoOf, TransactionExtension, ValidateResult,
91 Zero,
92};
93use sp_runtime::transaction_validity::{
94 InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
95 ValidTransaction,
96};
97use sp_runtime::type_with_default::TypeWithDefault;
98use sp_runtime::{
99 generic, impl_tx_ext_default, AccountId32, ApplyExtrinsicResult, ExtrinsicInclusionMode,
100 Perbill,
101};
102use sp_std::collections::btree_map::BTreeMap;
103use sp_std::collections::btree_set::BTreeSet;
104use sp_std::marker::PhantomData;
105use sp_std::prelude::*;
106use sp_subspace_mmr::ConsensusChainMmrLeafProof;
107use sp_version::RuntimeVersion;
108use static_assertions::const_assert;
109use subspace_core_primitives::objects::{BlockObject, BlockObjectMapping};
110use subspace_core_primitives::pieces::Piece;
111use subspace_core_primitives::segments::{
112 HistorySize, SegmentCommitment, SegmentHeader, SegmentIndex,
113};
114use subspace_core_primitives::solutions::SolutionRange;
115use subspace_core_primitives::{hashes, PublicKey, Randomness, SlotNumber, U256};
116use subspace_runtime_primitives::utility::{
117 nested_call_iter, DefaultNonceProvider, MaybeMultisigCall, MaybeNestedCall, MaybeUtilityCall,
118};
119use subspace_runtime_primitives::{
120 AccountId, Balance, BlockHashFor, BlockNumber, ConsensusEventSegmentSize, ExtrinsicFor,
121 FindBlockRewardAddress, Hash, HeaderFor, HoldIdentifier, Moment, Nonce, Signature,
122 SlowAdjustingFeeUpdate, TargetBlockFullness, XdmAdjustedWeightToFee, XdmFeeMultipler,
123 MAX_BLOCK_LENGTH, MAX_CALL_RECURSION_DEPTH, MIN_REPLICATION_FACTOR, SHANNON, SSC,
124};
125use subspace_test_primitives::DOMAINS_BLOCK_PRUNING_DEPTH;
126
127sp_runtime::impl_opaque_keys! {
128 pub struct SessionKeys {
129 }
130}
131
132const MAX_PIECES_IN_SECTOR: u16 = 32;
134
135#[sp_version::runtime_version]
138pub const VERSION: RuntimeVersion = RuntimeVersion {
139 spec_name: Cow::Borrowed("subspace"),
140 impl_name: Cow::Borrowed("subspace"),
141 authoring_version: 1,
142 spec_version: 100,
148 impl_version: 1,
149 apis: RUNTIME_API_VERSIONS,
150 transaction_version: 1,
151 system_version: 2,
152};
153
154pub const MILLISECS_PER_BLOCK: u64 = 2000;
173
174pub const SLOT_DURATION: u64 = 2000;
177
178const SLOT_PROBABILITY: (u64, u64) = (1, 1);
181const BLOCK_AUTHORING_DELAY: SlotNumber = 2;
183
184const POT_ENTROPY_INJECTION_INTERVAL: BlockNumber = 5;
186
187const POT_ENTROPY_INJECTION_LOOKBACK_DEPTH: u8 = 2;
189
190const POT_ENTROPY_INJECTION_DELAY: SlotNumber = 4;
192
193const_assert!(POT_ENTROPY_INJECTION_INTERVAL as u64 > POT_ENTROPY_INJECTION_DELAY);
196const_assert!(POT_ENTROPY_INJECTION_DELAY > BLOCK_AUTHORING_DELAY + 1);
200
201const ERA_DURATION_IN_BLOCKS: BlockNumber = 2016;
203
204const INITIAL_SOLUTION_RANGE: SolutionRange = SolutionRange::MAX;
206
207const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
209
210const BLOCK_WEIGHT_FOR_2_SEC: Weight =
212 Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX);
213
214parameter_types! {
215 pub const Version: RuntimeVersion = VERSION;
216 pub const BlockHashCount: BlockNumber = 250;
217 pub SubspaceBlockWeights: BlockWeights = BlockWeights::with_sensible_defaults(BLOCK_WEIGHT_FOR_2_SEC, NORMAL_DISPATCH_RATIO);
219 pub SubspaceBlockLength: BlockLength = BlockLength::max_with_normal_ratio(MAX_BLOCK_LENGTH, NORMAL_DISPATCH_RATIO);
221}
222
223pub type SS58Prefix = ConstU16<6094>;
224
225impl frame_system::Config for Runtime {
228 type BaseCallFilter = Everything;
233 type BlockWeights = SubspaceBlockWeights;
235 type BlockLength = SubspaceBlockLength;
237 type AccountId = AccountId;
239 type RuntimeCall = RuntimeCall;
241 type RuntimeTask = RuntimeTask;
243 type Lookup = AccountIdLookup<AccountId, ()>;
245 type Nonce = TypeWithDefault<Nonce, DefaultNonceProvider<System, Nonce>>;
247 type Hash = Hash;
249 type Hashing = BlakeTwo256;
251 type Block = Block;
253 type RuntimeEvent = RuntimeEvent;
255 type RuntimeOrigin = RuntimeOrigin;
257 type BlockHashCount = BlockHashCount;
259 type DbWeight = ParityDbWeight;
261 type Version = Version;
263 type PalletInfo = PalletInfo;
267 type OnNewAccount = ();
269 type OnKilledAccount = ();
271 type AccountData = pallet_balances::AccountData<Balance>;
273 type SystemWeightInfo = frame_system::weights::SubstrateWeight<Runtime>;
275 type SS58Prefix = SS58Prefix;
277 type OnSetCode = ();
279 type SingleBlockMigrations = ();
280 type MultiBlockMigrator = ();
281 type PreInherents = ();
282 type PostInherents = ();
283 type PostTransactions = ();
284 type MaxConsumers = ConstU32<16>;
285 type ExtensionsWeightInfo = frame_system::ExtensionsWeight<Runtime>;
286 type EventSegmentSize = ConsensusEventSegmentSize;
287}
288
289parameter_types! {
290 pub const BlockAuthoringDelay: SlotNumber = BLOCK_AUTHORING_DELAY;
291 pub const PotEntropyInjectionInterval: BlockNumber = POT_ENTROPY_INJECTION_INTERVAL;
292 pub const PotEntropyInjectionLookbackDepth: u8 = POT_ENTROPY_INJECTION_LOOKBACK_DEPTH;
293 pub const PotEntropyInjectionDelay: SlotNumber = POT_ENTROPY_INJECTION_DELAY;
294 pub const EraDuration: BlockNumber = ERA_DURATION_IN_BLOCKS;
295 pub const SlotProbability: (u64, u64) = SLOT_PROBABILITY;
296 pub const ShouldAdjustSolutionRange: bool = false;
297 pub const ExpectedVotesPerBlock: u32 = 9;
298 pub const ConfirmationDepthK: u32 = 5;
299 pub const RecentSegments: HistorySize = HistorySize::new(NonZeroU64::new(5).unwrap());
300 pub const RecentHistoryFraction: (HistorySize, HistorySize) = (
301 HistorySize::new(NonZeroU64::new(1).unwrap()),
302 HistorySize::new(NonZeroU64::new(10).unwrap()),
303 );
304 pub const MinSectorLifetime: HistorySize = HistorySize::new(NonZeroU64::new(4).unwrap());
305 pub const BlockSlotCount: u32 = 6;
306 pub TransactionWeightFee: Balance = 100_000 * SHANNON;
307}
308
309impl pallet_subspace::Config for Runtime {
310 type RuntimeEvent = RuntimeEvent;
311 type SubspaceOrigin = pallet_subspace::EnsureSubspaceOrigin;
312 type BlockAuthoringDelay = BlockAuthoringDelay;
313 type PotEntropyInjectionInterval = PotEntropyInjectionInterval;
314 type PotEntropyInjectionLookbackDepth = PotEntropyInjectionLookbackDepth;
315 type PotEntropyInjectionDelay = PotEntropyInjectionDelay;
316 type EraDuration = EraDuration;
317 type InitialSolutionRange = ConstU64<INITIAL_SOLUTION_RANGE>;
318 type SlotProbability = SlotProbability;
319 type ConfirmationDepthK = ConfirmationDepthK;
320 type RecentSegments = RecentSegments;
321 type RecentHistoryFraction = RecentHistoryFraction;
322 type MinSectorLifetime = MinSectorLifetime;
323 type ExpectedVotesPerBlock = ExpectedVotesPerBlock;
324 type MaxPiecesInSector = ConstU16<{ MAX_PIECES_IN_SECTOR }>;
325 type ShouldAdjustSolutionRange = ShouldAdjustSolutionRange;
326 type EraChangeTrigger = pallet_subspace::NormalEraChange;
327 type WeightInfo = pallet_subspace::weights::SubstrateWeight<Runtime>;
328 type BlockSlotCount = BlockSlotCount;
329 type ExtensionWeightInfo = pallet_subspace::extensions::weights::SubstrateWeight<Runtime>;
330}
331
332impl pallet_timestamp::Config for Runtime {
333 type Moment = Moment;
335 type OnTimestampSet = ();
336 type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
337 type WeightInfo = pallet_timestamp::weights::SubstrateWeight<Runtime>;
338}
339
340#[derive(
341 PartialEq, Eq, Clone, Encode, Decode, TypeInfo, MaxEncodedLen, Ord, PartialOrd, Copy, Debug,
342)]
343pub struct HoldIdentifierWrapper(HoldIdentifier);
344
345impl pallet_domains::HoldIdentifier<Runtime> for HoldIdentifierWrapper {
346 fn staking_staked() -> Self {
347 Self(HoldIdentifier::DomainStaking)
348 }
349
350 fn domain_instantiation_id() -> Self {
351 Self(HoldIdentifier::DomainInstantiation)
352 }
353
354 fn storage_fund_withdrawal() -> Self {
355 Self(HoldIdentifier::DomainStorageFund)
356 }
357}
358
359impl pallet_messenger::HoldIdentifier<Runtime> for HoldIdentifierWrapper {
360 fn messenger_channel() -> Self {
361 Self(HoldIdentifier::MessengerChannel)
362 }
363}
364
365impl VariantCount for HoldIdentifierWrapper {
366 const VARIANT_COUNT: u32 = mem::variant_count::<HoldIdentifier>() as u32;
367}
368
369impl pallet_balances::Config for Runtime {
370 type RuntimeFreezeReason = RuntimeFreezeReason;
371 type MaxLocks = ConstU32<50>;
372 type MaxReserves = ();
373 type ReserveIdentifier = [u8; 8];
374 type Balance = Balance;
376 type RuntimeEvent = RuntimeEvent;
378 type DustRemoval = ();
379 type ExistentialDeposit = ConstU128<{ 10_000_000_000_000 * SHANNON }>;
380 type AccountStore = System;
381 type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;
382 type FreezeIdentifier = ();
383 type MaxFreezes = ();
384 type RuntimeHoldReason = HoldIdentifierWrapper;
385 type DoneSlashHandler = ();
386}
387
388pub struct CreditSupply;
389
390impl Get<Balance> for CreditSupply {
391 fn get() -> Balance {
392 Balances::total_issuance()
393 }
394}
395
396pub struct TotalSpacePledged;
397
398impl Get<u128> for TotalSpacePledged {
399 fn get() -> u128 {
400 u128::from(u64::MAX)
403 .saturating_mul(Piece::SIZE as u128)
404 .saturating_mul(u128::from(SlotProbability::get().0))
405 / u128::from(Subspace::solution_ranges().current)
406 / u128::from(SlotProbability::get().1)
407 }
408}
409
410pub struct BlockchainHistorySize;
411
412impl Get<u128> for BlockchainHistorySize {
413 fn get() -> u128 {
414 u128::from(Subspace::archived_history_size())
415 }
416}
417
418impl pallet_transaction_fees::Config for Runtime {
419 type RuntimeEvent = RuntimeEvent;
420 type MinReplicationFactor = ConstU16<MIN_REPLICATION_FACTOR>;
421 type CreditSupply = CreditSupply;
422 type TotalSpacePledged = TotalSpacePledged;
423 type BlockchainHistorySize = BlockchainHistorySize;
424 type Currency = Balances;
425 type FindBlockRewardAddress = Subspace;
426 type DynamicCostOfStorage = ConstBool<false>;
427 type WeightInfo = pallet_transaction_fees::weights::SubstrateWeight<Runtime>;
428}
429
430pub struct TransactionByteFee;
431
432impl Get<Balance> for TransactionByteFee {
433 fn get() -> Balance {
434 TransactionFees::transaction_byte_fee()
435 }
436}
437
438pub struct LiquidityInfo {
439 storage_fee: Balance,
440 imbalance: NegativeImbalance<Runtime>,
441}
442
443pub struct OnChargeTransaction;
446
447impl pallet_transaction_payment::OnChargeTransaction<Runtime> for OnChargeTransaction {
448 type LiquidityInfo = Option<LiquidityInfo>;
449 type Balance = Balance;
450
451 fn withdraw_fee(
452 who: &AccountId,
453 call: &RuntimeCall,
454 _info: &DispatchInfoOf<RuntimeCall>,
455 fee: Self::Balance,
456 tip: Self::Balance,
457 ) -> Result<Self::LiquidityInfo, TransactionValidityError> {
458 if fee.is_zero() {
459 return Ok(None);
460 }
461
462 let withdraw_reason = if tip.is_zero() {
463 WithdrawReasons::TRANSACTION_PAYMENT
464 } else {
465 WithdrawReasons::TRANSACTION_PAYMENT | WithdrawReasons::TIP
466 };
467
468 let withdraw_result =
469 Balances::withdraw(who, fee, withdraw_reason, ExistenceRequirement::KeepAlive);
470 let imbalance = withdraw_result.map_err(|_error| InvalidTransaction::Payment)?;
471
472 let storage_fee = TransactionByteFee::get()
474 * Balance::try_from(call.encoded_size())
475 .expect("Size of the call never exceeds balance units; qed");
476
477 Ok(Some(LiquidityInfo {
478 storage_fee,
479 imbalance,
480 }))
481 }
482
483 fn correct_and_deposit_fee(
484 who: &AccountId,
485 _dispatch_info: &DispatchInfoOf<RuntimeCall>,
486 _post_info: &PostDispatchInfoOf<RuntimeCall>,
487 corrected_fee: Self::Balance,
488 tip: Self::Balance,
489 liquidity_info: Self::LiquidityInfo,
490 ) -> Result<(), TransactionValidityError> {
491 if let Some(LiquidityInfo {
492 storage_fee,
493 imbalance,
494 }) = liquidity_info
495 {
496 let refund_amount = imbalance.peek().saturating_sub(corrected_fee);
498 let refund_imbalance = Balances::deposit_into_existing(who, refund_amount)
501 .unwrap_or_else(|_| <Balances as Currency<AccountId>>::PositiveImbalance::zero());
502 let adjusted_paid = imbalance
504 .offset(refund_imbalance)
505 .same()
506 .map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?;
507
508 let (tip, fee) = adjusted_paid.split(tip);
510 let (paid_storage_fee, paid_compute_fee) = fee.split(storage_fee);
512
513 TransactionFees::note_transaction_fees(
514 paid_storage_fee.peek(),
515 paid_compute_fee.peek(),
516 tip.peek(),
517 );
518 }
519 Ok(())
520 }
521
522 fn can_withdraw_fee(
523 who: &AccountId,
524 _call: &RuntimeCall,
525 _dispatch_info: &DispatchInfoOf<RuntimeCall>,
526 fee: Self::Balance,
527 _tip: Self::Balance,
528 ) -> Result<(), TransactionValidityError> {
529 if fee.is_zero() {
530 return Ok(());
531 }
532
533 match Balances::can_withdraw(who, fee) {
534 WithdrawConsequence::Success => Ok(()),
535 _ => Err(InvalidTransaction::Payment.into()),
536 }
537 }
538}
539
540impl pallet_transaction_payment::Config for Runtime {
541 type RuntimeEvent = RuntimeEvent;
542 type OnChargeTransaction = OnChargeTransaction;
543 type OperationalFeeMultiplier = ConstU8<5>;
544 type WeightToFee = ConstantMultiplier<Balance, TransactionWeightFee>;
545 type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
546 type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Runtime, TargetBlockFullness>;
547 type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight<Runtime>;
548}
549
550impl pallet_utility::Config for Runtime {
551 type RuntimeEvent = RuntimeEvent;
552 type RuntimeCall = RuntimeCall;
553 type PalletsOrigin = OriginCaller;
554 type WeightInfo = pallet_utility::weights::SubstrateWeight<Runtime>;
555}
556
557impl MaybeMultisigCall<Runtime> for RuntimeCall {
558 fn maybe_multisig_call(&self) -> Option<&pallet_multisig::Call<Runtime>> {
560 match self {
561 RuntimeCall::Multisig(call) => Some(call),
562 _ => None,
563 }
564 }
565}
566
567impl MaybeUtilityCall<Runtime> for RuntimeCall {
568 fn maybe_utility_call(&self) -> Option<&pallet_utility::Call<Runtime>> {
570 match self {
571 RuntimeCall::Utility(call) => Some(call),
572 _ => None,
573 }
574 }
575}
576
577impl MaybeNestedCall<Runtime> for RuntimeCall {
578 fn maybe_nested_call(&self) -> Option<Vec<&RuntimeCallFor<Runtime>>> {
583 let calls = self.maybe_nested_utility_calls();
589 if calls.is_some() {
590 return calls;
591 }
592
593 let calls = self.maybe_nested_multisig_calls();
594 if calls.is_some() {
595 return calls;
596 }
597
598 None
599 }
600}
601
602impl pallet_sudo::Config for Runtime {
603 type RuntimeEvent = RuntimeEvent;
604 type RuntimeCall = RuntimeCall;
605 type WeightInfo = pallet_sudo::weights::SubstrateWeight<Runtime>;
606}
607
608parameter_types! {
609 pub SelfChainId: ChainId = ChainId::Consensus;
610}
611
612pub struct MmrProofVerifier;
613
614impl sp_subspace_mmr::MmrProofVerifier<mmr::Hash, NumberFor<Block>, Hash> for MmrProofVerifier {
615 fn verify_proof_and_extract_leaf(
616 mmr_leaf_proof: ConsensusChainMmrLeafProof<NumberFor<Block>, Hash, mmr::Hash>,
617 ) -> Option<mmr::Leaf> {
618 let mmr_root = SubspaceMmr::mmr_root_hash(mmr_leaf_proof.consensus_block_number)?;
619 Self::verify_proof_stateless(mmr_root, mmr_leaf_proof)
620 }
621
622 fn verify_proof_stateless(
623 mmr_root: mmr::Hash,
624 mmr_leaf_proof: ConsensusChainMmrLeafProof<NumberFor<Block>, Hash, mmr::Hash>,
625 ) -> Option<mmr::Leaf> {
626 let ConsensusChainMmrLeafProof {
627 opaque_mmr_leaf,
628 proof,
629 ..
630 } = mmr_leaf_proof;
631
632 pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(
633 mmr_root,
634 vec![mmr::DataOrHash::Data(
635 EncodableOpaqueLeaf(opaque_mmr_leaf.0.clone()).into_opaque_leaf(),
636 )],
637 proof,
638 )
639 .ok()?;
640
641 let leaf: mmr::Leaf = opaque_mmr_leaf.into_opaque_leaf().try_decode()?;
642
643 Some(leaf)
644 }
645}
646
647pub struct StorageKeys;
648
649impl sp_messenger::StorageKeys for StorageKeys {
650 fn confirmed_domain_block_storage_key(domain_id: DomainId) -> Option<Vec<u8>> {
651 Some(Domains::confirmed_domain_block_storage_key(domain_id))
652 }
653
654 fn outbox_storage_key(chain_id: ChainId, message_key: MessageKey) -> Option<Vec<u8>> {
655 get_storage_key(StorageKeyRequest::OutboxStorageKey {
656 chain_id,
657 message_key,
658 })
659 }
660
661 fn inbox_responses_storage_key(chain_id: ChainId, message_key: MessageKey) -> Option<Vec<u8>> {
662 get_storage_key(StorageKeyRequest::InboxResponseStorageKey {
663 chain_id,
664 message_key,
665 })
666 }
667}
668
669pub struct DomainRegistration;
670impl sp_messenger::DomainRegistration for DomainRegistration {
671 fn is_domain_registered(domain_id: DomainId) -> bool {
672 Domains::is_domain_registered(domain_id)
673 }
674}
675
676parameter_types! {
677 pub const ChannelReserveFee: Balance = SSC;
678 pub const ChannelInitReservePortion: Perbill = Perbill::from_percent(20);
679 pub const MaxOutgoingMessages: u32 = MAX_OUTGOING_MESSAGES;
680}
681
682const_assert!(MaxOutgoingMessages::get() >= 1);
684
685pub struct OnXDMRewards;
686
687impl sp_messenger::OnXDMRewards<Balance> for OnXDMRewards {
688 fn on_xdm_rewards(reward: Balance) {
689 if let Some(block_author) = Subspace::find_block_reward_address() {
690 let _ = Balances::deposit_creating(&block_author, reward);
691 }
692 }
693
694 fn on_chain_protocol_fees(chain_id: ChainId, fees: Balance) {
695 if let ChainId::Domain(domain_id) = chain_id {
698 Domains::reward_domain_operators(domain_id, OperatorRewardSource::XDMProtocolFees, fees)
699 }
700 }
701}
702
703impl pallet_messenger::Config for Runtime {
704 type RuntimeEvent = RuntimeEvent;
705 type SelfChainId = SelfChainId;
706
707 fn get_endpoint_handler(endpoint: &Endpoint) -> Option<Box<dyn EndpointHandlerT<MessageId>>> {
708 if endpoint == &Endpoint::Id(TransporterEndpointId::get()) {
709 Some(Box::new(EndpointHandler(PhantomData::<Runtime>)))
710 } else {
711 None
712 }
713 }
714
715 type Currency = Balances;
716 type WeightInfo = pallet_messenger::weights::SubstrateWeight<Runtime>;
717 type WeightToFee = ConstantMultiplier<Balance, TransactionWeightFee>;
718 type AdjustedWeightToFee = XdmAdjustedWeightToFee<Runtime>;
719 type FeeMultiplier = XdmFeeMultipler;
720 type OnXDMRewards = OnXDMRewards;
721 type MmrHash = mmr::Hash;
722 type MmrProofVerifier = MmrProofVerifier;
723 type StorageKeys = StorageKeys;
724 type DomainOwner = Domains;
725 type HoldIdentifier = HoldIdentifierWrapper;
726 type ChannelReserveFee = ChannelReserveFee;
727 type ChannelInitReservePortion = ChannelInitReservePortion;
728 type DomainRegistration = DomainRegistration;
729 type MaxOutgoingMessages = MaxOutgoingMessages;
730 type MessengerOrigin = pallet_messenger::EnsureMessengerOrigin;
731 type NoteChainTransfer = Transporter;
732 type ExtensionWeightInfo = pallet_messenger::extensions::weights::SubstrateWeight<Runtime>;
733}
734
735impl<C> frame_system::offchain::CreateTransactionBase<C> for Runtime
736where
737 RuntimeCall: From<C>,
738{
739 type Extrinsic = UncheckedExtrinsic;
740 type RuntimeCall = RuntimeCall;
741}
742
743impl<C> subspace_runtime_primitives::CreateUnsigned<C> for Runtime
744where
745 RuntimeCall: From<C>,
746{
747 fn create_unsigned(call: Self::RuntimeCall) -> Self::Extrinsic {
748 create_unsigned_general_extrinsic(call)
749 }
750}
751
752parameter_types! {
753 pub const TransporterEndpointId: EndpointId = 1;
754}
755
756impl pallet_transporter::Config for Runtime {
757 type RuntimeEvent = RuntimeEvent;
758 type SelfChainId = SelfChainId;
759 type SelfEndpointId = TransporterEndpointId;
760 type Currency = Balances;
761 type Sender = Messenger;
762 type AccountIdConverter = AccountIdConverter;
763 type WeightInfo = pallet_transporter::weights::SubstrateWeight<Runtime>;
764 type SkipBalanceTransferChecks = ();
765}
766
767parameter_types! {
768 pub const MaximumReceiptDrift: BlockNumber = 2;
769 pub const InitialDomainTxRange: u64 = INITIAL_DOMAIN_TX_RANGE;
770 pub const DomainTxRangeAdjustmentInterval: u64 = 100;
771 pub const MinOperatorStake: Balance = 100 * SSC;
772 pub const MinNominatorStake: Balance = SSC;
773 pub MaxDomainBlockSize: u32 = NORMAL_DISPATCH_RATIO * MAX_BLOCK_LENGTH;
775 pub MaxDomainBlockWeight: Weight = NORMAL_DISPATCH_RATIO * BLOCK_WEIGHT_FOR_2_SEC;
777 pub const DomainInstantiationDeposit: Balance = 100 * SSC;
778 pub const MaxDomainNameLength: u32 = 32;
779 pub const BlockTreePruningDepth: u32 = DOMAINS_BLOCK_PRUNING_DEPTH;
780 pub const StakeWithdrawalLockingPeriod: BlockNumber = 20;
781 pub const StakeEpochDuration: DomainNumber = 5;
782 pub TreasuryAccount: AccountId = PalletId(*b"treasury").into_account_truncating();
783 pub const MaxPendingStakingOperation: u32 = 512;
784 pub const DomainsPalletId: PalletId = PalletId(*b"domains_");
785 pub const MaxInitialDomainAccounts: u32 = 20;
786 pub const MinInitialDomainAccountBalance: Balance = SSC;
787 pub const BundleLongevity: u32 = 5;
788 pub const WithdrawalLimit: u32 = 32;
789}
790
791const_assert!(BlockSlotCount::get() >= 2 && BlockSlotCount::get() > BundleLongevity::get());
794
795const_assert!(BlockHashCount::get() > BlockSlotCount::get());
798
799const_assert!(MinOperatorStake::get() >= MinNominatorStake::get());
801
802pub struct BlockSlot;
803
804impl pallet_domains::BlockSlot<Runtime> for BlockSlot {
805 fn future_slot(block_number: BlockNumber) -> Option<Slot> {
806 let block_slots = Subspace::block_slots();
807 block_slots
808 .get(&block_number)
809 .map(|slot| *slot + Slot::from(BlockAuthoringDelay::get()))
810 }
811
812 fn slot_produced_after(to_check: Slot) -> Option<BlockNumber> {
813 let block_slots = Subspace::block_slots();
814 for (block_number, slot) in block_slots.into_iter().rev() {
815 if to_check > slot {
816 return Some(block_number);
817 }
818 }
819 None
820 }
821}
822
823pub struct OnChainRewards;
824
825impl sp_domains::OnChainRewards<Balance> for OnChainRewards {
826 fn on_chain_rewards(chain_id: ChainId, reward: Balance) {
827 match chain_id {
828 ChainId::Consensus => {
829 if let Some(block_author) = Subspace::find_block_reward_address() {
830 let _ = Balances::deposit_creating(&block_author, reward);
831 }
832 }
833 ChainId::Domain(domain_id) => Domains::reward_domain_operators(
834 domain_id,
835 OperatorRewardSource::XDMProtocolFees,
836 reward,
837 ),
838 }
839 }
840}
841
842impl pallet_domains::Config for Runtime {
843 type RuntimeEvent = RuntimeEvent;
844 type DomainOrigin = pallet_domains::EnsureDomainOrigin;
845 type DomainHash = DomainHash;
846 type Balance = Balance;
847 type DomainHeader = DomainHeader;
848 type ConfirmationDepthK = ConfirmationDepthK;
849 type Currency = Balances;
850 type Share = Balance;
851 type HoldIdentifier = HoldIdentifierWrapper;
852 type BlockTreePruningDepth = BlockTreePruningDepth;
853 type ConsensusSlotProbability = SlotProbability;
854 type MaxDomainBlockSize = MaxDomainBlockSize;
855 type MaxDomainBlockWeight = MaxDomainBlockWeight;
856 type MaxDomainNameLength = MaxDomainNameLength;
857 type DomainInstantiationDeposit = DomainInstantiationDeposit;
858 type WeightInfo = pallet_domains::weights::SubstrateWeight<Runtime>;
859 type InitialDomainTxRange = InitialDomainTxRange;
860 type DomainTxRangeAdjustmentInterval = DomainTxRangeAdjustmentInterval;
861 type MinOperatorStake = MinOperatorStake;
862 type MinNominatorStake = MinNominatorStake;
863 type StakeWithdrawalLockingPeriod = StakeWithdrawalLockingPeriod;
864 type StakeEpochDuration = StakeEpochDuration;
865 type TreasuryAccount = TreasuryAccount;
866 type MaxPendingStakingOperation = MaxPendingStakingOperation;
867 type Randomness = Subspace;
868 type PalletId = DomainsPalletId;
869 type StorageFee = TransactionFees;
870 type BlockTimestamp = pallet_timestamp::Pallet<Runtime>;
871 type BlockSlot = BlockSlot;
872 type DomainsTransfersTracker = Transporter;
873 type MaxInitialDomainAccounts = MaxInitialDomainAccounts;
874 type MinInitialDomainAccountBalance = MinInitialDomainAccountBalance;
875 type BundleLongevity = BundleLongevity;
876 type DomainBundleSubmitted = Messenger;
877 type OnDomainInstantiated = Messenger;
878 type MmrHash = mmr::Hash;
879 type MmrProofVerifier = MmrProofVerifier;
880 type FraudProofStorageKeyProvider = StorageKeyProvider;
881 type OnChainRewards = OnChainRewards;
882 type WithdrawalLimit = WithdrawalLimit;
883}
884
885parameter_types! {
886 pub const AvgBlockspaceUsageNumBlocks: BlockNumber = 100;
887 pub const ProposerTaxOnVotes: (u32, u32) = (1, 10);
888}
889
890impl pallet_rewards::Config for Runtime {
891 type RuntimeEvent = RuntimeEvent;
892 type Currency = Balances;
893 type AvgBlockspaceUsageNumBlocks = AvgBlockspaceUsageNumBlocks;
894 type TransactionByteFee = TransactionByteFee;
895 type MaxRewardPoints = ConstU32<20>;
896 type ProposerTaxOnVotes = ProposerTaxOnVotes;
897 type RewardsEnabled = Subspace;
898 type FindBlockRewardAddress = Subspace;
899 type FindVotingRewardAddresses = Subspace;
900 type WeightInfo = pallet_rewards::weights::SubstrateWeight<Runtime>;
901 type OnReward = ();
902}
903
904mod mmr {
905 use super::Runtime;
906 pub use pallet_mmr::primitives::*;
907
908 pub type Leaf = <<Runtime as pallet_mmr::Config>::LeafData as LeafDataProvider>::LeafData;
909 pub type Hashing = <Runtime as pallet_mmr::Config>::Hashing;
910 pub type Hash = <Hashing as sp_runtime::traits::Hash>::Output;
911}
912
913pub struct BlockHashProvider;
914
915impl pallet_mmr::BlockHashProvider<BlockNumber, Hash> for BlockHashProvider {
916 fn block_hash(block_number: BlockNumber) -> Hash {
917 sp_subspace_mmr::subspace_mmr_runtime_interface::consensus_block_hash(block_number)
918 .expect("Hash must exist for a given block number.")
919 }
920}
921
922impl pallet_mmr::Config for Runtime {
923 const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX;
924 type Hashing = Keccak256;
925 type LeafData = SubspaceMmr;
926 type OnNewRoot = SubspaceMmr;
927 type BlockHashProvider = BlockHashProvider;
928 type WeightInfo = ();
929 #[cfg(feature = "runtime-benchmarks")]
930 type BenchmarkHelper = ();
931}
932
933parameter_types! {
934 pub const MmrRootHashCount: u32 = 15;
935}
936
937impl pallet_subspace_mmr::Config for Runtime {
938 type MmrRootHash = mmr::Hash;
939 type MmrRootHashCount = MmrRootHashCount;
940}
941
942impl pallet_runtime_configs::Config for Runtime {
943 type WeightInfo = pallet_runtime_configs::weights::SubstrateWeight<Runtime>;
944}
945
946parameter_types! {
947 pub const MaxSignatories: u32 = 100;
948}
949
950macro_rules! deposit {
951 ($name:ident, $item_fee:expr, $items:expr, $bytes:expr) => {
952 pub struct $name;
953
954 impl Get<Balance> for $name {
955 fn get() -> Balance {
956 $item_fee.saturating_mul($items.into()).saturating_add(
957 TransactionFees::transaction_byte_fee().saturating_mul($bytes.into()),
958 )
959 }
960 }
961 };
962}
963
964deposit!(DepositBaseFee, 20 * SSC, 1u32, 88u32);
967
968deposit!(DepositFactor, 0u128, 0u32, 32u32);
970
971impl pallet_multisig::Config for Runtime {
972 type RuntimeEvent = RuntimeEvent;
973 type RuntimeCall = RuntimeCall;
974 type Currency = Balances;
975 type DepositBase = DepositBaseFee;
976 type DepositFactor = DepositFactor;
977 type MaxSignatories = MaxSignatories;
978 type WeightInfo = pallet_multisig::weights::SubstrateWeight<Runtime>;
979}
980
981construct_runtime!(
982 pub struct Runtime {
983 System: frame_system = 0,
984 Timestamp: pallet_timestamp = 1,
985
986 Subspace: pallet_subspace = 2,
987 Rewards: pallet_rewards = 9,
988
989 Balances: pallet_balances = 4,
990 TransactionFees: pallet_transaction_fees = 12,
991 TransactionPayment: pallet_transaction_payment = 5,
992 Utility: pallet_utility = 8,
993
994 Domains: pallet_domains = 11,
995 RuntimeConfigs: pallet_runtime_configs = 14,
996
997 Mmr: pallet_mmr = 30,
998 SubspaceMmr: pallet_subspace_mmr = 31,
999
1000 Messenger: pallet_messenger exclude_parts { Inherent } = 60,
1003 Transporter: pallet_transporter = 61,
1004
1005 Multisig: pallet_multisig = 90,
1007
1008 Sudo: pallet_sudo = 100,
1010 }
1011);
1012
1013pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
1015pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
1017pub type Block = generic::Block<Header, UncheckedExtrinsic>;
1019pub type SignedExtra = (
1021 frame_system::CheckNonZeroSender<Runtime>,
1022 frame_system::CheckSpecVersion<Runtime>,
1023 frame_system::CheckTxVersion<Runtime>,
1024 frame_system::CheckGenesis<Runtime>,
1025 frame_system::CheckMortality<Runtime>,
1026 frame_system::CheckNonce<Runtime>,
1027 frame_system::CheckWeight<Runtime>,
1028 pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
1029 DisablePallets,
1030 pallet_subspace::extensions::SubspaceExtension<Runtime>,
1031 pallet_domains::extensions::DomainsExtension<Runtime>,
1032 pallet_messenger::extensions::MessengerExtension<Runtime>,
1033);
1034pub type UncheckedExtrinsic =
1036 generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
1037pub type Executive = frame_executive::Executive<
1039 Runtime,
1040 Block,
1041 frame_system::ChainContext<Runtime>,
1042 Runtime,
1043 AllPalletsWithSystem,
1044>;
1045pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
1047
1048impl pallet_subspace::extensions::MaybeSubspaceCall<Runtime> for RuntimeCall {
1049 fn maybe_subspace_call(&self) -> Option<&pallet_subspace::Call<Runtime>> {
1050 match self {
1051 RuntimeCall::Subspace(call) => Some(call),
1052 _ => None,
1053 }
1054 }
1055}
1056
1057impl pallet_domains::extensions::MaybeDomainsCall<Runtime> for RuntimeCall {
1058 fn maybe_domains_call(&self) -> Option<&pallet_domains::Call<Runtime>> {
1059 match self {
1060 RuntimeCall::Domains(call) => Some(call),
1061 _ => None,
1062 }
1063 }
1064}
1065
1066impl pallet_messenger::extensions::MaybeMessengerCall<Runtime> for RuntimeCall {
1067 fn maybe_messenger_call(&self) -> Option<&pallet_messenger::Call<Runtime>> {
1068 match self {
1069 RuntimeCall::Messenger(call) => Some(call),
1070 _ => None,
1071 }
1072 }
1073}
1074
1075fn extract_segment_headers(ext: &UncheckedExtrinsic) -> Option<Vec<SegmentHeader>> {
1076 match &ext.function {
1077 RuntimeCall::Subspace(pallet_subspace::Call::store_segment_headers { segment_headers }) => {
1078 Some(segment_headers.clone())
1079 }
1080 _ => None,
1081 }
1082}
1083
1084fn is_xdm_mmr_proof_valid(ext: &ExtrinsicFor<Block>) -> Option<bool> {
1085 match &ext.function {
1086 RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })
1087 | RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1088 let ConsensusChainMmrLeafProof {
1089 consensus_block_number,
1090 opaque_mmr_leaf,
1091 proof,
1092 ..
1093 } = msg.proof.consensus_mmr_proof();
1094
1095 let mmr_root = SubspaceMmr::mmr_root_hash(consensus_block_number)?;
1096
1097 Some(
1098 pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(
1099 mmr_root,
1100 vec![mmr::DataOrHash::Data(
1101 EncodableOpaqueLeaf(opaque_mmr_leaf.0.clone()).into_opaque_leaf(),
1102 )],
1103 proof,
1104 )
1105 .is_ok(),
1106 )
1107 }
1108 _ => None,
1109 }
1110}
1111
1112fn extract_utility_block_object_mapping(
1114 mut base_offset: u32,
1115 objects: &mut Vec<BlockObject>,
1116 call: &pallet_utility::Call<Runtime>,
1117 mut recursion_depth_left: u16,
1118) {
1119 if recursion_depth_left == 0 {
1120 return;
1121 }
1122
1123 recursion_depth_left -= 1;
1124
1125 base_offset += 1;
1127
1128 match call {
1129 pallet_utility::Call::batch { calls }
1130 | pallet_utility::Call::batch_all { calls }
1131 | pallet_utility::Call::force_batch { calls } => {
1132 base_offset += Compact::compact_len(&(calls.len() as u32)) as u32;
1133
1134 for call in calls {
1135 extract_call_block_object_mapping(base_offset, objects, call, recursion_depth_left);
1136
1137 base_offset += call.encoded_size() as u32;
1138 }
1139 }
1140 pallet_utility::Call::as_derivative { index, call } => {
1141 base_offset += index.encoded_size() as u32;
1142
1143 extract_call_block_object_mapping(
1144 base_offset,
1145 objects,
1146 call.as_ref(),
1147 recursion_depth_left,
1148 );
1149 }
1150 pallet_utility::Call::dispatch_as { as_origin, call } => {
1151 base_offset += as_origin.encoded_size() as u32;
1152
1153 extract_call_block_object_mapping(
1154 base_offset,
1155 objects,
1156 call.as_ref(),
1157 recursion_depth_left,
1158 );
1159 }
1160 pallet_utility::Call::with_weight { call, .. } => {
1161 extract_call_block_object_mapping(
1162 base_offset,
1163 objects,
1164 call.as_ref(),
1165 recursion_depth_left,
1166 );
1167 }
1168 pallet_utility::Call::__Ignore(_, _) => {
1169 }
1171 }
1172}
1173
1174fn extract_call_block_object_mapping(
1175 mut base_offset: u32,
1176 objects: &mut Vec<BlockObject>,
1177 call: &RuntimeCall,
1178 recursion_depth_left: u16,
1179) {
1180 base_offset += 1;
1182
1183 match call {
1184 RuntimeCall::System(frame_system::Call::remark { remark }) => {
1186 objects.push(BlockObject {
1187 hash: hashes::blake3_hash(remark),
1188 offset: base_offset + 1,
1190 });
1191 }
1192 RuntimeCall::System(frame_system::Call::remark_with_event { remark }) => {
1193 objects.push(BlockObject {
1194 hash: hashes::blake3_hash(remark),
1195 offset: base_offset + 1,
1197 });
1198 }
1199
1200 RuntimeCall::Utility(call) => {
1202 extract_utility_block_object_mapping(base_offset, objects, call, recursion_depth_left)
1203 }
1204 _ => {}
1206 }
1207}
1208
1209fn extract_block_object_mapping(block: Block) -> BlockObjectMapping {
1210 let mut block_object_mapping = BlockObjectMapping::default();
1211 let mut base_offset =
1212 block.header.encoded_size() + Compact::compact_len(&(block.extrinsics.len() as u32));
1213 for extrinsic in block.extrinsics {
1214 let preamble_size = extrinsic.preamble.encoded_size();
1215 let base_extrinsic_offset = base_offset
1218 + Compact::compact_len(&((preamble_size + extrinsic.function.encoded_size()) as u32))
1219 + preamble_size;
1220
1221 extract_call_block_object_mapping(
1222 base_extrinsic_offset as u32,
1223 block_object_mapping.objects_mut(),
1224 &extrinsic.function,
1225 MAX_CALL_RECURSION_DEPTH as u16,
1226 );
1227
1228 base_offset += extrinsic.encoded_size();
1229 }
1230
1231 block_object_mapping
1232}
1233
1234fn extract_successful_bundles(
1235 domain_id: DomainId,
1236 extrinsics: Vec<UncheckedExtrinsic>,
1237) -> OpaqueBundles<Block, DomainHeader, Balance> {
1238 let successful_bundles = Domains::successful_bundles(domain_id);
1239 extrinsics
1240 .into_iter()
1241 .filter_map(|uxt| match uxt.function {
1242 RuntimeCall::Domains(pallet_domains::Call::submit_bundle { opaque_bundle })
1243 if opaque_bundle.domain_id() == domain_id
1244 && successful_bundles.contains(&opaque_bundle.hash()) =>
1245 {
1246 Some(opaque_bundle)
1247 }
1248 _ => None,
1249 })
1250 .collect()
1251}
1252
1253fn create_unsigned_general_extrinsic(call: RuntimeCall) -> UncheckedExtrinsic {
1254 let extra: SignedExtra = (
1255 frame_system::CheckNonZeroSender::<Runtime>::new(),
1256 frame_system::CheckSpecVersion::<Runtime>::new(),
1257 frame_system::CheckTxVersion::<Runtime>::new(),
1258 frame_system::CheckGenesis::<Runtime>::new(),
1259 frame_system::CheckMortality::<Runtime>::from(generic::Era::Immortal),
1260 frame_system::CheckNonce::<Runtime>::from(0u32.into()),
1263 frame_system::CheckWeight::<Runtime>::new(),
1264 pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(0u128),
1267 DisablePallets,
1268 pallet_subspace::extensions::SubspaceExtension::<Runtime>::new(),
1269 pallet_domains::extensions::DomainsExtension::<Runtime>::new(),
1270 pallet_messenger::extensions::MessengerExtension::<Runtime>::new(),
1271 );
1272
1273 UncheckedExtrinsic::new_transaction(call, extra)
1274}
1275
1276struct RewardAddress([u8; 32]);
1277
1278impl From<PublicKey> for RewardAddress {
1279 #[inline]
1280 fn from(public_key: PublicKey) -> Self {
1281 Self(*public_key)
1282 }
1283}
1284
1285impl From<RewardAddress> for AccountId32 {
1286 #[inline]
1287 fn from(reward_address: RewardAddress) -> Self {
1288 reward_address.0.into()
1289 }
1290}
1291
1292pub struct StorageKeyProvider;
1293impl FraudProofStorageKeyProvider<NumberFor<Block>> for StorageKeyProvider {
1294 fn storage_key(req: FraudProofStorageKeyRequest<NumberFor<Block>>) -> Vec<u8> {
1295 match req {
1296 FraudProofStorageKeyRequest::InvalidInherentExtrinsicData => {
1297 pallet_domains::BlockInherentExtrinsicData::<Runtime>::hashed_key().to_vec()
1298 }
1299 FraudProofStorageKeyRequest::SuccessfulBundles(domain_id) => {
1300 pallet_domains::SuccessfulBundles::<Runtime>::hashed_key_for(domain_id)
1301 }
1302 FraudProofStorageKeyRequest::DomainAllowlistUpdates(domain_id) => {
1303 Messenger::domain_allow_list_update_storage_key(domain_id)
1304 }
1305 FraudProofStorageKeyRequest::DomainRuntimeUpgrades => {
1306 pallet_domains::DomainRuntimeUpgrades::<Runtime>::hashed_key().to_vec()
1307 }
1308 FraudProofStorageKeyRequest::RuntimeRegistry(runtime_id) => {
1309 pallet_domains::RuntimeRegistry::<Runtime>::hashed_key_for(runtime_id)
1310 }
1311 FraudProofStorageKeyRequest::DomainSudoCall(domain_id) => {
1312 pallet_domains::DomainSudoCalls::<Runtime>::hashed_key_for(domain_id)
1313 }
1314 FraudProofStorageKeyRequest::EvmDomainContractCreationAllowedByCall(domain_id) => {
1315 pallet_domains::EvmDomainContractCreationAllowedByCalls::<Runtime>::hashed_key_for(
1316 domain_id,
1317 )
1318 }
1319 FraudProofStorageKeyRequest::MmrRoot(block_number) => {
1320 pallet_subspace_mmr::MmrRootHashes::<Runtime>::hashed_key_for(block_number)
1321 }
1322 }
1323 }
1324}
1325
1326impl_runtime_apis! {
1327 impl sp_api::Core<Block> for Runtime {
1328 fn version() -> RuntimeVersion {
1329 VERSION
1330 }
1331
1332 fn execute_block(block: Block) {
1333 Executive::execute_block(block);
1334 }
1335
1336 fn initialize_block(header: &HeaderFor<Block>) -> ExtrinsicInclusionMode {
1337 Executive::initialize_block(header)
1338 }
1339 }
1340
1341 impl sp_api::Metadata<Block> for Runtime {
1342 fn metadata() -> OpaqueMetadata {
1343 OpaqueMetadata::new(Runtime::metadata().into())
1344 }
1345
1346 fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
1347 Runtime::metadata_at_version(version)
1348 }
1349
1350 fn metadata_versions() -> Vec<u32> {
1351 Runtime::metadata_versions()
1352 }
1353 }
1354
1355 impl sp_block_builder::BlockBuilder<Block> for Runtime {
1356 fn apply_extrinsic(extrinsic: ExtrinsicFor<Block>) -> ApplyExtrinsicResult {
1357 Executive::apply_extrinsic(extrinsic)
1358 }
1359
1360 fn finalize_block() -> HeaderFor<Block> {
1361 Executive::finalize_block()
1362 }
1363
1364 fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<ExtrinsicFor<Block>> {
1365 data.create_extrinsics()
1366 }
1367
1368 fn check_inherents(
1369 block: Block,
1370 data: sp_inherents::InherentData,
1371 ) -> sp_inherents::CheckInherentsResult {
1372 data.check_extrinsics(&block)
1373 }
1374 }
1375
1376 impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
1377 fn validate_transaction(
1378 source: TransactionSource,
1379 tx: ExtrinsicFor<Block>,
1380 block_hash: BlockHashFor<Block>,
1381 ) -> TransactionValidity {
1382 Executive::validate_transaction(source, tx, block_hash)
1383 }
1384 }
1385
1386 impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
1387 fn offchain_worker(header: &HeaderFor<Block>) {
1388 Executive::offchain_worker(header)
1389 }
1390 }
1391
1392 impl sp_objects::ObjectsApi<Block> for Runtime {
1393 fn extract_block_object_mapping(block: Block) -> BlockObjectMapping {
1394 extract_block_object_mapping(block)
1395 }
1396 }
1397
1398 impl sp_consensus_subspace::SubspaceApi<Block, PublicKey> for Runtime {
1399 fn pot_parameters() -> PotParameters {
1400 Subspace::pot_parameters()
1401 }
1402
1403 fn solution_ranges() -> SolutionRanges {
1404 Subspace::solution_ranges()
1405 }
1406
1407 fn submit_vote_extrinsic(
1408 signed_vote: SignedVote<NumberFor<Block>, BlockHashFor<Block>, PublicKey>,
1409 ) {
1410 let SignedVote { vote, signature } = signed_vote;
1411 let Vote::V0 {
1412 height,
1413 parent_hash,
1414 slot,
1415 solution,
1416 proof_of_time,
1417 future_proof_of_time,
1418 } = vote;
1419
1420 Subspace::submit_vote(SignedVote {
1421 vote: Vote::V0 {
1422 height,
1423 parent_hash,
1424 slot,
1425 solution: solution.into_reward_address_format::<RewardAddress, AccountId32>(),
1426 proof_of_time,
1427 future_proof_of_time,
1428 },
1429 signature,
1430 })
1431 }
1432
1433 fn history_size() -> HistorySize {
1434 <pallet_subspace::Pallet<Runtime>>::history_size()
1435 }
1436
1437 fn max_pieces_in_sector() -> u16 {
1438 MAX_PIECES_IN_SECTOR
1439 }
1440
1441 fn segment_commitment(segment_index: SegmentIndex) -> Option<SegmentCommitment> {
1442 Subspace::segment_commitment(segment_index)
1443 }
1444
1445 fn extract_segment_headers(ext: &ExtrinsicFor<Block>) -> Option<Vec<SegmentHeader >> {
1446 extract_segment_headers(ext)
1447 }
1448
1449 fn is_inherent(ext: &ExtrinsicFor<Block>) -> bool {
1450 match &ext.function {
1451 RuntimeCall::Subspace(call) => Subspace::is_inherent(call),
1452 RuntimeCall::Timestamp(call) => Timestamp::is_inherent(call),
1453 _ => false,
1454 }
1455 }
1456
1457 fn root_plot_public_key() -> Option<PublicKey> {
1458 Subspace::root_plot_public_key()
1459 }
1460
1461 fn should_adjust_solution_range() -> bool {
1462 Subspace::should_adjust_solution_range()
1463 }
1464
1465 fn chain_constants() -> ChainConstants {
1466 ChainConstants::V0 {
1467 confirmation_depth_k: ConfirmationDepthK::get(),
1468 block_authoring_delay: Slot::from(BlockAuthoringDelay::get()),
1469 era_duration: EraDuration::get(),
1470 slot_probability: SlotProbability::get(),
1471 slot_duration: SlotDuration::from_millis(SLOT_DURATION),
1472 recent_segments: RecentSegments::get(),
1473 recent_history_fraction: RecentHistoryFraction::get(),
1474 min_sector_lifetime: MinSectorLifetime::get(),
1475 }
1476 }
1477 }
1478
1479 impl sp_domains::DomainsApi<Block, DomainHeader> for Runtime {
1480 fn submit_bundle_unsigned(
1481 opaque_bundle: OpaqueBundle<NumberFor<Block>, BlockHashFor<Block>, DomainHeader, Balance>,
1482 ) {
1483 Domains::submit_bundle_unsigned(opaque_bundle)
1484 }
1485
1486 fn submit_receipt_unsigned(
1487 singleton_receipt: sp_domains::SealedSingletonReceipt<NumberFor<Block>, BlockHashFor<Block>, DomainHeader, Balance>,
1488 ) {
1489 Domains::submit_receipt_unsigned(singleton_receipt)
1490 }
1491
1492 fn extract_successful_bundles(
1493 domain_id: DomainId,
1494 extrinsics: Vec<ExtrinsicFor<Block>>,
1495 ) -> OpaqueBundles<Block, DomainHeader, Balance> {
1496 extract_successful_bundles(domain_id, extrinsics)
1497 }
1498
1499 fn extrinsics_shuffling_seed() -> Randomness {
1500 Randomness::from(Domains::extrinsics_shuffling_seed().to_fixed_bytes())
1501 }
1502
1503 fn domain_runtime_code(domain_id: DomainId) -> Option<Vec<u8>> {
1504 Domains::domain_runtime_code(domain_id)
1505 }
1506
1507 fn runtime_id(domain_id: DomainId) -> Option<sp_domains::RuntimeId> {
1508 Domains::runtime_id(domain_id)
1509 }
1510
1511 fn runtime_upgrades() -> Vec<sp_domains::RuntimeId> {
1512 Domains::runtime_upgrades()
1513 }
1514
1515 fn domain_instance_data(domain_id: DomainId) -> Option<(DomainInstanceData, NumberFor<Block>)> {
1516 Domains::domain_instance_data(domain_id)
1517 }
1518
1519 fn domain_timestamp() -> Moment {
1520 Domains::timestamp()
1521 }
1522
1523 fn timestamp() -> Moment {
1524 Timestamp::now()
1525 }
1526
1527 fn consensus_transaction_byte_fee() -> Balance {
1528 Domains::consensus_transaction_byte_fee()
1529 }
1530
1531 fn consensus_chain_byte_fee() -> Balance {
1532 DOMAIN_STORAGE_FEE_MULTIPLIER * TransactionFees::transaction_byte_fee()
1533 }
1534
1535 fn domain_tx_range(_: DomainId) -> U256 {
1536 U256::MAX
1537 }
1538
1539 fn genesis_state_root(domain_id: DomainId) -> Option<H256> {
1540 Domains::genesis_state_root(domain_id)
1541 }
1542
1543 fn head_receipt_number(domain_id: DomainId) -> DomainNumber {
1544 Domains::head_receipt_number(domain_id)
1545 }
1546
1547 fn oldest_unconfirmed_receipt_number(domain_id: DomainId) -> Option<DomainNumber> {
1548 Domains::oldest_unconfirmed_receipt_number(domain_id)
1549 }
1550
1551 fn domain_bundle_limit(domain_id: DomainId) -> Option<sp_domains::DomainBundleLimit> {
1552 Domains::domain_bundle_limit(domain_id).ok().flatten()
1553 }
1554
1555 fn non_empty_er_exists(domain_id: DomainId) -> bool {
1556 Domains::non_empty_er_exists(domain_id)
1557 }
1558
1559 fn domain_best_number(domain_id: DomainId) -> Option<DomainNumber> {
1560 Domains::domain_best_number(domain_id).ok()
1561 }
1562
1563 fn execution_receipt(receipt_hash: DomainHash) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>> {
1564 Domains::execution_receipt(receipt_hash)
1565 }
1566
1567 fn domain_operators(domain_id: DomainId) -> Option<(BTreeMap<OperatorId, Balance>, Vec<OperatorId>)> {
1568 Domains::domain_staking_summary(domain_id).map(|summary| {
1569 let next_operators = summary.next_operators.into_iter().collect();
1570 (summary.current_operators, next_operators)
1571 })
1572 }
1573
1574 fn receipt_hash(domain_id: DomainId, domain_number: DomainNumber) -> Option<DomainHash> {
1575 Domains::receipt_hash(domain_id, domain_number)
1576 }
1577
1578 fn latest_confirmed_domain_block(domain_id: DomainId) -> Option<(DomainNumber, DomainHash)>{
1579 Domains::latest_confirmed_domain_block(domain_id)
1580 }
1581
1582 fn is_bad_er_pending_to_prune(domain_id: DomainId, receipt_hash: DomainHash) -> bool {
1583 Domains::execution_receipt(receipt_hash).map(
1584 |er| Domains::is_bad_er_pending_to_prune(domain_id, er.domain_block_number)
1585 )
1586 .unwrap_or(false)
1587 }
1588
1589 fn storage_fund_account_balance(operator_id: OperatorId) -> Balance {
1590 Domains::storage_fund_account_balance(operator_id)
1591 }
1592
1593 fn is_domain_runtime_upgraded_since(domain_id: DomainId, at: NumberFor<Block>) -> Option<bool> {
1594 Domains::is_domain_runtime_upgraded_since(domain_id, at)
1595 }
1596
1597 fn domain_sudo_call(domain_id: DomainId) -> Option<Vec<u8>> {
1598 Domains::domain_sudo_call(domain_id)
1599 }
1600
1601 fn evm_domain_contract_creation_allowed_by_call(domain_id: DomainId) -> Option<PermissionedActionAllowedBy<EthereumAccountId>> {
1602 Domains::evm_domain_contract_creation_allowed_by_call(domain_id)
1603 }
1604
1605 fn last_confirmed_domain_block_receipt(domain_id: DomainId) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>{
1606 Domains::latest_confirmed_domain_execution_receipt(domain_id)
1607 }
1608 }
1609
1610 impl sp_domains::BundleProducerElectionApi<Block, Balance> for Runtime {
1611 fn bundle_producer_election_params(domain_id: DomainId) -> Option<BundleProducerElectionParams<Balance>> {
1612 Domains::bundle_producer_election_params(domain_id)
1613 }
1614
1615 fn operator(operator_id: OperatorId) -> Option<(OperatorPublicKey, Balance)> {
1616 Domains::operator(operator_id)
1617 }
1618 }
1619
1620 impl sp_session::SessionKeys<Block> for Runtime {
1621 fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
1622 SessionKeys::generate(seed)
1623 }
1624
1625 fn decode_session_keys(
1626 encoded: Vec<u8>,
1627 ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
1628 SessionKeys::decode_into_raw_public_keys(&encoded)
1629 }
1630 }
1631
1632 impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
1633 fn account_nonce(account: AccountId) -> Nonce {
1634 *System::account_nonce(account)
1635 }
1636 }
1637
1638 impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
1639 fn query_info(
1640 uxt: ExtrinsicFor<Block>,
1641 len: u32,
1642 ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
1643 TransactionPayment::query_info(uxt, len)
1644 }
1645 fn query_fee_details(
1646 uxt: ExtrinsicFor<Block>,
1647 len: u32,
1648 ) -> pallet_transaction_payment::FeeDetails<Balance> {
1649 TransactionPayment::query_fee_details(uxt, len)
1650 }
1651 fn query_weight_to_fee(weight: Weight) -> Balance {
1652 TransactionPayment::weight_to_fee(weight)
1653 }
1654 fn query_length_to_fee(length: u32) -> Balance {
1655 TransactionPayment::length_to_fee(length)
1656 }
1657 }
1658
1659 impl sp_messenger::MessengerApi<Block, BlockNumber, BlockHashFor<Block>> for Runtime {
1660 fn is_xdm_mmr_proof_valid(
1661 extrinsic: &ExtrinsicFor<Block>
1662 ) -> Option<bool> {
1663 is_xdm_mmr_proof_valid(extrinsic)
1664 }
1665
1666 fn extract_xdm_mmr_proof(ext: &ExtrinsicFor<Block>) -> Option<ConsensusChainMmrLeafProof<BlockNumber, BlockHashFor<Block>, sp_core::H256>> {
1667 match &ext.function {
1668 RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })
1669 | RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1670 Some(msg.proof.consensus_mmr_proof())
1671 }
1672 _ => None,
1673 }
1674 }
1675
1676 fn batch_extract_xdm_mmr_proof(extrinsics: &Vec<ExtrinsicFor<Block>>) -> BTreeMap<u32, ConsensusChainMmrLeafProof<BlockNumber, BlockHashFor<Block>, sp_core::H256>> {
1677 let mut mmr_proofs = BTreeMap::new();
1678 for (index, ext) in extrinsics.iter().enumerate() {
1679 match &ext.function {
1680 RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })
1681 | RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1682 mmr_proofs.insert(index as u32, msg.proof.consensus_mmr_proof());
1683 }
1684 _ => {},
1685 }
1686 }
1687 mmr_proofs
1688 }
1689
1690 fn confirmed_domain_block_storage_key(domain_id: DomainId) -> Vec<u8> {
1691 Domains::confirmed_domain_block_storage_key(domain_id)
1692 }
1693
1694 fn outbox_storage_key(message_key: MessageKey) -> Vec<u8> {
1695 Messenger::outbox_storage_key(message_key)
1696 }
1697
1698 fn inbox_response_storage_key(message_key: MessageKey) -> Vec<u8> {
1699 Messenger::inbox_response_storage_key(message_key)
1700 }
1701
1702 fn domain_chains_allowlist_update(domain_id: DomainId) -> Option<DomainAllowlistUpdates>{
1703 Messenger::domain_chains_allowlist_update(domain_id)
1704 }
1705
1706 fn xdm_id(ext: &ExtrinsicFor<Block>) -> Option<XdmId> {
1707 match &ext.function {
1708 RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })=> {
1709 Some(XdmId::RelayMessage((msg.src_chain_id, msg.channel_id, msg.nonce)))
1710 }
1711 RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1712 Some(XdmId::RelayResponseMessage((msg.src_chain_id, msg.channel_id, msg.nonce)))
1713 }
1714 _ => None,
1715 }
1716 }
1717
1718 fn channel_nonce(chain_id: ChainId, channel_id: ChannelId) -> Option<ChannelNonce> {
1719 Messenger::channel_nonce(chain_id, channel_id)
1720 }
1721 }
1722
1723 impl sp_messenger::RelayerApi<Block, BlockNumber, BlockNumber, BlockHashFor<Block>> for Runtime {
1724 fn block_messages() -> BlockMessagesWithStorageKey {
1725 BlockMessagesWithStorageKey::default()
1726 }
1727
1728 fn outbox_message_unsigned(msg: CrossDomainMessage<NumberFor<Block>, BlockHashFor<Block>, BlockHashFor<Block>>) -> Option<ExtrinsicFor<Block>> {
1729 Messenger::outbox_message_unsigned(msg)
1730 }
1731
1732 fn inbox_response_message_unsigned(msg: CrossDomainMessage<NumberFor<Block>, BlockHashFor<Block>, BlockHashFor<Block>>) -> Option<ExtrinsicFor<Block>> {
1733 Messenger::inbox_response_message_unsigned(msg)
1734 }
1735
1736 fn should_relay_outbox_message(_: ChainId, _: MessageId) -> bool {
1737 false
1738 }
1739
1740 fn should_relay_inbox_message_response(_: ChainId, _: MessageId) -> bool {
1741 false
1742 }
1743
1744 fn updated_channels() -> BTreeSet<(ChainId, ChannelId)> {
1745 Messenger::updated_channels()
1746 }
1747
1748 fn channel_storage_key(chain_id: ChainId, channel_id: ChannelId) -> Vec<u8> {
1749 Messenger::channel_storage_key(chain_id, channel_id)
1750 }
1751
1752 fn open_channels() -> BTreeSet<(ChainId, ChannelId)> {
1753 Messenger::open_channels()
1754 }
1755
1756 fn block_messages_with_query(query: BlockMessagesQuery) -> MessagesWithStorageKey {
1757 Messenger::get_block_messages(query)
1758 }
1759
1760 fn channels_and_state() -> Vec<(ChainId, ChannelId, ChannelStateWithNonce)> {
1761 Messenger::channels_and_states()
1762 }
1763
1764 fn first_outbox_message_nonce_to_relay(dst_chain_id: ChainId, channel_id: ChannelId, from_nonce: XdmNonce) -> Option<XdmNonce> {
1765 Messenger::first_outbox_message_nonce_to_relay(dst_chain_id, channel_id, from_nonce)
1766 }
1767
1768 fn first_inbox_message_response_nonce_to_relay(dst_chain_id: ChainId, channel_id: ChannelId, from_nonce: XdmNonce) -> Option<XdmNonce> {
1769 Messenger::first_inbox_message_response_nonce_to_relay(dst_chain_id, channel_id, from_nonce)
1770 }
1771 }
1772
1773 impl sp_domains_fraud_proof::FraudProofApi<Block, DomainHeader> for Runtime {
1774 fn submit_fraud_proof_unsigned(fraud_proof: FraudProof<NumberFor<Block>, BlockHashFor<Block>, DomainHeader, H256>) {
1775 Domains::submit_fraud_proof_unsigned(fraud_proof)
1776 }
1777
1778 fn fraud_proof_storage_key(req: FraudProofStorageKeyRequest<NumberFor<Block>>) -> Vec<u8> {
1779 <StorageKeyProvider as FraudProofStorageKeyProvider<NumberFor<Block>>>::storage_key(req)
1780 }
1781 }
1782
1783 impl mmr::MmrApi<Block, mmr::Hash, BlockNumber> for Runtime {
1784 fn mmr_root() -> Result<mmr::Hash, mmr::Error> {
1785 Ok(Mmr::mmr_root())
1786 }
1787
1788 fn mmr_leaf_count() -> Result<mmr::LeafIndex, mmr::Error> {
1789 Ok(Mmr::mmr_leaves())
1790 }
1791
1792 fn generate_proof(
1793 block_numbers: Vec<BlockNumber>,
1794 best_known_block_number: Option<BlockNumber>,
1795 ) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::LeafProof<mmr::Hash>), mmr::Error> {
1796 Mmr::generate_proof(block_numbers, best_known_block_number).map(
1797 |(leaves, proof)| {
1798 (
1799 leaves
1800 .into_iter()
1801 .map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf))
1802 .collect(),
1803 proof,
1804 )
1805 },
1806 )
1807 }
1808
1809 fn verify_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::LeafProof<mmr::Hash>)
1810 -> Result<(), mmr::Error>
1811 {
1812 let leaves = leaves.into_iter().map(|leaf|
1813 leaf.into_opaque_leaf()
1814 .try_decode()
1815 .ok_or(mmr::Error::Verify)).collect::<Result<Vec<mmr::Leaf>, mmr::Error>>()?;
1816 Mmr::verify_leaves(leaves, proof)
1817 }
1818
1819 fn verify_proof_stateless(
1820 root: mmr::Hash,
1821 leaves: Vec<mmr::EncodableOpaqueLeaf>,
1822 proof: mmr::LeafProof<mmr::Hash>
1823 ) -> Result<(), mmr::Error> {
1824 let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect();
1825 pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(root, nodes, proof)
1826 }
1827 }
1828
1829 impl subspace_test_primitives::OnchainStateApi<Block, AccountId, Balance> for Runtime {
1830 fn free_balance(account_id: AccountId) -> Balance {
1831 Balances::free_balance(account_id)
1832 }
1833
1834 fn get_open_channel_for_chain(dst_chain_id: ChainId) -> Option<ChannelId> {
1835 Messenger::get_open_channel_for_chain(dst_chain_id)
1836 }
1837
1838 fn verify_proof_and_extract_leaf(mmr_leaf_proof: ConsensusChainMmrLeafProof<NumberFor<Block>, BlockHashFor<Block>, H256>) -> Option<mmr::Leaf> {
1839 <MmrProofVerifier as sp_subspace_mmr::MmrProofVerifier<_, _, _,>>::verify_proof_and_extract_leaf(mmr_leaf_proof)
1840 }
1841
1842 fn domain_balance(domain_id: DomainId) -> Balance {
1843 Transporter::domain_balances(domain_id)
1844 }
1845 }
1846
1847 impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
1848 fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
1849 build_state::<RuntimeGenesisConfig>(config)
1850 }
1851
1852 fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
1853 get_preset::<RuntimeGenesisConfig>(id, |_| None)
1854 }
1855
1856 fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
1857 vec![]
1858 }
1859 }
1860}
1861
1862#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, Default, TypeInfo)]
1864pub struct DisablePallets;
1865
1866impl DisablePallets {
1867 fn do_validate_unsigned(call: &RuntimeCall) -> TransactionValidity {
1868 if matches!(call, RuntimeCall::Domains(_)) && !RuntimeConfigs::enable_domains() {
1869 InvalidTransaction::Call.into()
1870 } else {
1871 Ok(ValidTransaction::default())
1872 }
1873 }
1874
1875 fn do_validate_signed(call: &RuntimeCall) -> TransactionValidity {
1876 if !RuntimeConfigs::enable_balance_transfers() && contains_balance_transfer(call) {
1878 Err(InvalidTransaction::Call.into())
1879 } else {
1880 Ok(ValidTransaction::default())
1881 }
1882 }
1883}
1884
1885impl TransactionExtension<RuntimeCall> for DisablePallets {
1886 const IDENTIFIER: &'static str = "DisablePallets";
1887 type Implicit = ();
1888 type Val = ();
1889 type Pre = ();
1890
1891 fn weight(&self, _call: &RuntimeCall) -> Weight {
1893 <Runtime as frame_system::Config>::DbWeight::get().reads(1)
1895 }
1896
1897 fn validate(
1898 &self,
1899 origin: OriginFor<Runtime>,
1900 call: &RuntimeCallFor<Runtime>,
1901 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
1902 _len: usize,
1903 _self_implicit: Self::Implicit,
1904 _inherited_implication: &impl Encode,
1905 _source: TransactionSource,
1906 ) -> ValidateResult<Self::Val, RuntimeCallFor<Runtime>> {
1907 let validity = if origin.as_system_origin_signer().is_some() {
1908 Self::do_validate_signed(call)?
1909 } else {
1910 ValidTransaction::default()
1911 };
1912
1913 Ok((validity, (), origin))
1914 }
1915
1916 impl_tx_ext_default!(RuntimeCallFor<Runtime>; prepare);
1917
1918 fn bare_validate(
1919 call: &RuntimeCallFor<Runtime>,
1920 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
1921 _len: usize,
1922 ) -> TransactionValidity {
1923 Self::do_validate_unsigned(call)
1924 }
1925
1926 fn bare_validate_and_prepare(
1927 call: &RuntimeCallFor<Runtime>,
1928 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
1929 _len: usize,
1930 ) -> Result<(), TransactionValidityError> {
1931 Self::do_validate_unsigned(call)?;
1932 Ok(())
1933 }
1934}
1935
1936fn contains_balance_transfer(call: &RuntimeCall) -> bool {
1937 for call in nested_call_iter::<Runtime>(call) {
1938 if let RuntimeCall::Balances(
1941 pallet_balances::Call::transfer_allow_death { .. }
1942 | pallet_balances::Call::transfer_keep_alive { .. }
1943 | pallet_balances::Call::transfer_all { .. },
1944 ) = call
1945 {
1946 return true;
1947 }
1948 }
1949
1950 false
1951}
1952
1953#[cfg(test)]
1954mod tests {
1955 use crate::Runtime;
1956 use pallet_domains::bundle_storage_fund::AccountType;
1957 use sp_domains::OperatorId;
1958 use sp_runtime::traits::AccountIdConversion;
1959
1960 #[test]
1961 fn test_bundle_storage_fund_account_uniqueness() {
1962 let _: <Runtime as frame_system::Config>::AccountId = <Runtime as pallet_domains::Config>::PalletId::get()
1963 .try_into_sub_account((AccountType::StorageFund, OperatorId::MAX))
1964 .expect(
1965 "The `AccountId` type must be large enough to fit the seed of the bundle storage fund account",
1966 );
1967 }
1968}