mithril_aggregator/commands/
tools_command.rs

1use anyhow::Context;
2use clap::{Parser, Subcommand};
3use config::{builder::DefaultState, ConfigBuilder};
4use mithril_common::StdResult;
5use mithril_persistence::sqlite::{SqliteCleaner, SqliteCleaningTask};
6use slog::{debug, Logger};
7use std::sync::Arc;
8
9use crate::{
10    database::repository::{CertificateRepository, SignedEntityStore},
11    dependency_injection::DependenciesBuilder,
12    tools::CertificatesHashMigrator,
13    Configuration,
14};
15
16/// List of tools to upkeep the aggregator
17#[derive(Parser, Debug, Clone)]
18pub struct ToolsCommand {
19    /// commands
20    #[clap(subcommand)]
21    pub genesis_subcommand: ToolsSubCommand,
22}
23
24impl ToolsCommand {
25    pub async fn execute(
26        &self,
27        root_logger: Logger,
28        config_builder: ConfigBuilder<DefaultState>,
29    ) -> StdResult<()> {
30        self.genesis_subcommand
31            .execute(root_logger, config_builder)
32            .await
33    }
34}
35
36/// Tools subcommands.
37#[derive(Debug, Clone, Subcommand)]
38pub enum ToolsSubCommand {
39    /// Load all certificates in the database to recompute their hash and update all related
40    /// entities.
41    ///
42    /// Since it will modify the aggregator sqlite database it's strongly recommended to backup it
43    /// before running this command.
44    RecomputeCertificatesHash(RecomputeCertificatesHashCommand),
45}
46
47impl ToolsSubCommand {
48    pub async fn execute(
49        &self,
50        root_logger: Logger,
51        config_builder: ConfigBuilder<DefaultState>,
52    ) -> StdResult<()> {
53        match self {
54            Self::RecomputeCertificatesHash(cmd) => cmd.execute(root_logger, config_builder).await,
55        }
56    }
57}
58
59/// Recompute certificates hash command.
60#[derive(Parser, Debug, Clone)]
61pub struct RecomputeCertificatesHashCommand {}
62
63impl RecomputeCertificatesHashCommand {
64    pub async fn execute(
65        &self,
66        root_logger: Logger,
67        config_builder: ConfigBuilder<DefaultState>,
68    ) -> StdResult<()> {
69        let config: Configuration = config_builder
70            .build()
71            .with_context(|| "configuration build error")?
72            .try_deserialize()
73            .with_context(|| "configuration deserialize error")?;
74        debug!(root_logger, "RECOMPUTE CERTIFICATES HASH command"; "config" => format!("{config:?}"));
75        println!("Recomputing all certificate hash",);
76        let mut dependencies_builder =
77            DependenciesBuilder::new(root_logger.clone(), config.clone());
78        let connection = dependencies_builder
79            .get_sqlite_connection()
80            .await
81            .with_context(|| "Dependencies Builder can not get sqlite connection")?;
82        let migrator = CertificatesHashMigrator::new(
83            CertificateRepository::new(connection.clone()),
84            Arc::new(SignedEntityStore::new(connection.clone())),
85            root_logger,
86        );
87
88        migrator
89            .migrate()
90            .await
91            .with_context(|| "recompute-certificates-hash: database migration error")?;
92
93        SqliteCleaner::new(&connection)
94            .with_tasks(&[SqliteCleaningTask::Vacuum])
95            .run()
96            .with_context(|| "recompute-certificates-hash: database vacuum error")?;
97
98        Ok(())
99    }
100}