1use tower::{BoxError, Service, ServiceExt};
5
6use cuprate_blockchain::service::{BlockchainReadHandle, BlockchainWriteHandle};
7use cuprate_consensus::{
8 generate_genesis_block, BlockchainContext, BlockchainContextService, ContextConfig,
9};
10use cuprate_cryptonight::cryptonight_hash_v0;
11use cuprate_p2p_core::{client::PeerSyncCallback, Network};
12use cuprate_pruning::PruningSeed;
13use cuprate_types::{
14 blockchain::{BlockchainReadRequest, BlockchainWriteRequest},
15 VerifiedBlockInformation,
16};
17
18mod chain_service;
19mod error;
20mod fast_sync;
21pub mod interface;
22mod manager;
23mod syncer;
24mod types;
25
26pub use error::IncomingBlockError;
27pub use fast_sync::get_fast_sync_hashes;
28pub use interface::BlockchainManagerHandle;
29pub use syncer::BlockchainSyncerHandle;
30pub use types::ConsensusBlockchainReadHandle;
31
32pub(crate) use manager::init_blockchain_manager;
33
34#[derive(Clone)]
36pub struct BlockchainInterface {
37 read: BlockchainReadHandle,
39 context_svc: BlockchainContextService,
41 manager: BlockchainManagerHandle,
43 syncer: BlockchainSyncerHandle,
45}
46
47impl BlockchainInterface {
48 pub(crate) const fn new(
49 read: BlockchainReadHandle,
50 context_svc: BlockchainContextService,
51 manager: BlockchainManagerHandle,
52 syncer: BlockchainSyncerHandle,
53 ) -> Self {
54 Self {
55 read,
56 context_svc,
57 manager,
58 syncer,
59 }
60 }
61
62 pub fn read(&self) -> BlockchainReadHandle {
64 self.read.clone()
65 }
66
67 pub fn context(&mut self) -> &BlockchainContext {
69 self.context_svc.blockchain_context()
70 }
71
72 pub fn manager(&self) -> BlockchainManagerHandle {
74 self.manager.clone()
75 }
76
77 pub fn syncer(&self) -> BlockchainSyncerHandle {
79 self.syncer.clone()
80 }
81
82 pub fn pruning_seed(&self) -> PruningSeed {
83 self.read.blockchain.pruning_seed()
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) -> anyhow::Result<()> {
104 if blockchain_read_handle
106 .ready()
107 .await?
108 .call(BlockchainReadRequest::ChainHeight)
109 .await
110 .is_ok()
111 {
112 return Ok(());
113 }
114
115 let genesis = generate_genesis_block(network);
116
117 assert_eq!(genesis.miner_transaction().prefix().outputs.len(), 1);
118 assert_eq!(genesis.transactions.len(), 0);
119
120 blockchain_write_handle
121 .ready()
122 .await?
123 .call(BlockchainWriteRequest::WriteBlock(
124 VerifiedBlockInformation {
125 block_blob: genesis.serialize(),
126 txs: vec![],
127 block_hash: genesis.hash(),
128 pow_hash: cryptonight_hash_v0(&genesis.serialize_pow_hash()),
129 height: 0,
130 generated_coins: genesis.miner_transaction().prefix().outputs[0]
131 .amount
132 .unwrap(),
133 weight: genesis.miner_transaction().weight(),
134 long_term_weight: genesis.miner_transaction().weight(),
135 cumulative_difficulty: 1,
136 block: genesis,
137 },
138 ))
139 .await?;
140
141 Ok(())
142}
143
144pub async fn init_consensus(
146 blockchain_read_handle: BlockchainReadHandle,
147 context_config: ContextConfig,
148) -> Result<BlockchainContextService, BoxError> {
149 let read_handle = ConsensusBlockchainReadHandle::new(blockchain_read_handle, BoxError::from);
150
151 let ctx_service =
152 cuprate_consensus::initialize_blockchain_context(context_config, read_handle.clone())
153 .await?;
154
155 Ok(ctx_service)
156}