1#![feature(
62 array_windows,
63 assert_matches,
64 box_into_inner,
65 duration_constructors,
66 let_chains,
67 more_qualified_paths
68)]
69
70mod aux_schema;
71mod bundle_processor;
72mod bundle_producer_election_solver;
73mod domain_block_processor;
74pub mod domain_bundle_producer;
75pub mod domain_bundle_proposer;
76mod domain_worker;
77mod fetch_domain_bootstrap_info;
78mod fraud_proof;
79mod operator;
80pub mod snap_sync;
81#[cfg(test)]
82mod tests;
83mod utils;
84
85pub use self::aux_schema::load_execution_receipt;
86pub use self::fetch_domain_bootstrap_info::{fetch_domain_bootstrap_info, BootstrapResult};
87pub use self::operator::Operator;
88pub use self::utils::{DomainBlockImportNotification, OperatorSlotInfo};
89pub use domain_worker::OpaqueBundleFor;
90use futures::channel::mpsc;
91use futures::Stream;
92use sc_client_api::{AuxStore, BlockImportNotification};
93use sc_consensus::BoxBlockImport;
94use sc_network::service::traits::NetworkService;
95use sc_network_sync::block_relay_protocol::BlockDownloader;
96use sc_network_sync::service::network::NetworkServiceHandle;
97use sc_network_sync::SyncingService;
98use sc_transaction_pool_api::OffchainTransactionPoolFactory;
99use sc_utils::mpsc::TracingUnboundedSender;
100use snap_sync::ConsensusChainSyncParams;
101use sp_blockchain::HeaderBackend;
102use sp_consensus::SyncOracle;
103use sp_consensus_slots::Slot;
104use sp_domain_digests::AsPredigest;
105use sp_domains::{Bundle, DomainId, ExecutionReceiptFor as ExecutionReceipt, OperatorId};
106use sp_keystore::KeystorePtr;
107use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
108use sp_runtime::DigestItem;
109use std::marker::PhantomData;
110use std::sync::atomic::{AtomicBool, Ordering};
111use std::sync::Arc;
112use subspace_core_primitives::pot::PotOutput;
113use subspace_runtime_primitives::{Balance, BlockHashFor, ExtrinsicFor, HeaderFor};
114
115#[derive(Debug, Clone)]
120pub struct DomainChainSyncOracle<SO>
121where
122 SO: SyncOracle + Send + Sync,
123{
124 domain_snap_sync_finished: Option<Arc<AtomicBool>>,
125 inner: SO,
126}
127
128impl<SO> SyncOracle for DomainChainSyncOracle<SO>
129where
130 SO: SyncOracle + Send + Sync,
131{
132 fn is_major_syncing(&self) -> bool {
133 self.inner.is_major_syncing()
134 || self
135 .domain_snap_sync_finished
136 .as_ref()
137 .map(|sync_finished| !sync_finished.load(Ordering::Acquire))
138 .unwrap_or_default()
139 }
140
141 fn is_offline(&self) -> bool {
142 self.inner.is_offline()
143 }
144}
145
146impl<SO> DomainChainSyncOracle<SO>
147where
148 SO: SyncOracle + Send + Sync,
149{
150 pub fn new(sync_oracle: SO, domain_snap_sync_finished: Option<Arc<AtomicBool>>) -> Self {
152 Self {
153 domain_snap_sync_finished,
154 inner: sync_oracle,
155 }
156 }
157}
158
159pub type ExecutionReceiptFor<Block, CBlock> = ExecutionReceipt<HeaderFor<Block>, CBlock, Balance>;
160
161type BundleSender<Block, CBlock> = TracingUnboundedSender<
162 Bundle<ExtrinsicFor<Block>, NumberFor<CBlock>, BlockHashFor<CBlock>, HeaderFor<Block>, Balance>,
163>;
164
165pub struct OperatorStreams<CBlock, IBNS, CIBNS, NSNS, ASS> {
167 pub consensus_block_import_throttling_buffer_size: u32,
170 pub block_importing_notification_stream: IBNS,
174 pub imported_block_notification_stream: CIBNS,
178 pub new_slot_notification_stream: NSNS,
180 pub acknowledgement_sender_stream: ASS,
183 pub _phantom: PhantomData<CBlock>,
184}
185
186type NewSlotNotification = (Slot, PotOutput);
187
188pub struct OperatorParams<
189 Block,
190 CBlock,
191 Client,
192 CClient,
193 TransactionPool,
194 Backend,
195 E,
196 IBNS,
197 CIBNS,
198 NSNS,
199 ASS,
200> where
201 Block: BlockT,
202 CBlock: BlockT,
203 IBNS: Stream<Item = (NumberFor<CBlock>, mpsc::Sender<()>)> + Send + 'static,
204 CIBNS: Stream<Item = BlockImportNotification<CBlock>> + Send + 'static,
205 NSNS: Stream<Item = NewSlotNotification> + Send + 'static,
206 ASS: Stream<Item = mpsc::Sender<()>> + Send + 'static,
207{
208 pub domain_id: DomainId,
209 pub domain_created_at: NumberFor<CBlock>,
210 pub consensus_client: Arc<CClient>,
211 pub consensus_offchain_tx_pool_factory: OffchainTransactionPoolFactory<CBlock>,
212 pub domain_sync_oracle: Arc<dyn SyncOracle + Send + Sync>,
213 pub client: Arc<Client>,
214 pub transaction_pool: Arc<TransactionPool>,
215 pub backend: Arc<Backend>,
216 pub code_executor: Arc<E>,
217 pub maybe_operator_id: Option<OperatorId>,
218 pub keystore: KeystorePtr,
219 pub bundle_sender: Arc<BundleSender<Block, CBlock>>,
220 pub operator_streams: OperatorStreams<CBlock, IBNS, CIBNS, NSNS, ASS>,
221 pub consensus_confirmation_depth_k: NumberFor<CBlock>,
222 pub challenge_period: NumberFor<CBlock>,
223 pub block_import: Arc<BoxBlockImport<Block>>,
224 pub skip_empty_bundle_production: bool,
225 pub skip_out_of_order_slot: bool,
226 pub sync_service: Arc<SyncingService<Block>>,
227 pub network_service: Arc<dyn NetworkService>,
228 pub block_downloader: Arc<dyn BlockDownloader<Block>>,
229 pub consensus_chain_sync_params: Option<ConsensusChainSyncParams<CBlock, Block::Header>>,
230 pub domain_fork_id: Option<String>,
231 pub domain_network_service_handle: NetworkServiceHandle,
232}
233
234pub fn load_execution_receipt_by_domain_hash<Block, CBlock, Client>(
235 domain_client: &Client,
236 domain_hash: Block::Hash,
237 domain_number: NumberFor<Block>,
238) -> Result<ExecutionReceiptFor<Block, CBlock>, sp_blockchain::Error>
239where
240 Block: BlockT,
241 CBlock: BlockT,
242 Client: AuxStore + HeaderBackend<Block>,
243{
244 let domain_header = domain_client.header(domain_hash)?.ok_or_else(|| {
245 sp_blockchain::Error::Backend(format!(
246 "Header for domain block {domain_hash}#{domain_number} not found"
247 ))
248 })?;
249
250 let consensus_block_hash = domain_header
251 .digest()
252 .convert_first(DigestItem::as_consensus_block_info)
253 .ok_or_else(|| {
254 sp_blockchain::Error::Application(format!(
255 "Domain block header {domain_hash}#{domain_number} must have consensus block info predigest"
256 ).into())
257 })?;
258
259 crate::aux_schema::load_execution_receipt::<_, Block, CBlock>(
261 domain_client,
262 consensus_block_hash,
263 )?
264 .ok_or_else(|| {
265 sp_blockchain::Error::Backend(format!(
266 "Receipt for consensus block {consensus_block_hash} and domain block \
267 {domain_hash}#{domain_number} not found"
268 ))
269 })
270}