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