cuprated/
main.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![allow(
4    unused_imports,
5    unreachable_pub,
6    unreachable_code,
7    unused_crate_dependencies,
8    dead_code,
9    unused_variables,
10    clippy::needless_pass_by_value,
11    clippy::unused_async,
12    clippy::diverging_sub_expression,
13    unused_mut,
14    clippy::let_unit_value,
15    clippy::needless_pass_by_ref_mut,
16    reason = "TODO: remove after v1.0.0"
17)]
18
19use std::{mem, sync::Arc};
20
21use tokio::sync::mpsc;
22use tower::{Service, ServiceExt};
23use tracing::{info, level_filters::LevelFilter};
24use tracing_subscriber::{layer::SubscriberExt, reload::Handle, util::SubscriberInitExt, Registry};
25
26use cuprate_consensus_context::{
27    BlockChainContextRequest, BlockChainContextResponse, BlockchainContextService,
28};
29use cuprate_helper::time::secs_to_hms;
30use cuprate_types::blockchain::BlockchainWriteRequest;
31
32use crate::{
33    config::Config, constants::PANIC_CRITICAL_SERVICE_ERROR, logging::CupratedTracingFilter,
34};
35
36mod blockchain;
37mod commands;
38mod config;
39mod constants;
40mod killswitch;
41mod logging;
42mod p2p;
43mod rpc;
44mod signals;
45mod statics;
46mod txpool;
47mod version;
48
49fn main() {
50    // Initialize the killswitch.
51    killswitch::init_killswitch();
52
53    // Initialize global static `LazyLock` data.
54    statics::init_lazylock_statics();
55
56    let config = config::read_config_and_args();
57
58    blockchain::set_fast_sync_hashes(!config.no_fast_sync, config.network());
59
60    // Initialize logging.
61    logging::init_logging(&config);
62
63    // Initialize the thread-pools
64
65    init_global_rayon_pool(&config);
66
67    let rt = init_tokio_rt(&config);
68
69    let db_thread_pool = cuprate_database_service::init_thread_pool(
70        cuprate_database_service::ReaderThreads::Number(config.storage.reader_threads),
71    );
72
73    // Start the blockchain & tx-pool databases.
74
75    let (mut blockchain_read_handle, mut blockchain_write_handle, _) =
76        cuprate_blockchain::service::init_with_pool(
77            config.blockchain_config(),
78            Arc::clone(&db_thread_pool),
79        )
80        .unwrap();
81    let (txpool_read_handle, txpool_write_handle, _) =
82        cuprate_txpool::service::init_with_pool(config.txpool_config(), db_thread_pool).unwrap();
83
84    // Initialize async tasks.
85
86    rt.block_on(async move {
87        // TODO: we could add an option for people to keep these like monerod?
88        blockchain_write_handle
89            .ready()
90            .await
91            .expect(PANIC_CRITICAL_SERVICE_ERROR)
92            .call(BlockchainWriteRequest::FlushAltBlocks)
93            .await
94            .expect(PANIC_CRITICAL_SERVICE_ERROR);
95
96        // Check add the genesis block to the blockchain.
97        blockchain::check_add_genesis(
98            &mut blockchain_read_handle,
99            &mut blockchain_write_handle,
100            config.network(),
101        )
102        .await;
103
104        // Start the context service and the block/tx verifier.
105        let context_svc =
106            blockchain::init_consensus(blockchain_read_handle.clone(), config.context_config())
107                .await
108                .unwrap();
109
110        // Start clearnet P2P.
111        let (clearnet, incoming_tx_handler_tx) = p2p::start_clearnet_p2p(
112            blockchain_read_handle.clone(),
113            context_svc.clone(),
114            txpool_read_handle.clone(),
115            config.clearnet_p2p_config(),
116        )
117        .await
118        .unwrap();
119
120        // Create the incoming tx handler service.
121        let tx_handler = txpool::IncomingTxHandler::init(
122            clearnet.clone(),
123            txpool_write_handle.clone(),
124            txpool_read_handle,
125            context_svc.clone(),
126            blockchain_read_handle.clone(),
127        );
128        if incoming_tx_handler_tx.send(tx_handler).is_err() {
129            unreachable!()
130        }
131
132        // Initialize the blockchain manager.
133        blockchain::init_blockchain_manager(
134            clearnet,
135            blockchain_write_handle,
136            blockchain_read_handle,
137            txpool_write_handle,
138            context_svc.clone(),
139            config.block_downloader_config(),
140        )
141        .await;
142
143        // Start the command listener.
144        if std::io::IsTerminal::is_terminal(&std::io::stdin()) {
145            let (command_tx, command_rx) = mpsc::channel(1);
146            std::thread::spawn(|| commands::command_listener(command_tx));
147
148            // Wait on the io_loop, spawned on a separate task as this improves performance.
149            tokio::spawn(commands::io_loop(command_rx, context_svc))
150                .await
151                .unwrap();
152        } else {
153            // If no STDIN, await OS exit signal.
154            info!("Terminal/TTY not detected, disabling STDIN commands");
155            tokio::signal::ctrl_c().await.unwrap();
156        }
157    });
158}
159
160/// Initialize the [`tokio`] runtime.
161fn init_tokio_rt(config: &Config) -> tokio::runtime::Runtime {
162    tokio::runtime::Builder::new_multi_thread()
163        .worker_threads(config.tokio.threads)
164        .thread_name("cuprated-tokio")
165        .enable_all()
166        .build()
167        .unwrap()
168}
169
170/// Initialize the global [`rayon`] thread-pool.
171fn init_global_rayon_pool(config: &Config) {
172    rayon::ThreadPoolBuilder::new()
173        .num_threads(config.rayon.threads)
174        .thread_name(|index| format!("cuprated-rayon-{index}"))
175        .build_global()
176        .unwrap();
177}