cuprated/
blockchain.rs

1//! Blockchain
2//!
3//! Contains the blockchain manager, syncer and an interface to mutate the blockchain.
4use 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::{generate_genesis_block, BlockchainContextService, ContextConfig};
12use cuprate_cryptonight::cryptonight_hash_v0;
13use cuprate_p2p::{block_downloader::BlockDownloaderConfig, NetworkInterface};
14use cuprate_p2p_core::{ClearNet, Network};
15use cuprate_types::{
16    blockchain::{BlockchainReadRequest, BlockchainWriteRequest},
17    VerifiedBlockInformation,
18};
19
20use crate::constants::PANIC_CRITICAL_SERVICE_ERROR;
21
22mod chain_service;
23mod fast_sync;
24pub mod interface;
25mod manager;
26mod syncer;
27mod types;
28
29pub use fast_sync::set_fast_sync_hashes;
30pub use manager::init_blockchain_manager;
31pub use types::ConsensusBlockchainReadHandle;
32
33/// Checks if the genesis block is in the blockchain and adds it if not.
34pub async fn check_add_genesis(
35    blockchain_read_handle: &mut BlockchainReadHandle,
36    blockchain_write_handle: &mut BlockchainWriteHandle,
37    network: Network,
38) {
39    // Try to get the chain height, will fail if the genesis block is not in the DB.
40    if blockchain_read_handle
41        .ready()
42        .await
43        .expect(PANIC_CRITICAL_SERVICE_ERROR)
44        .call(BlockchainReadRequest::ChainHeight)
45        .await
46        .is_ok()
47    {
48        return;
49    }
50
51    let genesis = generate_genesis_block(network);
52
53    assert_eq!(genesis.miner_transaction.prefix().outputs.len(), 1);
54    assert!(genesis.transactions.is_empty());
55
56    blockchain_write_handle
57        .ready()
58        .await
59        .expect(PANIC_CRITICAL_SERVICE_ERROR)
60        .call(BlockchainWriteRequest::WriteBlock(
61            VerifiedBlockInformation {
62                block_blob: genesis.serialize(),
63                txs: vec![],
64                block_hash: genesis.hash(),
65                pow_hash: cryptonight_hash_v0(&genesis.serialize_pow_hash()),
66                height: 0,
67                generated_coins: genesis.miner_transaction.prefix().outputs[0]
68                    .amount
69                    .unwrap(),
70                weight: genesis.miner_transaction.weight(),
71                long_term_weight: genesis.miner_transaction.weight(),
72                cumulative_difficulty: 1,
73                block: genesis,
74            },
75        ))
76        .await
77        .expect(PANIC_CRITICAL_SERVICE_ERROR);
78}
79
80/// Initializes the consensus services.
81pub async fn init_consensus(
82    blockchain_read_handle: BlockchainReadHandle,
83    context_config: ContextConfig,
84) -> Result<BlockchainContextService, BoxError> {
85    let read_handle = ConsensusBlockchainReadHandle::new(blockchain_read_handle, BoxError::from);
86
87    let ctx_service =
88        cuprate_consensus::initialize_blockchain_context(context_config, read_handle.clone())
89            .await?;
90
91    Ok(ctx_service)
92}