1#[cfg(all(not(target_env = "msvc"), feature = "jemalloc-global"))]
6#[global_allocator]
7static ALLOC: cfx_mallocator_utils::allocator::Allocator =
8 cfx_mallocator_utils::allocator::new_allocator();
9#[allow(non_upper_case_globals)]
11#[export_name = "malloc_conf"]
12#[cfg(all(not(target_env = "msvc"), feature = "jemalloc-prof"))]
13pub static malloc_conf: &[u8] =
14 b"prof:true,prof_active:true,lg_prof_sample:19\0"; #[cfg(test)]
17mod test;
18
19mod cli;
20mod command;
21
22use crate::command::rpc::RpcCommand;
23use cfxcore::NodeType;
24use clap::{crate_version, ArgMatches, CommandFactory};
25use cli::Cli;
26use client::{
27 archive::ArchiveClient,
28 common::{shutdown_handler, ClientTrait},
29 configuration::Configuration,
30 full::FullClient,
31 light::LightClient,
32};
33use command::{
34 account::{AccountCmd, ImportAccounts, ListAccounts, NewAccount},
35 dump::DumpCommand,
36};
37use log::{info, LevelFilter};
38use log4rs::{
39 append::{console::ConsoleAppender, file::FileAppender},
40 config::{Appender, Config as LogConfig, Logger, Root},
41 encode::pattern::PatternEncoder,
42};
43use network::throttling::THROTTLING_SERVICE;
44use parking_lot::{Condvar, Mutex};
45use std::sync::{Arc, OnceLock};
46
47static VERSION: OnceLock<String> = OnceLock::new();
48
49fn get_version() -> &'static str {
50 VERSION.get_or_init(|| parity_version::version(crate_version!()))
51}
52
53fn main() -> Result<(), String> {
54 #[cfg(feature = "deadlock-detection")]
55 {
56 use parking_lot::deadlock;
58 use std::{thread, time::Duration};
59
60 thread::spawn(move || loop {
62 thread::sleep(Duration::from_secs(10));
63 let deadlocks = deadlock::check_deadlock();
64 if deadlocks.is_empty() {
65 continue;
66 }
67
68 eprintln!("{} deadlocks detected", deadlocks.len());
69 for (i, threads) in deadlocks.iter().enumerate() {
70 eprintln!("Deadlock #{}", i);
71 for t in threads {
72 eprintln!("Thread Id {:#?}", t.thread_id());
73 eprintln!("{:#?}", t.backtrace());
74 }
75 }
76 });
77 } let matches = Cli::command().version(get_version()).get_matches();
80
81 if let Some(output) = handle_sub_command(&matches)? {
82 println!("{}", output);
83 return Ok(());
84 }
85
86 let conf = Configuration::parse(&matches)?;
87
88 setup_logger(&conf)?;
89
90 THROTTLING_SERVICE.write().initialize(
91 conf.raw_conf.egress_queue_capacity,
92 conf.raw_conf.egress_min_throttle,
93 conf.raw_conf.egress_max_throttle,
94 );
95
96 let exit = Arc::new((Mutex::new(false), Condvar::new()));
97
98 info!(
99 "
100:'######:::'#######::'##::: ##:'########:'##:::::::'##::::'##:'##::::'##:
101'##... ##:'##.... ##: ###:: ##: ##.....:: ##::::::: ##:::: ##:. ##::'##::
102 ##:::..:: ##:::: ##: ####: ##: ##::::::: ##::::::: ##:::: ##::. ##'##:::
103 ##::::::: ##:::: ##: ## ## ##: ######::: ##::::::: ##:::: ##:::. ###::::
104 ##::::::: ##:::: ##: ##. ####: ##...:::: ##::::::: ##:::: ##::: ## ##:::
105 ##::: ##: ##:::: ##: ##:. ###: ##::::::: ##::::::: ##:::: ##:: ##:. ##::
106. ######::. #######:: ##::. ##: ##::::::: ########:. #######:: ##:::. ##:
107:......::::.......:::..::::..::..::::::::........:::.......:::..:::::..::
108Current Version: {}
109",
110 get_version()
111 );
112
113 let client_handle: Box<dyn ClientTrait>;
114 client_handle = match conf.node_type() {
115 NodeType::Archive => {
116 info!("Starting archive client...");
117 ArchiveClient::start(conf, exit.clone())
118 .map_err(|e| format!("failed to start archive client: {}", e))?
119 }
120 NodeType::Full => {
121 info!("Starting full client...");
122 FullClient::start(conf, exit.clone())
123 .map_err(|e| format!("failed to start full client: {}", e))?
124 }
125 NodeType::Light => {
126 info!("Starting light client...");
127 LightClient::start(conf, exit.clone())
128 .map_err(|e| format!("failed to start light client: {}", e))?
129 }
130 NodeType::Unknown => return Err("Unknown node type".into()),
131 };
132 info!("Conflux client started");
133 shutdown_handler::run(client_handle, exit);
134
135 Ok(())
136}
137
138fn handle_sub_command(matches: &ArgMatches) -> Result<Option<String>, String> {
139 if matches.subcommand_name().is_none() {
140 return Ok(None);
141 }
142
143 if let Some(("account", account_matches)) = matches.subcommand() {
145 let account_cmd = match account_matches.subcommand() {
146 Some(("new", new_acc_matches)) => {
147 AccountCmd::New(NewAccount::new(new_acc_matches))
148 }
149 Some(("list", list_acc_matches)) => {
150 AccountCmd::List(ListAccounts::new(list_acc_matches))
151 }
152 Some(("import", import_acc_matches)) => {
153 AccountCmd::Import(ImportAccounts::new(import_acc_matches))
154 }
155 _ => unreachable!(),
156 };
157 let execute_output = command::account::execute(account_cmd)?;
158 return Ok(Some(execute_output));
159 }
160
161 if let Some(("dump", dump_matches)) = matches.subcommand() {
163 let dump_cmd = DumpCommand::parse(dump_matches).map_err(|e| {
164 format!("Failed to parse dump command arguments: {}", e)
165 })?;
166 let mut conf = Configuration::parse(&matches)?;
167 let execute_output = dump_cmd.execute(&mut conf)?;
168 return Ok(Some(execute_output));
169 }
170
171 let mut subcmd_matches = matches;
173 while let Some(m) = subcmd_matches.subcommand() {
174 subcmd_matches = m.1;
175 }
176
177 if let Some(cmd) = RpcCommand::parse(subcmd_matches)? {
178 let rt = tokio::runtime::Runtime::new().unwrap();
179 let result = rt.block_on(cmd.execute())?;
180 return Ok(Some(result));
181 }
182
183 Ok(None)
184}
185
186fn setup_logger(conf: &Configuration) -> Result<(), String> {
190 match conf.raw_conf.log_conf {
191 Some(ref log_conf) => {
192 log4rs::init_file(log_conf, Default::default()).map_err(|e| {
193 format!(
194 "failed to initialize log with log config file '{}': {:?}; maybe you want 'run/log.yaml'?",
195 log_conf, e
196 )
197 })?;
198 }
199 None => {
200 let mut conf_builder =
201 LogConfig::builder().appender(Appender::builder().build(
202 "stdout",
203 Box::new(ConsoleAppender::builder().build()),
204 ));
205 let mut root_builder = Root::builder().appender("stdout");
206 if let Some(ref log_file) = conf.raw_conf.log_file {
207 conf_builder =
208 conf_builder.appender(Appender::builder().build(
209 "logfile",
210 Box::new(
211 FileAppender::builder().encoder(
212 Box::new(
213 PatternEncoder::new(
214 "{d} {h({l}):5.5} {T:<20.20} {t:12.12} - {m}{n}")))
215 .build(log_file)
216 .map_err(
217 |e| format!("failed to build log pattern: {:?}", e))?,
218 ),
219 ));
220 root_builder = root_builder.appender("logfile");
221 };
222 for crate_name in [
224 "blockgen",
225 "cfxcore",
226 "cfx_statedb",
227 "cfx_storage",
228 "conflux",
229 "db",
230 "keymgr",
231 "network",
232 "txgen",
233 "client",
234 "primitives",
235 "io",
236 ]
237 .iter()
238 {
239 conf_builder = conf_builder.logger(
240 Logger::builder()
241 .build(*crate_name, conf.raw_conf.log_level),
242 );
243 }
244 let log_config = conf_builder
245 .build(root_builder.build(LevelFilter::Info))
246 .map_err(|e| format!("failed to build log config: {:?}", e))?;
247 log4rs::init_config(log_config).map_err(|e| {
248 format!("failed to initialize log with config: {:?}", e)
249 })?;
250 }
251 };
252
253 Ok(())
254}