1use std::sync::Arc;
5
6use futures::FutureExt;
7use tokio::sync::{mpsc, Notify};
8use tower::{BoxError, Service, ServiceExt};
9
10use cuprate_blockchain::service::{BlockchainReadHandle, BlockchainWriteHandle};
11use cuprate_consensus::{
12 generate_genesis_block, BlockchainContext, BlockchainContextService, ContextConfig,
13};
14use cuprate_cryptonight::cryptonight_hash_v0;
15use cuprate_p2p::{block_downloader::BlockDownloaderConfig, NetworkInterface};
16use cuprate_p2p_core::{client::PeerSyncCallback, ClearNet, Network};
17use cuprate_types::{
18 blockchain::{BlockchainReadRequest, BlockchainWriteRequest},
19 VerifiedBlockInformation,
20};
21
22use crate::constants::PANIC_CRITICAL_SERVICE_ERROR;
23
24mod chain_service;
25mod fast_sync;
26pub mod interface;
27mod manager;
28mod syncer;
29mod types;
30
31pub use fast_sync::get_fast_sync_hashes;
32pub use interface::BlockchainManagerHandle;
33pub use syncer::BlockchainSyncerHandle;
34pub use types::ConsensusBlockchainReadHandle;
35
36pub(crate) use manager::init_blockchain_manager;
37
38#[derive(Clone)]
40pub struct BlockchainInterface {
41 read: BlockchainReadHandle,
43 context_svc: BlockchainContextService,
45 manager: BlockchainManagerHandle,
47 syncer: BlockchainSyncerHandle,
49}
50
51impl BlockchainInterface {
52 pub(crate) const fn new(
53 read: BlockchainReadHandle,
54 context_svc: BlockchainContextService,
55 manager: BlockchainManagerHandle,
56 syncer: BlockchainSyncerHandle,
57 ) -> Self {
58 Self {
59 read,
60 context_svc,
61 manager,
62 syncer,
63 }
64 }
65
66 pub fn read(&self) -> BlockchainReadHandle {
68 self.read.clone()
69 }
70
71 pub fn context(&mut self) -> &BlockchainContext {
73 self.context_svc.blockchain_context()
74 }
75
76 pub fn manager(&self) -> BlockchainManagerHandle {
78 self.manager.clone()
79 }
80
81 pub fn syncer(&self) -> BlockchainSyncerHandle {
83 self.syncer.clone()
84 }
85
86 pub(crate) fn context_svc(&self) -> BlockchainContextService {
88 self.context_svc.clone()
89 }
90
91 pub(crate) fn peer_sync_callback(&self) -> PeerSyncCallback {
93 self.syncer
94 .callback(self.context_svc.clone(), self.manager.clone())
95 }
96}
97
98pub async fn check_add_genesis(
100 blockchain_read_handle: &mut BlockchainReadHandle,
101 blockchain_write_handle: &mut BlockchainWriteHandle,
102 network: Network,
103) {
104 if blockchain_read_handle
106 .ready()
107 .await
108 .expect(PANIC_CRITICAL_SERVICE_ERROR)
109 .call(BlockchainReadRequest::ChainHeight)
110 .await
111 .is_ok()
112 {
113 return;
114 }
115
116 let genesis = generate_genesis_block(network);
117
118 assert_eq!(genesis.miner_transaction().prefix().outputs.len(), 1);
119 assert!(genesis.transactions.is_empty());
120
121 blockchain_write_handle
122 .ready()
123 .await
124 .expect(PANIC_CRITICAL_SERVICE_ERROR)
125 .call(BlockchainWriteRequest::WriteBlock(
126 VerifiedBlockInformation {
127 block_blob: genesis.serialize(),
128 txs: vec![],
129 block_hash: genesis.hash(),
130 pow_hash: cryptonight_hash_v0(&genesis.serialize_pow_hash()),
131 height: 0,
132 generated_coins: genesis.miner_transaction().prefix().outputs[0]
133 .amount
134 .unwrap(),
135 weight: genesis.miner_transaction().weight(),
136 long_term_weight: genesis.miner_transaction().weight(),
137 cumulative_difficulty: 1,
138 block: genesis,
139 },
140 ))
141 .await
142 .expect(PANIC_CRITICAL_SERVICE_ERROR);
143}
144
145pub async fn init_consensus(
147 blockchain_read_handle: BlockchainReadHandle,
148 context_config: ContextConfig,
149) -> Result<BlockchainContextService, BoxError> {
150 let read_handle = ConsensusBlockchainReadHandle::new(blockchain_read_handle, BoxError::from);
151
152 let ctx_service =
153 cuprate_consensus::initialize_blockchain_context(context_config, read_handle.clone())
154 .await?;
155
156 Ok(ctx_service)
157}