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