//! `spectra admin`: the ledger's own checks (spec §9.5, §19). use super::{ui, Ctx}; use anyhow::Result; use spectra_core::ledger::{Ledger, NoKeys}; /// `spectra admin verify`: recompute the chain, check every checkpoint and /// proof; exit 1 when anything is wrong. pub async fn verify(ctx: &Ctx, json: bool) -> Result { let ledger = Ledger::open(&ctx.db()?, None).await?; let v = ledger.verify(&NoKeys).await?; if json { println!("{}", serde_json::to_string(&v)?); } else if v.clean() { println!("{} ledger verified", ui::done(ui::glyph("✔", "ok"))); println!("{}", ui::kv("events", v.events)); println!( "{}", ui::kv( "checkpoints", format!("{} (last at {})", v.checkpoints, v.last_checkpoint.map(|s| s.to_string()).unwrap_or("none".into())) ) ); println!("{}", ui::kv("uncovered", format!("{} event(s) after the last checkpoint", v.uncovered))); println!("{}", ui::kv("head", ui::hash(hex::encode(v.head)))); } else { println!("{} ledger does not verify: {} finding(s)", ui::err(ui::glyph("✘", "x")), v.findings.len()); for f in &v.findings { println!(" {} {:?}: {}", ui::id(format!("#{}", f.seq)), f.problem, f.detail); } } Ok(if v.clean() { 0 } else { 1 }) } /// `spectra admin check`: do the projections equal a rebuild? pub async fn check(ctx: &Ctx) -> Result { let ledger = Ledger::open(&ctx.db()?, None).await?; let differ = ledger.check().await?; if differ.is_empty() { println!("{} projections match the ledger", ui::done(ui::glyph("✔", "ok"))); Ok(0) } else { println!("{} projections differ from the ledger: {}", ui::err(ui::glyph("✘", "x")), differ.join(", ")); println!(" run {} to rebuild them", ui::id("spectra admin rebuild")); Ok(1) } } /// `spectra admin rebuild`: replay the ledger into every projection. pub async fn rebuild(ctx: &Ctx) -> Result { let ledger = Ledger::open(&ctx.db()?, None).await?; ledger.rebuild().await?; println!("{} projections rebuilt from {} event(s)", ui::done(ui::glyph("✔", "ok")), ledger.head().await.0); Ok(0) }