//! `start` subcommand - entry point for starting a zebra node //! //! ## Application Structure //! //! A zebra node consists of the following services and tasks: //! //! * Network Service //! * primary interface to the node //! * handles all external network requests for the Zcash protocol //! * via zebra_network::Message and zebra_network::Response //! * provides an interface to the rest of the network for other services and //! tasks running within this node //! * via zebra_network::Request //! * Consensus Service //! * handles all validation logic for the node //! * verifies blocks using zebra-chain and zebra-script, then stores verified //! blocks in zebra-state //! * Sync Task //! * This task runs in the background and continuously queries the network for //! new blocks to be verified and added to the local state use crate::components::tokio::RuntimeRun; use crate::config::ZebradConfig; use crate::{components::tokio::TokioComponent, prelude::*}; use abscissa_core::{config, Command, FrameworkError, Options, Runnable}; use color_eyre::eyre::Report; use tower::{buffer::Buffer, service_fn}; mod sync; /// `start` subcommand #[derive(Command, Debug, Options)] pub struct StartCmd { /// Filter strings #[options(free)] filters: Vec, } impl StartCmd { async fn start(&self) -> Result<(), Report> { info!(?self, "starting to connect to the network"); let config = app_config(); let state = zebra_state::on_disk::init(config.state.clone(), config.network.network); let verifier = zebra_consensus::chain::init(config.network.network, state.clone()).await; // The service that our node uses to respond to requests by peers let node = Buffer::new( service_fn(|req| async move { info!(?req); Ok::(zebra_network::Response::Nil) }), 1, ); let (peer_set, _address_book) = zebra_network::init(config.network.clone(), node).await; let mut syncer = sync::Syncer::new(config.network.network, peer_set, state, verifier); syncer.sync().await } } impl Runnable for StartCmd { /// Start the application. fn run(&self) { info!("Starting zebrad"); let rt = app_writer() .state_mut() .components .get_downcast_mut::() .expect("TokioComponent should be available") .rt .take(); rt.expect("runtime should not already be taken") .run(self.start()); } } impl config::Override for StartCmd { // Process the given command line options, overriding settings from // a configuration file using explicit flags taken from command-line // arguments. fn override_config(&self, mut config: ZebradConfig) -> Result { if !self.filters.is_empty() { config.tracing.filter = Some(self.filters.join(",")); } Ok(config) } }