1#![cfg_attr(not(feature = "std"), no_std)]
4
5pub mod bundle_producer_election;
6pub mod core_api;
7pub mod extrinsics;
8pub mod merkle_tree;
9pub mod proof_provider_and_verifier;
10pub mod storage;
11#[cfg(test)]
12mod tests;
13pub mod valued_trie;
14
15#[cfg(not(feature = "std"))]
16extern crate alloc;
17
18use crate::storage::{RawGenesis, StorageKey};
19#[cfg(not(feature = "std"))]
20use alloc::collections::BTreeSet;
21#[cfg(not(feature = "std"))]
22use alloc::string::String;
23#[cfg(not(feature = "std"))]
24use alloc::vec::Vec;
25use bundle_producer_election::{BundleProducerElectionParams, ProofOfElectionError};
26use core::num::ParseIntError;
27use core::ops::{Add, Sub};
28use core::str::FromStr;
29use domain_runtime_primitives::{EthereumAccountId, MultiAccountId};
30use frame_support::storage::storage_prefix;
31use frame_support::{Blake2_128Concat, StorageHasher};
32use hex_literal::hex;
33use parity_scale_codec::{Codec, Decode, Encode, MaxEncodedLen};
34use scale_info::TypeInfo;
35use serde::{Deserialize, Serialize};
36use sp_core::H256;
37use sp_core::crypto::KeyTypeId;
38use sp_core::sr25519::vrf::VrfSignature;
39#[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
40use sp_core::sr25519::vrf::{VrfPreOutput, VrfProof};
41use sp_runtime::generic::OpaqueDigestItemId;
42use sp_runtime::traits::{
43 BlakeTwo256, CheckedAdd, Hash as HashT, Header as HeaderT, NumberFor, Zero,
44};
45use sp_runtime::{Digest, DigestItem, OpaqueExtrinsic, Percent};
46use sp_runtime_interface::pass_by;
47use sp_runtime_interface::pass_by::PassBy;
48use sp_std::collections::btree_map::BTreeMap;
49use sp_std::fmt::{Display, Formatter};
50use sp_trie::TrieLayout;
51use sp_version::RuntimeVersion;
52use sp_weights::Weight;
53#[cfg(feature = "std")]
54use std::collections::BTreeSet;
55use subspace_core_primitives::hashes::{Blake3Hash, blake3_hash};
56use subspace_core_primitives::pot::PotOutput;
57use subspace_core_primitives::solutions::bidirectional_distance;
58use subspace_core_primitives::{Randomness, U256};
59use subspace_runtime_primitives::{Balance, BlockHashFor, Moment};
60
61pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"oper");
63
64pub const DOMAIN_EXTRINSICS_SHUFFLING_SEED_SUBJECT: &[u8] = b"extrinsics-shuffling-seed";
66
67mod app {
68 use super::KEY_TYPE;
69 use sp_application_crypto::{app_crypto, sr25519};
70
71 app_crypto!(sr25519, KEY_TYPE);
72}
73
74pub const DOMAIN_STORAGE_FEE_MULTIPLIER: Balance = 3;
81
82pub type OperatorSignature = app::Signature;
84
85#[cfg(feature = "std")]
88pub type OperatorPair = app::Pair;
89
90pub type OperatorPublicKey = app::Public;
92
93pub struct OperatorKey;
95
96impl sp_runtime::BoundToRuntimeAppPublic for OperatorKey {
97 type Public = OperatorPublicKey;
98}
99
100pub type StakeWeight = u128;
104
105pub type ExtrinsicsRoot = H256;
107
108pub type HeaderHashingFor<Header> = <Header as HeaderT>::Hashing;
110pub type HeaderNumberFor<Header> = <Header as HeaderT>::Number;
112pub type HeaderHashFor<Header> = <Header as HeaderT>::Hash;
114
115#[derive(
117 Clone,
118 Copy,
119 Debug,
120 Hash,
121 Default,
122 Eq,
123 PartialEq,
124 Ord,
125 PartialOrd,
126 Encode,
127 Decode,
128 TypeInfo,
129 Serialize,
130 Deserialize,
131 MaxEncodedLen,
132)]
133pub struct DomainId(u32);
134
135impl From<u32> for DomainId {
136 #[inline]
137 fn from(x: u32) -> Self {
138 Self(x)
139 }
140}
141
142impl From<DomainId> for u32 {
143 #[inline]
144 fn from(domain_id: DomainId) -> Self {
145 domain_id.0
146 }
147}
148
149impl FromStr for DomainId {
150 type Err = ParseIntError;
151
152 fn from_str(s: &str) -> Result<Self, Self::Err> {
153 s.parse::<u32>().map(Into::into)
154 }
155}
156
157impl Add<DomainId> for DomainId {
158 type Output = Self;
159
160 fn add(self, other: DomainId) -> Self {
161 Self(self.0 + other.0)
162 }
163}
164
165impl Sub<DomainId> for DomainId {
166 type Output = Self;
167
168 fn sub(self, other: DomainId) -> Self {
169 Self(self.0 - other.0)
170 }
171}
172
173impl CheckedAdd for DomainId {
174 fn checked_add(&self, rhs: &Self) -> Option<Self> {
175 self.0.checked_add(rhs.0).map(Self)
176 }
177}
178
179impl DomainId {
180 pub const fn new(id: u32) -> Self {
182 Self(id)
183 }
184
185 pub fn to_le_bytes(&self) -> [u8; 4] {
187 self.0.to_le_bytes()
188 }
189}
190
191impl Display for DomainId {
192 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
193 self.0.fmt(f)
194 }
195}
196
197impl PassBy for DomainId {
198 type PassBy = pass_by::Codec<Self>;
199}
200
201#[derive(
203 Clone,
204 Copy,
205 Debug,
206 Hash,
207 Eq,
208 PartialEq,
209 Ord,
210 PartialOrd,
211 Encode,
212 Decode,
213 TypeInfo,
214 Serialize,
215 Deserialize,
216 MaxEncodedLen,
217)]
218pub enum ChainId {
219 Consensus,
220 Domain(DomainId),
221}
222
223impl ChainId {
224 #[inline]
225 pub fn consensus_chain_id() -> Self {
226 Self::Consensus
227 }
228
229 #[inline]
230 pub fn is_consensus_chain(&self) -> bool {
231 match self {
232 ChainId::Consensus => true,
233 ChainId::Domain(_) => false,
234 }
235 }
236
237 #[inline]
238 pub fn maybe_domain_chain(&self) -> Option<DomainId> {
239 match self {
240 ChainId::Consensus => None,
241 ChainId::Domain(domain_id) => Some(*domain_id),
242 }
243 }
244}
245
246impl From<u32> for ChainId {
247 #[inline]
248 fn from(x: u32) -> Self {
249 Self::Domain(DomainId::new(x))
250 }
251}
252
253impl From<DomainId> for ChainId {
254 #[inline]
255 fn from(x: DomainId) -> Self {
256 Self::Domain(x)
257 }
258}
259
260#[derive(Clone, Debug, Decode, Default, Encode, Eq, PartialEq, TypeInfo)]
261pub struct BlockFees<Balance> {
262 pub consensus_storage_fee: Balance,
264 pub domain_execution_fee: Balance,
267 pub burned_balance: Balance,
269 pub chain_rewards: BTreeMap<ChainId, Balance>,
271}
272
273impl<Balance> BlockFees<Balance>
274where
275 Balance: CheckedAdd + Zero,
276{
277 pub fn new(
278 domain_execution_fee: Balance,
279 consensus_storage_fee: Balance,
280 burned_balance: Balance,
281 chain_rewards: BTreeMap<ChainId, Balance>,
282 ) -> Self {
283 BlockFees {
284 consensus_storage_fee,
285 domain_execution_fee,
286 burned_balance,
287 chain_rewards,
288 }
289 }
290
291 pub fn total_fees(&self) -> Option<Balance> {
293 let total_chain_reward = self
294 .chain_rewards
295 .values()
296 .try_fold(Zero::zero(), |acc: Balance, cr| acc.checked_add(cr))?;
297 self.consensus_storage_fee
298 .checked_add(&self.domain_execution_fee)
299 .and_then(|balance| balance.checked_add(&self.burned_balance))
300 .and_then(|balance| balance.checked_add(&total_chain_reward))
301 }
302}
303
304#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, Default)]
306pub struct Transfers<Balance> {
307 pub transfers_in: BTreeMap<ChainId, Balance>,
309 pub transfers_out: BTreeMap<ChainId, Balance>,
311 pub rejected_transfers_claimed: BTreeMap<ChainId, Balance>,
313 pub transfers_rejected: BTreeMap<ChainId, Balance>,
315}
316
317impl<Balance> Transfers<Balance> {
318 pub fn is_valid(&self, chain_id: ChainId) -> bool {
319 !self.transfers_rejected.contains_key(&chain_id)
320 && !self.transfers_in.contains_key(&chain_id)
321 && !self.transfers_out.contains_key(&chain_id)
322 && !self.rejected_transfers_claimed.contains_key(&chain_id)
323 }
324}
325
326pub const INITIAL_DOMAIN_TX_RANGE: u64 = 3;
331
332#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
333pub struct BundleHeader<Number, Hash, DomainHeader: HeaderT, Balance> {
334 pub proof_of_election: ProofOfElection,
336 pub receipt: ExecutionReceipt<
339 Number,
340 Hash,
341 HeaderNumberFor<DomainHeader>,
342 HeaderHashFor<DomainHeader>,
343 Balance,
344 >,
345 pub estimated_bundle_weight: Weight,
349 pub bundle_extrinsics_root: HeaderHashFor<DomainHeader>,
351}
352
353impl<Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
354 BundleHeader<Number, Hash, DomainHeader, Balance>
355{
356 pub fn hash(&self) -> HeaderHashFor<DomainHeader> {
358 HeaderHashingFor::<DomainHeader>::hash_of(self)
359 }
360}
361
362#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
364pub struct SealedBundleHeader<Number, Hash, DomainHeader: HeaderT, Balance> {
365 pub header: BundleHeader<Number, Hash, DomainHeader, Balance>,
367 pub signature: OperatorSignature,
369}
370
371impl<Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
372 SealedBundleHeader<Number, Hash, DomainHeader, Balance>
373{
374 pub fn new(
376 header: BundleHeader<Number, Hash, DomainHeader, Balance>,
377 signature: OperatorSignature,
378 ) -> Self {
379 Self { header, signature }
380 }
381
382 pub fn pre_hash(&self) -> HeaderHashFor<DomainHeader> {
384 self.header.hash()
385 }
386
387 pub fn hash(&self) -> HeaderHashFor<DomainHeader> {
389 HeaderHashingFor::<DomainHeader>::hash_of(self)
390 }
391
392 pub fn slot_number(&self) -> u64 {
393 self.header.proof_of_election.slot_number
394 }
395}
396
397#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
399pub struct Bundle<Extrinsic, Number, Hash, DomainHeader: HeaderT, Balance> {
400 pub sealed_header: SealedBundleHeader<Number, Hash, DomainHeader, Balance>,
402 pub extrinsics: Vec<Extrinsic>,
404}
405
406impl<Extrinsic: Encode, Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
407 Bundle<Extrinsic, Number, Hash, DomainHeader, Balance>
408{
409 pub fn hash(&self) -> H256 {
411 BlakeTwo256::hash_of(self)
412 }
413
414 pub fn domain_id(&self) -> DomainId {
416 self.sealed_header.header.proof_of_election.domain_id
417 }
418
419 pub fn extrinsics_root(&self) -> HeaderHashFor<DomainHeader> {
421 self.sealed_header.header.bundle_extrinsics_root
422 }
423
424 pub fn operator_id(&self) -> OperatorId {
426 self.sealed_header.header.proof_of_election.operator_id
427 }
428
429 pub fn receipt(
431 &self,
432 ) -> &ExecutionReceipt<
433 Number,
434 Hash,
435 HeaderNumberFor<DomainHeader>,
436 HeaderHashFor<DomainHeader>,
437 Balance,
438 > {
439 &self.sealed_header.header.receipt
440 }
441
442 pub fn into_receipt(
444 self,
445 ) -> ExecutionReceipt<
446 Number,
447 Hash,
448 HeaderNumberFor<DomainHeader>,
449 HeaderHashFor<DomainHeader>,
450 Balance,
451 > {
452 self.sealed_header.header.receipt
453 }
454
455 pub fn size(&self) -> u32 {
457 self.encoded_size() as u32
458 }
459
460 pub fn body_size(&self) -> u32 {
462 self.extrinsics
463 .iter()
464 .map(|tx| tx.encoded_size() as u32)
465 .sum::<u32>()
466 }
467
468 pub fn estimated_weight(&self) -> Weight {
469 self.sealed_header.header.estimated_bundle_weight
470 }
471
472 pub fn slot_number(&self) -> u64 {
473 self.sealed_header.header.proof_of_election.slot_number
474 }
475}
476
477pub type OpaqueBundle<Number, Hash, DomainHeader, Balance> =
479 Bundle<OpaqueExtrinsic, Number, Hash, DomainHeader, Balance>;
480
481pub type OpaqueBundles<Block, DomainHeader, Balance> =
483 Vec<OpaqueBundle<NumberFor<Block>, BlockHashFor<Block>, DomainHeader, Balance>>;
484
485impl<Extrinsic: Encode, Number, Hash, DomainHeader: HeaderT, Balance>
486 Bundle<Extrinsic, Number, Hash, DomainHeader, Balance>
487{
488 pub fn into_opaque_bundle(self) -> OpaqueBundle<Number, Hash, DomainHeader, Balance> {
490 let Bundle {
491 sealed_header,
492 extrinsics,
493 } = self;
494 let opaque_extrinsics = extrinsics
495 .into_iter()
496 .map(|xt| {
497 OpaqueExtrinsic::from_bytes(&xt.encode())
498 .expect("We have just encoded a valid extrinsic; qed")
499 })
500 .collect();
501 OpaqueBundle {
502 sealed_header,
503 extrinsics: opaque_extrinsics,
504 }
505 }
506}
507
508#[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
509pub fn dummy_opaque_bundle<
510 Number: Encode,
511 Hash: Default + Encode,
512 DomainHeader: HeaderT,
513 Balance: Encode,
514>(
515 domain_id: DomainId,
516 operator_id: OperatorId,
517 receipt: ExecutionReceipt<
518 Number,
519 Hash,
520 HeaderNumberFor<DomainHeader>,
521 HeaderHashFor<DomainHeader>,
522 Balance,
523 >,
524) -> OpaqueBundle<Number, Hash, DomainHeader, Balance> {
525 use sp_core::crypto::UncheckedFrom;
526
527 let header = BundleHeader {
528 proof_of_election: ProofOfElection::dummy(domain_id, operator_id),
529 receipt,
530 estimated_bundle_weight: Default::default(),
531 bundle_extrinsics_root: Default::default(),
532 };
533 let signature = OperatorSignature::unchecked_from([0u8; 64]);
534
535 OpaqueBundle {
536 sealed_header: SealedBundleHeader::new(header, signature),
537 extrinsics: Vec::new(),
538 }
539}
540
541#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
543pub struct BundleDigest<Hash> {
544 pub header_hash: Hash,
546 pub extrinsics_root: Hash,
548 pub size: u32,
550}
551
552#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
554pub struct ExecutionReceipt<Number, Hash, DomainNumber, DomainHash, Balance> {
555 pub domain_block_number: DomainNumber,
557 pub domain_block_hash: DomainHash,
559 pub domain_block_extrinsic_root: DomainHash,
561 pub parent_domain_block_receipt_hash: DomainHash,
563 pub consensus_block_number: Number,
566 pub consensus_block_hash: Hash,
568 pub inboxed_bundles: Vec<InboxedBundle<DomainHash>>,
570 pub final_state_root: DomainHash,
574 pub execution_trace: Vec<DomainHash>,
576 pub execution_trace_root: H256,
580 pub block_fees: BlockFees<Balance>,
583 pub transfers: Transfers<Balance>,
585}
586
587impl<Number, Hash, DomainNumber, DomainHash, Balance>
588 ExecutionReceipt<Number, Hash, DomainNumber, DomainHash, Balance>
589{
590 pub fn bundles_extrinsics_roots(&self) -> Vec<&DomainHash> {
591 self.inboxed_bundles
592 .iter()
593 .map(|b| &b.extrinsics_root)
594 .collect()
595 }
596
597 pub fn valid_bundle_digest_at(&self, index: usize) -> Option<DomainHash>
598 where
599 DomainHash: Copy,
600 {
601 match self.inboxed_bundles.get(index).map(|ib| &ib.bundle) {
602 Some(BundleValidity::Valid(bundle_digest_hash)) => Some(*bundle_digest_hash),
603 _ => None,
604 }
605 }
606
607 pub fn valid_bundle_digests(&self) -> Vec<DomainHash>
608 where
609 DomainHash: Copy,
610 {
611 self.inboxed_bundles
612 .iter()
613 .filter_map(|b| match b.bundle {
614 BundleValidity::Valid(bundle_digest_hash) => Some(bundle_digest_hash),
615 BundleValidity::Invalid(_) => None,
616 })
617 .collect()
618 }
619
620 pub fn valid_bundle_indexes(&self) -> Vec<u32> {
621 self.inboxed_bundles
622 .iter()
623 .enumerate()
624 .filter_map(|(index, b)| match b.bundle {
625 BundleValidity::Valid(_) => Some(index as u32),
626 BundleValidity::Invalid(_) => None,
627 })
628 .collect()
629 }
630}
631
632impl<
633 Number: Encode + Zero,
634 Hash: Encode + Default,
635 DomainNumber: Encode + Zero,
636 DomainHash: Clone + Encode + Default,
637 Balance: Encode + Zero + Default,
638> ExecutionReceipt<Number, Hash, DomainNumber, DomainHash, Balance>
639{
640 pub fn hash<DomainHashing: HashT<Output = DomainHash>>(&self) -> DomainHash {
642 DomainHashing::hash_of(self)
643 }
644
645 pub fn genesis(
646 genesis_state_root: DomainHash,
647 genesis_extrinsic_root: DomainHash,
648 genesis_domain_block_hash: DomainHash,
649 ) -> Self {
650 ExecutionReceipt {
651 domain_block_number: Zero::zero(),
652 domain_block_hash: genesis_domain_block_hash,
653 domain_block_extrinsic_root: genesis_extrinsic_root,
654 parent_domain_block_receipt_hash: Default::default(),
655 consensus_block_hash: Default::default(),
656 consensus_block_number: Zero::zero(),
657 inboxed_bundles: Vec::new(),
658 final_state_root: genesis_state_root.clone(),
659 execution_trace: sp_std::vec![genesis_state_root],
660 execution_trace_root: Default::default(),
661 block_fees: Default::default(),
662 transfers: Default::default(),
663 }
664 }
665
666 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
667 pub fn dummy<DomainHashing>(
668 consensus_block_number: Number,
669 consensus_block_hash: Hash,
670 domain_block_number: DomainNumber,
671 parent_domain_block_receipt_hash: DomainHash,
672 ) -> ExecutionReceipt<Number, Hash, DomainNumber, DomainHash, Balance>
673 where
674 DomainHashing: HashT<Output = DomainHash>,
675 {
676 let execution_trace = sp_std::vec![Default::default(), Default::default()];
677 let execution_trace_root = {
678 let trace: Vec<[u8; 32]> = execution_trace
679 .iter()
680 .map(|r: &DomainHash| r.encode().try_into().expect("H256 must fit into [u8; 32]"))
681 .collect();
682 crate::merkle_tree::MerkleTree::from_leaves(trace.as_slice())
683 .root()
684 .expect("Compute merkle root of trace should success")
685 .into()
686 };
687 ExecutionReceipt {
688 domain_block_number,
689 domain_block_hash: Default::default(),
690 domain_block_extrinsic_root: Default::default(),
691 parent_domain_block_receipt_hash,
692 consensus_block_number,
693 consensus_block_hash,
694 inboxed_bundles: sp_std::vec![InboxedBundle::dummy(Default::default())],
695 final_state_root: Default::default(),
696 execution_trace,
697 execution_trace_root,
698 block_fees: Default::default(),
699 transfers: Default::default(),
700 }
701 }
702}
703
704#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
705pub struct ProofOfElection {
706 pub domain_id: DomainId,
708 pub slot_number: u64,
710 pub proof_of_time: PotOutput,
712 pub vrf_signature: VrfSignature,
714 pub operator_id: OperatorId,
716}
717
718impl ProofOfElection {
719 pub fn verify_vrf_signature(
720 &self,
721 operator_signing_key: &OperatorPublicKey,
722 ) -> Result<(), ProofOfElectionError> {
723 let global_challenge = self
724 .proof_of_time
725 .derive_global_randomness()
726 .derive_global_challenge(self.slot_number);
727 bundle_producer_election::verify_vrf_signature(
728 self.domain_id,
729 operator_signing_key,
730 &self.vrf_signature,
731 &global_challenge,
732 )
733 }
734
735 pub fn vrf_hash(&self) -> Blake3Hash {
737 let mut bytes = self.vrf_signature.pre_output.encode();
738 bytes.append(&mut self.vrf_signature.proof.encode());
739 blake3_hash(&bytes)
740 }
741
742 pub fn slot_number(&self) -> u64 {
743 self.slot_number
744 }
745}
746
747impl ProofOfElection {
748 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
749 pub fn dummy(domain_id: DomainId, operator_id: OperatorId) -> Self {
750 let output_bytes = sp_std::vec![0u8; VrfPreOutput::max_encoded_len()];
751 let proof_bytes = sp_std::vec![0u8; VrfProof::max_encoded_len()];
752 let vrf_signature = VrfSignature {
753 pre_output: VrfPreOutput::decode(&mut output_bytes.as_slice()).unwrap(),
754 proof: VrfProof::decode(&mut proof_bytes.as_slice()).unwrap(),
755 };
756 Self {
757 domain_id,
758 slot_number: 0u64,
759 proof_of_time: PotOutput::default(),
760 vrf_signature,
761 operator_id,
762 }
763 }
764}
765
766#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
769pub struct SingletonReceipt<Number, Hash, DomainHeader: HeaderT, Balance> {
770 pub proof_of_election: ProofOfElection,
772 pub receipt: ExecutionReceipt<
774 Number,
775 Hash,
776 HeaderNumberFor<DomainHeader>,
777 HeaderHashFor<DomainHeader>,
778 Balance,
779 >,
780}
781
782impl<Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
783 SingletonReceipt<Number, Hash, DomainHeader, Balance>
784{
785 pub fn hash(&self) -> HeaderHashFor<DomainHeader> {
786 HeaderHashingFor::<DomainHeader>::hash_of(&self)
787 }
788}
789
790#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
791pub struct SealedSingletonReceipt<Number, Hash, DomainHeader: HeaderT, Balance> {
792 pub singleton_receipt: SingletonReceipt<Number, Hash, DomainHeader, Balance>,
794 pub signature: OperatorSignature,
796}
797
798impl<Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
799 SealedSingletonReceipt<Number, Hash, DomainHeader, Balance>
800{
801 pub fn domain_id(&self) -> DomainId {
803 self.singleton_receipt.proof_of_election.domain_id
804 }
805
806 pub fn operator_id(&self) -> OperatorId {
808 self.singleton_receipt.proof_of_election.operator_id
809 }
810
811 pub fn slot_number(&self) -> u64 {
813 self.singleton_receipt.proof_of_election.slot_number
814 }
815
816 pub fn receipt(
818 &self,
819 ) -> &ExecutionReceipt<
820 Number,
821 Hash,
822 HeaderNumberFor<DomainHeader>,
823 HeaderHashFor<DomainHeader>,
824 Balance,
825 > {
826 &self.singleton_receipt.receipt
827 }
828
829 pub fn into_receipt(
831 self,
832 ) -> ExecutionReceipt<
833 Number,
834 Hash,
835 HeaderNumberFor<DomainHeader>,
836 HeaderHashFor<DomainHeader>,
837 Balance,
838 > {
839 self.singleton_receipt.receipt
840 }
841
842 pub fn pre_hash(&self) -> HeaderHashFor<DomainHeader> {
844 HeaderHashingFor::<DomainHeader>::hash_of(&self.singleton_receipt)
845 }
846
847 pub fn size(&self) -> u32 {
849 self.encoded_size() as u32
850 }
851}
852
853#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
855pub enum OperatorAllowList<AccountId: Ord> {
856 Anyone,
858 Operators(BTreeSet<AccountId>),
861}
862
863impl<AccountId: Ord> OperatorAllowList<AccountId> {
864 pub fn is_operator_allowed(&self, operator: &AccountId) -> bool {
866 match self {
867 OperatorAllowList::Anyone => true,
868 OperatorAllowList::Operators(allowed_operators) => allowed_operators.contains(operator),
869 }
870 }
871}
872
873#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
875pub enum PermissionedActionAllowedBy<AccountId: Codec + Clone> {
876 Accounts(Vec<AccountId>),
877 Anyone,
878}
879
880impl<AccountId: Codec + PartialEq + Clone> PermissionedActionAllowedBy<AccountId> {
881 pub fn is_allowed(&self, who: &AccountId) -> bool {
882 match self {
883 PermissionedActionAllowedBy::Accounts(accounts) => accounts.contains(who),
884 PermissionedActionAllowedBy::Anyone => true,
885 }
886 }
887
888 pub fn is_anyone_allowed(&self) -> bool {
889 matches!(self, PermissionedActionAllowedBy::Anyone)
890 }
891}
892
893#[derive(
895 TypeInfo, Debug, Default, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize,
896)]
897pub enum EvmType {
898 #[default]
899 Public,
901 Private {
903 initial_contract_creation_allow_list: PermissionedActionAllowedBy<EthereumAccountId>,
906 },
907}
908
909impl EvmType {
910 pub fn initial_contract_creation_allow_list(
912 &self,
913 ) -> Option<&PermissionedActionAllowedBy<EthereumAccountId>> {
914 match self {
915 EvmType::Public => None,
916 EvmType::Private {
917 initial_contract_creation_allow_list,
918 } => Some(initial_contract_creation_allow_list),
919 }
920 }
921
922 pub fn is_public_evm_domain(&self) -> bool {
924 matches!(self, EvmType::Public)
925 }
926
927 pub fn is_private_evm_domain(&self) -> bool {
929 matches!(self, EvmType::Private { .. })
930 }
931}
932
933#[derive(
935 TypeInfo, Debug, Default, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize,
936)]
937pub struct EvmDomainRuntimeConfig {
938 pub evm_type: EvmType,
939}
940
941#[derive(
943 TypeInfo, Debug, Default, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize,
944)]
945pub struct AutoIdDomainRuntimeConfig {
946 }
948
949#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
951pub enum DomainRuntimeConfig {
952 Evm(EvmDomainRuntimeConfig),
953 AutoId(AutoIdDomainRuntimeConfig),
954}
955
956impl Default for DomainRuntimeConfig {
957 fn default() -> Self {
958 Self::default_evm()
959 }
960}
961
962impl From<EvmDomainRuntimeConfig> for DomainRuntimeConfig {
963 fn from(evm_config: EvmDomainRuntimeConfig) -> Self {
964 DomainRuntimeConfig::Evm(evm_config)
965 }
966}
967
968impl From<AutoIdDomainRuntimeConfig> for DomainRuntimeConfig {
969 fn from(auto_id_config: AutoIdDomainRuntimeConfig) -> Self {
970 DomainRuntimeConfig::AutoId(auto_id_config)
971 }
972}
973
974impl DomainRuntimeConfig {
975 pub fn default_evm() -> Self {
976 DomainRuntimeConfig::Evm(EvmDomainRuntimeConfig::default())
977 }
978
979 pub fn default_auto_id() -> Self {
980 DomainRuntimeConfig::AutoId(AutoIdDomainRuntimeConfig::default())
981 }
982
983 pub fn is_evm_domain(&self) -> bool {
984 matches!(self, DomainRuntimeConfig::Evm(_))
985 }
986
987 pub fn is_auto_id(&self) -> bool {
988 matches!(self, DomainRuntimeConfig::AutoId(_))
989 }
990
991 pub fn evm(&self) -> Option<&EvmDomainRuntimeConfig> {
992 match self {
993 DomainRuntimeConfig::Evm(evm_config) => Some(evm_config),
994 _ => None,
995 }
996 }
997
998 pub fn initial_contract_creation_allow_list(
999 &self,
1000 ) -> Option<&PermissionedActionAllowedBy<EthereumAccountId>> {
1001 self.evm()
1002 .and_then(|evm_config| evm_config.evm_type.initial_contract_creation_allow_list())
1003 }
1004
1005 pub fn auto_id(&self) -> Option<&AutoIdDomainRuntimeConfig> {
1006 match self {
1007 DomainRuntimeConfig::AutoId(auto_id_config) => Some(auto_id_config),
1008 _ => None,
1009 }
1010 }
1011}
1012
1013#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
1014pub struct GenesisDomain<AccountId: Ord, Balance> {
1015 pub runtime_name: String,
1017 pub runtime_type: RuntimeType,
1018 pub runtime_version: RuntimeVersion,
1019 pub raw_genesis_storage: Vec<u8>,
1020
1021 pub owner_account_id: AccountId,
1023 pub domain_name: String,
1024 pub bundle_slot_probability: (u64, u64),
1025 pub operator_allow_list: OperatorAllowList<AccountId>,
1026 pub domain_runtime_config: DomainRuntimeConfig,
1028
1029 pub signing_key: OperatorPublicKey,
1031 pub minimum_nominator_stake: Balance,
1032 pub nomination_tax: Percent,
1033
1034 pub initial_balances: Vec<(MultiAccountId, Balance)>,
1036}
1037
1038#[derive(
1040 Debug, Default, Encode, Decode, TypeInfo, Copy, Clone, PartialEq, Eq, Serialize, Deserialize,
1041)]
1042pub enum RuntimeType {
1043 #[default]
1044 Evm,
1045 AutoId,
1046}
1047
1048pub type RuntimeId = u32;
1050
1051pub type EpochIndex = u32;
1053
1054pub type OperatorId = u64;
1056
1057pub type ChannelId = sp_core::U256;
1059
1060#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
1062pub enum DomainDigestItem {
1063 DomainRuntimeUpgraded(RuntimeId),
1064 DomainInstantiated(DomainId),
1065}
1066
1067pub trait DomainsDigestItem {
1069 fn domain_runtime_upgrade(runtime_id: RuntimeId) -> Self;
1070 fn as_domain_runtime_upgrade(&self) -> Option<RuntimeId>;
1071
1072 fn domain_instantiation(domain_id: DomainId) -> Self;
1073 fn as_domain_instantiation(&self) -> Option<DomainId>;
1074}
1075
1076impl DomainsDigestItem for DigestItem {
1077 fn domain_runtime_upgrade(runtime_id: RuntimeId) -> Self {
1078 Self::Other(DomainDigestItem::DomainRuntimeUpgraded(runtime_id).encode())
1079 }
1080
1081 fn as_domain_runtime_upgrade(&self) -> Option<RuntimeId> {
1082 match self.try_to::<DomainDigestItem>(OpaqueDigestItemId::Other) {
1083 Some(DomainDigestItem::DomainRuntimeUpgraded(runtime_id)) => Some(runtime_id),
1084 _ => None,
1085 }
1086 }
1087
1088 fn domain_instantiation(domain_id: DomainId) -> Self {
1089 Self::Other(DomainDigestItem::DomainInstantiated(domain_id).encode())
1090 }
1091
1092 fn as_domain_instantiation(&self) -> Option<DomainId> {
1093 match self.try_to::<DomainDigestItem>(OpaqueDigestItemId::Other) {
1094 Some(DomainDigestItem::DomainInstantiated(domain_id)) => Some(domain_id),
1095 _ => None,
1096 }
1097 }
1098}
1099
1100pub(crate) fn evm_chain_id_storage_key() -> StorageKey {
1107 StorageKey(
1108 storage_prefix(
1109 "EVMChainId".as_bytes(),
1112 "ChainId".as_bytes(),
1114 )
1115 .to_vec(),
1116 )
1117}
1118
1119pub(crate) fn evm_contract_creation_allowed_by_storage_key() -> StorageKey {
1126 StorageKey(
1127 storage_prefix(
1128 "EVMNoncetracker".as_bytes(),
1131 "ContractCreationAllowedBy".as_bytes(),
1133 )
1134 .to_vec(),
1135 )
1136}
1137
1138pub fn domain_total_issuance_storage_key() -> StorageKey {
1145 StorageKey(
1146 storage_prefix(
1147 "Balances".as_bytes(),
1149 "TotalIssuance".as_bytes(),
1151 )
1152 .to_vec(),
1153 )
1154}
1155
1156pub fn domain_account_storage_key<AccountId: Encode>(who: AccountId) -> StorageKey {
1163 let storage_prefix = storage_prefix("System".as_bytes(), "Account".as_bytes());
1164 let key_hashed = who.using_encoded(Blake2_128Concat::hash);
1165
1166 let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len());
1167
1168 final_key.extend_from_slice(&storage_prefix);
1169 final_key.extend_from_slice(key_hashed.as_ref());
1170
1171 StorageKey(final_key)
1172}
1173
1174pub fn self_domain_id_storage_key() -> StorageKey {
1179 StorageKey(
1180 frame_support::storage::storage_prefix(
1181 "SelfDomainId".as_bytes(),
1184 "SelfDomainId".as_bytes(),
1186 )
1187 .to_vec(),
1188 )
1189}
1190
1191#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
1193pub struct DomainInstanceData {
1194 pub runtime_type: RuntimeType,
1195 pub raw_genesis: RawGenesis,
1196}
1197
1198#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
1199pub struct DomainBundleLimit {
1200 pub max_bundle_size: u32,
1202 pub max_bundle_weight: Weight,
1204}
1205
1206pub fn calculate_max_bundle_weight_and_size(
1210 max_domain_block_size: u32,
1211 max_domain_block_weight: Weight,
1212 consensus_slot_probability: (u64, u64),
1213 bundle_slot_probability: (u64, u64),
1214) -> Option<DomainBundleLimit> {
1215 let expected_bundles_per_block = bundle_slot_probability
1218 .0
1219 .checked_mul(consensus_slot_probability.1)?
1220 .checked_div(
1221 bundle_slot_probability
1222 .1
1223 .checked_mul(consensus_slot_probability.0)?,
1224 )?;
1225
1226 let max_proof_size = max_domain_block_weight.proof_size();
1229 let max_bundle_weight = max_domain_block_weight
1230 .checked_div(expected_bundles_per_block)?
1231 .set_proof_size(max_proof_size);
1232
1233 let max_bundle_size =
1234 (max_domain_block_size as u64).checked_div(expected_bundles_per_block)? as u32;
1235
1236 Some(DomainBundleLimit {
1237 max_bundle_size,
1238 max_bundle_weight,
1239 })
1240}
1241
1242pub fn signer_in_tx_range(bundle_vrf_hash: &U256, signer_id_hash: &U256, tx_range: &U256) -> bool {
1244 let distance_from_vrf_hash = bidirectional_distance(bundle_vrf_hash, signer_id_hash);
1245 distance_from_vrf_hash <= (*tx_range / 2)
1246}
1247
1248#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
1250pub enum InvalidReceipt {
1251 InvalidBundles,
1253}
1254
1255#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
1256pub enum ReceiptValidity {
1257 Valid,
1258 Invalid(InvalidReceipt),
1259}
1260
1261#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
1265pub enum InvalidBundleType {
1266 #[codec(index = 0)]
1268 UndecodableTx(u32),
1269 #[codec(index = 1)]
1271 OutOfRangeTx(u32),
1272 #[codec(index = 2)]
1274 IllegalTx(u32),
1275 #[codec(index = 3)]
1277 InvalidXDM(u32),
1278 #[codec(index = 4)]
1280 InherentExtrinsic(u32),
1281 #[codec(index = 5)]
1283 InvalidBundleWeight,
1284}
1285
1286impl InvalidBundleType {
1287 pub fn checking_order(&self) -> u64 {
1289 let extrinsic_order = match self {
1292 Self::UndecodableTx(i) => *i,
1293 Self::OutOfRangeTx(i) => *i,
1294 Self::IllegalTx(i) => *i,
1295 Self::InvalidXDM(i) => *i,
1296 Self::InherentExtrinsic(i) => *i,
1297 Self::InvalidBundleWeight => u32::MAX,
1302 };
1303
1304 let rule_order = match self {
1311 Self::UndecodableTx(_) => 1,
1312 Self::OutOfRangeTx(_) => 2,
1313 Self::InherentExtrinsic(_) => 3,
1314 Self::InvalidXDM(_) => 4,
1315 Self::IllegalTx(_) => 5,
1316 Self::InvalidBundleWeight => 6,
1317 };
1318
1319 ((extrinsic_order as u64) << 32) | (rule_order as u64)
1324 }
1325
1326 pub fn extrinsic_index(&self) -> Option<u32> {
1331 match self {
1332 Self::UndecodableTx(i) => Some(*i),
1333 Self::OutOfRangeTx(i) => Some(*i),
1334 Self::IllegalTx(i) => Some(*i),
1335 Self::InvalidXDM(i) => Some(*i),
1336 Self::InherentExtrinsic(i) => Some(*i),
1337 Self::InvalidBundleWeight => None,
1338 }
1339 }
1340}
1341
1342#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
1343pub enum BundleValidity<Hash> {
1344 Invalid(InvalidBundleType),
1347 Valid(Hash),
1351}
1352
1353#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
1355pub struct InboxedBundle<Hash> {
1356 pub bundle: BundleValidity<Hash>,
1357 pub extrinsics_root: Hash,
1359}
1360
1361impl<Hash> InboxedBundle<Hash> {
1362 pub fn valid(bundle_digest_hash: Hash, extrinsics_root: Hash) -> Self {
1363 InboxedBundle {
1364 bundle: BundleValidity::Valid(bundle_digest_hash),
1365 extrinsics_root,
1366 }
1367 }
1368
1369 pub fn invalid(invalid_bundle_type: InvalidBundleType, extrinsics_root: Hash) -> Self {
1370 InboxedBundle {
1371 bundle: BundleValidity::Invalid(invalid_bundle_type),
1372 extrinsics_root,
1373 }
1374 }
1375
1376 pub fn is_invalid(&self) -> bool {
1377 matches!(self.bundle, BundleValidity::Invalid(_))
1378 }
1379
1380 pub fn invalid_extrinsic_index(&self) -> Option<u32> {
1381 match &self.bundle {
1382 BundleValidity::Invalid(invalid_bundle_type) => invalid_bundle_type.extrinsic_index(),
1383 BundleValidity::Valid(_) => None,
1384 }
1385 }
1386
1387 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
1388 pub fn dummy(extrinsics_root: Hash) -> Self
1389 where
1390 Hash: Default,
1391 {
1392 InboxedBundle {
1393 bundle: BundleValidity::Valid(Hash::default()),
1394 extrinsics_root,
1395 }
1396 }
1397}
1398
1399pub const EMPTY_EXTRINSIC_ROOT: ExtrinsicsRoot = ExtrinsicsRoot {
1401 0: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314"),
1402};
1403
1404pub fn derive_domain_block_hash<DomainHeader: HeaderT>(
1405 domain_block_number: DomainHeader::Number,
1406 extrinsics_root: DomainHeader::Hash,
1407 state_root: DomainHeader::Hash,
1408 parent_domain_block_hash: DomainHeader::Hash,
1409 digest: Digest,
1410) -> DomainHeader::Hash {
1411 let domain_header = DomainHeader::new(
1412 domain_block_number,
1413 extrinsics_root,
1414 state_root,
1415 parent_domain_block_hash,
1416 digest,
1417 );
1418
1419 domain_header.hash()
1420}
1421
1422#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
1424pub enum ExtrinsicDigest {
1425 Data(Vec<u8>),
1427 Hash(H256),
1429}
1430
1431impl ExtrinsicDigest {
1432 pub fn new<Layout: TrieLayout>(ext: Vec<u8>) -> Self
1433 where
1434 Layout::Hash: HashT,
1435 <Layout::Hash as HashT>::Output: Into<H256>,
1436 {
1437 if let Some(threshold) = Layout::MAX_INLINE_VALUE {
1438 if ext.len() >= threshold as usize {
1439 ExtrinsicDigest::Hash(Layout::Hash::hash(&ext).into())
1440 } else {
1441 ExtrinsicDigest::Data(ext)
1442 }
1443 } else {
1444 ExtrinsicDigest::Data(ext)
1445 }
1446 }
1447}
1448
1449pub trait DomainsTransfersTracker<Balance> {
1451 type Error;
1452
1453 fn initialize_domain_balance(domain_id: DomainId, amount: Balance) -> Result<(), Self::Error>;
1455
1456 fn note_transfer(
1459 from_chain_id: ChainId,
1460 to_chain_id: ChainId,
1461 amount: Balance,
1462 ) -> Result<(), Self::Error>;
1463
1464 fn confirm_transfer(
1466 from_chain_id: ChainId,
1467 to_chain_id: ChainId,
1468 amount: Balance,
1469 ) -> Result<(), Self::Error>;
1470
1471 fn claim_rejected_transfer(
1473 from_chain_id: ChainId,
1474 to_chain_id: ChainId,
1475 amount: Balance,
1476 ) -> Result<(), Self::Error>;
1477
1478 fn reject_transfer(
1480 from_chain_id: ChainId,
1481 to_chain_id: ChainId,
1482 amount: Balance,
1483 ) -> Result<(), Self::Error>;
1484
1485 fn reduce_domain_balance(domain_id: DomainId, amount: Balance) -> Result<(), Self::Error>;
1487}
1488
1489pub trait DomainOwner<AccountId> {
1491 fn is_domain_owner(domain_id: DomainId, acc: AccountId) -> bool;
1493}
1494
1495impl<AccountId> DomainOwner<AccountId> for () {
1496 fn is_domain_owner(_domain_id: DomainId, _acc: AccountId) -> bool {
1497 false
1498 }
1499}
1500
1501pub trait DomainBundleSubmitted {
1503 fn domain_bundle_submitted(domain_id: DomainId);
1506}
1507
1508impl DomainBundleSubmitted for () {
1509 fn domain_bundle_submitted(_domain_id: DomainId) {}
1510}
1511
1512pub trait OnDomainInstantiated {
1514 fn on_domain_instantiated(domain_id: DomainId);
1515}
1516
1517impl OnDomainInstantiated for () {
1518 fn on_domain_instantiated(_domain_id: DomainId) {}
1519}
1520
1521pub type ExecutionReceiptFor<DomainHeader, CBlock, Balance> = ExecutionReceipt<
1522 NumberFor<CBlock>,
1523 BlockHashFor<CBlock>,
1524 <DomainHeader as HeaderT>::Number,
1525 <DomainHeader as HeaderT>::Hash,
1526 Balance,
1527>;
1528
1529#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
1531pub struct DomainAllowlistUpdates {
1532 pub allow_chains: BTreeSet<ChainId>,
1534 pub remove_chains: BTreeSet<ChainId>,
1536}
1537
1538impl DomainAllowlistUpdates {
1539 pub fn is_empty(&self) -> bool {
1540 self.allow_chains.is_empty() && self.remove_chains.is_empty()
1541 }
1542
1543 pub fn clear(&mut self) {
1544 self.allow_chains.clear();
1545 self.remove_chains.clear();
1546 }
1547}
1548
1549#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
1555pub struct DomainSudoCall {
1556 pub maybe_call: Option<Vec<u8>>,
1557}
1558
1559impl DomainSudoCall {
1560 pub fn clear(&mut self) {
1561 self.maybe_call.take();
1562 }
1563}
1564
1565#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
1571pub struct EvmDomainContractCreationAllowedByCall {
1572 pub maybe_call: Option<PermissionedActionAllowedBy<EthereumAccountId>>,
1573}
1574
1575impl EvmDomainContractCreationAllowedByCall {
1576 pub fn clear(&mut self) {
1577 self.maybe_call.take();
1578 }
1579}
1580
1581#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
1582pub struct RuntimeObject<Number, Hash> {
1583 pub runtime_name: String,
1584 pub runtime_type: RuntimeType,
1585 pub runtime_upgrades: u32,
1586 pub instance_count: u32,
1587 pub hash: Hash,
1588 pub raw_genesis: RawGenesis,
1591 pub version: RuntimeVersion,
1592 pub created_at: Number,
1593 pub updated_at: Number,
1594}
1595
1596pub fn system_digest_final_key() -> Vec<u8> {
1599 frame_support::storage::storage_prefix("System".as_ref(), "Digest".as_ref()).to_vec()
1600}
1601
1602pub trait OnChainRewards<Balance> {
1604 fn on_chain_rewards(chain_id: ChainId, reward: Balance);
1605}
1606
1607impl<Balance> OnChainRewards<Balance> for () {
1608 fn on_chain_rewards(_chain_id: ChainId, _reward: Balance) {}
1609}
1610
1611#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
1612pub enum OperatorRewardSource<Number> {
1613 Bundle {
1614 at_block_number: Number,
1615 },
1616 XDMProtocolFees,
1617 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
1618 Dummy,
1619}
1620
1621pub trait SkipBalanceChecks {
1622 fn should_skip_balance_check(chain_id: ChainId) -> bool;
1623}
1624
1625impl SkipBalanceChecks for () {
1626 fn should_skip_balance_check(_chain_id: ChainId) -> bool {
1627 false
1628 }
1629}
1630
1631sp_api::decl_runtime_apis! {
1632 #[api_version(4)]
1637 pub trait DomainsApi<DomainHeader: HeaderT> {
1638 fn submit_bundle_unsigned(opaque_bundle: OpaqueBundle<NumberFor<Block>, Block::Hash, DomainHeader, Balance>);
1640
1641 fn submit_receipt_unsigned(singleton_receipt: SealedSingletonReceipt<NumberFor<Block>, Block::Hash, DomainHeader, Balance>);
1643
1644 fn extract_successful_bundles(
1646 domain_id: DomainId,
1647 extrinsics: Vec<Block::Extrinsic>,
1648 ) -> OpaqueBundles<Block, DomainHeader, Balance>;
1649
1650 fn extrinsics_shuffling_seed() -> Randomness;
1652
1653 fn domain_runtime_code(domain_id: DomainId) -> Option<Vec<u8>>;
1655
1656 fn runtime_id(domain_id: DomainId) -> Option<RuntimeId>;
1658
1659 fn runtime_upgrades() -> Vec<RuntimeId>;
1662
1663 fn domain_instance_data(domain_id: DomainId) -> Option<(DomainInstanceData, NumberFor<Block>)>;
1665
1666 fn domain_timestamp() -> Moment;
1668
1669 #[allow(clippy::deprecated_semver)]
1671 #[deprecated(since = "3", note = "Use `domain_timestamp()` instead")]
1672 fn timestamp() -> Moment;
1673
1674 fn consensus_transaction_byte_fee() -> Balance;
1677
1678 #[allow(clippy::deprecated_semver)]
1681 #[deprecated(since = "3", note = "Use `consensus_transaction_byte_fee()` instead")]
1682 fn consensus_chain_byte_fee() -> Balance;
1683
1684 fn domain_tx_range(domain_id: DomainId) -> U256;
1686
1687 fn genesis_state_root(domain_id: DomainId) -> Option<H256>;
1689
1690 fn head_receipt_number(domain_id: DomainId) -> HeaderNumberFor<DomainHeader>;
1692
1693 fn oldest_unconfirmed_receipt_number(domain_id: DomainId) -> Option<HeaderNumberFor<DomainHeader>>;
1695
1696 fn domain_bundle_limit(domain_id: DomainId) -> Option<DomainBundleLimit>;
1698
1699 fn non_empty_er_exists(domain_id: DomainId) -> bool;
1701
1702 fn domain_best_number(domain_id: DomainId) -> Option<HeaderNumberFor<DomainHeader>>;
1704
1705 fn execution_receipt(receipt_hash: HeaderHashFor<DomainHeader>) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1707
1708 fn domain_operators(domain_id: DomainId) -> Option<(BTreeMap<OperatorId, Balance>, Vec<OperatorId>)>;
1710
1711 fn receipt_hash(domain_id: DomainId, domain_number: HeaderNumberFor<DomainHeader>) -> Option<HeaderHashFor<DomainHeader>>;
1713
1714 fn latest_confirmed_domain_block(domain_id: DomainId) -> Option<(HeaderNumberFor<DomainHeader>, HeaderHashFor<DomainHeader>)>;
1716
1717 fn is_bad_er_pending_to_prune(domain_id: DomainId, receipt_hash: HeaderHashFor<DomainHeader>) -> bool;
1719
1720 fn storage_fund_account_balance(operator_id: OperatorId) -> Balance;
1722
1723 fn is_domain_runtime_upgraded_since(domain_id: DomainId, at: NumberFor<Block>) -> Option<bool>;
1725
1726 fn domain_sudo_call(domain_id: DomainId) -> Option<Vec<u8>>;
1728
1729 fn evm_domain_contract_creation_allowed_by_call(domain_id: DomainId) -> Option<PermissionedActionAllowedBy<EthereumAccountId>>;
1732
1733 fn last_confirmed_domain_block_receipt(domain_id: DomainId) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1735 }
1736
1737 pub trait BundleProducerElectionApi<Balance: Encode + Decode> {
1738 fn bundle_producer_election_params(domain_id: DomainId) -> Option<BundleProducerElectionParams<Balance>>;
1739
1740 fn operator(operator_id: OperatorId) -> Option<(OperatorPublicKey, Balance)>;
1741 }
1742}