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_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 DecodeWithMemTracking,
137)]
138pub struct DomainId(u32);
139
140impl From<u32> for DomainId {
141 #[inline]
142 fn from(x: u32) -> Self {
143 Self(x)
144 }
145}
146
147impl From<DomainId> for u32 {
148 #[inline]
149 fn from(domain_id: DomainId) -> Self {
150 domain_id.0
151 }
152}
153
154impl FromStr for DomainId {
155 type Err = ParseIntError;
156
157 fn from_str(s: &str) -> Result<Self, Self::Err> {
158 s.parse::<u32>().map(Into::into)
159 }
160}
161
162impl Add<DomainId> for DomainId {
163 type Output = Self;
164
165 fn add(self, other: DomainId) -> Self {
166 Self(self.0 + other.0)
167 }
168}
169
170impl Sub<DomainId> for DomainId {
171 type Output = Self;
172
173 fn sub(self, other: DomainId) -> Self {
174 Self(self.0 - other.0)
175 }
176}
177
178impl CheckedAdd for DomainId {
179 fn checked_add(&self, rhs: &Self) -> Option<Self> {
180 self.0.checked_add(rhs.0).map(Self)
181 }
182}
183
184impl DomainId {
185 pub const fn new(id: u32) -> Self {
187 Self(id)
188 }
189
190 pub fn to_le_bytes(&self) -> [u8; 4] {
192 self.0.to_le_bytes()
193 }
194}
195
196impl Display for DomainId {
197 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
198 self.0.fmt(f)
199 }
200}
201
202impl PassBy for DomainId {
203 type PassBy = pass_by::Codec<Self>;
204}
205
206#[derive(
208 Clone,
209 Copy,
210 Debug,
211 Hash,
212 Eq,
213 PartialEq,
214 Ord,
215 PartialOrd,
216 Encode,
217 Decode,
218 TypeInfo,
219 Serialize,
220 Deserialize,
221 MaxEncodedLen,
222 DecodeWithMemTracking,
223)]
224pub enum ChainId {
225 Consensus,
226 Domain(DomainId),
227}
228
229impl ChainId {
230 #[inline]
231 pub fn consensus_chain_id() -> Self {
232 Self::Consensus
233 }
234
235 #[inline]
236 pub fn is_consensus_chain(&self) -> bool {
237 match self {
238 ChainId::Consensus => true,
239 ChainId::Domain(_) => false,
240 }
241 }
242
243 #[inline]
244 pub fn maybe_domain_chain(&self) -> Option<DomainId> {
245 match self {
246 ChainId::Consensus => None,
247 ChainId::Domain(domain_id) => Some(*domain_id),
248 }
249 }
250}
251
252impl From<u32> for ChainId {
253 #[inline]
254 fn from(x: u32) -> Self {
255 Self::Domain(DomainId::new(x))
256 }
257}
258
259impl From<DomainId> for ChainId {
260 #[inline]
261 fn from(x: DomainId) -> Self {
262 Self::Domain(x)
263 }
264}
265
266pub const INITIAL_DOMAIN_TX_RANGE: u64 = 3;
271
272#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
273pub struct ProofOfElection {
274 pub domain_id: DomainId,
276 pub slot_number: u64,
278 pub proof_of_time: PotOutput,
280 pub vrf_signature: VrfSignature,
282 pub operator_id: OperatorId,
284}
285
286impl ProofOfElection {
287 pub fn verify_vrf_signature(
288 &self,
289 operator_signing_key: &OperatorPublicKey,
290 ) -> Result<(), ProofOfElectionError> {
291 let global_challenge = self
292 .proof_of_time
293 .derive_global_randomness()
294 .derive_global_challenge(self.slot_number);
295 bundle_producer_election::verify_vrf_signature(
296 self.domain_id,
297 operator_signing_key,
298 &self.vrf_signature,
299 &global_challenge,
300 )
301 }
302
303 pub fn vrf_hash(&self) -> Blake3Hash {
305 let mut bytes = self.vrf_signature.pre_output.encode();
306 bytes.append(&mut self.vrf_signature.proof.encode());
307 blake3_hash(&bytes)
308 }
309
310 pub fn slot_number(&self) -> u64 {
311 self.slot_number
312 }
313}
314
315impl ProofOfElection {
316 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
317 pub fn dummy(domain_id: DomainId, operator_id: OperatorId) -> Self {
318 let output_bytes = sp_std::vec![0u8; VrfPreOutput::max_encoded_len()];
319 let proof_bytes = sp_std::vec![0u8; VrfProof::max_encoded_len()];
320 let vrf_signature = VrfSignature {
321 pre_output: VrfPreOutput::decode(&mut output_bytes.as_slice()).unwrap(),
322 proof: VrfProof::decode(&mut proof_bytes.as_slice()).unwrap(),
323 };
324 Self {
325 domain_id,
326 slot_number: 0u64,
327 proof_of_time: PotOutput::default(),
328 vrf_signature,
329 operator_id,
330 }
331 }
332}
333
334#[derive(
336 TypeInfo,
337 Debug,
338 Encode,
339 Decode,
340 Clone,
341 PartialEq,
342 Eq,
343 Serialize,
344 Deserialize,
345 DecodeWithMemTracking,
346)]
347pub enum OperatorAllowList<AccountId: Ord> {
348 Anyone,
350 Operators(BTreeSet<AccountId>),
353}
354
355impl<AccountId: Ord> OperatorAllowList<AccountId> {
356 pub fn is_operator_allowed(&self, operator: &AccountId) -> bool {
358 match self {
359 OperatorAllowList::Anyone => true,
360 OperatorAllowList::Operators(allowed_operators) => allowed_operators.contains(operator),
361 }
362 }
363}
364
365#[derive(
367 TypeInfo,
368 Debug,
369 Encode,
370 Decode,
371 Clone,
372 PartialEq,
373 Eq,
374 Serialize,
375 Deserialize,
376 DecodeWithMemTracking,
377)]
378pub enum PermissionedActionAllowedBy<AccountId: Codec + Clone> {
379 Accounts(Vec<AccountId>),
380 Anyone,
381}
382
383impl<AccountId: Codec + PartialEq + Clone> PermissionedActionAllowedBy<AccountId> {
384 pub fn is_allowed(&self, who: &AccountId) -> bool {
385 match self {
386 PermissionedActionAllowedBy::Accounts(accounts) => accounts.contains(who),
387 PermissionedActionAllowedBy::Anyone => true,
388 }
389 }
390
391 pub fn is_anyone_allowed(&self) -> bool {
392 matches!(self, PermissionedActionAllowedBy::Anyone)
393 }
394}
395
396#[derive(
398 TypeInfo,
399 Debug,
400 Default,
401 Encode,
402 Decode,
403 Clone,
404 PartialEq,
405 Eq,
406 Serialize,
407 Deserialize,
408 DecodeWithMemTracking,
409)]
410pub enum EvmType {
411 #[default]
412 Public,
414 Private {
416 initial_contract_creation_allow_list: PermissionedActionAllowedBy<EthereumAccountId>,
419 },
420}
421
422impl EvmType {
423 pub fn initial_contract_creation_allow_list(
425 &self,
426 ) -> Option<&PermissionedActionAllowedBy<EthereumAccountId>> {
427 match self {
428 EvmType::Public => None,
429 EvmType::Private {
430 initial_contract_creation_allow_list,
431 } => Some(initial_contract_creation_allow_list),
432 }
433 }
434
435 pub fn is_public_evm_domain(&self) -> bool {
437 matches!(self, EvmType::Public)
438 }
439
440 pub fn is_private_evm_domain(&self) -> bool {
442 matches!(self, EvmType::Private { .. })
443 }
444}
445
446#[derive(
448 TypeInfo,
449 Debug,
450 Default,
451 Encode,
452 Decode,
453 Clone,
454 PartialEq,
455 Eq,
456 Serialize,
457 Deserialize,
458 DecodeWithMemTracking,
459)]
460pub struct EvmDomainRuntimeConfig {
461 pub evm_type: EvmType,
462}
463
464#[derive(
466 TypeInfo,
467 Debug,
468 Default,
469 Encode,
470 Decode,
471 Clone,
472 PartialEq,
473 Eq,
474 Serialize,
475 Deserialize,
476 DecodeWithMemTracking,
477)]
478pub struct AutoIdDomainRuntimeConfig {
479 }
481
482#[derive(
484 TypeInfo,
485 Debug,
486 Encode,
487 Decode,
488 Clone,
489 PartialEq,
490 Eq,
491 Serialize,
492 Deserialize,
493 DecodeWithMemTracking,
494)]
495pub enum DomainRuntimeInfo {
496 Evm {
497 chain_id: EVMChainId,
499 domain_runtime_config: EvmDomainRuntimeConfig,
501 },
502 AutoId {
503 domain_runtime_config: AutoIdDomainRuntimeConfig,
505 },
506}
507
508impl From<(EVMChainId, EvmDomainRuntimeConfig)> for DomainRuntimeInfo {
509 fn from(v: (EVMChainId, EvmDomainRuntimeConfig)) -> Self {
510 DomainRuntimeInfo::Evm {
511 chain_id: v.0,
512 domain_runtime_config: v.1,
513 }
514 }
515}
516
517impl From<AutoIdDomainRuntimeConfig> for DomainRuntimeInfo {
518 fn from(auto_id_config: AutoIdDomainRuntimeConfig) -> Self {
519 DomainRuntimeInfo::AutoId {
520 domain_runtime_config: auto_id_config,
521 }
522 }
523}
524
525impl DomainRuntimeInfo {
526 pub fn evm(&self) -> Option<&EvmDomainRuntimeConfig> {
527 match self {
528 DomainRuntimeInfo::Evm {
529 domain_runtime_config,
530 ..
531 } => Some(domain_runtime_config),
532 _ => None,
533 }
534 }
535
536 pub fn initial_contract_creation_allow_list(
537 &self,
538 ) -> Option<&PermissionedActionAllowedBy<EthereumAccountId>> {
539 self.evm()
540 .and_then(|evm_config| evm_config.evm_type.initial_contract_creation_allow_list())
541 }
542
543 pub fn auto_id(&self) -> Option<&AutoIdDomainRuntimeConfig> {
544 match self {
545 DomainRuntimeInfo::AutoId {
546 domain_runtime_config,
547 } => Some(domain_runtime_config),
548 _ => None,
549 }
550 }
551
552 pub fn evm_chain_id(&self) -> Option<EVMChainId> {
554 match self {
555 Self::Evm { chain_id, .. } => Some(*chain_id),
556 _ => None,
557 }
558 }
559
560 pub fn is_evm_domain(&self) -> bool {
561 matches!(self, Self::Evm { .. })
562 }
563
564 pub fn is_private_evm_domain(&self) -> bool {
567 if let Self::Evm {
568 domain_runtime_config,
569 ..
570 } = self
571 {
572 domain_runtime_config.evm_type.is_private_evm_domain()
573 } else {
574 false
575 }
576 }
577
578 pub fn is_auto_id(&self) -> bool {
579 matches!(self, Self::AutoId { .. })
580 }
581}
582
583#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq, Serialize, Deserialize)]
584pub struct GenesisDomain<AccountId: Ord, Balance> {
585 pub runtime_name: String,
587 pub runtime_type: RuntimeType,
588 pub runtime_version: RuntimeVersion,
589 pub raw_genesis_storage: Vec<u8>,
590
591 pub owner_account_id: AccountId,
593 pub domain_name: String,
594 pub bundle_slot_probability: (u64, u64),
595 pub operator_allow_list: OperatorAllowList<AccountId>,
596 pub domain_runtime_info: DomainRuntimeInfo,
598
599 pub signing_key: OperatorPublicKey,
601 pub minimum_nominator_stake: Balance,
602 pub nomination_tax: Percent,
603
604 pub initial_balances: Vec<(MultiAccountId, Balance)>,
606}
607
608#[derive(
610 Debug,
611 Default,
612 Encode,
613 Decode,
614 TypeInfo,
615 Copy,
616 Clone,
617 PartialEq,
618 Eq,
619 Serialize,
620 Deserialize,
621 DecodeWithMemTracking,
622)]
623pub enum RuntimeType {
624 #[default]
625 Evm,
626 AutoId,
627}
628
629pub type RuntimeId = u32;
631
632pub type EpochIndex = u32;
634
635pub type OperatorId = u64;
637
638pub type ChannelId = sp_core::U256;
640
641#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
643pub enum DomainDigestItem {
644 DomainRuntimeUpgraded(RuntimeId),
645 DomainInstantiated(DomainId),
646}
647
648pub trait DomainsDigestItem {
650 fn domain_runtime_upgrade(runtime_id: RuntimeId) -> Self;
651 fn as_domain_runtime_upgrade(&self) -> Option<RuntimeId>;
652
653 fn domain_instantiation(domain_id: DomainId) -> Self;
654 fn as_domain_instantiation(&self) -> Option<DomainId>;
655}
656
657impl DomainsDigestItem for DigestItem {
658 fn domain_runtime_upgrade(runtime_id: RuntimeId) -> Self {
659 Self::Other(DomainDigestItem::DomainRuntimeUpgraded(runtime_id).encode())
660 }
661
662 fn as_domain_runtime_upgrade(&self) -> Option<RuntimeId> {
663 match self.try_to::<DomainDigestItem>(OpaqueDigestItemId::Other) {
664 Some(DomainDigestItem::DomainRuntimeUpgraded(runtime_id)) => Some(runtime_id),
665 _ => None,
666 }
667 }
668
669 fn domain_instantiation(domain_id: DomainId) -> Self {
670 Self::Other(DomainDigestItem::DomainInstantiated(domain_id).encode())
671 }
672
673 fn as_domain_instantiation(&self) -> Option<DomainId> {
674 match self.try_to::<DomainDigestItem>(OpaqueDigestItemId::Other) {
675 Some(DomainDigestItem::DomainInstantiated(domain_id)) => Some(domain_id),
676 _ => None,
677 }
678 }
679}
680
681pub(crate) fn evm_chain_id_storage_key() -> StorageKey {
688 StorageKey(
689 storage_prefix(
690 "EVMChainId".as_bytes(),
693 "ChainId".as_bytes(),
695 )
696 .to_vec(),
697 )
698}
699
700pub(crate) fn evm_contract_creation_allowed_by_storage_key() -> StorageKey {
707 StorageKey(
708 storage_prefix(
709 "EVMNoncetracker".as_bytes(),
712 "ContractCreationAllowedBy".as_bytes(),
714 )
715 .to_vec(),
716 )
717}
718
719pub fn domain_total_issuance_storage_key() -> StorageKey {
726 StorageKey(
727 storage_prefix(
728 "Balances".as_bytes(),
730 "TotalIssuance".as_bytes(),
732 )
733 .to_vec(),
734 )
735}
736
737pub fn domain_account_storage_key<AccountId: Encode>(who: AccountId) -> StorageKey {
744 let storage_prefix = storage_prefix("System".as_bytes(), "Account".as_bytes());
745 let key_hashed = who.using_encoded(Blake2_128Concat::hash);
746
747 let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len());
748
749 final_key.extend_from_slice(&storage_prefix);
750 final_key.extend_from_slice(key_hashed.as_ref());
751
752 StorageKey(final_key)
753}
754
755pub fn self_domain_id_storage_key() -> StorageKey {
760 StorageKey(
761 frame_support::storage::storage_prefix(
762 "SelfDomainId".as_bytes(),
765 "SelfDomainId".as_bytes(),
767 )
768 .to_vec(),
769 )
770}
771
772#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
774pub struct DomainInstanceData {
775 pub runtime_type: RuntimeType,
776 pub raw_genesis: RawGenesis,
777}
778
779#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq, DecodeWithMemTracking)]
780pub struct DomainBundleLimit {
781 pub max_bundle_size: u32,
783 pub max_bundle_weight: Weight,
785}
786
787pub fn calculate_max_bundle_weight_and_size(
791 max_domain_block_size: u32,
792 max_domain_block_weight: Weight,
793 consensus_slot_probability: (u64, u64),
794 bundle_slot_probability: (u64, u64),
795) -> Option<DomainBundleLimit> {
796 let expected_bundles_per_block = bundle_slot_probability
799 .0
800 .checked_mul(consensus_slot_probability.1)?
801 .checked_div(
802 bundle_slot_probability
803 .1
804 .checked_mul(consensus_slot_probability.0)?,
805 )?;
806
807 let max_proof_size = max_domain_block_weight.proof_size();
810 let max_bundle_weight = max_domain_block_weight
811 .checked_div(expected_bundles_per_block)?
812 .set_proof_size(max_proof_size);
813
814 let max_bundle_size =
815 (max_domain_block_size as u64).checked_div(expected_bundles_per_block)? as u32;
816
817 Some(DomainBundleLimit {
818 max_bundle_size,
819 max_bundle_weight,
820 })
821}
822
823pub fn signer_in_tx_range(bundle_vrf_hash: &U256, signer_id_hash: &U256, tx_range: &U256) -> bool {
825 let distance_from_vrf_hash = bidirectional_distance(bundle_vrf_hash, signer_id_hash);
826 distance_from_vrf_hash <= (*tx_range / 2)
827}
828
829#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
831pub enum InvalidReceipt {
832 InvalidBundles,
834}
835
836#[derive(Debug, Decode, Encode, TypeInfo, Clone, PartialEq, Eq)]
837pub enum ReceiptValidity {
838 Valid,
839 Invalid(InvalidReceipt),
840}
841
842pub const EMPTY_EXTRINSIC_ROOT: ExtrinsicsRoot = ExtrinsicsRoot {
844 0: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314"),
845};
846
847pub fn derive_domain_block_hash<DomainHeader: HeaderT>(
848 domain_block_number: DomainHeader::Number,
849 extrinsics_root: DomainHeader::Hash,
850 state_root: DomainHeader::Hash,
851 parent_domain_block_hash: DomainHeader::Hash,
852 digest: Digest,
853) -> DomainHeader::Hash {
854 let domain_header = DomainHeader::new(
855 domain_block_number,
856 extrinsics_root,
857 state_root,
858 parent_domain_block_hash,
859 digest,
860 );
861
862 domain_header.hash()
863}
864
865#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
867pub enum ExtrinsicDigest {
868 Data(Vec<u8>),
870 Hash(H256),
872}
873
874impl ExtrinsicDigest {
875 pub fn new<Layout: TrieLayout>(ext: Vec<u8>) -> Self
876 where
877 Layout::Hash: HashT,
878 <Layout::Hash as HashT>::Output: Into<H256>,
879 {
880 if let Some(threshold) = Layout::MAX_INLINE_VALUE {
881 if ext.len() >= threshold as usize {
882 ExtrinsicDigest::Hash(Layout::Hash::hash(&ext).into())
883 } else {
884 ExtrinsicDigest::Data(ext)
885 }
886 } else {
887 ExtrinsicDigest::Data(ext)
888 }
889 }
890}
891
892pub trait DomainsTransfersTracker<Balance> {
894 type Error;
895
896 fn initialize_domain_balance(domain_id: DomainId, amount: Balance) -> Result<(), Self::Error>;
898
899 fn note_transfer(
902 from_chain_id: ChainId,
903 to_chain_id: ChainId,
904 amount: Balance,
905 ) -> Result<(), Self::Error>;
906
907 fn confirm_transfer(
909 from_chain_id: ChainId,
910 to_chain_id: ChainId,
911 amount: Balance,
912 ) -> Result<(), Self::Error>;
913
914 fn claim_rejected_transfer(
916 from_chain_id: ChainId,
917 to_chain_id: ChainId,
918 amount: Balance,
919 ) -> Result<(), Self::Error>;
920
921 fn reject_transfer(
923 from_chain_id: ChainId,
924 to_chain_id: ChainId,
925 amount: Balance,
926 ) -> Result<(), Self::Error>;
927
928 fn reduce_domain_balance(domain_id: DomainId, amount: Balance) -> Result<(), Self::Error>;
930}
931
932pub trait DomainOwner<AccountId> {
934 fn is_domain_owner(domain_id: DomainId, acc: AccountId) -> bool;
936}
937
938impl<AccountId> DomainOwner<AccountId> for () {
939 fn is_domain_owner(_domain_id: DomainId, _acc: AccountId) -> bool {
940 false
941 }
942}
943
944pub trait DomainBundleSubmitted {
946 fn domain_bundle_submitted(domain_id: DomainId);
949}
950
951impl DomainBundleSubmitted for () {
952 fn domain_bundle_submitted(_domain_id: DomainId) {}
953}
954
955pub trait OnDomainInstantiated {
957 fn on_domain_instantiated(domain_id: DomainId);
958}
959
960impl OnDomainInstantiated for () {
961 fn on_domain_instantiated(_domain_id: DomainId) {}
962}
963
964#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo, DecodeWithMemTracking)]
966pub struct DomainAllowlistUpdates {
967 pub allow_chains: BTreeSet<ChainId>,
969 pub remove_chains: BTreeSet<ChainId>,
971}
972
973impl DomainAllowlistUpdates {
974 pub fn is_empty(&self) -> bool {
975 self.allow_chains.is_empty() && self.remove_chains.is_empty()
976 }
977
978 pub fn clear(&mut self) {
979 self.allow_chains.clear();
980 self.remove_chains.clear();
981 }
982}
983
984#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
990pub struct DomainSudoCall {
991 pub maybe_call: Option<Vec<u8>>,
992}
993
994impl DomainSudoCall {
995 pub fn clear(&mut self) {
996 self.maybe_call.take();
997 }
998}
999
1000#[derive(Default, Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)]
1006pub struct EvmDomainContractCreationAllowedByCall {
1007 pub maybe_call: Option<PermissionedActionAllowedBy<EthereumAccountId>>,
1008}
1009
1010impl EvmDomainContractCreationAllowedByCall {
1011 pub fn clear(&mut self) {
1012 self.maybe_call.take();
1013 }
1014}
1015
1016#[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)]
1017pub struct RuntimeObject<Number, Hash> {
1018 pub runtime_name: String,
1019 pub runtime_type: RuntimeType,
1020 pub runtime_upgrades: u32,
1021 pub instance_count: u32,
1022 pub hash: Hash,
1023 pub raw_genesis: RawGenesis,
1026 pub version: RuntimeVersion,
1027 pub created_at: Number,
1028 pub updated_at: Number,
1029}
1030
1031pub fn system_digest_final_key() -> Vec<u8> {
1034 frame_support::storage::storage_prefix("System".as_ref(), "Digest".as_ref()).to_vec()
1035}
1036
1037pub trait OnChainRewards<Balance> {
1039 fn on_chain_rewards(chain_id: ChainId, reward: Balance);
1040}
1041
1042impl<Balance> OnChainRewards<Balance> for () {
1043 fn on_chain_rewards(_chain_id: ChainId, _reward: Balance) {}
1044}
1045
1046#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
1047pub enum OperatorRewardSource<Number> {
1048 Bundle {
1049 at_block_number: Number,
1050 },
1051 XDMProtocolFees,
1052 #[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
1053 Dummy,
1054}
1055
1056#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, Copy)]
1058pub struct BundleAndExecutionReceiptVersion {
1059 pub bundle_version: BundleVersion,
1060 pub execution_receipt_version: ExecutionReceiptVersion,
1061}
1062
1063#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)]
1065pub struct StorageFeeDeposit<Balance> {
1066 pub total_deposited: Balance,
1068 pub current_value: Balance,
1070}
1071
1072#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)]
1074pub struct PendingDeposit<Balance> {
1075 pub amount: Balance,
1077 pub effective_epoch: EpochIndex,
1079}
1080
1081#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)]
1083pub struct PendingWithdrawal<Balance, DomainBlockNumber> {
1084 pub stake_withdrawal_amount: Balance,
1086 pub storage_fee_refund: Balance,
1088 pub unlock_at_block: DomainBlockNumber,
1090}
1091
1092#[derive(Debug, Encode, Decode, TypeInfo, Clone, PartialEq, Eq)]
1094pub struct NominatorPosition<Balance, DomainBlockNumber, Share> {
1095 pub current_staked_value: Balance,
1097 pub total_shares: Share,
1099 pub storage_fee_deposit: StorageFeeDeposit<Balance>,
1101 pub pending_deposit: Option<PendingDeposit<Balance>>,
1103 pub pending_withdrawals: Vec<PendingWithdrawal<Balance, DomainBlockNumber>>,
1105}
1106
1107sp_api::decl_runtime_apis! {
1108 #[api_version(6)]
1111 pub trait DomainsApi<DomainHeader: HeaderT> {
1112 fn submit_bundle_unsigned(opaque_bundle: OpaqueBundle<NumberFor<Block>, Block::Hash, DomainHeader, Balance>);
1114
1115 fn submit_receipt_unsigned(singleton_receipt: SealedSingletonReceipt<NumberFor<Block>, Block::Hash, DomainHeader, Balance>);
1117
1118 fn extract_successful_bundles(
1120 domain_id: DomainId,
1121 extrinsics: Vec<Block::Extrinsic>,
1122 ) -> OpaqueBundles<Block, DomainHeader, Balance>;
1123
1124 fn extrinsics_shuffling_seed() -> Randomness;
1126
1127 fn domain_runtime_code(domain_id: DomainId) -> Option<Vec<u8>>;
1129
1130 fn runtime_id(domain_id: DomainId) -> Option<RuntimeId>;
1132
1133 fn runtime_upgrades() -> Vec<RuntimeId>;
1135
1136 fn domain_instance_data(domain_id: DomainId) -> Option<(DomainInstanceData, NumberFor<Block>)>;
1138
1139 fn domain_timestamp() -> Moment;
1141
1142 fn consensus_transaction_byte_fee() -> Balance;
1145
1146 fn domain_tx_range(domain_id: DomainId) -> U256;
1148
1149 fn genesis_state_root(domain_id: DomainId) -> Option<H256>;
1151
1152 fn head_receipt_number(domain_id: DomainId) -> HeaderNumberFor<DomainHeader>;
1154
1155 fn oldest_unconfirmed_receipt_number(domain_id: DomainId) -> Option<HeaderNumberFor<DomainHeader>>;
1157
1158 fn domain_bundle_limit(domain_id: DomainId) -> Option<DomainBundleLimit>;
1160
1161 fn non_empty_er_exists(domain_id: DomainId) -> bool;
1163
1164 fn domain_best_number(domain_id: DomainId) -> Option<HeaderNumberFor<DomainHeader>>;
1166
1167 fn execution_receipt(receipt_hash: HeaderHashFor<DomainHeader>) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1169
1170 fn domain_operators(domain_id: DomainId) -> Option<(BTreeMap<OperatorId, Balance>, Vec<OperatorId>)>;
1172
1173 fn receipt_hash(domain_id: DomainId, domain_number: HeaderNumberFor<DomainHeader>) -> Option<HeaderHashFor<DomainHeader>>;
1175
1176 fn latest_confirmed_domain_block(domain_id: DomainId) -> Option<(HeaderNumberFor<DomainHeader>, HeaderHashFor<DomainHeader>)>;
1178
1179 fn is_bad_er_pending_to_prune(domain_id: DomainId, receipt_hash: HeaderHashFor<DomainHeader>) -> bool;
1181
1182 fn storage_fund_account_balance(operator_id: OperatorId) -> Balance;
1184
1185 fn is_domain_runtime_upgraded_since(domain_id: DomainId, at: NumberFor<Block>) -> Option<bool>;
1187
1188 fn domain_sudo_call(domain_id: DomainId) -> Option<Vec<u8>>;
1190
1191 fn evm_domain_contract_creation_allowed_by_call(domain_id: DomainId) -> Option<PermissionedActionAllowedBy<EthereumAccountId>>;
1193
1194 fn last_confirmed_domain_block_receipt(domain_id: DomainId) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1196
1197 fn current_bundle_and_execution_receipt_version() -> BundleAndExecutionReceiptVersion;
1199
1200 fn genesis_execution_receipt(domain_id: DomainId) -> Option<ExecutionReceiptFor<DomainHeader, Block, Balance>>;
1202
1203 fn nominator_position(
1212 operator_id: OperatorId,
1213 nominator_account: sp_runtime::AccountId32,
1214 ) -> Option<NominatorPosition<Balance, HeaderNumberFor<DomainHeader>, Balance>>;
1215
1216 fn block_pruning_depth() -> NumberFor<Block>;
1219 }
1220
1221 pub trait BundleProducerElectionApi<Balance: Encode + Decode> {
1222 fn bundle_producer_election_params(domain_id: DomainId) -> Option<BundleProducerElectionParams<Balance>>;
1223
1224 fn operator(operator_id: OperatorId) -> Option<(OperatorPublicKey, Balance)>;
1225 }
1226}