feat(util): add a `zebra-tip-height` utility (#4289)

* Move `init_tracing` to `lib.rs`

Allow it to be reused by other binaries.

* Fix `hex` dependency inclusion in `zebra-chain`

It would previously fail because `hex` was being included without the
`serde` feature, even though we required that for `transparent::Script`.

* Implement `FromStr` for `Network`

Make it easy to receive it as a command-line parameter.

* Add `zebra-tip-height` utility

Obtains the chain tip height of a directory containing Zebra state.

* Remove Tokio dependency from `zebra-utils`

It wasn't actually used by the `zebra-tip-height` utility.

* Remove `BoxStateService` type alias

It's not needed if we don't return the unused state service. This also
allows removing the `tower` dependency.

* Remove unnecessary attribute

Leftover from copied code.

* Make `cache_dir` argument optional

Fallback to the default Zebra state cache directory.

* Remove added newline

Minor formatting fix, to avoid adding an unnecessary newline.

* Move `tip-height` command into `zebrad`

Make it available as a sub-command in `zebrad`.

* Make some zebrad sub-commands only log warnings

Co-authored-by: teor <teor@riseup.net>
This commit is contained in:
Janito Vaqueiro Ferreira Filho 2022-05-06 00:31:52 -03:00 committed by GitHub
parent f3f26ff85f
commit 9538ad29e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 139 additions and 18 deletions

View File

@ -9,7 +9,7 @@ edition = "2021"
[features]
default = []
proptest-impl = ["proptest", "proptest-derive", "zebra-test", "rand", "rand_chacha", "tokio", "hex/serde"]
proptest-impl = ["proptest", "proptest-derive", "zebra-test", "rand", "rand_chacha", "tokio"]
bench = ["zebra-test"]
[dependencies]
@ -29,7 +29,7 @@ fpe = "0.5.1"
futures = "0.3.21"
group = "0.11.0"
halo2 = { package = "halo2_proofs", version = "=0.1.0-beta.4" }
hex = "0.4.3"
hex = { version = "0.4.3", features = ["serde"] }
incrementalmerkletree = "0.3.0-beta.2"
itertools = "0.10.3"
jubjub = "0.8.0"
@ -77,8 +77,6 @@ itertools = "0.10.3"
spandoc = "0.2.2"
tracing = "0.1.31"
hex = { version = "0.4.3", features = ["serde"] }
proptest = "0.10.1"
proptest-derive = "0.3.0"
rand = { version = "0.8.5", package = "rand" }

View File

@ -1,4 +1,6 @@
use std::{convert::From, fmt};
use std::{convert::From, fmt, str::FromStr};
use thiserror::Error;
use crate::{block::Height, parameters::NetworkUpgrade::Canopy};
@ -117,3 +119,19 @@ impl Default for Network {
Network::Mainnet
}
}
impl FromStr for Network {
type Err = InvalidNetworkError;
fn from_str(string: &str) -> Result<Self, Self::Err> {
match string.to_lowercase().as_str() {
"mainnet" => Ok(Network::Mainnet),
"testnet" => Ok(Network::Testnet),
_ => Err(InvalidNetworkError(string.to_owned())),
}
}
}
#[derive(Clone, Debug, Error)]
#[error("Invalid network: {0}")]
pub struct InvalidNetworkError(String);

View File

@ -12,22 +12,15 @@ use color_eyre::eyre::{ensure, Result};
use serde_json::Value;
use std::process::Stdio;
use structopt::StructOpt;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use zebra_chain::block;
use zebra_utils::init_tracing;
#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;
mod args;
/// Initialise tracing using its defaults.
fn init_tracing() {
tracing_subscriber::Registry::default()
.with(tracing_error::ErrorLayer::default())
.init();
}
/// Return a new `zcash-cli` command, including the `zebra-checkpoints`
/// passthrough arguments.
fn passthrough_cmd() -> std::process::Command {

View File

@ -4,3 +4,12 @@
#![doc(html_favicon_url = "https://zfnd.org/wp-content/uploads/2022/03/zebra-favicon-128.png")]
#![doc(html_logo_url = "https://zfnd.org/wp-content/uploads/2022/03/zebra-icon.png")]
#![doc(html_root_url = "https://doc.zebra.zfnd.org/zebra_utils")]
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
/// Initialise tracing using its defaults.
pub fn init_tracing() {
tracing_subscriber::Registry::default()
.with(tracing_error::ErrorLayer::default())
.init();
}

View File

@ -342,14 +342,18 @@ impl Application for ZebradApp {
.as_ref()
.expect("config is loaded before register_components");
let default_filter = if command.verbose { "debug" } else { "info" };
let default_filter = command
.command
.as_ref()
.map(|zcmd| zcmd.default_tracing_filter(command.verbose))
.unwrap_or("warn");
let is_server = command
.command
.as_ref()
.map(ZebradCmd::is_server)
.unwrap_or(false);
// Ignore the tracing filter for short-lived commands
// Ignore the configured tracing filter for short-lived utility commands
let mut tracing_config = cfg_ref.tracing.clone();
if is_server {
// Override the default tracing filter based on the command-line verbosity.

View File

@ -4,12 +4,13 @@ mod copy_state;
mod download;
mod generate;
mod start;
mod tip_height;
mod version;
use self::ZebradCmd::*;
use self::{
copy_state::CopyStateCmd, download::DownloadCmd, generate::GenerateCmd, start::StartCmd,
version::VersionCmd,
tip_height::TipHeightCmd, version::VersionCmd,
};
use crate::config::ZebradConfig;
@ -46,6 +47,10 @@ pub enum ZebradCmd {
#[options(help = "start the application")]
Start(StartCmd),
/// The `tip-height` subcommand
#[options(help = "get the block height of Zebra's persisted chain state")]
TipHeight(TipHeightCmd),
/// The `version` subcommand
#[options(help = "display version information")]
Version(VersionCmd),
@ -54,12 +59,41 @@ pub enum ZebradCmd {
impl ZebradCmd {
/// Returns true if this command is a server command.
///
/// Servers load extra components, and use the configured tracing filter.
///
/// For example, `Start` acts as a Zcash node.
pub(crate) fn is_server(&self) -> bool {
// List all the commands, so new commands have to make a choice here
match self {
// List all the commands, so new commands have to make a choice here
// Commands that run as a configured server
CopyState(_) | Start(_) => true,
Download(_) | Generate(_) | Help(_) | Version(_) => false,
// Utility commands that don't use server components
Download(_) | Generate(_) | Help(_) | TipHeight(_) | Version(_) => false,
}
}
/// Returns the default log level for this command, based on the `verbose` command line flag.
///
/// Some commands need to be quiet by default.
pub(crate) fn default_tracing_filter(&self, verbose: bool) -> &'static str {
let only_show_warnings = match self {
// Commands that generate quiet output by default.
// This output:
// - is used by automated tools, or
// - needs to be read easily.
Generate(_) | TipHeight(_) | Help(_) | Version(_) => true,
// Commands that generate informative logging output by default.
CopyState(_) | Download(_) | Start(_) => false,
};
if only_show_warnings && !verbose {
"warn"
} else if only_show_warnings || !verbose {
"info"
} else {
"debug"
}
}
}
@ -72,6 +106,7 @@ impl Runnable for ZebradCmd {
Generate(cmd) => cmd.run(),
ZebradCmd::Help(cmd) => cmd.run(),
Start(cmd) => cmd.run(),
TipHeight(cmd) => cmd.run(),
Version(cmd) => cmd.run(),
}
}

View File

@ -0,0 +1,64 @@
//! `tip-height` subcommand - prints the block height of Zebra's persisted chain state.
//!
//! Prints the chain tip height stored in Zebra's state. This is useful for developers to inspect
//! Zebra state directories.
use std::path::PathBuf;
use abscissa_core::{Command, Options, Runnable};
use color_eyre::eyre::{eyre, Result};
use zebra_chain::{block, chain_tip::ChainTip, parameters::Network};
use zebra_state::LatestChainTip;
use crate::prelude::app_config;
/// `zebra-tip-height` subcommand
#[derive(Command, Debug, Options)]
pub struct TipHeightCmd {
/// Path to Zebra's cached state.
#[options(help = "path to directory with the Zebra chain state")]
cache_dir: Option<PathBuf>,
/// The network to obtain the chain tip.
#[options(default = "mainnet", help = "the network of the chain to load")]
network: Network,
}
impl Runnable for TipHeightCmd {
/// `tip-height` sub-command entrypoint.
///
/// Reads the chain tip height from a cache directory with Zebra's state.
#[allow(clippy::print_stdout)]
fn run(&self) {
match self.load_tip_height() {
Ok(height) => println!("{}", height.0),
Err(error) => tracing::error!("Failed to read chain tip height from state: {error}"),
}
}
}
impl TipHeightCmd {
/// Load the chain tip height from the state cache directory.
fn load_tip_height(&self) -> Result<block::Height> {
let latest_chain_tip = self.load_latest_chain_tip();
latest_chain_tip
.best_tip_height()
.ok_or_else(|| eyre!("State directory doesn't have a chain tip block"))
}
/// Starts a state service using the `cache_dir` and `network` from the provided arguments.
fn load_latest_chain_tip(&self) -> LatestChainTip {
let mut config = app_config().state.clone();
if let Some(cache_dir) = self.cache_dir.clone() {
config.cache_dir = cache_dir;
}
let (_state_service, _read_state_service, latest_chain_tip, _chain_tip_change) =
zebra_state::init(config, self.network);
latest_chain_tip
}
}