use std::path::PathBuf;
use abscissa_core::{Application, Command, Runnable};
use clap::Parser;
use color_eyre::eyre::Result;
use zakura_chain::parameters::Network;
use zakura_state::{PruneFinalizedStateOptions, PruneFinalizedStateSummary};
use crate::prelude::APPLICATION;
#[derive(Command, Debug, Default, Parser)]
pub struct PruneStateCmd {
#[clap(long, help = "recent finalized blocks below the tip to keep")]
tx_retention: u32,
#[clap(long, short, help = "path to directory with the Zebra chain state")]
cache_dir: Option<PathBuf>,
#[clap(
long,
short,
required = true,
help = "the network of the chain to load"
)]
network: Network,
#[clap(long, help = "apply the pruning plan instead of only previewing it")]
confirm: bool,
}
impl Runnable for PruneStateCmd {
fn run(&self) {
let config = APPLICATION.config();
if let Err(error) = self.run_with_config(config.state.clone()) {
tracing::error!("Failed to prune finalized state: {error}");
std::process::exit(1);
}
}
}
impl PruneStateCmd {
#[allow(clippy::print_stdout)]
pub fn run_with_config(&self, mut state_config: zakura_state::Config) -> Result<()> {
if let Some(cache_dir) = self.cache_dir.clone() {
state_config.cache_dir = cache_dir;
}
let options = PruneFinalizedStateOptions {
tx_retention: self.tx_retention,
};
if self.confirm {
let summary =
zakura_state::prune_finalized_state(state_config, &self.network, options)?;
print_summary("pruning complete", &summary);
} else {
let preview =
zakura_state::preview_prune_finalized_state(state_config, &self.network, options)?;
print_summary("pruning plan", &preview);
println!(" no changes written: pass --confirm to apply this plan");
}
Ok(())
}
}
#[allow(clippy::print_stdout)]
fn print_summary(label: &str, summary: &PruneFinalizedStateSummary) {
println!("{label}:");
println!(
" finalized tip: height {}, hash {}",
summary.tip.0 .0, summary.tip.1
);
println!(" tx retention: {} blocks", summary.tx_retention);
println!(
" previous lowest retained height: {}",
optional_height(summary.previous_lowest_retained_height)
);
println!(
" new lowest retained height: {}",
optional_height(summary.new_lowest_retained_height)
);
if summary.pruned_height_ranges.is_empty() {
println!(" pruned height ranges: none");
} else {
println!(
" pruned height ranges: {} ({} heights)",
summary.pruned_height_ranges.len(),
summary.pruned_height_count
);
for (from, until) in &summary.pruned_height_ranges {
println!(" [{}..{})", from.0, until.0);
}
}
if let Some((from, until)) = summary.compacted_height_range {
println!(" compacted raw tx range: [{}..{})", from.0, until.0);
} else {
println!(" compacted raw tx range: none");
}
}
fn optional_height(height: Option<zakura_chain::block::Height>) -> String {
height.map_or_else(|| "none".to_string(), |height| height.0.to_string())
}