domain_client_operator/
fetch_domain_bootstrap_info.rs1use futures::StreamExt;
2use sc_client_api::backend::Backend;
3use sc_client_api::{BlockchainEvents, ImportNotifications};
4use sp_api::ProvideRuntimeApi;
5use sp_blockchain::HeaderBackend;
6use sp_domains::{DomainId, DomainInstanceData, DomainsApi};
7use sp_runtime::traits::{Block as BlockT, NumberFor, Zero};
8
9#[derive(Debug)]
10pub struct BootstrapResult<CBlock: BlockT> {
11 pub domain_instance_data: DomainInstanceData,
14 pub domain_created_at: NumberFor<CBlock>,
16 pub imported_block_notification_stream: ImportNotifications<CBlock>,
22}
23
24pub async fn fetch_domain_bootstrap_info<Block, CBlock, CClient, DomainBackend>(
25 consensus_client: &CClient,
26 domain_backend: &DomainBackend,
27 self_domain_id: DomainId,
28) -> Result<BootstrapResult<CBlock>, Box<dyn std::error::Error>>
29where
30 Block: BlockT,
31 CBlock: BlockT,
32 CClient: HeaderBackend<CBlock> + ProvideRuntimeApi<CBlock> + BlockchainEvents<CBlock>,
33 CClient::Api: DomainsApi<CBlock, Block::Header>,
34 DomainBackend: Backend<Block>,
35{
36 let is_domain_started = domain_backend.blockchain().info().finalized_state.is_some();
39
40 let mut imported_block_notification_stream =
41 consensus_client.every_import_notification_stream();
42
43 let best_hash = consensus_client.info().best_hash;
45 if let Some((domain_instance_data, domain_created_at)) = consensus_client
46 .runtime_api()
47 .domain_instance_data(best_hash, self_domain_id)?
48 {
49 let domain_best_number = consensus_client
50 .runtime_api()
51 .domain_best_number(best_hash, self_domain_id)?
52 .unwrap_or_default();
53
54 if !is_domain_started && !domain_best_number.is_zero() {
65 return Err(
66 "An existing consensus node can't be restarted as a domain node, in order to
67 proceed please wipe the `db` and `domains` folders"
68 .to_string()
69 .into(),
70 );
71 }
72
73 return Ok(BootstrapResult {
74 domain_instance_data,
75 domain_created_at,
76 imported_block_notification_stream,
77 });
78 }
79
80 if is_domain_started {
84 return Err(
85 "The domain chain is ahead of the consensus chain, inconsistent `db` and `domains`
86 folders from the last run"
87 .to_string()
88 .into(),
89 );
90 }
91
92 let (domain_instance_data, domain_created_at) = loop {
94 let Some(block_imported) = imported_block_notification_stream.next().await else {
95 return Err("Imported block notification stream end unexpectedly"
96 .to_string()
97 .into());
98 };
99 let Some(data) = consensus_client
100 .runtime_api()
101 .domain_instance_data(block_imported.hash, self_domain_id)?
102 else {
103 continue;
104 };
105 break data;
106 };
107
108 Ok(BootstrapResult {
109 domain_instance_data,
110 domain_created_at,
111 imported_block_notification_stream,
112 })
113}