confium_log_monitor/
main.rs1mod client;
29mod store;
30mod verify;
31
32use std::path::PathBuf;
33use std::time::Duration;
34
35use anyhow::Result;
36use clap::Parser;
37
38#[derive(Parser, Debug)]
39#[command(name = "confium-log-monitor", version)]
40pub struct Args {
41 #[arg(long, default_value = "http://127.0.0.1:8080")]
43 pub log_url: String,
44
45 #[arg(long, default_value = "./confium-monitor-state")]
47 pub state: PathBuf,
48
49 #[arg(long, default_value_t = 30)]
51 pub poll_interval: u64,
52
53 #[arg(long)]
55 pub once: bool,
56}
57
58#[tokio::main]
59async fn main() -> Result<()> {
60 tracing_subscriber::fmt()
61 .with_env_filter(
62 tracing_subscriber::EnvFilter::try_from_default_env()
63 .unwrap_or_else(|_| "confium_log_monitor=info".into()),
64 )
65 .init();
66
67 let args = Args::parse();
68 let client = client::LogClient::new(args.log_url.clone());
69 let store = store::StateStore::open(&args.state)?;
70
71 loop {
72 if let Err(e) = run_cycle(&client, &store).await {
73 tracing::error!(?e, "monitor cycle failed");
74 }
75 if args.once {
76 return Ok(());
77 }
78 tokio::time::sleep(Duration::from_secs(args.poll_interval)).await;
79 }
80}
81
82async fn run_cycle(client: &client::LogClient, store: &store::StateStore) -> Result<()> {
83 let head = client.fetch_head().await?;
84 tracing::info!(tree_size = head.tree_size, root = %head.root, "fetched head");
85
86 let last_size = store.last_tree_size()?;
87 if head.tree_size > last_size {
88 if last_size > 0 {
90 let proof = client.fetch_consistency(last_size).await?;
91 let last_root = store.last_root()?;
92 verify::verify_consistency(&last_root, last_size, &head, &proof)?;
93 tracing::info!(
94 from = last_size,
95 to = head.tree_size,
96 "consistency verified"
97 );
98 }
99 store.put_head(&head)?;
101 } else if head.tree_size < last_size {
102 tracing::error!(
104 observed = head.tree_size,
105 cached = last_size,
106 "TREE SIZE WENT BACKWARDS — possible fork"
107 );
108 }
109
110 Ok(())
111}