OXYGENHUB

Coverage / src/cli/admin.rs 90.9%

50 of 55 lines run, 7 of 16 functions · run #7 on main · run missed

1
//! `spectra admin`: the ledger's own checks (spec §9.5, §19).
2
3
use super::{ui, Ctx};
4
use anyhow::Result;
5
use spectra_core::ledger::Ledger;
6
use spectra_core::principals::Principals;
7
8
/// `spectra admin verify`: recompute the chain, check every checkpoint and
9
/// proof; exit 1 when anything is wrong.
109×
pub async fn verify(ctx: &Ctx, json: bool) -> Result<i32> {
119×
    let ledger = Ledger::open_read_only(&ctx.db()?).await?;
128×
    let spin = if json { None } else { Some(ui::spinner("verifying the ledger")) };
138×
    let v = ledger.verify(&mut Principals::default()).await?;
148×
    if let Some(s) = spin {
154×
        s.clear();
164×
    }
178×
    if json {
184×
        println!("{}", serde_json::to_string(&v)?);
194×
        return Ok(if v.clean() { 0 } else { 1 });
204×
    }
214×
    if v.clean() {
223×
        println!("{} {}", ui::done("Verified"), ui::subject("the ledger"));
233×
    } else {
241×
        println!(
251×
            "{} {} {}",
261×
            ui::err(ui::glyph("✘", "x")),
271×
            ui::err("The ledger does not verify:"),
281×
            ui::err(format!("{} finding(s)", v.findings.len()))
291×
        );
301×
    }
314×
    println!("{}", ui::kv("events", v.events));
324×
    let last = v.last_checkpoint.map(|s| format!("last at #{s}")).unwrap_or_else(|| "none yet".into());
334×
    println!("{}", ui::kv("signed", format!("{} checkpoint(s){}{last}", v.checkpoints, ui::sep())));
344×
    if v.uncovered > 0 {
350×
        println!("{}", ui::kv("pending", ui::dim(format!("{} event(s) since, chained and awaiting the next checkpoint", v.uncovered))));
364×
    }
374×
    println!("{}", ui::kv("head", ui::hash(hex::encode(v.head))));
384×
    for f in &v.findings {
391×
        println!("  {} {} {}", ui::id(format!("#{}", f.seq)), ui::err(format!("{:?}", f.problem)), f.detail);
401×
    }
414×
    Ok(if v.clean() { 0 } else { 1 })
429×
}
43
44
/// `spectra admin check`: do the projections equal a rebuild?
454×
pub async fn check(ctx: &Ctx) -> Result<i32> {
464×
    let ledger = ctx.writer().await?;
474×
    let differ = ledger.check().await?;
484×
    if differ.is_empty() {
494×
        println!("{} {}", ui::done("Checked"), ui::subject("every projection matches the ledger"));
504×
        Ok(0)
51
    } else {
520×
        println!("{} projections differ from the ledger: {}", ui::caution(), ui::err(differ.join(", ")));
530×
        println!("  {} {}", ui::note(), ui::dim("rebuild them with spectra admin rebuild"));
540×
        Ok(1)
55
    }
564×
}
57
58
/// `spectra admin rebuild`: replay the ledger into every projection.
591×
pub async fn rebuild(ctx: &Ctx) -> Result<i32> {
601×
    let ledger = ctx.writer().await?;
611×
    let spin = ui::spinner("replaying the ledger");
621×
    ledger.rebuild().await?;
631×
    spin.done(&format!("{} {}", ui::done("Rebuilt"), ui::subject(format!("projections from {} events", ledger.head().await.0))));
641×
    Ok(0)
651×
}