snarkos_aot/ledger/
checkpoint.rs

1use std::path::PathBuf;
2
3use anyhow::Result;
4use clap::Parser;
5use snarkvm::{console::program::Network, ledger::Block, utilities::ToBytes};
6use snops_checkpoint::{path_from_height, Checkpoint, CheckpointManager, RetentionPolicy};
7use tracing::{info, trace};
8
9use super::truncate::Truncate;
10use crate::{ledger::util, DbLedger};
11
12/// A command to interact with checkpoints.
13#[derive(Debug, Parser)]
14pub enum CheckpointCommand {
15    /// Create a checkpoint for the given ledger.
16    Create,
17    /// Apply a checkpoint to the given ledger.
18    Apply {
19        /// Checkpoint file to apply.
20        checkpoint: PathBuf,
21        /// When present, clean up old checkpoints that are no longer applicable
22        /// after applying the checkpoint.
23        #[clap(long, short, default_value = "false")]
24        clean: bool,
25    },
26    /// View the available checkpoints.
27    View,
28    /// Cleanup old checkpoints.
29    Clean,
30}
31
32impl CheckpointCommand {
33    pub fn parse<N: Network>(self, genesis: Block<N>, ledger: PathBuf) -> Result<()> {
34        match self {
35            CheckpointCommand::Create => open_and_checkpoint::<N>(genesis, ledger),
36            CheckpointCommand::Apply { checkpoint, clean } => {
37                Truncate::rewind::<N>(genesis, ledger.clone(), checkpoint)?;
38                if clean {
39                    let mut manager = CheckpointManager::load(ledger, RetentionPolicy::default())?;
40                    info!(
41                        "removed {} old checkpoints",
42                        manager.cull_incompatible::<N>()?
43                    );
44                }
45                Ok(())
46            }
47            CheckpointCommand::View => {
48                let manager = CheckpointManager::load(ledger, RetentionPolicy::default())?;
49                println!("{manager}");
50                Ok(())
51            }
52            CheckpointCommand::Clean => {
53                let mut manager = CheckpointManager::load(ledger, RetentionPolicy::default())?;
54                info!(
55                    "removed {} old checkpoints",
56                    manager.cull_incompatible::<N>()?
57                );
58                Ok(())
59            }
60        }
61    }
62}
63
64pub fn open_and_checkpoint<N: Network>(genesis: Block<N>, ledger_path: PathBuf) -> Result<()> {
65    let ledger: DbLedger<N> = util::open_ledger(genesis, ledger_path.clone())?;
66    let height = ledger.latest_height();
67
68    info!("creating checkpoint @ {height}...");
69    let bytes = Checkpoint::<N>::new(ledger_path.clone())?.to_bytes_le()?;
70
71    info!("created checkpoint; {} bytes", bytes.len());
72
73    if let Some(path) = path_from_height(&ledger_path, height) {
74        // write the checkpoint file
75        std::fs::write(&path, bytes)?;
76        trace!("checkpoint written to {path:?}");
77    };
78
79    Ok(())
80}