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(any(test, feature = "test-ethereum"))]
12pub mod test_ethereum;
13#[cfg(any(test, feature = "test-ethereum"))]
14pub mod test_ethereum_tx;
15#[cfg(test)]
16mod tests;
17pub mod valued_trie;
18
19#[cfg(not(feature = "std"))]
20extern crate alloc;
21
22use crate::storage::{RawGenesis, StorageKey};
23#[cfg(not(feature = "std"))]
24use alloc::collections::BTreeSet;
25#[cfg(not(feature = "std"))]
26use alloc::string::String;
27#[cfg(not(feature = "std"))]
28use alloc::vec::Vec;
29use bundle_producer_election::{BundleProducerElectionParams, ProofOfElectionError};
30use core::num::ParseIntError;
31use core::ops::{Add, Sub};
32use core::str::FromStr;
33use domain_runtime_primitives::{EthereumAccountId, MultiAccountId};
34use frame_support::storage::storage_prefix;
35use frame_support::{Blake2_128Concat, StorageHasher};
36use hexlit::hex;
37use parity_scale_codec::{Codec, Decode, Encode, MaxEncodedLen};
38use scale_info::TypeInfo;
39use serde::{Deserialize, Serialize};
40use sp_core::crypto::KeyTypeId;
41use sp_core::sr25519::vrf::VrfSignature;
42#[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
43use sp_core::sr25519::vrf::{VrfPreOutput, VrfProof};
44use sp_core::H256;
45use sp_runtime::generic::OpaqueDigestItemId;
46use sp_runtime::traits::{
47 BlakeTwo256, Block as BlockT, CheckedAdd, Hash as HashT, Header as HeaderT, NumberFor, Zero,
48};
49use sp_runtime::{Digest, DigestItem, OpaqueExtrinsic, Percent};
50use sp_runtime_interface::pass_by;
51use sp_runtime_interface::pass_by::PassBy;
52use sp_std::collections::btree_map::BTreeMap;
53use sp_std::fmt::{Display, Formatter};
54use sp_trie::TrieLayout;
55use sp_version::RuntimeVersion;
56use sp_weights::Weight;
57#[cfg(feature = "std")]
58use std::collections::BTreeSet;
59use subspace_core_primitives::hashes::{blake3_hash, Blake3Hash};
60use subspace_core_primitives::pot::PotOutput;
61use subspace_core_primitives::solutions::bidirectional_distance;
62use subspace_core_primitives::{Randomness, U256};
63use subspace_runtime_primitives::{Balance, Moment};
64
65pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"oper");
67
68pub const DOMAIN_EXTRINSICS_SHUFFLING_SEED_SUBJECT: &[u8] = b"extrinsics-shuffling-seed";
70
71mod app {
72 use super::KEY_TYPE;
73 use sp_application_crypto::{app_crypto, sr25519};
74
75 app_crypto!(sr25519, KEY_TYPE);
76}
77
78pub const DOMAIN_STORAGE_FEE_MULTIPLIER: Balance = 3;
85
86pub type OperatorSignature = app::Signature;
88
89#[cfg(feature = "std")]
92pub type OperatorPair = app::Pair;
93
94pub type OperatorPublicKey = app::Public;
96
97pub struct OperatorKey;
99
100impl sp_runtime::BoundToRuntimeAppPublic for OperatorKey {
101 type Public = OperatorPublicKey;
102}
103
104pub type StakeWeight = u128;
108
109pub type ExtrinsicsRoot = H256;
111
112pub type HeaderHashingFor<Header> = <Header as HeaderT>::Hashing;
114pub type HeaderNumberFor<Header> = <Header as HeaderT>::Number;
116pub type HeaderHashFor<Header> = <Header as HeaderT>::Hash;
118
119#[derive(
121 Clone,
122 Copy,
123 Debug,
124 Hash,
125 Default,
126 Eq,
127 PartialEq,
128 Ord,
129 PartialOrd,
130 Encode,
131 Decode,
132 TypeInfo,
133 Serialize,
134 Deserialize,
135 MaxEncodedLen,
136)]
137pub struct DomainId(u32);
138
139impl From<u32> for DomainId {
140 #[inline]
141 fn from(x: u32) -> Self {
142 Self(x)
143 }
144}
145
146impl From<DomainId> for u32 {
147 #[inline]
148 fn from(domain_id: DomainId) -> Self {
149 domain_id.0
150 }
151}
152
153impl FromStr for DomainId {
154 type Err = ParseIntError;
155
156 fn from_str(s: &str) -> Result<Self, Self::Err> {
157 s.parse::<u32>().map(Into::into)
158 }
159}
160
161impl Add<DomainId> for DomainId {
162 type Output = Self;
163
164 fn add(self, other: DomainId) -> Self {
165 Self(self.0 + other.0)
166 }
167}
168
169impl Sub<DomainId> for DomainId {
170 type Output = Self;
171
172 fn sub(self, other: DomainId) -> Self {
173 Self(self.0 - other.0)
174 }
175}
176
177impl CheckedAdd for DomainId {
178 fn checked_add(&self, rhs: &Self) -> Option<Self> {
179 self.0.checked_add(rhs.0).map(Self)
180 }
181}
182
183impl DomainId {
184 pub const fn new(id: u32) -> Self {
186 Self(id)
187 }
188
189 pub fn to_le_bytes(&self) -> [u8; 4] {
191 self.0.to_le_bytes()
192 }
193}
194
195impl Display for DomainId {
196 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
197 self.0.fmt(f)
198 }
199}
200
201impl PassBy for DomainId {
202 type PassBy = pass_by::Codec<Self>;
203}
204
205#[derive(
207 Clone,
208 Copy,
209 Debug,
210 Hash,
211 Eq,
212 PartialEq,
213 Ord,
214 PartialOrd,
215 Encode,
216 Decode,
217 TypeInfo,
218 Serialize,
219 Deserialize,
220 MaxEncodedLen,
221)]
222pub enum ChainId {
223 Consensus,
224 Domain(DomainId),
225}
226
227impl ChainId {
228 #[inline]
229 pub fn consensus_chain_id() -> Self {
230 Self::Consensus
231 }
232
233 #[inline]
234 pub fn is_consensus_chain(&self) -> bool {
235 match self {
236 ChainId::Consensus => true,
237 ChainId::Domain(_) => false,
238 }
239 }
240
241 #[inline]
242 pub fn maybe_domain_chain(&self) -> Option<DomainId> {
243 match self {
244 ChainId::Consensus => None,
245 ChainId::Domain(domain_id) => Some(*domain_id),
246 }
247 }
248}
249
250impl From<u32> for ChainId {
251 #[inline]
252 fn from(x: u32) -> Self {
253 Self::Domain(DomainId::new(x))
254 }
255}
256
257impl From<DomainId> for ChainId {
258 #[inline]
259 fn from(x: DomainId) -> Self {
260 Self::Domain(x)
261 }
262}
263
264#[derive(Clone, Debug, Decode, Default, Encode, Eq, PartialEq, TypeInfo)]
265pub struct BlockFees<Balance> {
266 pub consensus_storage_fee: Balance,
268 pub domain_execution_fee: Balance,
271 pub burned_balance: Balance,
273 pub chain_rewards: BTreeMap<ChainId, Balance>,
275}
276
277impl<Balance> BlockFees<Balance>
278where
279 Balance: CheckedAdd + Zero,
280{
281 pub fn new(
282 domain_execution_fee: Balance,
283 consensus_storage_fee: Balance,
284 burned_balance: Balance,
285 chain_rewards: BTreeMap<ChainId, Balance>,
286 ) -> Self {
287 BlockFees {
288 consensus_storage_fee,
289 domain_execution_fee,
290 burned_balance,
291 chain_rewards,
292 }
293 }
294
295 pub fn total_fees(&self) -> Option<Balance> {
297 let total_chain_reward = self
298 .chain_rewards
299 .values()
300 .try_fold(Zero::zero(), |acc: Balance, cr| acc.checked_add(cr))?;
301 self.consensus_storage_fee
302 .checked_add(&self.domain_execution_fee)
303 .and_then(|balance| balance.checked_add(&self.burned_balance))
304 .and_then(|balance| balance.checked_add(&total_chain_reward))
305 }
306}
307
308#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, Default)]
310pub struct Transfers<Balance> {
311 pub transfers_in: BTreeMap<ChainId, Balance>,
313 pub transfers_out: BTreeMap<ChainId, Balance>,
315 pub rejected_transfers_claimed: BTreeMap<ChainId, Balance>,
317 pub transfers_rejected: BTreeMap<ChainId, Balance>,
319}
320
321impl<Balance> Transfers<Balance> {
322 pub fn is_valid(&self, chain_id: ChainId) -> bool {
323 !self.transfers_rejected.contains_key(&chain_id)
324 && !self.transfers_in.contains_key(&chain_id)
325 && !self.transfers_out.contains_key(&chain_id)
326 && !self.rejected_transfers_claimed.contains_key(&chain_id)
327 }
328}
329
330pub const INITIAL_DOMAIN_TX_RANGE: u64 = 3;
335
336#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
337pub struct BundleHeader<Number, Hash, DomainHeader: HeaderT, Balance> {
338 pub proof_of_election: ProofOfElection,
340 pub receipt: ExecutionReceipt<
343 Number,
344 Hash,
345 HeaderNumberFor<DomainHeader>,
346 HeaderHashFor<DomainHeader>,
347 Balance,
348 >,
349 pub estimated_bundle_weight: Weight,
353 pub bundle_extrinsics_root: HeaderHashFor<DomainHeader>,
355}
356
357impl<Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
358 BundleHeader<Number, Hash, DomainHeader, Balance>
359{
360 pub fn hash(&self) -> HeaderHashFor<DomainHeader> {
362 HeaderHashingFor::<DomainHeader>::hash_of(self)
363 }
364}
365
366#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
368pub struct SealedBundleHeader<Number, Hash, DomainHeader: HeaderT, Balance> {
369 pub header: BundleHeader<Number, Hash, DomainHeader, Balance>,
371 pub signature: OperatorSignature,
373}
374
375impl<Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
376 SealedBundleHeader<Number, Hash, DomainHeader, Balance>
377{
378 pub fn new(
380 header: BundleHeader<Number, Hash, DomainHeader, Balance>,
381 signature: OperatorSignature,
382 ) -> Self {
383 Self { header, signature }
384 }
385
386 pub fn pre_hash(&self) -> HeaderHashFor<DomainHeader> {
388 self.header.hash()
389 }
390
391 pub fn hash(&self) -> HeaderHashFor<DomainHeader> {
393 HeaderHashingFor::<DomainHeader>::hash_of(self)
394 }
395
396 pub fn slot_number(&self) -> u64 {
397 self.header.proof_of_election.slot_number
398 }
399}
400
401#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
403pub struct Bundle<Extrinsic, Number, Hash, DomainHeader: HeaderT, Balance> {
404 pub sealed_header: SealedBundleHeader<Number, Hash, DomainHeader, Balance>,
406 pub extrinsics: Vec<Extrinsic>,
408}
409
410impl<Extrinsic: Encode, Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
411 Bundle<Extrinsic, Number, Hash, DomainHeader, Balance>
412{
413 pub fn hash(&self) -> H256 {
415 BlakeTwo256::hash_of(self)
416 }
417
418 pub fn domain_id(&self) -> DomainId {
420 self.sealed_header.header.proof_of_election.domain_id
421 }
422
423 pub fn extrinsics_root(&self) -> HeaderHashFor<DomainHeader> {
425 self.sealed_header.header.bundle_extrinsics_root
426 }
427
428 pub fn operator_id(&self) -> OperatorId {
430 self.sealed_header.header.proof_of_election.operator_id
431 }
432
433 pub fn receipt(
435 &self,
436 ) -> &ExecutionReceipt<
437 Number,
438 Hash,
439 HeaderNumberFor<DomainHeader>,
440 HeaderHashFor<DomainHeader>,
441 Balance,
442 > {
443 &self.sealed_header.header.receipt
444 }
445
446 pub fn into_receipt(
448 self,
449 ) -> ExecutionReceipt<
450 Number,
451 Hash,
452 HeaderNumberFor<DomainHeader>,
453 HeaderHashFor<DomainHeader>,
454 Balance,
455 > {
456 self.sealed_header.header.receipt
457 }
458
459 pub fn size(&self) -> u32 {
461 self.encoded_size() as u32
462 }
463
464 pub fn body_size(&self) -> u32 {
466 self.extrinsics
467 .iter()
468 .map(|tx| tx.encoded_size() as u32)
469 .sum::<u32>()
470 }
471
472 pub fn estimated_weight(&self) -> Weight {
473 self.sealed_header.header.estimated_bundle_weight
474 }
475
476 pub fn slot_number(&self) -> u64 {
477 self.sealed_header.header.proof_of_election.slot_number
478 }
479}
480
481pub type OpaqueBundle<Number, Hash, DomainHeader, Balance> =
483 Bundle<OpaqueExtrinsic, Number, Hash, DomainHeader, Balance>;
484
485pub type OpaqueBundles<Block, DomainHeader, Balance> =
487 Vec<OpaqueBundle<NumberFor<Block>, <Block as BlockT>::Hash, DomainHeader, Balance>>;
488
489impl<Extrinsic: Encode, Number, Hash, DomainHeader: HeaderT, Balance>
490 Bundle<Extrinsic, Number, Hash, DomainHeader, Balance>
491{
492 pub fn into_opaque_bundle(self) -> OpaqueBundle<Number, Hash, DomainHeader, Balance> {
494 let Bundle {
495 sealed_header,
496 extrinsics,
497 } = self;
498 let opaque_extrinsics = extrinsics
499 .into_iter()
500 .map(|xt| {
501 OpaqueExtrinsic::from_bytes(&xt.encode())
502 .expect("We have just encoded a valid extrinsic; qed")
503 })
504 .collect();
505 OpaqueBundle {
506 sealed_header,
507 extrinsics: opaque_extrinsics,
508 }
509 }
510}
511
512#[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
513pub fn dummy_opaque_bundle<
514 Number: Encode,
515 Hash: Default + Encode,
516 DomainHeader: HeaderT,
517 Balance: Encode,
518>(
519 domain_id: DomainId,
520 operator_id: OperatorId,
521 receipt: ExecutionReceipt<
522 Number,
523 Hash,
524 HeaderNumberFor<DomainHeader>,
525 HeaderHashFor<DomainHeader>,
526 Balance,
527 >,
528) -> OpaqueBundle<Number, Hash, DomainHeader, Balance> {
529 use sp_core::crypto::UncheckedFrom;
530
531 let header = BundleHeader {
532 proof_of_election: ProofOfElection::dummy(domain_id, operator_id),
533 receipt,
534 estimated_bundle_weight: Default::default(),
535 bundle_extrinsics_root: Default::default(),
536 };
537 let signature = OperatorSignature::unchecked_from([0u8; 64]);
538
539 OpaqueBundle {
540 sealed_header: SealedBundleHeader::new(header, signature),
541 extrinsics: Vec::new(),
542 }
543}
544
545#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
547pub struct BundleDigest<Hash> {
548 pub header_hash: Hash,
550 pub extrinsics_root: Hash,
552 pub size: u32,
554}
555
556#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
558pub struct ExecutionReceipt<Number, Hash, DomainNumber, DomainHash, Balance> {
559 pub domain_block_number: DomainNumber,
561 pub domain_block_hash: DomainHash,
563 pub domain_block_extrinsic_root: DomainHash,
565 pub parent_domain_block_receipt_hash: DomainHash,
567 pub consensus_block_number: Number,
570 pub consensus_block_hash: Hash,
572 pub inboxed_bundles: Vec<InboxedBundle<DomainHash>>,
574 pub final_state_root: DomainHash,
578 pub execution_trace: Vec<DomainHash>,
580 pub execution_trace_root: H256,
584 pub block_fees: BlockFees<Balance>,
587 pub transfers: Transfers<Balance>,
589}
590
591impl<Number, Hash, DomainNumber, DomainHash, Balance>
592 ExecutionReceipt<Number, Hash, DomainNumber, DomainHash, Balance>
593{
594 pub fn bundles_extrinsics_roots(&self) -> Vec<&DomainHash> {
595 self.inboxed_bundles
596 .iter()
597 .map(|b| &b.extrinsics_root)
598 .collect()
599 }
600
601 pub fn valid_bundle_digest_at(&self, index: usize) -> Option<DomainHash>
602 where
603 DomainHash: Copy,
604 {
605 match self.inboxed_bundles.get(index).map(|ib| &ib.bundle) {
606 Some(BundleValidity::Valid(bundle_digest_hash)) => Some(*bundle_digest_hash),
607 _ => None,
608 }
609 }
610
611 pub fn valid_bundle_digests(&self) -> Vec<DomainHash>
612 where
613 DomainHash: Copy,
614 {
615 self.inboxed_bundles
616 .iter()
617 .filter_map(|b| match b.bundle {
618 BundleValidity::Valid(bundle_digest_hash) => Some(bundle_digest_hash),
619 BundleValidity::Invalid(_) => None,
620 })
621 .collect()
622 }
623
624 pub fn valid_bundle_indexes(&self) -> Vec<u32> {
625 self.inboxed_bundles
626 .iter()
627 .enumerate()
628 .filter_map(|(index, b)| match b.bundle {
629 BundleValidity::Valid(_) => Some(index as u32),
630 BundleValidity::Invalid(_) => None,
631 })
632 .collect()
633 }
634}
635
636impl<
637 Number: Encode + Zero,
638 Hash: Encode + Default,
639 DomainNumber: Encode + Zero,
640 DomainHash: Clone + Encode + Default,
641 Balance: Encode + Zero + Default,
642 > ExecutionReceipt<Number, Hash, DomainNumber, DomainHash, Balance>
643{
644 pub fn hash<DomainHashing: HashT<Output = DomainHash>>(&self) -> DomainHash {
646 DomainHashing::hash_of(self)
647 }
648
649 pub fn genesis(
650 genesis_state_root: DomainHash,
651 genesis_extrinsic_root: DomainHash,
652 genesis_domain_block_hash: DomainHash,
653 ) -> Self {
654 ExecutionReceipt {
655 domain_block_number: Zero::zero(),
656 domain_block_hash: genesis_domain_block_hash,
657 domain_block_extrinsic_root: genesis_extrinsic_root,
658 parent_domain_block_receipt_hash: Default::default(),
659 consensus_block_hash: Default::default(),
660 consensus_block_number: Zero::zero(),
661 inboxed_bundles: Vec::new(),
662 final_state_root: genesis_state_root.clone(),
663 execution_trace: sp_std::vec![genesis_state_root],
664 execution_trace_root: Default::default(),
665 block_fees: Default::default(),
666 transfers: Default::default(),
667 }
668 }
669
670 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
671 pub fn dummy<DomainHashing>(
672 consensus_block_number: Number,
673 consensus_block_hash: Hash,
674 domain_block_number: DomainNumber,
675 parent_domain_block_receipt_hash: DomainHash,
676 ) -> ExecutionReceipt<Number, Hash, DomainNumber, DomainHash, Balance>
677 where
678 DomainHashing: HashT<Output = DomainHash>,
679 {
680 let execution_trace = sp_std::vec![Default::default(), Default::default()];
681 let execution_trace_root = {
682 let trace: Vec<[u8; 32]> = execution_trace
683 .iter()
684 .map(|r: &DomainHash| r.encode().try_into().expect("H256 must fit into [u8; 32]"))
685 .collect();
686 crate::merkle_tree::MerkleTree::from_leaves(trace.as_slice())
687 .root()
688 .expect("Compute merkle root of trace should success")
689 .into()
690 };
691 ExecutionReceipt {
692 domain_block_number,
693 domain_block_hash: Default::default(),
694 domain_block_extrinsic_root: Default::default(),
695 parent_domain_block_receipt_hash,
696 consensus_block_number,
697 consensus_block_hash,
698 inboxed_bundles: sp_std::vec![InboxedBundle::dummy(Default::default())],
699 final_state_root: Default::default(),
700 execution_trace,
701 execution_trace_root,
702 block_fees: Default::default(),
703 transfers: Default::default(),
704 }
705 }
706}
707
708#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
709pub struct ProofOfElection {
710 pub domain_id: DomainId,
712 pub slot_number: u64,
714 pub proof_of_time: PotOutput,
716 pub vrf_signature: VrfSignature,
718 pub operator_id: OperatorId,
720}
721
722impl ProofOfElection {
723 pub fn verify_vrf_signature(
724 &self,
725 operator_signing_key: &OperatorPublicKey,
726 ) -> Result<(), ProofOfElectionError> {
727 let global_challenge = self
728 .proof_of_time
729 .derive_global_randomness()
730 .derive_global_challenge(self.slot_number);
731 bundle_producer_election::verify_vrf_signature(
732 self.domain_id,
733 operator_signing_key,
734 &self.vrf_signature,
735 &global_challenge,
736 )
737 }
738
739 pub fn vrf_hash(&self) -> Blake3Hash {
741 let mut bytes = self.vrf_signature.pre_output.encode();
742 bytes.append(&mut self.vrf_signature.proof.encode());
743 blake3_hash(&bytes)
744 }
745
746 pub fn slot_number(&self) -> u64 {
747 self.slot_number
748 }
749}
750
751impl ProofOfElection {
752 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
753 pub fn dummy(domain_id: DomainId, operator_id: OperatorId) -> Self {
754 let output_bytes = sp_std::vec![0u8; VrfPreOutput::max_encoded_len()];
755 let proof_bytes = sp_std::vec![0u8; VrfProof::max_encoded_len()];
756 let vrf_signature = VrfSignature {
757 pre_output: VrfPreOutput::decode(&mut output_bytes.as_slice()).unwrap(),
758 proof: VrfProof::decode(&mut proof_bytes.as_slice()).unwrap(),
759 };
760 Self {
761 domain_id,
762 slot_number: 0u64,
763 proof_of_time: PotOutput::default(),
764 vrf_signature,
765 operator_id,
766 }
767 }
768}
769
770#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
773pub struct SingletonReceipt<Number, Hash, DomainHeader: HeaderT, Balance> {
774 pub proof_of_election: ProofOfElection,
776 pub receipt: ExecutionReceipt<
778 Number,
779 Hash,
780 HeaderNumberFor<DomainHeader>,
781 HeaderHashFor<DomainHeader>,
782 Balance,
783 >,
784}
785
786impl<Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
787 SingletonReceipt<Number, Hash, DomainHeader, Balance>
788{
789 pub fn hash(&self) -> HeaderHashFor<DomainHeader> {
790 HeaderHashingFor::<DomainHeader>::hash_of(&self)
791 }
792}
793
794#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
795pub struct SealedSingletonReceipt<Number, Hash, DomainHeader: HeaderT, Balance> {
796 pub singleton_receipt: SingletonReceipt<Number, Hash, DomainHeader, Balance>,
798 pub signature: OperatorSignature,
800}
801
802impl<Number: Encode, Hash: Encode, DomainHeader: HeaderT, Balance: Encode>
803 SealedSingletonReceipt<Number, Hash, DomainHeader, Balance>
804{
805 pub fn domain_id(&self) -> DomainId {
807 self.singleton_receipt.proof_of_election.domain_id
808 }
809
810 pub fn operator_id(&self) -> OperatorId {
812 self.singleton_receipt.proof_of_election.operator_id
813 }
814
815 pub fn slot_number(&self) -> u64 {
817 self.singleton_receipt.proof_of_election.slot_number
818 }
819
820 pub fn receipt(
822 &self,
823 ) -> &ExecutionReceipt<
824 Number,
825 Hash,
826 HeaderNumberFor<DomainHeader>,
827 HeaderHashFor<DomainHeader>,
828 Balance,
829 > {
830 &self.singleton_receipt.receipt
831 }
832
833 pub fn into_receipt(
835 self,
836 ) -> ExecutionReceipt<
837 Number,
838 Hash,
839 HeaderNumberFor<DomainHeader>,
840 HeaderHashFor<DomainHeader>,
841 Balance,
842 > {
843 self.singleton_receipt.receipt
844 }
845
846 pub fn pre_hash(&self) -> HeaderHashFor<DomainHeader> {
848 HeaderHashingFor::<DomainHeader>::hash_of(&self.singleton_receipt)
849 }
850
851 pub fn size(&self) -> u32 {
853 self.encoded_size() as u32
854 }
855}
856
857#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
859pub enum OperatorAllowList<AccountId: Ord> {
860 Anyone,
862 Operators(BTreeSet<AccountId>),
865}
866
867impl<AccountId: Ord> OperatorAllowList<AccountId> {
868 pub fn is_operator_allowed(&self, operator: &AccountId) -> bool {
870 match self {
871 OperatorAllowList::Anyone => true,
872 OperatorAllowList::Operators(allowed_operators) => allowed_operators.contains(operator),
873 }
874 }
875}
876
877#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
879pub enum PermissionedActionAllowedBy<AccountId: Codec + Clone> {
880 Accounts(Vec<AccountId>),
881 Anyone,
882}
883
884impl<AccountId: Codec + PartialEq + Clone> PermissionedActionAllowedBy<AccountId> {
885 pub fn is_allowed(&self, who: &AccountId) -> bool {
886 match self {
887 PermissionedActionAllowedBy::Accounts(accounts) => accounts.contains(who),
888 PermissionedActionAllowedBy::Anyone => true,
889 }
890 }
891
892 pub fn is_anyone_allowed(&self) -> bool {
893 matches!(self, PermissionedActionAllowedBy::Anyone)
894 }
895}
896
897#[derive(
899 TypeInfo, Debug, Default, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize,
900)]
901pub enum EvmType {
902 #[default]
903 Public,
905 Private {
907 initial_contract_creation_allow_list: PermissionedActionAllowedBy<EthereumAccountId>,
910 },
911}
912
913impl EvmType {
914 pub fn initial_contract_creation_allow_list(
916 &self,
917 ) -> Option<&PermissionedActionAllowedBy<EthereumAccountId>> {
918 match self {
919 EvmType::Public => None,
920 EvmType::Private {
921 initial_contract_creation_allow_list,
922 } => Some(initial_contract_creation_allow_list),
923 }
924 }
925
926 pub fn is_public_evm_domain(&self) -> bool {
928 matches!(self, EvmType::Public)
929 }
930
931 pub fn is_private_evm_domain(&self) -> bool {
933 matches!(self, EvmType::Private { .. })
934 }
935}
936
937#[derive(
939 TypeInfo, Debug, Default, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize,
940)]
941pub struct EvmDomainRuntimeConfig {
942 pub evm_type: EvmType,
943}
944
945#[derive(
947 TypeInfo, Debug, Default, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize,
948)]
949pub struct AutoIdDomainRuntimeConfig {
950 }
952
953#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
955pub enum DomainRuntimeConfig {
956 Evm(EvmDomainRuntimeConfig),
957 AutoId(AutoIdDomainRuntimeConfig),
958}
959
960impl Default for DomainRuntimeConfig {
961 fn default() -> Self {
962 Self::default_evm()
963 }
964}
965
966impl From<EvmDomainRuntimeConfig> for DomainRuntimeConfig {
967 fn from(evm_config: EvmDomainRuntimeConfig) -> Self {
968 DomainRuntimeConfig::Evm(evm_config)
969 }
970}
971
972impl From<AutoIdDomainRuntimeConfig> for DomainRuntimeConfig {
973 fn from(auto_id_config: AutoIdDomainRuntimeConfig) -> Self {
974 DomainRuntimeConfig::AutoId(auto_id_config)
975 }
976}
977
978impl DomainRuntimeConfig {
979 pub fn default_evm() -> Self {
980 DomainRuntimeConfig::Evm(EvmDomainRuntimeConfig::default())
981 }
982
983 pub fn default_auto_id() -> Self {
984 DomainRuntimeConfig::AutoId(AutoIdDomainRuntimeConfig::default())
985 }
986
987 pub fn is_evm_domain(&self) -> bool {
988 matches!(self, DomainRuntimeConfig::Evm(_))
989 }
990
991 pub fn is_auto_id(&self) -> bool {
992 matches!(self, DomainRuntimeConfig::AutoId(_))
993 }
994
995 pub fn evm(&self) -> Option<&EvmDomainRuntimeConfig> {
996 match self {
997 DomainRuntimeConfig::Evm(evm_config) => Some(evm_config),
998 _ => None,
999 }
1000 }
1001
1002 pub fn initial_contract_creation_allow_list(
1003 &self,
1004 ) -> Option<&PermissionedActionAllowedBy<EthereumAccountId>> {
1005 self.evm()
1006 .and_then(|evm_config| evm_config.evm_type.initial_contract_creation_allow_list())
1007 }
1008
1009 pub fn auto_id(&self) -> Option<&AutoIdDomainRuntimeConfig> {
1010 match self {
1011 DomainRuntimeConfig::AutoId(auto_id_config) => Some(auto_id_config),
1012 _ => None,
1013 }
1014 }
1015}
1016
1017#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
1018pub struct GenesisDomain<AccountId: Ord, Balance> {
1019 pub runtime_name: String,
1021 pub runtime_type: RuntimeType,
1022 pub runtime_version: RuntimeVersion,
1023 pub raw_genesis_storage: Vec<u8>,
1024
1025 pub owner_account_id: AccountId,
1027 pub domain_name: String,
1028 pub bundle_slot_probability: (u64, u64),
1029 pub operator_allow_list: OperatorAllowList<AccountId>,
1030 pub domain_runtime_config: DomainRuntimeConfig,
1032
1033 pub signing_key: OperatorPublicKey,
1035 pub minimum_nominator_stake: Balance,
1036 pub nomination_tax: Percent,
1037
1038 pub initial_balances: Vec<(MultiAccountId, Balance)>,
1040}
1041
1042#[derive(
1044 Debug, Default, Encode, Decode, TypeInfo, Copy, Clone, PartialEq, Eq, Serialize, Deserialize,
1045)]
1046pub enum RuntimeType {
1047 #[default]
1048 Evm,
1049 AutoId,
1050}
1051
1052pub type RuntimeId = u32;
1054
1055pub type EpochIndex = u32;
1057
1058pub type OperatorId = u64;
1060
1061pub type ChannelId = sp_core::U256;
1063
1064#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
1066pub enum DomainDigestItem {
1067 DomainRuntimeUpgraded(RuntimeId),
1068 DomainInstantiated(DomainId),
1069}
1070
1071pub trait DomainsDigestItem {
1073 fn domain_runtime_upgrade(runtime_id: RuntimeId) -> Self;
1074 fn as_domain_runtime_upgrade(&self) -> Option<RuntimeId>;
1075
1076 fn domain_instantiation(domain_id: DomainId) -> Self;
1077 fn as_domain_instantiation(&self) -> Option<DomainId>;
1078}
1079
1080impl DomainsDigestItem for DigestItem {
1081 fn domain_runtime_upgrade(runtime_id: RuntimeId) -> Self {
1082 Self::Other(DomainDigestItem::DomainRuntimeUpgraded(runtime_id).encode())
1083 }
1084
1085 fn as_domain_runtime_upgrade(&self) -> Option<RuntimeId> {
1086 match self.try_to::<DomainDigestItem>(OpaqueDigestItemId::Other) {
1087 Some(DomainDigestItem::DomainRuntimeUpgraded(runtime_id)) => Some(runtime_id),
1088 _ => None,
1089 }
1090 }
1091
1092 fn domain_instantiation(domain_id: DomainId) -> Self {
1093 Self::Other(DomainDigestItem::DomainInstantiated(domain_id).encode())
1094 }
1095
1096 fn as_domain_instantiation(&self) -> Option<DomainId> {
1097 match self.try_to::<DomainDigestItem>(OpaqueDigestItemId::Other) {
1098 Some(DomainDigestItem::DomainInstantiated(domain_id)) => Some(domain_id),
1099 _ => None,
1100 }
1101 }
1102}
1103
1104pub(crate) fn evm_chain_id_storage_key() -> StorageKey {
1111 StorageKey(
1112 storage_prefix(
1113 "EVMChainId".as_bytes(),
1116 "ChainId".as_bytes(),
1118 )
1119 .to_vec(),
1120 )
1121}
1122
1123pub(crate) fn evm_contract_creation_allowed_by_storage_key() -> StorageKey {
1130 StorageKey(
1131 storage_prefix(
1132 "EVMNoncetracker".as_bytes(),
1135 "ContractCreationAllowedBy".as_bytes(),
1137 )
1138 .to_vec(),
1139 )
1140}
1141
1142pub fn domain_total_issuance_storage_key() -> StorageKey {
1149 StorageKey(
1150 storage_prefix(
1151 "Balances".as_bytes(),
1153 "TotalIssuance".as_bytes(),
1155 )
1156 .to_vec(),
1157 )
1158}
1159
1160pub fn domain_account_storage_key<AccountId: Encode>(who: AccountId) -> StorageKey {
1167 let storage_prefix = storage_prefix("System".as_bytes(), "Account".as_bytes());
1168 let key_hashed = who.using_encoded(Blake2_128Concat::hash);
1169
1170 let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len());
1171
1172 final_key.extend_from_slice(&storage_prefix);
1173 final_key.extend_from_slice(key_hashed.as_ref());
1174
1175 StorageKey(final_key)
1176}
1177
1178pub fn self_domain_id_storage_key() -> StorageKey {
1183 StorageKey(
1184 frame_support::storage::storage_prefix(
1185 "SelfDomainId".as_bytes(),
1188 "SelfDomainId".as_bytes(),
1190 )
1191 .to_vec(),
1192 )
1193}
1194
1195#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
1197pub struct DomainInstanceData {
1198 pub runtime_type: RuntimeType,
1199 pub raw_genesis: RawGenesis,
1200}
1201
1202#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
1203pub struct DomainBundleLimit {
1204 pub max_bundle_size: u32,
1206 pub max_bundle_weight: Weight,
1208}
1209
1210pub fn calculate_max_bundle_weight_and_size(
1214 max_domain_block_size: u32,
1215 max_domain_block_weight: Weight,
1216 consensus_slot_probability: (u64, u64),
1217 bundle_slot_probability: (u64, u64),
1218) -> Option<DomainBundleLimit> {
1219 let expected_bundles_per_block = bundle_slot_probability
1222 .0
1223 .checked_mul(consensus_slot_probability.1)?
1224 .checked_div(
1225 bundle_slot_probability
1226 .1
1227 .checked_mul(consensus_slot_probability.0)?,
1228 )?;
1229
1230 let max_proof_size = max_domain_block_weight.proof_size();
1233 let max_bundle_weight = max_domain_block_weight
1234 .checked_div(expected_bundles_per_block)?
1235 .set_proof_size(max_proof_size);
1236
1237 let max_bundle_size =
1238 (max_domain_block_size as u64).checked_div(expected_bundles_per_block)? as u32;
1239
1240 Some(DomainBundleLimit {
1241 max_bundle_size,
1242 max_bundle_weight,
1243 })
1244}
1245
1246pub fn signer_in_tx_range(bundle_vrf_hash: &U256, signer_id_hash: &U256, tx_range: &U256) -> bool {
1248 let distance_from_vrf_hash = bidirectional_distance(bundle_vrf_hash, signer_id_hash);
1249 distance_from_vrf_hash <= (*tx_range / 2)
1250}
1251
1252#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
1254pub enum InvalidReceipt {
1255 InvalidBundles,
1257}
1258
1259#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
1260pub enum ReceiptValidity {
1261 Valid,
1262 Invalid(InvalidReceipt),
1263}
1264
1265#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
1269pub enum InvalidBundleType {
1270 #[codec(index = 0)]
1272 UndecodableTx(u32),
1273 #[codec(index = 1)]
1275 OutOfRangeTx(u32),
1276 #[codec(index = 2)]
1278 IllegalTx(u32),
1279 #[codec(index = 3)]
1281 InvalidXDM(u32),
1282 #[codec(index = 4)]
1284 InherentExtrinsic(u32),
1285 #[codec(index = 5)]
1287 InvalidBundleWeight,
1288}
1289
1290impl InvalidBundleType {
1291 pub fn checking_order(&self) -> u64 {
1293 let extrinsic_order = match self {
1296 Self::UndecodableTx(i) => *i,
1297 Self::OutOfRangeTx(i) => *i,
1298 Self::IllegalTx(i) => *i,
1299 Self::InvalidXDM(i) => *i,
1300 Self::InherentExtrinsic(i) => *i,
1301 Self::InvalidBundleWeight => u32::MAX,
1306 };
1307
1308 let rule_order = match self {
1315 Self::UndecodableTx(_) => 1,
1316 Self::OutOfRangeTx(_) => 2,
1317 Self::InherentExtrinsic(_) => 3,
1318 Self::InvalidXDM(_) => 4,
1319 Self::IllegalTx(_) => 5,
1320 Self::InvalidBundleWeight => 6,
1321 };
1322
1323 ((extrinsic_order as u64) << 32) | (rule_order as u64)
1328 }
1329
1330 pub fn extrinsic_index(&self) -> Option<u32> {
1335 match self {
1336 Self::UndecodableTx(i) => Some(*i),
1337 Self::OutOfRangeTx(i) => Some(*i),
1338 Self::IllegalTx(i) => Some(*i),
1339 Self::InvalidXDM(i) => Some(*i),
1340 Self::InherentExtrinsic(i) => Some(*i),
1341 Self::InvalidBundleWeight => None,
1342 }
1343 }
1344}
1345
1346#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
1347pub enum BundleValidity<Hash> {
1348 Invalid(InvalidBundleType),
1351 Valid(Hash),
1355}
1356
1357#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
1359pub struct InboxedBundle<Hash> {
1360 pub bundle: BundleValidity<Hash>,
1361 pub extrinsics_root: Hash,
1363}
1364
1365impl<Hash> InboxedBundle<Hash> {
1366 pub fn valid(bundle_digest_hash: Hash, extrinsics_root: Hash) -> Self {
1367 InboxedBundle {
1368 bundle: BundleValidity::Valid(bundle_digest_hash),
1369 extrinsics_root,
1370 }
1371 }
1372
1373 pub fn invalid(invalid_bundle_type: InvalidBundleType, extrinsics_root: Hash) -> Self {
1374 InboxedBundle {
1375 bundle: BundleValidity::Invalid(invalid_bundle_type),
1376 extrinsics_root,
1377 }
1378 }
1379
1380 pub fn is_invalid(&self) -> bool {
1381 matches!(self.bundle, BundleValidity::Invalid(_))
1382 }
1383
1384 pub fn invalid_extrinsic_index(&self) -> Option<u32> {
1385 match &self.bundle {
1386 BundleValidity::Invalid(invalid_bundle_type) => invalid_bundle_type.extrinsic_index(),
1387 BundleValidity::Valid(_) => None,
1388 }
1389 }
1390
1391 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
1392 pub fn dummy(extrinsics_root: Hash) -> Self
1393 where
1394 Hash: Default,
1395 {
1396 InboxedBundle {
1397 bundle: BundleValidity::Valid(Hash::default()),
1398 extrinsics_root,
1399 }
1400 }
1401}
1402
1403pub const EMPTY_EXTRINSIC_ROOT: ExtrinsicsRoot = ExtrinsicsRoot {
1405 0: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314"),
1406};
1407
1408pub fn derive_domain_block_hash<DomainHeader: HeaderT>(
1409 domain_block_number: DomainHeader::Number,
1410 extrinsics_root: DomainHeader::Hash,
1411 state_root: DomainHeader::Hash,
1412 parent_domain_block_hash: DomainHeader::Hash,
1413 digest: Digest,
1414) -> DomainHeader::Hash {
1415 let domain_header = DomainHeader::new(
1416 domain_block_number,
1417 extrinsics_root,
1418 state_root,
1419 parent_domain_block_hash,
1420 digest,
1421 );
1422
1423 domain_header.hash()
1424}
1425
1426#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
1428pub enum ExtrinsicDigest {
1429 Data(Vec<u8>),
1431 Hash(H256),
1433}
1434
1435impl ExtrinsicDigest {
1436 pub fn new<Layout: TrieLayout>(ext: Vec<u8>) -> Self
1437 where
1438 Layout::Hash: HashT,
1439 <Layout::Hash as HashT>::Output: Into<H256>,
1440 {
1441 if let Some(threshold) = Layout::MAX_INLINE_VALUE {
1442 if ext.len() >= threshold as usize {
1443 ExtrinsicDigest::Hash(Layout::Hash::hash(&ext).into())
1444 } else {
1445 ExtrinsicDigest::Data(ext)
1446 }
1447 } else {
1448 ExtrinsicDigest::Data(ext)
1449 }
1450 }
1451}
1452
1453pub trait DomainsTransfersTracker<Balance> {
1455 type Error;
1456
1457 fn initialize_domain_balance(domain_id: DomainId, amount: Balance) -> Result<(), Self::Error>;
1459
1460 fn note_transfer(
1463 from_chain_id: ChainId,
1464 to_chain_id: ChainId,
1465 amount: Balance,
1466 ) -> Result<(), Self::Error>;
1467
1468 fn confirm_transfer(
1470 from_chain_id: ChainId,
1471 to_chain_id: ChainId,
1472 amount: Balance,
1473 ) -> Result<(), Self::Error>;
1474
1475 fn claim_rejected_transfer(
1477 from_chain_id: ChainId,
1478 to_chain_id: ChainId,
1479 amount: Balance,
1480 ) -> Result<(), Self::Error>;
1481
1482 fn reject_transfer(
1484 from_chain_id: ChainId,
1485 to_chain_id: ChainId,
1486 amount: Balance,
1487 ) -> Result<(), Self::Error>;
1488
1489 fn reduce_domain_balance(domain_id: DomainId, amount: Balance) -> Result<(), Self::Error>;
1491}
1492
1493pub trait DomainOwner<AccountId> {
1495 fn is_domain_owner(domain_id: DomainId, acc: AccountId) -> bool;
1497}
1498
1499impl<AccountId> DomainOwner<AccountId> for () {
1500 fn is_domain_owner(_domain_id: DomainId, _acc: AccountId) -> bool {
1501 false
1502 }
1503}
1504
1505pub trait DomainBundleSubmitted {
1507 fn domain_bundle_submitted(domain_id: DomainId);
1510}
1511
1512impl DomainBundleSubmitted for () {
1513 fn domain_bundle_submitted(_domain_id: DomainId) {}
1514}
1515
1516pub trait OnDomainInstantiated {
1518 fn on_domain_instantiated(domain_id: DomainId);
1519}
1520
1521impl OnDomainInstantiated for () {
1522 fn on_domain_instantiated(_domain_id: DomainId) {}
1523}
1524
1525pub type ExecutionReceiptFor<DomainHeader, CBlock, Balance> = ExecutionReceipt<
1526 NumberFor<CBlock>,
1527 <CBlock as BlockT>::Hash,
1528 <DomainHeader as HeaderT>::Number,
1529 <DomainHeader as HeaderT>::Hash,
1530 Balance,
1531>;
1532
1533#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
1535pub struct DomainAllowlistUpdates {
1536 pub allow_chains: BTreeSet<ChainId>,
1538 pub remove_chains: BTreeSet<ChainId>,
1540}
1541
1542impl DomainAllowlistUpdates {
1543 pub fn is_empty(&self) -> bool {
1544 self.allow_chains.is_empty() && self.remove_chains.is_empty()
1545 }
1546
1547 pub fn clear(&mut self) {
1548 self.allow_chains.clear();
1549 self.remove_chains.clear();
1550 }
1551}
1552
1553#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
1559pub struct DomainSudoCall {
1560 pub maybe_call: Option<Vec<u8>>,
1561}
1562
1563impl DomainSudoCall {
1564 pub fn clear(&mut self) {
1565 self.maybe_call.take();
1566 }
1567}
1568
1569#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
1575pub struct EvmDomainContractCreationAllowedByCall {
1576 pub maybe_call: Option<PermissionedActionAllowedBy<EthereumAccountId>>,
1577}
1578
1579impl EvmDomainContractCreationAllowedByCall {
1580 pub fn clear(&mut self) {
1581 self.maybe_call.take();
1582 }
1583}
1584
1585#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
1586pub struct RuntimeObject<Number, Hash> {
1587 pub runtime_name: String,
1588 pub runtime_type: RuntimeType,
1589 pub runtime_upgrades: u32,
1590 pub instance_count: u32,
1591 pub hash: Hash,
1592 pub raw_genesis: RawGenesis,
1595 pub version: RuntimeVersion,
1596 pub created_at: Number,
1597 pub updated_at: Number,
1598}
1599
1600pub fn system_digest_final_key() -> Vec<u8> {
1603 frame_support::storage::storage_prefix("System".as_ref(), "Digest".as_ref()).to_vec()
1604}
1605
1606pub trait OnChainRewards<Balance> {
1608 fn on_chain_rewards(chain_id: ChainId, reward: Balance);
1609}
1610
1611impl<Balance> OnChainRewards<Balance> for () {
1612 fn on_chain_rewards(_chain_id: ChainId, _reward: Balance) {}
1613}
1614
1615#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
1616pub enum OperatorRewardSource<Number> {
1617 Bundle {
1618 at_block_number: Number,
1619 },
1620 XDMProtocolFees,
1621 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
1622 Dummy,
1623}
1624
1625sp_api::decl_runtime_apis! {
1626 #[api_version(4)]
1631 pub trait DomainsApi<DomainHeader: HeaderT> {
1632 fn submit_bundle_unsigned(opaque_bundle: OpaqueBundle<NumberFor<Block>, Block::Hash, DomainHeader, Balance>);
1634
1635 fn submit_receipt_unsigned(singleton_receipt: SealedSingletonReceipt<NumberFor<Block>, Block::Hash, DomainHeader, Balance>);
1637
1638 fn extract_successful_bundles(
1640 domain_id: DomainId,
1641 extrinsics: Vec<Block::Extrinsic>,
1642 ) -> OpaqueBundles<Block, DomainHeader, Balance>;
1643
1644 fn extrinsics_shuffling_seed() -> Randomness;
1646
1647 fn domain_runtime_code(domain_id: DomainId) -> Option<Vec<u8>>;
1649
1650 fn runtime_id(domain_id: DomainId) -> Option<RuntimeId>;
1652
1653 fn runtime_upgrades() -> Vec<RuntimeId>;
1656
1657 fn domain_instance_data(domain_id: DomainId) -> Option<(DomainInstanceData, NumberFor<Block>)>;
1659
1660 fn domain_timestamp() -> Moment;
1662
1663 #[allow(clippy::deprecated_semver)]
1665 #[deprecated(since = "3", note = "Use `domain_timestamp()` instead")]
1666 fn timestamp() -> Moment;
1667
1668 fn consensus_transaction_byte_fee() -> Balance;
1671
1672 #[allow(clippy::deprecated_semver)]
1675 #[deprecated(since = "3", note = "Use `consensus_transaction_byte_fee()` instead")]
1676 fn consensus_chain_byte_fee() -> Balance;
1677
1678 fn domain_tx_range(domain_id: DomainId) -> U256;
1680
1681 fn genesis_state_root(domain_id: DomainId) -> Option<H256>;
1683
1684 fn head_receipt_number(domain_id: DomainId) -> HeaderNumberFor<DomainHeader>;
1686
1687 fn oldest_unconfirmed_receipt_number(domain_id: DomainId) -> Option<HeaderNumberFor<DomainHeader>>;
1689
1690 fn domain_bundle_limit(domain_id: DomainId) -> Option<DomainBundleLimit>;
1692
1693 fn non_empty_er_exists(domain_id: DomainId) -> bool;
1695
1696 fn domain_best_number(domain_id: DomainId) -> Option<HeaderNumberFor<DomainHeader>>;
1698
1699 fn execution_receipt(receipt_hash: HeaderHashFor<DomainHeader>) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1701
1702 fn domain_operators(domain_id: DomainId) -> Option<(BTreeMap<OperatorId, Balance>, Vec<OperatorId>)>;
1704
1705 fn receipt_hash(domain_id: DomainId, domain_number: HeaderNumberFor<DomainHeader>) -> Option<HeaderHashFor<DomainHeader>>;
1707
1708 fn latest_confirmed_domain_block(domain_id: DomainId) -> Option<(HeaderNumberFor<DomainHeader>, HeaderHashFor<DomainHeader>)>;
1710
1711 fn is_bad_er_pending_to_prune(domain_id: DomainId, receipt_hash: HeaderHashFor<DomainHeader>) -> bool;
1713
1714 fn storage_fund_account_balance(operator_id: OperatorId) -> Balance;
1716
1717 fn is_domain_runtime_upgraded_since(domain_id: DomainId, at: NumberFor<Block>) -> Option<bool>;
1719
1720 fn domain_sudo_call(domain_id: DomainId) -> Option<Vec<u8>>;
1722
1723 fn evm_domain_contract_creation_allowed_by_call(domain_id: DomainId) -> Option<PermissionedActionAllowedBy<EthereumAccountId>>;
1726
1727 fn last_confirmed_domain_block_receipt(domain_id: DomainId) ->Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1729 }
1730
1731 pub trait BundleProducerElectionApi<Balance: Encode + Decode> {
1732 fn bundle_producer_election_params(domain_id: DomainId) -> Option<BundleProducerElectionParams<Balance>>;
1733
1734 fn operator(operator_id: OperatorId) -> Option<(OperatorPublicKey, Balance)>;
1735 }
1736}