1#![cfg_attr(not(feature = "std"), no_std)]
4
5pub mod bundle;
6pub mod bundle_producer_election;
7pub mod core_api;
8pub mod execution_receipt;
9pub mod extrinsics;
10pub mod merkle_tree;
11pub mod offline_operators;
12pub mod proof_provider_and_verifier;
13pub mod storage;
14#[cfg(test)]
15mod tests;
16pub mod valued_trie;
17
18#[cfg(not(feature = "std"))]
19extern crate alloc;
20
21use crate::bundle::{BundleVersion, OpaqueBundle, OpaqueBundles};
22use crate::execution_receipt::ExecutionReceiptVersion;
23use crate::storage::{RawGenesis, StorageKey};
24#[cfg(not(feature = "std"))]
25use alloc::collections::BTreeSet;
26#[cfg(not(feature = "std"))]
27use alloc::string::String;
28#[cfg(not(feature = "std"))]
29use alloc::vec::Vec;
30use bundle_producer_election::{BundleProducerElectionParams, ProofOfElectionError};
31use core::num::ParseIntError;
32use core::ops::{Add, Sub};
33use core::str::FromStr;
34use domain_runtime_primitives::{EVMChainId, EthereumAccountId, MultiAccountId};
35use execution_receipt::{ExecutionReceiptFor, SealedSingletonReceipt};
36use frame_support::storage::storage_prefix;
37use frame_support::{Blake2_128Concat, StorageHasher};
38use hex_literal::hex;
39use parity_scale_codec::{Codec, Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
40use scale_info::TypeInfo;
41use serde::{Deserialize, Serialize};
42use sp_core::H256;
43use sp_core::crypto::KeyTypeId;
44use sp_core::sr25519::vrf::VrfSignature;
45#[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
46use sp_core::sr25519::vrf::{VrfPreOutput, VrfProof};
47use sp_runtime::generic::OpaqueDigestItemId;
48use sp_runtime::traits::{CheckedAdd, Hash as HashT, Header as HeaderT, NumberFor};
49use sp_runtime::{Digest, DigestItem, Percent};
50use sp_std::collections::btree_map::BTreeMap;
51use sp_std::fmt::{Display, Formatter};
52use sp_trie::TrieLayout;
53use sp_version::RuntimeVersion;
54use sp_weights::Weight;
55#[cfg(feature = "std")]
56use std::collections::BTreeSet;
57use subspace_core_primitives::hashes::{Blake3Hash, blake3_hash};
58use subspace_core_primitives::pot::PotOutput;
59use subspace_core_primitives::solutions::bidirectional_distance;
60use subspace_core_primitives::{Randomness, U256};
61use subspace_runtime_primitives::{Balance, Moment};
62
63pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"oper");
65
66pub const DOMAIN_EXTRINSICS_SHUFFLING_SEED_SUBJECT: &[u8] = b"extrinsics-shuffling-seed";
68
69mod app {
70 use super::KEY_TYPE;
71 use sp_application_crypto::{app_crypto, sr25519};
72
73 app_crypto!(sr25519, KEY_TYPE);
74}
75
76pub const DOMAIN_STORAGE_FEE_MULTIPLIER: Balance = 3;
83
84pub type OperatorSignature = app::Signature;
86
87#[cfg(feature = "std")]
90pub type OperatorPair = app::Pair;
91
92pub type OperatorPublicKey = app::Public;
94
95pub struct OperatorKey;
97
98impl sp_runtime::BoundToRuntimeAppPublic for OperatorKey {
99 type Public = OperatorPublicKey;
100}
101
102pub type StakeWeight = u128;
106
107pub type ExtrinsicsRoot = H256;
109
110pub type HeaderHashingFor<Header> = <Header as HeaderT>::Hashing;
112pub type HeaderNumberFor<Header> = <Header as HeaderT>::Number;
114pub type HeaderHashFor<Header> = <Header as HeaderT>::Hash;
116
117#[derive(
119 Clone,
120 Copy,
121 Debug,
122 Hash,
123 Default,
124 Eq,
125 PartialEq,
126 Ord,
127 PartialOrd,
128 Encode,
129 Decode,
130 TypeInfo,
131 Serialize,
132 Deserialize,
133 MaxEncodedLen,
134 DecodeWithMemTracking,
135)]
136pub struct DomainId(u32);
137
138impl From<u32> for DomainId {
139 #[inline]
140 fn from(x: u32) -> Self {
141 Self(x)
142 }
143}
144
145impl From<DomainId> for u32 {
146 #[inline]
147 fn from(domain_id: DomainId) -> Self {
148 domain_id.0
149 }
150}
151
152impl FromStr for DomainId {
153 type Err = ParseIntError;
154
155 fn from_str(s: &str) -> Result<Self, Self::Err> {
156 s.parse::<u32>().map(Into::into)
157 }
158}
159
160impl Add<DomainId> for DomainId {
161 type Output = Self;
162
163 fn add(self, other: DomainId) -> Self {
164 Self(self.0 + other.0)
165 }
166}
167
168impl Sub<DomainId> for DomainId {
169 type Output = Self;
170
171 fn sub(self, other: DomainId) -> Self {
172 Self(self.0 - other.0)
173 }
174}
175
176impl CheckedAdd for DomainId {
177 fn checked_add(&self, rhs: &Self) -> Option<Self> {
178 self.0.checked_add(rhs.0).map(Self)
179 }
180}
181
182impl DomainId {
183 pub const fn new(id: u32) -> Self {
185 Self(id)
186 }
187
188 pub fn to_le_bytes(&self) -> [u8; 4] {
190 self.0.to_le_bytes()
191 }
192}
193
194impl Display for DomainId {
195 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
196 self.0.fmt(f)
197 }
198}
199
200#[derive(
202 Clone,
203 Copy,
204 Debug,
205 Hash,
206 Eq,
207 PartialEq,
208 Ord,
209 PartialOrd,
210 Encode,
211 Decode,
212 TypeInfo,
213 Serialize,
214 Deserialize,
215 MaxEncodedLen,
216 DecodeWithMemTracking,
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
260pub const INITIAL_DOMAIN_TX_RANGE: u64 = 3;
265
266#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
267pub struct ProofOfElection {
268 pub domain_id: DomainId,
270 pub slot_number: u64,
272 pub proof_of_time: PotOutput,
274 pub vrf_signature: VrfSignature,
276 pub operator_id: OperatorId,
278}
279
280impl ProofOfElection {
281 pub fn verify_vrf_signature(
282 &self,
283 operator_signing_key: &OperatorPublicKey,
284 ) -> Result<(), ProofOfElectionError> {
285 let global_challenge = self
286 .proof_of_time
287 .derive_global_randomness()
288 .derive_global_challenge(self.slot_number);
289 bundle_producer_election::verify_vrf_signature(
290 self.domain_id,
291 operator_signing_key,
292 &self.vrf_signature,
293 &global_challenge,
294 )
295 }
296
297 pub fn vrf_hash(&self) -> Blake3Hash {
299 let mut bytes = self.vrf_signature.pre_output.encode();
300 bytes.append(&mut self.vrf_signature.proof.encode());
301 blake3_hash(&bytes)
302 }
303
304 pub fn slot_number(&self) -> u64 {
305 self.slot_number
306 }
307}
308
309impl ProofOfElection {
310 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
311 pub fn dummy(domain_id: DomainId, operator_id: OperatorId) -> Self {
312 let output_bytes = sp_std::vec![0u8; VrfPreOutput::max_encoded_len()];
313 let proof_bytes = sp_std::vec![0u8; VrfProof::max_encoded_len()];
314 let vrf_signature = VrfSignature {
315 pre_output: VrfPreOutput::decode(&mut output_bytes.as_slice()).unwrap(),
316 proof: VrfProof::decode(&mut proof_bytes.as_slice()).unwrap(),
317 };
318 Self {
319 domain_id,
320 slot_number: 0u64,
321 proof_of_time: PotOutput::default(),
322 vrf_signature,
323 operator_id,
324 }
325 }
326}
327
328#[derive(
330 TypeInfo,
331 Debug,
332 Encode,
333 Decode,
334 Clone,
335 PartialEq,
336 Eq,
337 Serialize,
338 Deserialize,
339 DecodeWithMemTracking,
340)]
341pub enum OperatorAllowList<AccountId: Ord> {
342 Anyone,
344 Operators(BTreeSet<AccountId>),
347}
348
349impl<AccountId: Ord> OperatorAllowList<AccountId> {
350 pub fn is_operator_allowed(&self, operator: &AccountId) -> bool {
352 match self {
353 OperatorAllowList::Anyone => true,
354 OperatorAllowList::Operators(allowed_operators) => allowed_operators.contains(operator),
355 }
356 }
357}
358
359#[derive(
361 TypeInfo,
362 Debug,
363 Encode,
364 Decode,
365 Clone,
366 PartialEq,
367 Eq,
368 Serialize,
369 Deserialize,
370 DecodeWithMemTracking,
371)]
372pub enum PermissionedActionAllowedBy<AccountId: Codec + Clone> {
373 Accounts(Vec<AccountId>),
374 Anyone,
375}
376
377impl<AccountId: Codec + PartialEq + Clone> PermissionedActionAllowedBy<AccountId> {
378 pub fn is_allowed(&self, who: &AccountId) -> bool {
379 match self {
380 PermissionedActionAllowedBy::Accounts(accounts) => accounts.contains(who),
381 PermissionedActionAllowedBy::Anyone => true,
382 }
383 }
384
385 pub fn is_anyone_allowed(&self) -> bool {
386 matches!(self, PermissionedActionAllowedBy::Anyone)
387 }
388}
389
390#[derive(
392 TypeInfo,
393 Debug,
394 Default,
395 Encode,
396 Decode,
397 Clone,
398 PartialEq,
399 Eq,
400 Serialize,
401 Deserialize,
402 DecodeWithMemTracking,
403)]
404pub enum EvmType {
405 #[default]
406 Public,
408 Private {
410 initial_contract_creation_allow_list: PermissionedActionAllowedBy<EthereumAccountId>,
413 },
414}
415
416impl EvmType {
417 pub fn initial_contract_creation_allow_list(
419 &self,
420 ) -> Option<&PermissionedActionAllowedBy<EthereumAccountId>> {
421 match self {
422 EvmType::Public => None,
423 EvmType::Private {
424 initial_contract_creation_allow_list,
425 } => Some(initial_contract_creation_allow_list),
426 }
427 }
428
429 pub fn is_public_evm_domain(&self) -> bool {
431 matches!(self, EvmType::Public)
432 }
433
434 pub fn is_private_evm_domain(&self) -> bool {
436 matches!(self, EvmType::Private { .. })
437 }
438}
439
440#[derive(
442 TypeInfo,
443 Debug,
444 Default,
445 Encode,
446 Decode,
447 Clone,
448 PartialEq,
449 Eq,
450 Serialize,
451 Deserialize,
452 DecodeWithMemTracking,
453)]
454pub struct EvmDomainRuntimeConfig {
455 pub evm_type: EvmType,
456}
457
458#[derive(
460 TypeInfo,
461 Debug,
462 Default,
463 Encode,
464 Decode,
465 Clone,
466 PartialEq,
467 Eq,
468 Serialize,
469 Deserialize,
470 DecodeWithMemTracking,
471)]
472pub struct AutoIdDomainRuntimeConfig {
473 }
475
476#[derive(
478 TypeInfo,
479 Debug,
480 Encode,
481 Decode,
482 Clone,
483 PartialEq,
484 Eq,
485 Serialize,
486 Deserialize,
487 DecodeWithMemTracking,
488)]
489pub enum DomainRuntimeInfo {
490 Evm {
491 chain_id: EVMChainId,
493 domain_runtime_config: EvmDomainRuntimeConfig,
495 },
496 AutoId {
497 domain_runtime_config: AutoIdDomainRuntimeConfig,
499 },
500}
501
502impl From<(EVMChainId, EvmDomainRuntimeConfig)> for DomainRuntimeInfo {
503 fn from(v: (EVMChainId, EvmDomainRuntimeConfig)) -> Self {
504 DomainRuntimeInfo::Evm {
505 chain_id: v.0,
506 domain_runtime_config: v.1,
507 }
508 }
509}
510
511impl From<AutoIdDomainRuntimeConfig> for DomainRuntimeInfo {
512 fn from(auto_id_config: AutoIdDomainRuntimeConfig) -> Self {
513 DomainRuntimeInfo::AutoId {
514 domain_runtime_config: auto_id_config,
515 }
516 }
517}
518
519impl DomainRuntimeInfo {
520 pub fn evm(&self) -> Option<&EvmDomainRuntimeConfig> {
521 match self {
522 DomainRuntimeInfo::Evm {
523 domain_runtime_config,
524 ..
525 } => Some(domain_runtime_config),
526 _ => None,
527 }
528 }
529
530 pub fn initial_contract_creation_allow_list(
531 &self,
532 ) -> Option<&PermissionedActionAllowedBy<EthereumAccountId>> {
533 self.evm()
534 .and_then(|evm_config| evm_config.evm_type.initial_contract_creation_allow_list())
535 }
536
537 pub fn auto_id(&self) -> Option<&AutoIdDomainRuntimeConfig> {
538 match self {
539 DomainRuntimeInfo::AutoId {
540 domain_runtime_config,
541 } => Some(domain_runtime_config),
542 _ => None,
543 }
544 }
545
546 pub fn evm_chain_id(&self) -> Option<EVMChainId> {
548 match self {
549 Self::Evm { chain_id, .. } => Some(*chain_id),
550 _ => None,
551 }
552 }
553
554 pub fn is_evm_domain(&self) -> bool {
555 matches!(self, Self::Evm { .. })
556 }
557
558 pub fn is_private_evm_domain(&self) -> bool {
561 if let Self::Evm {
562 domain_runtime_config,
563 ..
564 } = self
565 {
566 domain_runtime_config.evm_type.is_private_evm_domain()
567 } else {
568 false
569 }
570 }
571
572 pub fn is_auto_id(&self) -> bool {
573 matches!(self, Self::AutoId { .. })
574 }
575}
576
577#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
578pub struct GenesisDomain<AccountId: Ord, Balance> {
579 pub runtime_name: String,
581 pub runtime_type: RuntimeType,
582 pub runtime_version: RuntimeVersion,
583 pub raw_genesis_storage: Vec<u8>,
584
585 pub owner_account_id: AccountId,
587 pub domain_name: String,
588 pub bundle_slot_probability: (u64, u64),
589 pub operator_allow_list: OperatorAllowList<AccountId>,
590 pub domain_runtime_info: DomainRuntimeInfo,
592
593 pub signing_key: OperatorPublicKey,
595 pub minimum_nominator_stake: Balance,
596 pub nomination_tax: Percent,
597
598 pub initial_balances: Vec<(MultiAccountId, Balance)>,
600}
601
602#[derive(
604 Debug,
605 Default,
606 Encode,
607 Decode,
608 TypeInfo,
609 Copy,
610 Clone,
611 PartialEq,
612 Eq,
613 Serialize,
614 Deserialize,
615 DecodeWithMemTracking,
616)]
617pub enum RuntimeType {
618 #[default]
619 Evm,
620 AutoId,
621}
622
623pub type RuntimeId = u32;
625
626pub type EpochIndex = u32;
628
629pub type OperatorId = u64;
631
632pub type ChannelId = sp_core::U256;
634
635#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
637pub enum DomainDigestItem {
638 DomainRuntimeUpgraded(RuntimeId),
639 DomainInstantiated(DomainId),
640}
641
642pub trait DomainsDigestItem {
644 fn domain_runtime_upgrade(runtime_id: RuntimeId) -> Self;
645 fn as_domain_runtime_upgrade(&self) -> Option<RuntimeId>;
646
647 fn domain_instantiation(domain_id: DomainId) -> Self;
648 fn as_domain_instantiation(&self) -> Option<DomainId>;
649}
650
651impl DomainsDigestItem for DigestItem {
652 fn domain_runtime_upgrade(runtime_id: RuntimeId) -> Self {
653 Self::Other(DomainDigestItem::DomainRuntimeUpgraded(runtime_id).encode())
654 }
655
656 fn as_domain_runtime_upgrade(&self) -> Option<RuntimeId> {
657 match self.try_to::<DomainDigestItem>(OpaqueDigestItemId::Other) {
658 Some(DomainDigestItem::DomainRuntimeUpgraded(runtime_id)) => Some(runtime_id),
659 _ => None,
660 }
661 }
662
663 fn domain_instantiation(domain_id: DomainId) -> Self {
664 Self::Other(DomainDigestItem::DomainInstantiated(domain_id).encode())
665 }
666
667 fn as_domain_instantiation(&self) -> Option<DomainId> {
668 match self.try_to::<DomainDigestItem>(OpaqueDigestItemId::Other) {
669 Some(DomainDigestItem::DomainInstantiated(domain_id)) => Some(domain_id),
670 _ => None,
671 }
672 }
673}
674
675pub(crate) fn evm_chain_id_storage_key() -> StorageKey {
682 StorageKey(
683 storage_prefix(
684 "EVMChainId".as_bytes(),
687 "ChainId".as_bytes(),
689 )
690 .to_vec(),
691 )
692}
693
694pub(crate) fn evm_contract_creation_allowed_by_storage_key() -> StorageKey {
701 StorageKey(
702 storage_prefix(
703 "EVMNoncetracker".as_bytes(),
706 "ContractCreationAllowedBy".as_bytes(),
708 )
709 .to_vec(),
710 )
711}
712
713pub fn domain_total_issuance_storage_key() -> StorageKey {
720 StorageKey(
721 storage_prefix(
722 "Balances".as_bytes(),
724 "TotalIssuance".as_bytes(),
726 )
727 .to_vec(),
728 )
729}
730
731pub fn domain_account_storage_key<AccountId: Encode>(who: AccountId) -> StorageKey {
738 let storage_prefix = storage_prefix("System".as_bytes(), "Account".as_bytes());
739 let key_hashed = who.using_encoded(Blake2_128Concat::hash);
740
741 let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len());
742
743 final_key.extend_from_slice(&storage_prefix);
744 final_key.extend_from_slice(key_hashed.as_ref());
745
746 StorageKey(final_key)
747}
748
749pub fn self_domain_id_storage_key() -> StorageKey {
754 StorageKey(
755 frame_support::storage::storage_prefix(
756 "SelfDomainId".as_bytes(),
759 "SelfDomainId".as_bytes(),
761 )
762 .to_vec(),
763 )
764}
765
766#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
768pub struct DomainInstanceData {
769 pub runtime_type: RuntimeType,
770 pub raw_genesis: RawGenesis,
771}
772
773#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq, DecodeWithMemTracking)]
774pub struct DomainBundleLimit {
775 pub max_bundle_size: u32,
777 pub max_bundle_weight: Weight,
779}
780
781pub fn calculate_max_bundle_weight_and_size(
785 max_domain_block_size: u32,
786 max_domain_block_weight: Weight,
787 consensus_slot_probability: (u64, u64),
788 bundle_slot_probability: (u64, u64),
789) -> Option<DomainBundleLimit> {
790 let expected_bundles_per_block = bundle_slot_probability
793 .0
794 .checked_mul(consensus_slot_probability.1)?
795 .checked_div(
796 bundle_slot_probability
797 .1
798 .checked_mul(consensus_slot_probability.0)?,
799 )?;
800
801 let max_proof_size = max_domain_block_weight.proof_size();
804 let max_bundle_weight = max_domain_block_weight
805 .checked_div(expected_bundles_per_block)?
806 .set_proof_size(max_proof_size);
807
808 let max_bundle_size =
809 (max_domain_block_size as u64).checked_div(expected_bundles_per_block)? as u32;
810
811 Some(DomainBundleLimit {
812 max_bundle_size,
813 max_bundle_weight,
814 })
815}
816
817pub fn signer_in_tx_range(bundle_vrf_hash: &U256, signer_id_hash: &U256, tx_range: &U256) -> bool {
819 let distance_from_vrf_hash = bidirectional_distance(bundle_vrf_hash, signer_id_hash);
820 distance_from_vrf_hash <= (*tx_range / 2)
821}
822
823#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
825pub enum InvalidReceipt {
826 InvalidBundles,
828}
829
830#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
831pub enum ReceiptValidity {
832 Valid,
833 Invalid(InvalidReceipt),
834}
835
836pub const EMPTY_EXTRINSIC_ROOT: ExtrinsicsRoot = ExtrinsicsRoot {
838 0: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314"),
839};
840
841pub fn derive_domain_block_hash<DomainHeader: HeaderT>(
842 domain_block_number: DomainHeader::Number,
843 extrinsics_root: DomainHeader::Hash,
844 state_root: DomainHeader::Hash,
845 parent_domain_block_hash: DomainHeader::Hash,
846 digest: Digest,
847) -> DomainHeader::Hash {
848 let domain_header = DomainHeader::new(
849 domain_block_number,
850 extrinsics_root,
851 state_root,
852 parent_domain_block_hash,
853 digest,
854 );
855
856 domain_header.hash()
857}
858
859#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
861pub enum ExtrinsicDigest {
862 Data(Vec<u8>),
864 Hash(H256),
866}
867
868impl ExtrinsicDigest {
869 pub fn new<Layout: TrieLayout>(ext: Vec<u8>) -> Self
870 where
871 Layout::Hash: HashT,
872 <Layout::Hash as HashT>::Output: Into<H256>,
873 {
874 if let Some(threshold) = Layout::MAX_INLINE_VALUE {
875 if ext.len() >= threshold as usize {
876 ExtrinsicDigest::Hash(Layout::Hash::hash(&ext).into())
877 } else {
878 ExtrinsicDigest::Data(ext)
879 }
880 } else {
881 ExtrinsicDigest::Data(ext)
882 }
883 }
884}
885
886pub trait DomainsTransfersTracker<Balance> {
888 type Error;
889
890 fn initialize_domain_balance(domain_id: DomainId, amount: Balance) -> Result<(), Self::Error>;
892
893 fn note_transfer(
896 from_chain_id: ChainId,
897 to_chain_id: ChainId,
898 amount: Balance,
899 ) -> Result<(), Self::Error>;
900
901 fn confirm_transfer(
903 from_chain_id: ChainId,
904 to_chain_id: ChainId,
905 amount: Balance,
906 ) -> Result<(), Self::Error>;
907
908 fn claim_rejected_transfer(
910 from_chain_id: ChainId,
911 to_chain_id: ChainId,
912 amount: Balance,
913 ) -> Result<(), Self::Error>;
914
915 fn reject_transfer(
917 from_chain_id: ChainId,
918 to_chain_id: ChainId,
919 amount: Balance,
920 ) -> Result<(), Self::Error>;
921
922 fn reduce_domain_balance(domain_id: DomainId, amount: Balance) -> Result<(), Self::Error>;
924}
925
926pub trait DomainOwner<AccountId> {
928 fn is_domain_owner(domain_id: DomainId, acc: AccountId) -> bool;
930}
931
932impl<AccountId> DomainOwner<AccountId> for () {
933 fn is_domain_owner(_domain_id: DomainId, _acc: AccountId) -> bool {
934 false
935 }
936}
937
938pub trait DomainBundleSubmitted {
940 fn domain_bundle_submitted(domain_id: DomainId);
943}
944
945impl DomainBundleSubmitted for () {
946 fn domain_bundle_submitted(_domain_id: DomainId) {}
947}
948
949pub trait OnDomainInstantiated {
951 fn on_domain_instantiated(domain_id: DomainId);
952}
953
954impl OnDomainInstantiated for () {
955 fn on_domain_instantiated(_domain_id: DomainId) {}
956}
957
958#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo, DecodeWithMemTracking)]
960pub struct DomainAllowlistUpdates {
961 pub allow_chains: BTreeSet<ChainId>,
963 pub remove_chains: BTreeSet<ChainId>,
965}
966
967impl DomainAllowlistUpdates {
968 pub fn is_empty(&self) -> bool {
969 self.allow_chains.is_empty() && self.remove_chains.is_empty()
970 }
971
972 pub fn clear(&mut self) {
973 self.allow_chains.clear();
974 self.remove_chains.clear();
975 }
976}
977
978#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
984pub struct DomainSudoCall {
985 pub maybe_call: Option<Vec<u8>>,
986}
987
988impl DomainSudoCall {
989 pub fn clear(&mut self) {
990 self.maybe_call.take();
991 }
992}
993
994#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
1000pub struct EvmDomainContractCreationAllowedByCall {
1001 pub maybe_call: Option<PermissionedActionAllowedBy<EthereumAccountId>>,
1002}
1003
1004impl EvmDomainContractCreationAllowedByCall {
1005 pub fn clear(&mut self) {
1006 self.maybe_call.take();
1007 }
1008}
1009
1010#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
1011pub struct RuntimeObject<Number, Hash> {
1012 pub runtime_name: String,
1013 pub runtime_type: RuntimeType,
1014 pub runtime_upgrades: u32,
1015 pub instance_count: u32,
1016 pub hash: Hash,
1017 pub raw_genesis: RawGenesis,
1020 pub version: RuntimeVersion,
1021 pub created_at: Number,
1022 pub updated_at: Number,
1023}
1024
1025pub fn system_digest_final_key() -> Vec<u8> {
1028 frame_support::storage::storage_prefix("System".as_ref(), "Digest".as_ref()).to_vec()
1029}
1030
1031pub trait OnChainRewards<Balance> {
1033 fn on_chain_rewards(chain_id: ChainId, reward: Balance);
1034}
1035
1036impl<Balance> OnChainRewards<Balance> for () {
1037 fn on_chain_rewards(_chain_id: ChainId, _reward: Balance) {}
1038}
1039
1040#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
1041pub enum OperatorRewardSource<Number> {
1042 Bundle {
1043 at_block_number: Number,
1044 },
1045 XDMProtocolFees,
1046 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
1047 Dummy,
1048}
1049
1050#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, Copy)]
1052pub struct BundleAndExecutionReceiptVersion {
1053 pub bundle_version: BundleVersion,
1054 pub execution_receipt_version: ExecutionReceiptVersion,
1055}
1056
1057#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)]
1059pub struct StorageFeeDeposit<Balance> {
1060 pub total_deposited: Balance,
1062 pub current_value: Balance,
1064}
1065
1066#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)]
1068pub struct PendingDeposit<Balance> {
1069 pub amount: Balance,
1071 pub effective_epoch: EpochIndex,
1073}
1074
1075#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)]
1077pub struct PendingWithdrawal<Balance, DomainBlockNumber> {
1078 pub stake_withdrawal_amount: Balance,
1080 pub storage_fee_refund: Balance,
1082 pub unlock_at_block: DomainBlockNumber,
1084}
1085
1086#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)]
1088pub struct NominatorPosition<Balance, DomainBlockNumber, Share> {
1089 pub current_staked_value: Balance,
1091 pub total_shares: Share,
1093 pub storage_fee_deposit: StorageFeeDeposit<Balance>,
1095 pub pending_deposit: Option<PendingDeposit<Balance>>,
1097 pub pending_withdrawals: Vec<PendingWithdrawal<Balance, DomainBlockNumber>>,
1099}
1100
1101sp_api::decl_runtime_apis! {
1102 #[api_version(6)]
1105 pub trait DomainsApi<DomainHeader: HeaderT> {
1106 fn submit_bundle_unsigned(opaque_bundle: OpaqueBundle<NumberFor<Block>, Block::Hash, DomainHeader, Balance>);
1108
1109 fn submit_receipt_unsigned(singleton_receipt: SealedSingletonReceipt<NumberFor<Block>, Block::Hash, DomainHeader, Balance>);
1111
1112 fn extract_successful_bundles(
1114 domain_id: DomainId,
1115 extrinsics: Vec<Block::Extrinsic>,
1116 ) -> OpaqueBundles<Block, DomainHeader, Balance>;
1117
1118 fn extrinsics_shuffling_seed() -> Randomness;
1120
1121 fn domain_runtime_code(domain_id: DomainId) -> Option<Vec<u8>>;
1123
1124 fn runtime_id(domain_id: DomainId) -> Option<RuntimeId>;
1126
1127 fn runtime_upgrades() -> Vec<RuntimeId>;
1129
1130 fn domain_instance_data(domain_id: DomainId) -> Option<(DomainInstanceData, NumberFor<Block>)>;
1132
1133 fn domain_timestamp() -> Moment;
1135
1136 fn consensus_transaction_byte_fee() -> Balance;
1139
1140 fn domain_tx_range(domain_id: DomainId) -> U256;
1142
1143 fn genesis_state_root(domain_id: DomainId) -> Option<H256>;
1145
1146 fn head_receipt_number(domain_id: DomainId) -> HeaderNumberFor<DomainHeader>;
1148
1149 fn oldest_unconfirmed_receipt_number(domain_id: DomainId) -> Option<HeaderNumberFor<DomainHeader>>;
1151
1152 fn domain_bundle_limit(domain_id: DomainId) -> Option<DomainBundleLimit>;
1154
1155 fn non_empty_er_exists(domain_id: DomainId) -> bool;
1157
1158 fn domain_best_number(domain_id: DomainId) -> Option<HeaderNumberFor<DomainHeader>>;
1160
1161 fn execution_receipt(receipt_hash: HeaderHashFor<DomainHeader>) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1163
1164 fn domain_operators(domain_id: DomainId) -> Option<(BTreeMap<OperatorId, Balance>, Vec<OperatorId>)>;
1166
1167 fn receipt_hash(domain_id: DomainId, domain_number: HeaderNumberFor<DomainHeader>) -> Option<HeaderHashFor<DomainHeader>>;
1169
1170 fn latest_confirmed_domain_block(domain_id: DomainId) -> Option<(HeaderNumberFor<DomainHeader>, HeaderHashFor<DomainHeader>)>;
1172
1173 fn is_bad_er_pending_to_prune(domain_id: DomainId, receipt_hash: HeaderHashFor<DomainHeader>) -> bool;
1175
1176 fn storage_fund_account_balance(operator_id: OperatorId) -> Balance;
1178
1179 fn is_domain_runtime_upgraded_since(domain_id: DomainId, at: NumberFor<Block>) -> Option<bool>;
1181
1182 fn domain_sudo_call(domain_id: DomainId) -> Option<Vec<u8>>;
1184
1185 fn evm_domain_contract_creation_allowed_by_call(domain_id: DomainId) -> Option<PermissionedActionAllowedBy<EthereumAccountId>>;
1187
1188 fn last_confirmed_domain_block_receipt(domain_id: DomainId) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1190
1191 fn current_bundle_and_execution_receipt_version() -> BundleAndExecutionReceiptVersion;
1193
1194 fn genesis_execution_receipt(domain_id: DomainId) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1196
1197 fn nominator_position(
1206 operator_id: OperatorId,
1207 nominator_account: sp_runtime::AccountId32,
1208 ) -> Option<NominatorPosition<Balance, HeaderNumberFor<DomainHeader>, Balance>>;
1209
1210 fn block_pruning_depth() -> NumberFor<Block>;
1213 }
1214
1215 pub trait BundleProducerElectionApi<Balance: Encode + Decode> {
1216 fn bundle_producer_election_params(domain_id: DomainId) -> Option<BundleProducerElectionParams<Balance>>;
1217
1218 fn operator(operator_id: OperatorId) -> Option<(OperatorPublicKey, Balance)>;
1219 }
1220}