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 BlockMessagesWithStorageKey, ChainId, ChannelId, CrossDomainMessage, FeeModel, MessageId,
83 MessageKey,
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, Block as BlockT,
90 ConstBool, DispatchInfoOf, Keccak256, NumberFor, PostDispatchInfoOf, TransactionExtension,
91 ValidateResult, 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, BlockNumber, ConsensusEventSegmentSize, FindBlockRewardAddress, Hash,
121 HoldIdentifier, Moment, Nonce, Signature, SlowAdjustingFeeUpdate, TargetBlockFullness,
122 XdmAdjustedWeightToFee, XdmFeeMultipler, MAX_BLOCK_LENGTH, MAX_CALL_RECURSION_DEPTH,
123 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 ChannelFeeModel: FeeModel<Balance> = FeeModel{relay_fee: SSC};
680 pub const MaxOutgoingMessages: u32 = MAX_OUTGOING_MESSAGES;
681 pub const MessageVersion: pallet_messenger::MessageVersion = pallet_messenger::MessageVersion::V1;
682}
683
684const_assert!(MaxOutgoingMessages::get() >= 1);
686
687pub struct OnXDMRewards;
688
689impl sp_messenger::OnXDMRewards<Balance> for OnXDMRewards {
690 fn on_xdm_rewards(reward: Balance) {
691 if let Some(block_author) = Subspace::find_block_reward_address() {
692 let _ = Balances::deposit_creating(&block_author, reward);
693 }
694 }
695
696 fn on_chain_protocol_fees(chain_id: ChainId, fees: Balance) {
697 if let ChainId::Domain(domain_id) = chain_id {
700 Domains::reward_domain_operators(domain_id, OperatorRewardSource::XDMProtocolFees, fees)
701 }
702 }
703}
704
705impl pallet_messenger::Config for Runtime {
706 type RuntimeEvent = RuntimeEvent;
707 type SelfChainId = SelfChainId;
708
709 fn get_endpoint_handler(endpoint: &Endpoint) -> Option<Box<dyn EndpointHandlerT<MessageId>>> {
710 if endpoint == &Endpoint::Id(TransporterEndpointId::get()) {
711 Some(Box::new(EndpointHandler(PhantomData::<Runtime>)))
712 } else {
713 None
714 }
715 }
716
717 type Currency = Balances;
718 type WeightInfo = pallet_messenger::weights::SubstrateWeight<Runtime>;
719 type WeightToFee = ConstantMultiplier<Balance, TransactionWeightFee>;
720 type AdjustedWeightToFee = XdmAdjustedWeightToFee<Runtime>;
721 type FeeMultiplier = XdmFeeMultipler;
722 type OnXDMRewards = OnXDMRewards;
723 type MmrHash = mmr::Hash;
724 type MmrProofVerifier = MmrProofVerifier;
725 type StorageKeys = StorageKeys;
726 type DomainOwner = Domains;
727 type HoldIdentifier = HoldIdentifierWrapper;
728 type ChannelReserveFee = ChannelReserveFee;
729 type ChannelInitReservePortion = ChannelInitReservePortion;
730 type DomainRegistration = DomainRegistration;
731 type ChannelFeeModel = ChannelFeeModel;
732 type MaxOutgoingMessages = MaxOutgoingMessages;
733 type MessengerOrigin = pallet_messenger::EnsureMessengerOrigin;
734 type MessageVersion = MessageVersion;
735 type NoteChainTransfer = Transporter;
736}
737
738impl<C> frame_system::offchain::CreateTransactionBase<C> for Runtime
739where
740 RuntimeCall: From<C>,
741{
742 type Extrinsic = UncheckedExtrinsic;
743 type RuntimeCall = RuntimeCall;
744}
745
746impl<C> subspace_runtime_primitives::CreateUnsigned<C> for Runtime
747where
748 RuntimeCall: From<C>,
749{
750 fn create_unsigned(call: Self::RuntimeCall) -> Self::Extrinsic {
751 create_unsigned_general_extrinsic(call)
752 }
753}
754
755parameter_types! {
756 pub const TransporterEndpointId: EndpointId = 1;
757}
758
759impl pallet_transporter::Config for Runtime {
760 type RuntimeEvent = RuntimeEvent;
761 type SelfChainId = SelfChainId;
762 type SelfEndpointId = TransporterEndpointId;
763 type Currency = Balances;
764 type Sender = Messenger;
765 type AccountIdConverter = AccountIdConverter;
766 type WeightInfo = pallet_transporter::weights::SubstrateWeight<Runtime>;
767}
768
769parameter_types! {
770 pub const MaximumReceiptDrift: BlockNumber = 2;
771 pub const InitialDomainTxRange: u64 = INITIAL_DOMAIN_TX_RANGE;
772 pub const DomainTxRangeAdjustmentInterval: u64 = 100;
773 pub const MinOperatorStake: Balance = 100 * SSC;
774 pub const MinNominatorStake: Balance = SSC;
775 pub MaxDomainBlockSize: u32 = NORMAL_DISPATCH_RATIO * MAX_BLOCK_LENGTH;
777 pub MaxDomainBlockWeight: Weight = NORMAL_DISPATCH_RATIO * BLOCK_WEIGHT_FOR_2_SEC;
779 pub const DomainInstantiationDeposit: Balance = 100 * SSC;
780 pub const MaxDomainNameLength: u32 = 32;
781 pub const BlockTreePruningDepth: u32 = DOMAINS_BLOCK_PRUNING_DEPTH;
782 pub const StakeWithdrawalLockingPeriod: BlockNumber = 20;
783 pub const StakeEpochDuration: DomainNumber = 5;
784 pub TreasuryAccount: AccountId = PalletId(*b"treasury").into_account_truncating();
785 pub const MaxPendingStakingOperation: u32 = 512;
786 pub const DomainsPalletId: PalletId = PalletId(*b"domains_");
787 pub const MaxInitialDomainAccounts: u32 = 20;
788 pub const MinInitialDomainAccountBalance: Balance = SSC;
789 pub const BundleLongevity: u32 = 5;
790 pub const WithdrawalLimit: u32 = 32;
791}
792
793const_assert!(BlockSlotCount::get() >= 2 && BlockSlotCount::get() > BundleLongevity::get());
796
797const_assert!(BlockHashCount::get() > BlockSlotCount::get());
800
801const_assert!(MinOperatorStake::get() >= MinNominatorStake::get());
803
804pub struct BlockSlot;
805
806impl pallet_domains::BlockSlot<Runtime> for BlockSlot {
807 fn future_slot(block_number: BlockNumber) -> Option<Slot> {
808 let block_slots = Subspace::block_slots();
809 block_slots
810 .get(&block_number)
811 .map(|slot| *slot + Slot::from(BlockAuthoringDelay::get()))
812 }
813
814 fn slot_produced_after(to_check: Slot) -> Option<BlockNumber> {
815 let block_slots = Subspace::block_slots();
816 for (block_number, slot) in block_slots.into_iter().rev() {
817 if to_check > slot {
818 return Some(block_number);
819 }
820 }
821 None
822 }
823}
824
825pub struct OnChainRewards;
826
827impl sp_domains::OnChainRewards<Balance> for OnChainRewards {
828 fn on_chain_rewards(chain_id: ChainId, reward: Balance) {
829 match chain_id {
830 ChainId::Consensus => {
831 if let Some(block_author) = Subspace::find_block_reward_address() {
832 let _ = Balances::deposit_creating(&block_author, reward);
833 }
834 }
835 ChainId::Domain(domain_id) => Domains::reward_domain_operators(
836 domain_id,
837 OperatorRewardSource::XDMProtocolFees,
838 reward,
839 ),
840 }
841 }
842}
843
844impl pallet_domains::Config for Runtime {
845 type RuntimeEvent = RuntimeEvent;
846 type DomainOrigin = pallet_domains::EnsureDomainOrigin;
847 type DomainHash = DomainHash;
848 type Balance = Balance;
849 type DomainHeader = DomainHeader;
850 type ConfirmationDepthK = ConfirmationDepthK;
851 type Currency = Balances;
852 type Share = Balance;
853 type HoldIdentifier = HoldIdentifierWrapper;
854 type BlockTreePruningDepth = BlockTreePruningDepth;
855 type ConsensusSlotProbability = SlotProbability;
856 type MaxDomainBlockSize = MaxDomainBlockSize;
857 type MaxDomainBlockWeight = MaxDomainBlockWeight;
858 type MaxDomainNameLength = MaxDomainNameLength;
859 type DomainInstantiationDeposit = DomainInstantiationDeposit;
860 type WeightInfo = pallet_domains::weights::SubstrateWeight<Runtime>;
861 type InitialDomainTxRange = InitialDomainTxRange;
862 type DomainTxRangeAdjustmentInterval = DomainTxRangeAdjustmentInterval;
863 type MinOperatorStake = MinOperatorStake;
864 type MinNominatorStake = MinNominatorStake;
865 type StakeWithdrawalLockingPeriod = StakeWithdrawalLockingPeriod;
866 type StakeEpochDuration = StakeEpochDuration;
867 type TreasuryAccount = TreasuryAccount;
868 type MaxPendingStakingOperation = MaxPendingStakingOperation;
869 type Randomness = Subspace;
870 type PalletId = DomainsPalletId;
871 type StorageFee = TransactionFees;
872 type BlockTimestamp = pallet_timestamp::Pallet<Runtime>;
873 type BlockSlot = BlockSlot;
874 type DomainsTransfersTracker = Transporter;
875 type MaxInitialDomainAccounts = MaxInitialDomainAccounts;
876 type MinInitialDomainAccountBalance = MinInitialDomainAccountBalance;
877 type BundleLongevity = BundleLongevity;
878 type DomainBundleSubmitted = Messenger;
879 type OnDomainInstantiated = Messenger;
880 type MmrHash = mmr::Hash;
881 type MmrProofVerifier = MmrProofVerifier;
882 type FraudProofStorageKeyProvider = StorageKeyProvider;
883 type OnChainRewards = OnChainRewards;
884 type WithdrawalLimit = WithdrawalLimit;
885}
886
887parameter_types! {
888 pub const AvgBlockspaceUsageNumBlocks: BlockNumber = 100;
889 pub const ProposerTaxOnVotes: (u32, u32) = (1, 10);
890}
891
892impl pallet_rewards::Config for Runtime {
893 type RuntimeEvent = RuntimeEvent;
894 type Currency = Balances;
895 type AvgBlockspaceUsageNumBlocks = AvgBlockspaceUsageNumBlocks;
896 type TransactionByteFee = TransactionByteFee;
897 type MaxRewardPoints = ConstU32<20>;
898 type ProposerTaxOnVotes = ProposerTaxOnVotes;
899 type RewardsEnabled = Subspace;
900 type FindBlockRewardAddress = Subspace;
901 type FindVotingRewardAddresses = Subspace;
902 type WeightInfo = pallet_rewards::weights::SubstrateWeight<Runtime>;
903 type OnReward = ();
904}
905
906mod mmr {
907 use super::Runtime;
908 pub use pallet_mmr::primitives::*;
909
910 pub type Leaf = <<Runtime as pallet_mmr::Config>::LeafData as LeafDataProvider>::LeafData;
911 pub type Hashing = <Runtime as pallet_mmr::Config>::Hashing;
912 pub type Hash = <Hashing as sp_runtime::traits::Hash>::Output;
913}
914
915pub struct BlockHashProvider;
916
917impl pallet_mmr::BlockHashProvider<BlockNumber, Hash> for BlockHashProvider {
918 fn block_hash(block_number: BlockNumber) -> Hash {
919 sp_subspace_mmr::subspace_mmr_runtime_interface::consensus_block_hash(block_number)
920 .expect("Hash must exist for a given block number.")
921 }
922}
923
924impl pallet_mmr::Config for Runtime {
925 const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX;
926 type Hashing = Keccak256;
927 type LeafData = SubspaceMmr;
928 type OnNewRoot = SubspaceMmr;
929 type BlockHashProvider = BlockHashProvider;
930 type WeightInfo = ();
931 #[cfg(feature = "runtime-benchmarks")]
932 type BenchmarkHelper = ();
933}
934
935parameter_types! {
936 pub const MmrRootHashCount: u32 = 15;
937}
938
939impl pallet_subspace_mmr::Config for Runtime {
940 type MmrRootHash = mmr::Hash;
941 type MmrRootHashCount = MmrRootHashCount;
942}
943
944impl pallet_runtime_configs::Config for Runtime {
945 type WeightInfo = pallet_runtime_configs::weights::SubstrateWeight<Runtime>;
946}
947
948parameter_types! {
949 pub const MaxSignatories: u32 = 100;
950}
951
952macro_rules! deposit {
953 ($name:ident, $item_fee:expr, $items:expr, $bytes:expr) => {
954 pub struct $name;
955
956 impl Get<Balance> for $name {
957 fn get() -> Balance {
958 $item_fee.saturating_mul($items.into()).saturating_add(
959 TransactionFees::transaction_byte_fee().saturating_mul($bytes.into()),
960 )
961 }
962 }
963 };
964}
965
966deposit!(DepositBaseFee, 20 * SSC, 1u32, 88u32);
969
970deposit!(DepositFactor, 0u128, 0u32, 32u32);
972
973impl pallet_multisig::Config for Runtime {
974 type RuntimeEvent = RuntimeEvent;
975 type RuntimeCall = RuntimeCall;
976 type Currency = Balances;
977 type DepositBase = DepositBaseFee;
978 type DepositFactor = DepositFactor;
979 type MaxSignatories = MaxSignatories;
980 type WeightInfo = pallet_multisig::weights::SubstrateWeight<Runtime>;
981}
982
983construct_runtime!(
984 pub struct Runtime {
985 System: frame_system = 0,
986 Timestamp: pallet_timestamp = 1,
987
988 Subspace: pallet_subspace = 2,
989 Rewards: pallet_rewards = 9,
990
991 Balances: pallet_balances = 4,
992 TransactionFees: pallet_transaction_fees = 12,
993 TransactionPayment: pallet_transaction_payment = 5,
994 Utility: pallet_utility = 8,
995
996 Domains: pallet_domains = 11,
997 RuntimeConfigs: pallet_runtime_configs = 14,
998
999 Mmr: pallet_mmr = 30,
1000 SubspaceMmr: pallet_subspace_mmr = 31,
1001
1002 Messenger: pallet_messenger exclude_parts { Inherent } = 60,
1005 Transporter: pallet_transporter = 61,
1006
1007 Multisig: pallet_multisig = 90,
1009
1010 Sudo: pallet_sudo = 100,
1012 }
1013);
1014
1015pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
1017pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
1019pub type Block = generic::Block<Header, UncheckedExtrinsic>;
1021pub type SignedExtra = (
1023 frame_system::CheckNonZeroSender<Runtime>,
1024 frame_system::CheckSpecVersion<Runtime>,
1025 frame_system::CheckTxVersion<Runtime>,
1026 frame_system::CheckGenesis<Runtime>,
1027 frame_system::CheckMortality<Runtime>,
1028 frame_system::CheckNonce<Runtime>,
1029 frame_system::CheckWeight<Runtime>,
1030 pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
1031 DisablePallets,
1032 pallet_subspace::extensions::SubspaceExtension<Runtime>,
1033 pallet_domains::extensions::DomainsExtension<Runtime>,
1034 pallet_messenger::extensions::MessengerExtension<Runtime>,
1035);
1036pub type UncheckedExtrinsic =
1038 generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
1039pub type Executive = frame_executive::Executive<
1041 Runtime,
1042 Block,
1043 frame_system::ChainContext<Runtime>,
1044 Runtime,
1045 AllPalletsWithSystem,
1046>;
1047pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
1049
1050impl pallet_subspace::extensions::MaybeSubspaceCall<Runtime> for RuntimeCall {
1051 fn maybe_subspace_call(&self) -> Option<&pallet_subspace::Call<Runtime>> {
1052 match self {
1053 RuntimeCall::Subspace(call) => Some(call),
1054 _ => None,
1055 }
1056 }
1057}
1058
1059impl pallet_domains::extensions::MaybeDomainsCall<Runtime> for RuntimeCall {
1060 fn maybe_domains_call(&self) -> Option<&pallet_domains::Call<Runtime>> {
1061 match self {
1062 RuntimeCall::Domains(call) => Some(call),
1063 _ => None,
1064 }
1065 }
1066}
1067
1068impl pallet_messenger::extensions::MaybeMessengerCall<Runtime> for RuntimeCall {
1069 fn maybe_messenger_call(&self) -> Option<&pallet_messenger::Call<Runtime>> {
1070 match self {
1071 RuntimeCall::Messenger(call) => Some(call),
1072 _ => None,
1073 }
1074 }
1075}
1076
1077fn extract_segment_headers(ext: &UncheckedExtrinsic) -> Option<Vec<SegmentHeader>> {
1078 match &ext.function {
1079 RuntimeCall::Subspace(pallet_subspace::Call::store_segment_headers { segment_headers }) => {
1080 Some(segment_headers.clone())
1081 }
1082 _ => None,
1083 }
1084}
1085
1086fn is_xdm_mmr_proof_valid(ext: &<Block as BlockT>::Extrinsic) -> Option<bool> {
1087 match &ext.function {
1088 RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })
1089 | RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1090 let ConsensusChainMmrLeafProof {
1091 consensus_block_number,
1092 opaque_mmr_leaf,
1093 proof,
1094 ..
1095 } = msg.proof.consensus_mmr_proof();
1096
1097 let mmr_root = SubspaceMmr::mmr_root_hash(consensus_block_number)?;
1098
1099 Some(
1100 pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(
1101 mmr_root,
1102 vec![mmr::DataOrHash::Data(
1103 EncodableOpaqueLeaf(opaque_mmr_leaf.0.clone()).into_opaque_leaf(),
1104 )],
1105 proof,
1106 )
1107 .is_ok(),
1108 )
1109 }
1110 _ => None,
1111 }
1112}
1113
1114fn extract_utility_block_object_mapping(
1116 mut base_offset: u32,
1117 objects: &mut Vec<BlockObject>,
1118 call: &pallet_utility::Call<Runtime>,
1119 mut recursion_depth_left: u16,
1120) {
1121 if recursion_depth_left == 0 {
1122 return;
1123 }
1124
1125 recursion_depth_left -= 1;
1126
1127 base_offset += 1;
1129
1130 match call {
1131 pallet_utility::Call::batch { calls }
1132 | pallet_utility::Call::batch_all { calls }
1133 | pallet_utility::Call::force_batch { calls } => {
1134 base_offset += Compact::compact_len(&(calls.len() as u32)) as u32;
1135
1136 for call in calls {
1137 extract_call_block_object_mapping(base_offset, objects, call, recursion_depth_left);
1138
1139 base_offset += call.encoded_size() as u32;
1140 }
1141 }
1142 pallet_utility::Call::as_derivative { index, call } => {
1143 base_offset += index.encoded_size() as u32;
1144
1145 extract_call_block_object_mapping(
1146 base_offset,
1147 objects,
1148 call.as_ref(),
1149 recursion_depth_left,
1150 );
1151 }
1152 pallet_utility::Call::dispatch_as { as_origin, call } => {
1153 base_offset += as_origin.encoded_size() as u32;
1154
1155 extract_call_block_object_mapping(
1156 base_offset,
1157 objects,
1158 call.as_ref(),
1159 recursion_depth_left,
1160 );
1161 }
1162 pallet_utility::Call::with_weight { call, .. } => {
1163 extract_call_block_object_mapping(
1164 base_offset,
1165 objects,
1166 call.as_ref(),
1167 recursion_depth_left,
1168 );
1169 }
1170 pallet_utility::Call::__Ignore(_, _) => {
1171 }
1173 }
1174}
1175
1176fn extract_call_block_object_mapping(
1177 mut base_offset: u32,
1178 objects: &mut Vec<BlockObject>,
1179 call: &RuntimeCall,
1180 recursion_depth_left: u16,
1181) {
1182 base_offset += 1;
1184
1185 match call {
1186 RuntimeCall::System(frame_system::Call::remark { remark }) => {
1188 objects.push(BlockObject {
1189 hash: hashes::blake3_hash(remark),
1190 offset: base_offset + 1,
1192 });
1193 }
1194 RuntimeCall::System(frame_system::Call::remark_with_event { remark }) => {
1195 objects.push(BlockObject {
1196 hash: hashes::blake3_hash(remark),
1197 offset: base_offset + 1,
1199 });
1200 }
1201
1202 RuntimeCall::Utility(call) => {
1204 extract_utility_block_object_mapping(base_offset, objects, call, recursion_depth_left)
1205 }
1206 _ => {}
1208 }
1209}
1210
1211fn extract_block_object_mapping(block: Block) -> BlockObjectMapping {
1212 let mut block_object_mapping = BlockObjectMapping::default();
1213 let mut base_offset =
1214 block.header.encoded_size() + Compact::compact_len(&(block.extrinsics.len() as u32));
1215 for extrinsic in block.extrinsics {
1216 let preamble_size = extrinsic.preamble.encoded_size();
1217 let base_extrinsic_offset = base_offset
1220 + Compact::compact_len(&((preamble_size + extrinsic.function.encoded_size()) as u32))
1221 + preamble_size;
1222
1223 extract_call_block_object_mapping(
1224 base_extrinsic_offset as u32,
1225 block_object_mapping.objects_mut(),
1226 &extrinsic.function,
1227 MAX_CALL_RECURSION_DEPTH as u16,
1228 );
1229
1230 base_offset += extrinsic.encoded_size();
1231 }
1232
1233 block_object_mapping
1234}
1235
1236fn extract_successful_bundles(
1237 domain_id: DomainId,
1238 extrinsics: Vec<UncheckedExtrinsic>,
1239) -> OpaqueBundles<Block, DomainHeader, Balance> {
1240 let successful_bundles = Domains::successful_bundles(domain_id);
1241 extrinsics
1242 .into_iter()
1243 .filter_map(|uxt| match uxt.function {
1244 RuntimeCall::Domains(pallet_domains::Call::submit_bundle { opaque_bundle })
1245 if opaque_bundle.domain_id() == domain_id
1246 && successful_bundles.contains(&opaque_bundle.hash()) =>
1247 {
1248 Some(opaque_bundle)
1249 }
1250 _ => None,
1251 })
1252 .collect()
1253}
1254
1255fn create_unsigned_general_extrinsic(call: RuntimeCall) -> UncheckedExtrinsic {
1256 let extra: SignedExtra = (
1257 frame_system::CheckNonZeroSender::<Runtime>::new(),
1258 frame_system::CheckSpecVersion::<Runtime>::new(),
1259 frame_system::CheckTxVersion::<Runtime>::new(),
1260 frame_system::CheckGenesis::<Runtime>::new(),
1261 frame_system::CheckMortality::<Runtime>::from(generic::Era::Immortal),
1262 frame_system::CheckNonce::<Runtime>::from(0u32.into()),
1265 frame_system::CheckWeight::<Runtime>::new(),
1266 pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(0u128),
1269 DisablePallets,
1270 pallet_subspace::extensions::SubspaceExtension::<Runtime>::new(),
1271 pallet_domains::extensions::DomainsExtension::<Runtime>::new(),
1272 pallet_messenger::extensions::MessengerExtension::<Runtime>::new(),
1273 );
1274
1275 UncheckedExtrinsic::new_transaction(call, extra)
1276}
1277
1278struct RewardAddress([u8; 32]);
1279
1280impl From<PublicKey> for RewardAddress {
1281 #[inline]
1282 fn from(public_key: PublicKey) -> Self {
1283 Self(*public_key)
1284 }
1285}
1286
1287impl From<RewardAddress> for AccountId32 {
1288 #[inline]
1289 fn from(reward_address: RewardAddress) -> Self {
1290 reward_address.0.into()
1291 }
1292}
1293
1294pub struct StorageKeyProvider;
1295impl FraudProofStorageKeyProvider<NumberFor<Block>> for StorageKeyProvider {
1296 fn storage_key(req: FraudProofStorageKeyRequest<NumberFor<Block>>) -> Vec<u8> {
1297 match req {
1298 FraudProofStorageKeyRequest::InvalidInherentExtrinsicData => {
1299 pallet_domains::BlockInherentExtrinsicData::<Runtime>::hashed_key().to_vec()
1300 }
1301 FraudProofStorageKeyRequest::SuccessfulBundles(domain_id) => {
1302 pallet_domains::SuccessfulBundles::<Runtime>::hashed_key_for(domain_id)
1303 }
1304 FraudProofStorageKeyRequest::DomainAllowlistUpdates(domain_id) => {
1305 Messenger::domain_allow_list_update_storage_key(domain_id)
1306 }
1307 FraudProofStorageKeyRequest::DomainRuntimeUpgrades => {
1308 pallet_domains::DomainRuntimeUpgrades::<Runtime>::hashed_key().to_vec()
1309 }
1310 FraudProofStorageKeyRequest::RuntimeRegistry(runtime_id) => {
1311 pallet_domains::RuntimeRegistry::<Runtime>::hashed_key_for(runtime_id)
1312 }
1313 FraudProofStorageKeyRequest::DomainSudoCall(domain_id) => {
1314 pallet_domains::DomainSudoCalls::<Runtime>::hashed_key_for(domain_id)
1315 }
1316 FraudProofStorageKeyRequest::EvmDomainContractCreationAllowedByCall(domain_id) => {
1317 pallet_domains::EvmDomainContractCreationAllowedByCalls::<Runtime>::hashed_key_for(
1318 domain_id,
1319 )
1320 }
1321 FraudProofStorageKeyRequest::MmrRoot(block_number) => {
1322 pallet_subspace_mmr::MmrRootHashes::<Runtime>::hashed_key_for(block_number)
1323 }
1324 }
1325 }
1326}
1327
1328impl_runtime_apis! {
1329 impl sp_api::Core<Block> for Runtime {
1330 fn version() -> RuntimeVersion {
1331 VERSION
1332 }
1333
1334 fn execute_block(block: Block) {
1335 Executive::execute_block(block);
1336 }
1337
1338 fn initialize_block(header: &<Block as BlockT>::Header) -> ExtrinsicInclusionMode {
1339 Executive::initialize_block(header)
1340 }
1341 }
1342
1343 impl sp_api::Metadata<Block> for Runtime {
1344 fn metadata() -> OpaqueMetadata {
1345 OpaqueMetadata::new(Runtime::metadata().into())
1346 }
1347
1348 fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
1349 Runtime::metadata_at_version(version)
1350 }
1351
1352 fn metadata_versions() -> Vec<u32> {
1353 Runtime::metadata_versions()
1354 }
1355 }
1356
1357 impl sp_block_builder::BlockBuilder<Block> for Runtime {
1358 fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
1359 Executive::apply_extrinsic(extrinsic)
1360 }
1361
1362 fn finalize_block() -> <Block as BlockT>::Header {
1363 Executive::finalize_block()
1364 }
1365
1366 fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
1367 data.create_extrinsics()
1368 }
1369
1370 fn check_inherents(
1371 block: Block,
1372 data: sp_inherents::InherentData,
1373 ) -> sp_inherents::CheckInherentsResult {
1374 data.check_extrinsics(&block)
1375 }
1376 }
1377
1378 impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
1379 fn validate_transaction(
1380 source: TransactionSource,
1381 tx: <Block as BlockT>::Extrinsic,
1382 block_hash: <Block as BlockT>::Hash,
1383 ) -> TransactionValidity {
1384 Executive::validate_transaction(source, tx, block_hash)
1385 }
1386 }
1387
1388 impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
1389 fn offchain_worker(header: &<Block as BlockT>::Header) {
1390 Executive::offchain_worker(header)
1391 }
1392 }
1393
1394 impl sp_objects::ObjectsApi<Block> for Runtime {
1395 fn extract_block_object_mapping(block: Block) -> BlockObjectMapping {
1396 extract_block_object_mapping(block)
1397 }
1398 }
1399
1400 impl sp_consensus_subspace::SubspaceApi<Block, PublicKey> for Runtime {
1401 fn pot_parameters() -> PotParameters {
1402 Subspace::pot_parameters()
1403 }
1404
1405 fn solution_ranges() -> SolutionRanges {
1406 Subspace::solution_ranges()
1407 }
1408
1409 fn submit_vote_extrinsic(
1410 signed_vote: SignedVote<NumberFor<Block>, <Block as BlockT>::Hash, PublicKey>,
1411 ) {
1412 let SignedVote { vote, signature } = signed_vote;
1413 let Vote::V0 {
1414 height,
1415 parent_hash,
1416 slot,
1417 solution,
1418 proof_of_time,
1419 future_proof_of_time,
1420 } = vote;
1421
1422 Subspace::submit_vote(SignedVote {
1423 vote: Vote::V0 {
1424 height,
1425 parent_hash,
1426 slot,
1427 solution: solution.into_reward_address_format::<RewardAddress, AccountId32>(),
1428 proof_of_time,
1429 future_proof_of_time,
1430 },
1431 signature,
1432 })
1433 }
1434
1435 fn history_size() -> HistorySize {
1436 <pallet_subspace::Pallet<Runtime>>::history_size()
1437 }
1438
1439 fn max_pieces_in_sector() -> u16 {
1440 MAX_PIECES_IN_SECTOR
1441 }
1442
1443 fn segment_commitment(segment_index: SegmentIndex) -> Option<SegmentCommitment> {
1444 Subspace::segment_commitment(segment_index)
1445 }
1446
1447 fn extract_segment_headers(ext: &<Block as BlockT>::Extrinsic) -> Option<Vec<SegmentHeader >> {
1448 extract_segment_headers(ext)
1449 }
1450
1451 fn is_inherent(ext: &<Block as BlockT>::Extrinsic) -> bool {
1452 match &ext.function {
1453 RuntimeCall::Subspace(call) => Subspace::is_inherent(call),
1454 RuntimeCall::Timestamp(call) => Timestamp::is_inherent(call),
1455 _ => false,
1456 }
1457 }
1458
1459 fn root_plot_public_key() -> Option<PublicKey> {
1460 Subspace::root_plot_public_key()
1461 }
1462
1463 fn should_adjust_solution_range() -> bool {
1464 Subspace::should_adjust_solution_range()
1465 }
1466
1467 fn chain_constants() -> ChainConstants {
1468 ChainConstants::V0 {
1469 confirmation_depth_k: ConfirmationDepthK::get(),
1470 block_authoring_delay: Slot::from(BlockAuthoringDelay::get()),
1471 era_duration: EraDuration::get(),
1472 slot_probability: SlotProbability::get(),
1473 slot_duration: SlotDuration::from_millis(SLOT_DURATION),
1474 recent_segments: RecentSegments::get(),
1475 recent_history_fraction: RecentHistoryFraction::get(),
1476 min_sector_lifetime: MinSectorLifetime::get(),
1477 }
1478 }
1479 }
1480
1481 impl sp_domains::DomainsApi<Block, DomainHeader> for Runtime {
1482 fn submit_bundle_unsigned(
1483 opaque_bundle: OpaqueBundle<NumberFor<Block>, <Block as BlockT>::Hash, DomainHeader, Balance>,
1484 ) {
1485 Domains::submit_bundle_unsigned(opaque_bundle)
1486 }
1487
1488 fn submit_receipt_unsigned(
1489 singleton_receipt: sp_domains::SealedSingletonReceipt<NumberFor<Block>, <Block as BlockT>::Hash, DomainHeader, Balance>,
1490 ) {
1491 Domains::submit_receipt_unsigned(singleton_receipt)
1492 }
1493
1494 fn extract_successful_bundles(
1495 domain_id: DomainId,
1496 extrinsics: Vec<<Block as BlockT>::Extrinsic>,
1497 ) -> OpaqueBundles<Block, DomainHeader, Balance> {
1498 extract_successful_bundles(domain_id, extrinsics)
1499 }
1500
1501 fn extrinsics_shuffling_seed() -> Randomness {
1502 Randomness::from(Domains::extrinsics_shuffling_seed().to_fixed_bytes())
1503 }
1504
1505 fn domain_runtime_code(domain_id: DomainId) -> Option<Vec<u8>> {
1506 Domains::domain_runtime_code(domain_id)
1507 }
1508
1509 fn runtime_id(domain_id: DomainId) -> Option<sp_domains::RuntimeId> {
1510 Domains::runtime_id(domain_id)
1511 }
1512
1513 fn runtime_upgrades() -> Vec<sp_domains::RuntimeId> {
1514 Domains::runtime_upgrades()
1515 }
1516
1517 fn domain_instance_data(domain_id: DomainId) -> Option<(DomainInstanceData, NumberFor<Block>)> {
1518 Domains::domain_instance_data(domain_id)
1519 }
1520
1521 fn domain_timestamp() -> Moment {
1522 Domains::timestamp()
1523 }
1524
1525 fn timestamp() -> Moment {
1526 Timestamp::now()
1527 }
1528
1529 fn consensus_transaction_byte_fee() -> Balance {
1530 Domains::consensus_transaction_byte_fee()
1531 }
1532
1533 fn consensus_chain_byte_fee() -> Balance {
1534 DOMAIN_STORAGE_FEE_MULTIPLIER * TransactionFees::transaction_byte_fee()
1535 }
1536
1537 fn domain_tx_range(_: DomainId) -> U256 {
1538 U256::MAX
1539 }
1540
1541 fn genesis_state_root(domain_id: DomainId) -> Option<H256> {
1542 Domains::genesis_state_root(domain_id)
1543 }
1544
1545 fn head_receipt_number(domain_id: DomainId) -> DomainNumber {
1546 Domains::head_receipt_number(domain_id)
1547 }
1548
1549 fn oldest_unconfirmed_receipt_number(domain_id: DomainId) -> Option<DomainNumber> {
1550 Domains::oldest_unconfirmed_receipt_number(domain_id)
1551 }
1552
1553 fn domain_bundle_limit(domain_id: DomainId) -> Option<sp_domains::DomainBundleLimit> {
1554 Domains::domain_bundle_limit(domain_id).ok().flatten()
1555 }
1556
1557 fn non_empty_er_exists(domain_id: DomainId) -> bool {
1558 Domains::non_empty_er_exists(domain_id)
1559 }
1560
1561 fn domain_best_number(domain_id: DomainId) -> Option<DomainNumber> {
1562 Domains::domain_best_number(domain_id).ok()
1563 }
1564
1565 fn execution_receipt(receipt_hash: DomainHash) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>> {
1566 Domains::execution_receipt(receipt_hash)
1567 }
1568
1569 fn domain_operators(domain_id: DomainId) -> Option<(BTreeMap<OperatorId, Balance>, Vec<OperatorId>)> {
1570 Domains::domain_staking_summary(domain_id).map(|summary| {
1571 let next_operators = summary.next_operators.into_iter().collect();
1572 (summary.current_operators, next_operators)
1573 })
1574 }
1575
1576 fn receipt_hash(domain_id: DomainId, domain_number: DomainNumber) -> Option<DomainHash> {
1577 Domains::receipt_hash(domain_id, domain_number)
1578 }
1579
1580 fn latest_confirmed_domain_block(domain_id: DomainId) -> Option<(DomainNumber, DomainHash)>{
1581 Domains::latest_confirmed_domain_block(domain_id)
1582 }
1583
1584 fn is_bad_er_pending_to_prune(domain_id: DomainId, receipt_hash: DomainHash) -> bool {
1585 Domains::execution_receipt(receipt_hash).map(
1586 |er| Domains::is_bad_er_pending_to_prune(domain_id, er.domain_block_number)
1587 )
1588 .unwrap_or(false)
1589 }
1590
1591 fn storage_fund_account_balance(operator_id: OperatorId) -> Balance {
1592 Domains::storage_fund_account_balance(operator_id)
1593 }
1594
1595 fn is_domain_runtime_upgraded_since(domain_id: DomainId, at: NumberFor<Block>) -> Option<bool> {
1596 Domains::is_domain_runtime_upgraded_since(domain_id, at)
1597 }
1598
1599 fn domain_sudo_call(domain_id: DomainId) -> Option<Vec<u8>> {
1600 Domains::domain_sudo_call(domain_id)
1601 }
1602
1603 fn evm_domain_contract_creation_allowed_by_call(domain_id: DomainId) -> Option<PermissionedActionAllowedBy<EthereumAccountId>> {
1604 Domains::evm_domain_contract_creation_allowed_by_call(domain_id)
1605 }
1606
1607 fn last_confirmed_domain_block_receipt(domain_id: DomainId) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>{
1608 Domains::latest_confirmed_domain_execution_receipt(domain_id)
1609 }
1610 }
1611
1612 impl sp_domains::BundleProducerElectionApi<Block, Balance> for Runtime {
1613 fn bundle_producer_election_params(domain_id: DomainId) -> Option<BundleProducerElectionParams<Balance>> {
1614 Domains::bundle_producer_election_params(domain_id)
1615 }
1616
1617 fn operator(operator_id: OperatorId) -> Option<(OperatorPublicKey, Balance)> {
1618 Domains::operator(operator_id)
1619 }
1620 }
1621
1622 impl sp_session::SessionKeys<Block> for Runtime {
1623 fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
1624 SessionKeys::generate(seed)
1625 }
1626
1627 fn decode_session_keys(
1628 encoded: Vec<u8>,
1629 ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
1630 SessionKeys::decode_into_raw_public_keys(&encoded)
1631 }
1632 }
1633
1634 impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
1635 fn account_nonce(account: AccountId) -> Nonce {
1636 *System::account_nonce(account)
1637 }
1638 }
1639
1640 impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
1641 fn query_info(
1642 uxt: <Block as BlockT>::Extrinsic,
1643 len: u32,
1644 ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
1645 TransactionPayment::query_info(uxt, len)
1646 }
1647 fn query_fee_details(
1648 uxt: <Block as BlockT>::Extrinsic,
1649 len: u32,
1650 ) -> pallet_transaction_payment::FeeDetails<Balance> {
1651 TransactionPayment::query_fee_details(uxt, len)
1652 }
1653 fn query_weight_to_fee(weight: Weight) -> Balance {
1654 TransactionPayment::weight_to_fee(weight)
1655 }
1656 fn query_length_to_fee(length: u32) -> Balance {
1657 TransactionPayment::length_to_fee(length)
1658 }
1659 }
1660
1661 impl sp_messenger::MessengerApi<Block, BlockNumber, <Block as BlockT>::Hash> for Runtime {
1662 fn is_xdm_mmr_proof_valid(
1663 extrinsic: &<Block as BlockT>::Extrinsic
1664 ) -> Option<bool> {
1665 is_xdm_mmr_proof_valid(extrinsic)
1666 }
1667
1668 fn extract_xdm_mmr_proof(ext: &<Block as BlockT>::Extrinsic) -> Option<ConsensusChainMmrLeafProof<BlockNumber, <Block as BlockT>::Hash, sp_core::H256>> {
1669 match &ext.function {
1670 RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })
1671 | RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1672 Some(msg.proof.consensus_mmr_proof())
1673 }
1674 _ => None,
1675 }
1676 }
1677
1678 fn confirmed_domain_block_storage_key(domain_id: DomainId) -> Vec<u8> {
1679 Domains::confirmed_domain_block_storage_key(domain_id)
1680 }
1681
1682 fn outbox_storage_key(message_key: MessageKey) -> Vec<u8> {
1683 Messenger::outbox_storage_key(message_key)
1684 }
1685
1686 fn inbox_response_storage_key(message_key: MessageKey) -> Vec<u8> {
1687 Messenger::inbox_response_storage_key(message_key)
1688 }
1689
1690 fn domain_chains_allowlist_update(domain_id: DomainId) -> Option<DomainAllowlistUpdates>{
1691 Messenger::domain_chains_allowlist_update(domain_id)
1692 }
1693
1694 fn xdm_id(ext: &<Block as BlockT>::Extrinsic) -> Option<XdmId> {
1695 match &ext.function {
1696 RuntimeCall::Messenger(pallet_messenger::Call::relay_message { msg })=> {
1697 Some(XdmId::RelayMessage((msg.src_chain_id, msg.channel_id, msg.nonce)))
1698 }
1699 RuntimeCall::Messenger(pallet_messenger::Call::relay_message_response { msg }) => {
1700 Some(XdmId::RelayResponseMessage((msg.src_chain_id, msg.channel_id, msg.nonce)))
1701 }
1702 _ => None,
1703 }
1704 }
1705
1706 fn channel_nonce(chain_id: ChainId, channel_id: ChannelId) -> Option<ChannelNonce> {
1707 Messenger::channel_nonce(chain_id, channel_id)
1708 }
1709 }
1710
1711 impl sp_messenger::RelayerApi<Block, BlockNumber, BlockNumber, <Block as BlockT>::Hash> for Runtime {
1712 fn block_messages() -> BlockMessagesWithStorageKey {
1713 Messenger::get_block_messages()
1714 }
1715
1716 fn outbox_message_unsigned(msg: CrossDomainMessage<NumberFor<Block>, <Block as BlockT>::Hash, <Block as BlockT>::Hash>) -> Option<<Block as BlockT>::Extrinsic> {
1717 Messenger::outbox_message_unsigned(msg)
1718 }
1719
1720 fn inbox_response_message_unsigned(msg: CrossDomainMessage<NumberFor<Block>, <Block as BlockT>::Hash, <Block as BlockT>::Hash>) -> Option<<Block as BlockT>::Extrinsic> {
1721 Messenger::inbox_response_message_unsigned(msg)
1722 }
1723
1724 fn should_relay_outbox_message(dst_chain_id: ChainId, msg_id: MessageId) -> bool {
1725 Messenger::should_relay_outbox_message(dst_chain_id, msg_id)
1726 }
1727
1728 fn should_relay_inbox_message_response(dst_chain_id: ChainId, msg_id: MessageId) -> bool {
1729 Messenger::should_relay_inbox_message_response(dst_chain_id, msg_id)
1730 }
1731
1732 fn updated_channels() -> BTreeSet<(ChainId, ChannelId)> {
1733 Messenger::updated_channels()
1734 }
1735
1736 fn channel_storage_key(chain_id: ChainId, channel_id: ChannelId) -> Vec<u8> {
1737 Messenger::channel_storage_key(chain_id, channel_id)
1738 }
1739
1740 fn open_channels() -> BTreeSet<(ChainId, ChannelId)> {
1741 Messenger::open_channels()
1742 }
1743 }
1744
1745 impl sp_domains_fraud_proof::FraudProofApi<Block, DomainHeader> for Runtime {
1746 fn submit_fraud_proof_unsigned(fraud_proof: FraudProof<NumberFor<Block>, <Block as BlockT>::Hash, DomainHeader, H256>) {
1747 Domains::submit_fraud_proof_unsigned(fraud_proof)
1748 }
1749
1750 fn fraud_proof_storage_key(req: FraudProofStorageKeyRequest<NumberFor<Block>>) -> Vec<u8> {
1751 <StorageKeyProvider as FraudProofStorageKeyProvider<NumberFor<Block>>>::storage_key(req)
1752 }
1753 }
1754
1755 impl mmr::MmrApi<Block, mmr::Hash, BlockNumber> for Runtime {
1756 fn mmr_root() -> Result<mmr::Hash, mmr::Error> {
1757 Ok(Mmr::mmr_root())
1758 }
1759
1760 fn mmr_leaf_count() -> Result<mmr::LeafIndex, mmr::Error> {
1761 Ok(Mmr::mmr_leaves())
1762 }
1763
1764 fn generate_proof(
1765 block_numbers: Vec<BlockNumber>,
1766 best_known_block_number: Option<BlockNumber>,
1767 ) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::LeafProof<mmr::Hash>), mmr::Error> {
1768 Mmr::generate_proof(block_numbers, best_known_block_number).map(
1769 |(leaves, proof)| {
1770 (
1771 leaves
1772 .into_iter()
1773 .map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf))
1774 .collect(),
1775 proof,
1776 )
1777 },
1778 )
1779 }
1780
1781 fn verify_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::LeafProof<mmr::Hash>)
1782 -> Result<(), mmr::Error>
1783 {
1784 let leaves = leaves.into_iter().map(|leaf|
1785 leaf.into_opaque_leaf()
1786 .try_decode()
1787 .ok_or(mmr::Error::Verify)).collect::<Result<Vec<mmr::Leaf>, mmr::Error>>()?;
1788 Mmr::verify_leaves(leaves, proof)
1789 }
1790
1791 fn verify_proof_stateless(
1792 root: mmr::Hash,
1793 leaves: Vec<mmr::EncodableOpaqueLeaf>,
1794 proof: mmr::LeafProof<mmr::Hash>
1795 ) -> Result<(), mmr::Error> {
1796 let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect();
1797 pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(root, nodes, proof)
1798 }
1799 }
1800
1801 impl subspace_test_primitives::OnchainStateApi<Block, AccountId, Balance> for Runtime {
1802 fn free_balance(account_id: AccountId) -> Balance {
1803 Balances::free_balance(account_id)
1804 }
1805
1806 fn get_open_channel_for_chain(dst_chain_id: ChainId) -> Option<ChannelId> {
1807 Messenger::get_open_channel_for_chain(dst_chain_id).map(|(c, _)| c)
1808 }
1809
1810 fn verify_proof_and_extract_leaf(mmr_leaf_proof: ConsensusChainMmrLeafProof<NumberFor<Block>, <Block as BlockT>::Hash, H256>) -> Option<mmr::Leaf> {
1811 <MmrProofVerifier as sp_subspace_mmr::MmrProofVerifier<_, _, _,>>::verify_proof_and_extract_leaf(mmr_leaf_proof)
1812 }
1813
1814 fn domain_balance(domain_id: DomainId) -> Balance {
1815 Transporter::domain_balances(domain_id)
1816 }
1817 }
1818
1819 impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
1820 fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
1821 build_state::<RuntimeGenesisConfig>(config)
1822 }
1823
1824 fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
1825 get_preset::<RuntimeGenesisConfig>(id, |_| None)
1826 }
1827
1828 fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
1829 vec![]
1830 }
1831 }
1832}
1833
1834#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, Default, TypeInfo)]
1836pub struct DisablePallets;
1837
1838impl DisablePallets {
1839 fn do_validate_unsigned(call: &RuntimeCall) -> TransactionValidity {
1840 if matches!(call, RuntimeCall::Domains(_)) && !RuntimeConfigs::enable_domains() {
1841 InvalidTransaction::Call.into()
1842 } else {
1843 Ok(ValidTransaction::default())
1844 }
1845 }
1846
1847 fn do_validate_signed(call: &RuntimeCall) -> TransactionValidity {
1848 if !RuntimeConfigs::enable_balance_transfers() && contains_balance_transfer(call) {
1850 Err(InvalidTransaction::Call.into())
1851 } else {
1852 Ok(ValidTransaction::default())
1853 }
1854 }
1855}
1856
1857impl TransactionExtension<RuntimeCall> for DisablePallets {
1858 const IDENTIFIER: &'static str = "DisablePallets";
1859 type Implicit = ();
1860 type Val = ();
1861 type Pre = ();
1862
1863 fn weight(&self, _call: &RuntimeCall) -> Weight {
1865 <Runtime as frame_system::Config>::DbWeight::get().reads(1)
1867 }
1868
1869 fn validate(
1870 &self,
1871 origin: OriginFor<Runtime>,
1872 call: &RuntimeCallFor<Runtime>,
1873 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
1874 _len: usize,
1875 _self_implicit: Self::Implicit,
1876 _inherited_implication: &impl Encode,
1877 _source: TransactionSource,
1878 ) -> ValidateResult<Self::Val, RuntimeCallFor<Runtime>> {
1879 let validity = if origin.as_system_origin_signer().is_some() {
1880 Self::do_validate_signed(call)?
1881 } else {
1882 ValidTransaction::default()
1883 };
1884
1885 Ok((validity, (), origin))
1886 }
1887
1888 impl_tx_ext_default!(RuntimeCallFor<Runtime>; prepare);
1889
1890 fn bare_validate(
1891 call: &RuntimeCallFor<Runtime>,
1892 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
1893 _len: usize,
1894 ) -> TransactionValidity {
1895 Self::do_validate_unsigned(call)
1896 }
1897
1898 fn bare_validate_and_prepare(
1899 call: &RuntimeCallFor<Runtime>,
1900 _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
1901 _len: usize,
1902 ) -> Result<(), TransactionValidityError> {
1903 Self::do_validate_unsigned(call)?;
1904 Ok(())
1905 }
1906}
1907
1908fn contains_balance_transfer(call: &RuntimeCall) -> bool {
1909 for call in nested_call_iter::<Runtime>(call) {
1910 if let RuntimeCall::Balances(
1913 pallet_balances::Call::transfer_allow_death { .. }
1914 | pallet_balances::Call::transfer_keep_alive { .. }
1915 | pallet_balances::Call::transfer_all { .. },
1916 ) = call
1917 {
1918 return true;
1919 }
1920 }
1921
1922 false
1923}
1924
1925#[cfg(test)]
1926mod tests {
1927 use crate::Runtime;
1928 use pallet_domains::bundle_storage_fund::AccountType;
1929 use sp_domains::OperatorId;
1930 use sp_runtime::traits::AccountIdConversion;
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}