use super::*;
use std::{env, fs, io};
use rusk_recovery_tools::Theme;
use rusk_recovery_tools::state::{deploy, restore_state, tar};
use tracing::info;
pub fn recovery_state(
input: PathBuf,
force: bool,
output_file: Option<PathBuf>,
) -> Result<(), Box<dyn std::error::Error>> {
let config = fs::read_to_string(input.as_path())
.map_err(|_| format!("file {input:?} not found"))?;
let init = toml::from_str(&config)?;
let theme = Theme::default();
info!("{} Network state", theme.action("Checking"));
let _tmpdir = match output_file.clone() {
Some(output) if output.exists() => Err("Output already exists")?,
Some(_) => {
let tmp_dir = tempfile::tempdir()?;
unsafe { env::set_var("RUSK_STATE_PATH", tmp_dir.path()) };
Some(tmp_dir)
}
None => None,
};
if force {
clean_state()?;
}
let state_dir = rusk_profile::get_rusk_state_dir()?;
let state_id_path = rusk_profile::to_rusk_state_id_path(&state_dir);
if state_dir.exists() && state_id_path.exists() {
info!("{} existing state", theme.info("Found"));
let (_, commit_id) = restore_state(state_dir)?;
info!(
"{} state id at {}",
theme.success("Checked"),
state_id_path.display()
);
info!("{} {}", theme.action("Root"), hex::encode(commit_id));
return Ok(());
}
info!("{} new state", theme.info("Building"));
let (_, commit_id) =
deploy(&state_dir, &init, *rusk::DUSK_CONSENSUS_KEY, |_| {})?;
info!("{} {}", theme.action("Final Root"), hex::encode(commit_id));
info!(
"{} network state at {}",
theme.success("Stored"),
state_dir.display()
);
info!(
"{} persisted id at {}",
theme.success("Stored"),
state_id_path.display()
);
if let Some(output) = output_file {
let state_folder = rusk_profile::get_rusk_state_dir()?;
info!(
"{} state into {}",
theme.info("Compressing"),
output.display()
);
tar::archive(&state_folder, &output)?;
}
Ok(())
}
fn clean_state() -> Result<(), io::Error> {
let state_path = rusk_profile::get_rusk_state_dir()?;
fs::remove_dir_all(state_path).or_else(|e| {
if e.kind() == io::ErrorKind::NotFound {
Ok(())
} else {
Err(e)
}
})
}