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, 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_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::{Blake3Hash, blake3_hash};
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
264pub const INITIAL_DOMAIN_TX_RANGE: u64 = 3;
269
270#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
271pub struct ProofOfElection {
272 pub domain_id: DomainId,
274 pub slot_number: u64,
276 pub proof_of_time: PotOutput,
278 pub vrf_signature: VrfSignature,
280 pub operator_id: OperatorId,
282}
283
284impl ProofOfElection {
285 pub fn verify_vrf_signature(
286 &self,
287 operator_signing_key: &OperatorPublicKey,
288 ) -> Result<(), ProofOfElectionError> {
289 let global_challenge = self
290 .proof_of_time
291 .derive_global_randomness()
292 .derive_global_challenge(self.slot_number);
293 bundle_producer_election::verify_vrf_signature(
294 self.domain_id,
295 operator_signing_key,
296 &self.vrf_signature,
297 &global_challenge,
298 )
299 }
300
301 pub fn vrf_hash(&self) -> Blake3Hash {
303 let mut bytes = self.vrf_signature.pre_output.encode();
304 bytes.append(&mut self.vrf_signature.proof.encode());
305 blake3_hash(&bytes)
306 }
307
308 pub fn slot_number(&self) -> u64 {
309 self.slot_number
310 }
311}
312
313impl ProofOfElection {
314 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
315 pub fn dummy(domain_id: DomainId, operator_id: OperatorId) -> Self {
316 let output_bytes = sp_std::vec![0u8; VrfPreOutput::max_encoded_len()];
317 let proof_bytes = sp_std::vec![0u8; VrfProof::max_encoded_len()];
318 let vrf_signature = VrfSignature {
319 pre_output: VrfPreOutput::decode(&mut output_bytes.as_slice()).unwrap(),
320 proof: VrfProof::decode(&mut proof_bytes.as_slice()).unwrap(),
321 };
322 Self {
323 domain_id,
324 slot_number: 0u64,
325 proof_of_time: PotOutput::default(),
326 vrf_signature,
327 operator_id,
328 }
329 }
330}
331
332#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
334pub enum OperatorAllowList<AccountId: Ord> {
335 Anyone,
337 Operators(BTreeSet<AccountId>),
340}
341
342impl<AccountId: Ord> OperatorAllowList<AccountId> {
343 pub fn is_operator_allowed(&self, operator: &AccountId) -> bool {
345 match self {
346 OperatorAllowList::Anyone => true,
347 OperatorAllowList::Operators(allowed_operators) => allowed_operators.contains(operator),
348 }
349 }
350}
351
352#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
354pub enum PermissionedActionAllowedBy<AccountId: Codec + Clone> {
355 Accounts(Vec<AccountId>),
356 Anyone,
357}
358
359impl<AccountId: Codec + PartialEq + Clone> PermissionedActionAllowedBy<AccountId> {
360 pub fn is_allowed(&self, who: &AccountId) -> bool {
361 match self {
362 PermissionedActionAllowedBy::Accounts(accounts) => accounts.contains(who),
363 PermissionedActionAllowedBy::Anyone => true,
364 }
365 }
366
367 pub fn is_anyone_allowed(&self) -> bool {
368 matches!(self, PermissionedActionAllowedBy::Anyone)
369 }
370}
371
372#[derive(
374 TypeInfo, Debug, Default, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize,
375)]
376pub enum EvmType {
377 #[default]
378 Public,
380 Private {
382 initial_contract_creation_allow_list: PermissionedActionAllowedBy<EthereumAccountId>,
385 },
386}
387
388impl EvmType {
389 pub fn initial_contract_creation_allow_list(
391 &self,
392 ) -> Option<&PermissionedActionAllowedBy<EthereumAccountId>> {
393 match self {
394 EvmType::Public => None,
395 EvmType::Private {
396 initial_contract_creation_allow_list,
397 } => Some(initial_contract_creation_allow_list),
398 }
399 }
400
401 pub fn is_public_evm_domain(&self) -> bool {
403 matches!(self, EvmType::Public)
404 }
405
406 pub fn is_private_evm_domain(&self) -> bool {
408 matches!(self, EvmType::Private { .. })
409 }
410}
411
412#[derive(
414 TypeInfo, Debug, Default, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize,
415)]
416pub struct EvmDomainRuntimeConfig {
417 pub evm_type: EvmType,
418}
419
420#[derive(
422 TypeInfo, Debug, Default, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize,
423)]
424pub struct AutoIdDomainRuntimeConfig {
425 }
427
428#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
430pub enum DomainRuntimeInfo {
431 Evm {
432 chain_id: EVMChainId,
434 domain_runtime_config: EvmDomainRuntimeConfig,
436 },
437 AutoId {
438 domain_runtime_config: AutoIdDomainRuntimeConfig,
440 },
441}
442
443impl From<(EVMChainId, EvmDomainRuntimeConfig)> for DomainRuntimeInfo {
444 fn from(v: (EVMChainId, EvmDomainRuntimeConfig)) -> Self {
445 DomainRuntimeInfo::Evm {
446 chain_id: v.0,
447 domain_runtime_config: v.1,
448 }
449 }
450}
451
452impl From<AutoIdDomainRuntimeConfig> for DomainRuntimeInfo {
453 fn from(auto_id_config: AutoIdDomainRuntimeConfig) -> Self {
454 DomainRuntimeInfo::AutoId {
455 domain_runtime_config: auto_id_config,
456 }
457 }
458}
459
460impl DomainRuntimeInfo {
461 pub fn evm(&self) -> Option<&EvmDomainRuntimeConfig> {
462 match self {
463 DomainRuntimeInfo::Evm {
464 domain_runtime_config,
465 ..
466 } => Some(domain_runtime_config),
467 _ => None,
468 }
469 }
470
471 pub fn initial_contract_creation_allow_list(
472 &self,
473 ) -> Option<&PermissionedActionAllowedBy<EthereumAccountId>> {
474 self.evm()
475 .and_then(|evm_config| evm_config.evm_type.initial_contract_creation_allow_list())
476 }
477
478 pub fn auto_id(&self) -> Option<&AutoIdDomainRuntimeConfig> {
479 match self {
480 DomainRuntimeInfo::AutoId {
481 domain_runtime_config,
482 } => Some(domain_runtime_config),
483 _ => None,
484 }
485 }
486
487 pub fn evm_chain_id(&self) -> Option<EVMChainId> {
489 match self {
490 Self::Evm { chain_id, .. } => Some(*chain_id),
491 _ => None,
492 }
493 }
494
495 pub fn is_evm_domain(&self) -> bool {
496 matches!(self, Self::Evm { .. })
497 }
498
499 pub fn is_private_evm_domain(&self) -> bool {
502 if let Self::Evm {
503 domain_runtime_config,
504 ..
505 } = self
506 {
507 domain_runtime_config.evm_type.is_private_evm_domain()
508 } else {
509 false
510 }
511 }
512
513 pub fn is_auto_id(&self) -> bool {
514 matches!(self, Self::AutoId { .. })
515 }
516}
517
518#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
519pub struct GenesisDomain<AccountId: Ord, Balance> {
520 pub runtime_name: String,
522 pub runtime_type: RuntimeType,
523 pub runtime_version: RuntimeVersion,
524 pub raw_genesis_storage: Vec<u8>,
525
526 pub owner_account_id: AccountId,
528 pub domain_name: String,
529 pub bundle_slot_probability: (u64, u64),
530 pub operator_allow_list: OperatorAllowList<AccountId>,
531 pub domain_runtime_info: DomainRuntimeInfo,
533
534 pub signing_key: OperatorPublicKey,
536 pub minimum_nominator_stake: Balance,
537 pub nomination_tax: Percent,
538
539 pub initial_balances: Vec<(MultiAccountId, Balance)>,
541}
542
543#[derive(
545 Debug, Default, Encode, Decode, TypeInfo, Copy, Clone, PartialEq, Eq, Serialize, Deserialize,
546)]
547pub enum RuntimeType {
548 #[default]
549 Evm,
550 AutoId,
551}
552
553pub type RuntimeId = u32;
555
556pub type EpochIndex = u32;
558
559pub type OperatorId = u64;
561
562pub type ChannelId = sp_core::U256;
564
565#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
567pub enum DomainDigestItem {
568 DomainRuntimeUpgraded(RuntimeId),
569 DomainInstantiated(DomainId),
570}
571
572pub trait DomainsDigestItem {
574 fn domain_runtime_upgrade(runtime_id: RuntimeId) -> Self;
575 fn as_domain_runtime_upgrade(&self) -> Option<RuntimeId>;
576
577 fn domain_instantiation(domain_id: DomainId) -> Self;
578 fn as_domain_instantiation(&self) -> Option<DomainId>;
579}
580
581impl DomainsDigestItem for DigestItem {
582 fn domain_runtime_upgrade(runtime_id: RuntimeId) -> Self {
583 Self::Other(DomainDigestItem::DomainRuntimeUpgraded(runtime_id).encode())
584 }
585
586 fn as_domain_runtime_upgrade(&self) -> Option<RuntimeId> {
587 match self.try_to::<DomainDigestItem>(OpaqueDigestItemId::Other) {
588 Some(DomainDigestItem::DomainRuntimeUpgraded(runtime_id)) => Some(runtime_id),
589 _ => None,
590 }
591 }
592
593 fn domain_instantiation(domain_id: DomainId) -> Self {
594 Self::Other(DomainDigestItem::DomainInstantiated(domain_id).encode())
595 }
596
597 fn as_domain_instantiation(&self) -> Option<DomainId> {
598 match self.try_to::<DomainDigestItem>(OpaqueDigestItemId::Other) {
599 Some(DomainDigestItem::DomainInstantiated(domain_id)) => Some(domain_id),
600 _ => None,
601 }
602 }
603}
604
605pub(crate) fn evm_chain_id_storage_key() -> StorageKey {
612 StorageKey(
613 storage_prefix(
614 "EVMChainId".as_bytes(),
617 "ChainId".as_bytes(),
619 )
620 .to_vec(),
621 )
622}
623
624pub(crate) fn evm_contract_creation_allowed_by_storage_key() -> StorageKey {
631 StorageKey(
632 storage_prefix(
633 "EVMNoncetracker".as_bytes(),
636 "ContractCreationAllowedBy".as_bytes(),
638 )
639 .to_vec(),
640 )
641}
642
643pub fn domain_total_issuance_storage_key() -> StorageKey {
650 StorageKey(
651 storage_prefix(
652 "Balances".as_bytes(),
654 "TotalIssuance".as_bytes(),
656 )
657 .to_vec(),
658 )
659}
660
661pub fn domain_account_storage_key<AccountId: Encode>(who: AccountId) -> StorageKey {
668 let storage_prefix = storage_prefix("System".as_bytes(), "Account".as_bytes());
669 let key_hashed = who.using_encoded(Blake2_128Concat::hash);
670
671 let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len());
672
673 final_key.extend_from_slice(&storage_prefix);
674 final_key.extend_from_slice(key_hashed.as_ref());
675
676 StorageKey(final_key)
677}
678
679pub fn self_domain_id_storage_key() -> StorageKey {
684 StorageKey(
685 frame_support::storage::storage_prefix(
686 "SelfDomainId".as_bytes(),
689 "SelfDomainId".as_bytes(),
691 )
692 .to_vec(),
693 )
694}
695
696#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
698pub struct DomainInstanceData {
699 pub runtime_type: RuntimeType,
700 pub raw_genesis: RawGenesis,
701}
702
703#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
704pub struct DomainBundleLimit {
705 pub max_bundle_size: u32,
707 pub max_bundle_weight: Weight,
709}
710
711pub fn calculate_max_bundle_weight_and_size(
715 max_domain_block_size: u32,
716 max_domain_block_weight: Weight,
717 consensus_slot_probability: (u64, u64),
718 bundle_slot_probability: (u64, u64),
719) -> Option<DomainBundleLimit> {
720 let expected_bundles_per_block = bundle_slot_probability
723 .0
724 .checked_mul(consensus_slot_probability.1)?
725 .checked_div(
726 bundle_slot_probability
727 .1
728 .checked_mul(consensus_slot_probability.0)?,
729 )?;
730
731 let max_proof_size = max_domain_block_weight.proof_size();
734 let max_bundle_weight = max_domain_block_weight
735 .checked_div(expected_bundles_per_block)?
736 .set_proof_size(max_proof_size);
737
738 let max_bundle_size =
739 (max_domain_block_size as u64).checked_div(expected_bundles_per_block)? as u32;
740
741 Some(DomainBundleLimit {
742 max_bundle_size,
743 max_bundle_weight,
744 })
745}
746
747pub fn signer_in_tx_range(bundle_vrf_hash: &U256, signer_id_hash: &U256, tx_range: &U256) -> bool {
749 let distance_from_vrf_hash = bidirectional_distance(bundle_vrf_hash, signer_id_hash);
750 distance_from_vrf_hash <= (*tx_range / 2)
751}
752
753#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
755pub enum InvalidReceipt {
756 InvalidBundles,
758}
759
760#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
761pub enum ReceiptValidity {
762 Valid,
763 Invalid(InvalidReceipt),
764}
765
766pub const EMPTY_EXTRINSIC_ROOT: ExtrinsicsRoot = ExtrinsicsRoot {
768 0: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314"),
769};
770
771pub fn derive_domain_block_hash<DomainHeader: HeaderT>(
772 domain_block_number: DomainHeader::Number,
773 extrinsics_root: DomainHeader::Hash,
774 state_root: DomainHeader::Hash,
775 parent_domain_block_hash: DomainHeader::Hash,
776 digest: Digest,
777) -> DomainHeader::Hash {
778 let domain_header = DomainHeader::new(
779 domain_block_number,
780 extrinsics_root,
781 state_root,
782 parent_domain_block_hash,
783 digest,
784 );
785
786 domain_header.hash()
787}
788
789#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
791pub enum ExtrinsicDigest {
792 Data(Vec<u8>),
794 Hash(H256),
796}
797
798impl ExtrinsicDigest {
799 pub fn new<Layout: TrieLayout>(ext: Vec<u8>) -> Self
800 where
801 Layout::Hash: HashT,
802 <Layout::Hash as HashT>::Output: Into<H256>,
803 {
804 if let Some(threshold) = Layout::MAX_INLINE_VALUE {
805 if ext.len() >= threshold as usize {
806 ExtrinsicDigest::Hash(Layout::Hash::hash(&ext).into())
807 } else {
808 ExtrinsicDigest::Data(ext)
809 }
810 } else {
811 ExtrinsicDigest::Data(ext)
812 }
813 }
814}
815
816pub trait DomainsTransfersTracker<Balance> {
818 type Error;
819
820 fn initialize_domain_balance(domain_id: DomainId, amount: Balance) -> Result<(), Self::Error>;
822
823 fn note_transfer(
826 from_chain_id: ChainId,
827 to_chain_id: ChainId,
828 amount: Balance,
829 ) -> Result<(), Self::Error>;
830
831 fn confirm_transfer(
833 from_chain_id: ChainId,
834 to_chain_id: ChainId,
835 amount: Balance,
836 ) -> Result<(), Self::Error>;
837
838 fn claim_rejected_transfer(
840 from_chain_id: ChainId,
841 to_chain_id: ChainId,
842 amount: Balance,
843 ) -> Result<(), Self::Error>;
844
845 fn reject_transfer(
847 from_chain_id: ChainId,
848 to_chain_id: ChainId,
849 amount: Balance,
850 ) -> Result<(), Self::Error>;
851
852 fn reduce_domain_balance(domain_id: DomainId, amount: Balance) -> Result<(), Self::Error>;
854}
855
856pub trait DomainOwner<AccountId> {
858 fn is_domain_owner(domain_id: DomainId, acc: AccountId) -> bool;
860}
861
862impl<AccountId> DomainOwner<AccountId> for () {
863 fn is_domain_owner(_domain_id: DomainId, _acc: AccountId) -> bool {
864 false
865 }
866}
867
868pub trait DomainBundleSubmitted {
870 fn domain_bundle_submitted(domain_id: DomainId);
873}
874
875impl DomainBundleSubmitted for () {
876 fn domain_bundle_submitted(_domain_id: DomainId) {}
877}
878
879pub trait OnDomainInstantiated {
881 fn on_domain_instantiated(domain_id: DomainId);
882}
883
884impl OnDomainInstantiated for () {
885 fn on_domain_instantiated(_domain_id: DomainId) {}
886}
887
888#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
890pub struct DomainAllowlistUpdates {
891 pub allow_chains: BTreeSet<ChainId>,
893 pub remove_chains: BTreeSet<ChainId>,
895}
896
897impl DomainAllowlistUpdates {
898 pub fn is_empty(&self) -> bool {
899 self.allow_chains.is_empty() && self.remove_chains.is_empty()
900 }
901
902 pub fn clear(&mut self) {
903 self.allow_chains.clear();
904 self.remove_chains.clear();
905 }
906}
907
908#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
914pub struct DomainSudoCall {
915 pub maybe_call: Option<Vec<u8>>,
916}
917
918impl DomainSudoCall {
919 pub fn clear(&mut self) {
920 self.maybe_call.take();
921 }
922}
923
924#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
930pub struct EvmDomainContractCreationAllowedByCall {
931 pub maybe_call: Option<PermissionedActionAllowedBy<EthereumAccountId>>,
932}
933
934impl EvmDomainContractCreationAllowedByCall {
935 pub fn clear(&mut self) {
936 self.maybe_call.take();
937 }
938}
939
940#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
941pub struct RuntimeObject<Number, Hash> {
942 pub runtime_name: String,
943 pub runtime_type: RuntimeType,
944 pub runtime_upgrades: u32,
945 pub instance_count: u32,
946 pub hash: Hash,
947 pub raw_genesis: RawGenesis,
950 pub version: RuntimeVersion,
951 pub created_at: Number,
952 pub updated_at: Number,
953}
954
955pub fn system_digest_final_key() -> Vec<u8> {
958 frame_support::storage::storage_prefix("System".as_ref(), "Digest".as_ref()).to_vec()
959}
960
961pub trait OnChainRewards<Balance> {
963 fn on_chain_rewards(chain_id: ChainId, reward: Balance);
964}
965
966impl<Balance> OnChainRewards<Balance> for () {
967 fn on_chain_rewards(_chain_id: ChainId, _reward: Balance) {}
968}
969
970#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
971pub enum OperatorRewardSource<Number> {
972 Bundle {
973 at_block_number: Number,
974 },
975 XDMProtocolFees,
976 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
977 Dummy,
978}
979
980#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, Copy)]
982pub struct BundleAndExecutionReceiptVersion {
983 pub bundle_version: BundleVersion,
984 pub execution_receipt_version: ExecutionReceiptVersion,
985}
986
987#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)]
989pub struct StorageFeeDeposit<Balance> {
990 pub total_deposited: Balance,
992 pub current_value: Balance,
994}
995
996#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)]
998pub struct PendingDeposit<Balance> {
999 pub amount: Balance,
1001 pub effective_epoch: EpochIndex,
1003}
1004
1005#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)]
1007pub struct PendingWithdrawal<Balance, DomainBlockNumber> {
1008 pub stake_withdrawal_amount: Balance,
1010 pub storage_fee_refund: Balance,
1012 pub unlock_at_block: DomainBlockNumber,
1014}
1015
1016#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)]
1018pub struct NominatorPosition<Balance, DomainBlockNumber, Share> {
1019 pub current_staked_value: Balance,
1021 pub total_shares: Share,
1023 pub storage_fee_deposit: StorageFeeDeposit<Balance>,
1025 pub pending_deposit: Option<PendingDeposit<Balance>>,
1027 pub pending_withdrawals: Vec<PendingWithdrawal<Balance, DomainBlockNumber>>,
1029}
1030
1031sp_api::decl_runtime_apis! {
1032 #[api_version(6)]
1035 pub trait DomainsApi<DomainHeader: HeaderT> {
1036 fn submit_bundle_unsigned(opaque_bundle: OpaqueBundle<NumberFor<Block>, Block::Hash, DomainHeader, Balance>);
1038
1039 fn submit_receipt_unsigned(singleton_receipt: SealedSingletonReceipt<NumberFor<Block>, Block::Hash, DomainHeader, Balance>);
1041
1042 fn extract_successful_bundles(
1044 domain_id: DomainId,
1045 extrinsics: Vec<Block::Extrinsic>,
1046 ) -> OpaqueBundles<Block, DomainHeader, Balance>;
1047
1048 fn extrinsics_shuffling_seed() -> Randomness;
1050
1051 fn domain_runtime_code(domain_id: DomainId) -> Option<Vec<u8>>;
1053
1054 fn runtime_id(domain_id: DomainId) -> Option<RuntimeId>;
1056
1057 fn runtime_upgrades() -> Vec<RuntimeId>;
1059
1060 fn domain_instance_data(domain_id: DomainId) -> Option<(DomainInstanceData, NumberFor<Block>)>;
1062
1063 fn domain_timestamp() -> Moment;
1065
1066 fn consensus_transaction_byte_fee() -> Balance;
1069
1070 fn domain_tx_range(domain_id: DomainId) -> U256;
1072
1073 fn genesis_state_root(domain_id: DomainId) -> Option<H256>;
1075
1076 fn head_receipt_number(domain_id: DomainId) -> HeaderNumberFor<DomainHeader>;
1078
1079 fn oldest_unconfirmed_receipt_number(domain_id: DomainId) -> Option<HeaderNumberFor<DomainHeader>>;
1081
1082 fn domain_bundle_limit(domain_id: DomainId) -> Option<DomainBundleLimit>;
1084
1085 fn non_empty_er_exists(domain_id: DomainId) -> bool;
1087
1088 fn domain_best_number(domain_id: DomainId) -> Option<HeaderNumberFor<DomainHeader>>;
1090
1091 fn execution_receipt(receipt_hash: HeaderHashFor<DomainHeader>) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1093
1094 fn domain_operators(domain_id: DomainId) -> Option<(BTreeMap<OperatorId, Balance>, Vec<OperatorId>)>;
1096
1097 fn receipt_hash(domain_id: DomainId, domain_number: HeaderNumberFor<DomainHeader>) -> Option<HeaderHashFor<DomainHeader>>;
1099
1100 fn latest_confirmed_domain_block(domain_id: DomainId) -> Option<(HeaderNumberFor<DomainHeader>, HeaderHashFor<DomainHeader>)>;
1102
1103 fn is_bad_er_pending_to_prune(domain_id: DomainId, receipt_hash: HeaderHashFor<DomainHeader>) -> bool;
1105
1106 fn storage_fund_account_balance(operator_id: OperatorId) -> Balance;
1108
1109 fn is_domain_runtime_upgraded_since(domain_id: DomainId, at: NumberFor<Block>) -> Option<bool>;
1111
1112 fn domain_sudo_call(domain_id: DomainId) -> Option<Vec<u8>>;
1114
1115 fn evm_domain_contract_creation_allowed_by_call(domain_id: DomainId) -> Option<PermissionedActionAllowedBy<EthereumAccountId>>;
1117
1118 fn last_confirmed_domain_block_receipt(domain_id: DomainId) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1120
1121 fn current_bundle_and_execution_receipt_version() -> BundleAndExecutionReceiptVersion;
1123
1124 fn genesis_execution_receipt(domain_id: DomainId) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1126
1127 fn nominator_position(
1136 operator_id: OperatorId,
1137 nominator_account: sp_runtime::AccountId32,
1138 ) -> Option<NominatorPosition<Balance, HeaderNumberFor<DomainHeader>, Balance>>;
1139
1140 fn block_pruning_depth() -> NumberFor<Block>;
1143 }
1144
1145 pub trait BundleProducerElectionApi<Balance: Encode + Decode> {
1146 fn bundle_producer_election_params(domain_id: DomainId) -> Option<BundleProducerElectionParams<Balance>>;
1147
1148 fn operator(operator_id: OperatorId) -> Option<(OperatorPublicKey, Balance)>;
1149 }
1150}