-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(scanner): Add a new
zebra-scanner
binary (#8608)
* add a new `zebra-scanner` binary * update arguments * allow birthday in config * remove required feature * add `env-filter` feature to `tracing-subscriber` dependency * use sync task * codespell --------- Co-authored-by: Arya <aryasolhi@gmail.com>
- Loading branch information
1 parent
4213e82
commit a94b2be
Showing
7 changed files
with
186 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
//! The zebra-scanner binary. | ||
//! | ||
//! The zebra-scanner binary is a standalone binary that scans the Zcash blockchain for transactions using the given sapling keys. | ||
use color_eyre::eyre::eyre; | ||
use lazy_static::lazy_static; | ||
use structopt::StructOpt; | ||
use tracing::*; | ||
|
||
use zebra_chain::{block::Height, parameters::Network}; | ||
use zebra_state::SaplingScanningKey; | ||
|
||
use core::net::SocketAddr; | ||
use std::path::PathBuf; | ||
|
||
/// A structure with sapling key and birthday height. | ||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize)] | ||
pub struct SaplingKey { | ||
key: SaplingScanningKey, | ||
#[serde(default = "min_height")] | ||
birthday_height: Height, | ||
} | ||
|
||
fn min_height() -> Height { | ||
Height(0) | ||
} | ||
|
||
impl std::str::FromStr for SaplingKey { | ||
type Err = Box<dyn std::error::Error>; | ||
fn from_str(value: &str) -> Result<Self, Self::Err> { | ||
Ok(serde_json::from_str(value)?) | ||
} | ||
} | ||
|
||
#[tokio::main] | ||
/// Runs the zebra scanner binary with the given arguments. | ||
async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
// Display all logs from the zebra-scan crate. | ||
tracing_subscriber::fmt::fmt() | ||
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) | ||
.init(); | ||
|
||
// Parse command line arguments. | ||
let args = Args::from_args(); | ||
|
||
let zebrad_cache_dir = args.zebrad_cache_dir; | ||
let scanning_cache_dir = args.scanning_cache_dir; | ||
let mut db_config = zebra_scan::Config::default().db_config; | ||
db_config.cache_dir = scanning_cache_dir; | ||
let network = args.network; | ||
let sapling_keys_to_scan = args | ||
.sapling_keys_to_scan | ||
.into_iter() | ||
.map(|key| (key.key, key.birthday_height.0)) | ||
.collect(); | ||
let listen_addr = args.listen_addr; | ||
|
||
// Create a state config with arguments. | ||
let state_config = zebra_state::Config { | ||
cache_dir: zebrad_cache_dir, | ||
..zebra_state::Config::default() | ||
}; | ||
|
||
// Create a scanner config with arguments. | ||
let scanner_config = zebra_scan::Config { | ||
sapling_keys_to_scan, | ||
listen_addr, | ||
db_config, | ||
}; | ||
|
||
// Get a read-only state and the database. | ||
let (read_state, _latest_chain_tip, chain_tip_change, sync_task) = | ||
zebra_rpc::sync::init_read_state_with_syncer( | ||
state_config, | ||
&network, | ||
args.zebra_rpc_listen_addr, | ||
) | ||
.await? | ||
.map_err(|err| eyre!(err))?; | ||
|
||
// Spawn the scan task. | ||
let scan_task_handle = | ||
{ zebra_scan::spawn_init(scanner_config, network, read_state, chain_tip_change) }; | ||
|
||
// Pin the scan task handle. | ||
tokio::pin!(scan_task_handle); | ||
tokio::pin!(sync_task); | ||
|
||
// Wait for task to finish | ||
tokio::select! { | ||
scan_result = &mut scan_task_handle => scan_result | ||
.expect("unexpected panic in the scan task") | ||
.map(|_| info!("scan task exited")) | ||
.map_err(Into::into), | ||
sync_result = &mut sync_task => { | ||
sync_result.expect("unexpected panic in the scan task"); | ||
Ok(()) | ||
} | ||
} | ||
} | ||
|
||
// Default values for the zebra-scanner arguments. | ||
lazy_static! { | ||
static ref DEFAULT_ZEBRAD_CACHE_DIR: String = zebra_state::Config::default() | ||
.cache_dir | ||
.to_str() | ||
.expect("default cache dir is valid") | ||
.to_string(); | ||
static ref DEFAULT_SCANNER_CACHE_DIR: String = zebra_scan::Config::default() | ||
.db_config | ||
.cache_dir | ||
.to_str() | ||
.expect("default cache dir is valid") | ||
.to_string(); | ||
static ref DEFAULT_NETWORK: String = Network::default().to_string(); | ||
} | ||
|
||
/// zebra-scanner arguments | ||
#[derive(Clone, Debug, Eq, PartialEq, StructOpt)] | ||
pub struct Args { | ||
/// Path to zebrad state. | ||
#[structopt(default_value = &DEFAULT_ZEBRAD_CACHE_DIR, long)] | ||
pub zebrad_cache_dir: PathBuf, | ||
|
||
/// Path to scanning state. | ||
#[structopt(default_value = &DEFAULT_SCANNER_CACHE_DIR, long)] | ||
pub scanning_cache_dir: PathBuf, | ||
|
||
/// The Zcash network. | ||
#[structopt(default_value = &DEFAULT_NETWORK, long)] | ||
pub network: Network, | ||
|
||
/// The sapling keys to scan for. | ||
#[structopt(long)] | ||
pub sapling_keys_to_scan: Vec<SaplingKey>, | ||
|
||
/// The listen address of Zebra's RPC server used by the syncer to check for chain tip changes | ||
/// and get blocks in Zebra's non-finalized state. | ||
#[structopt(long)] | ||
pub zebra_rpc_listen_addr: SocketAddr, | ||
|
||
/// IP address and port for the gRPC server. | ||
#[structopt(long)] | ||
pub listen_addr: Option<SocketAddr>, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters