use blockchain::exit; use blockchain::log::{error, logger}; use blockchain::startup::daemonize::daemonize_after_wallet_prompt; use blockchain::startup::daemonize::handle_control_command; use blockchain::startup::initialize_startup::obtain_startup_wallet_key; use blockchain::startup::initialize_startup::prepare_pre_wallet_startup; use blockchain::startup::node_runtime::initialize_node_logging; use blockchain::startup::node_runtime::install_panic_cleanup; use blockchain::startup::node_runtime::run_unlocked_node; use blockchain::startup::windows_service::handle_windows_service_command; use blockchain::startup::windows_service::try_run_as_windows_service; use blockchain::Runtime; use tokio::runtime::Builder; fn main() { // Linux-specific control commands are handled before any startup work begins. match handle_control_command() { Ok(true) => return, Ok(false) => {} Err(e) => { eprintln!("Control command failed: {e}"); exit(1); } } // Windows service management commands are also handled before normal node startup. match handle_windows_service_command() { Ok(true) => return, Ok(false) => {} Err(e) => { eprintln!("Windows service command failed: {e}"); exit(1); } } // If the binary was launched by the Windows Service Control Manager, the service // entrypoint takes over and the normal console path stops here. match try_run_as_windows_service() { Ok(true) => return, Ok(false) => {} Err(e) => { eprintln!("Failed to start Windows service path: {e}"); exit(1); } } // The pre-wallet startup work runs in a temporary runtime so Linux can daemonize // only after the wallet key is obtained, while Windows console launches still use // the same shared startup sequence. let startup_runtime = Builder::new_current_thread() .enable_all() .build() .expect("Failed to create startup runtime"); startup_runtime.block_on(prepare_pre_wallet_startup()); let wallet_key = startup_runtime.block_on(obtain_startup_wallet_key()); drop(startup_runtime); // Linux detaches after the wallet prompt unless --foreground is supplied. if let Err(e) = daemonize_after_wallet_prompt() { eprintln!("Failed to daemonize: {e}"); exit(1); } // Once the platform-specific startup path is settled, the shared node runtime // takes over for normal unlocked operation. let runtime = Runtime::new().expect("Failed to create main runtime"); let _log_handle = runtime.block_on(async { match initialize_node_logging().await { Ok(handle) => Some(handle), Err(e) => { eprintln!("Failed to initialize logging: {e}"); None } } }); install_panic_cleanup(); if let Err(e) = runtime.block_on(run_unlocked_node(wallet_key, true)) { error!("Failed to start unlocked node runtime: {e}"); logger().flush(); eprintln!("Failed to start unlocked node runtime: {e}"); exit(1); } }