mithril_aggregator/commands/
genesis_command.rs1use anyhow::Context;
2use clap::{Parser, Subcommand};
3use config::{builder::DefaultState, ConfigBuilder};
4use mithril_common::{
5 crypto_helper::{ProtocolGenesisSecretKey, ProtocolGenesisSigner},
6 entities::HexEncodedGenesisSecretKey,
7 StdResult,
8};
9use slog::{debug, Logger};
10use std::path::PathBuf;
11
12use crate::{dependency_injection::DependenciesBuilder, tools::GenesisTools, Configuration};
13
14#[derive(Parser, Debug, Clone)]
16pub struct GenesisCommand {
17 #[clap(subcommand)]
19 pub genesis_subcommand: GenesisSubCommand,
20}
21
22impl GenesisCommand {
23 pub async fn execute(
24 &self,
25 root_logger: Logger,
26 config_builder: ConfigBuilder<DefaultState>,
27 ) -> StdResult<()> {
28 self.genesis_subcommand
29 .execute(root_logger, config_builder)
30 .await
31 }
32}
33
34#[derive(Debug, Clone, Subcommand)]
36pub enum GenesisSubCommand {
37 Export(ExportGenesisSubCommand),
39
40 Import(ImportGenesisSubCommand),
42
43 Sign(SignGenesisSubCommand),
45
46 Bootstrap(BootstrapGenesisSubCommand),
48
49 GenerateKeypair(GenerateKeypairGenesisSubCommand),
51}
52
53impl GenesisSubCommand {
54 pub async fn execute(
55 &self,
56 root_logger: Logger,
57 config_builder: ConfigBuilder<DefaultState>,
58 ) -> StdResult<()> {
59 match self {
60 Self::Bootstrap(cmd) => cmd.execute(root_logger, config_builder).await,
61 Self::Export(cmd) => cmd.execute(root_logger, config_builder).await,
62 Self::Import(cmd) => cmd.execute(root_logger, config_builder).await,
63 Self::Sign(cmd) => cmd.execute(root_logger, config_builder).await,
64 Self::GenerateKeypair(cmd) => cmd.execute(root_logger, config_builder).await,
65 }
66 }
67}
68
69#[derive(Parser, Debug, Clone)]
71pub struct ExportGenesisSubCommand {
72 #[clap(long)]
74 target_path: PathBuf,
75}
76
77impl ExportGenesisSubCommand {
78 pub async fn execute(
79 &self,
80 root_logger: Logger,
81 config_builder: ConfigBuilder<DefaultState>,
82 ) -> StdResult<()> {
83 let config: Configuration = config_builder
84 .build()
85 .with_context(|| "configuration build error")?
86 .try_deserialize()
87 .with_context(|| "configuration deserialize error")?;
88 debug!(root_logger, "EXPORT GENESIS command"; "config" => format!("{config:?}"));
89 println!(
90 "Genesis export payload to sign to {}",
91 self.target_path.display()
92 );
93 let mut dependencies_builder =
94 DependenciesBuilder::new(root_logger.clone(), config.clone());
95 let dependencies = dependencies_builder
96 .create_genesis_container()
97 .await
98 .with_context(|| {
99 "Dependencies Builder can not create genesis command dependencies container"
100 })?;
101
102 let genesis_tools = GenesisTools::from_dependencies(dependencies)
103 .await
104 .with_context(|| "genesis-tools: initialization error")?;
105 genesis_tools
106 .export_payload_to_sign(&self.target_path)
107 .with_context(|| "genesis-tools: export error")?;
108 Ok(())
109 }
110}
111
112#[derive(Parser, Debug, Clone)]
113pub struct ImportGenesisSubCommand {
114 #[clap(long)]
116 signed_payload_path: PathBuf,
117}
118
119impl ImportGenesisSubCommand {
120 pub async fn execute(
121 &self,
122 root_logger: Logger,
123 config_builder: ConfigBuilder<DefaultState>,
124 ) -> StdResult<()> {
125 let config: Configuration = config_builder
126 .build()
127 .with_context(|| "configuration build error")?
128 .try_deserialize()
129 .with_context(|| "configuration deserialize error")?;
130 debug!(root_logger, "IMPORT GENESIS command"; "config" => format!("{config:?}"));
131 println!(
132 "Genesis import signed payload from {}",
133 self.signed_payload_path.to_string_lossy()
134 );
135 let mut dependencies_builder =
136 DependenciesBuilder::new(root_logger.clone(), config.clone());
137 let dependencies = dependencies_builder
138 .create_genesis_container()
139 .await
140 .with_context(|| {
141 "Dependencies Builder can not create genesis command dependencies container"
142 })?;
143
144 let genesis_tools = GenesisTools::from_dependencies(dependencies)
145 .await
146 .with_context(|| "genesis-tools: initialization error")?;
147 genesis_tools
148 .import_payload_signature(&self.signed_payload_path)
149 .await
150 .with_context(|| "genesis-tools: import error")?;
151 Ok(())
152 }
153}
154
155#[derive(Parser, Debug, Clone)]
156pub struct SignGenesisSubCommand {
157 #[clap(long)]
159 to_sign_payload_path: PathBuf,
160
161 #[clap(long)]
163 target_signed_payload_path: PathBuf,
164
165 #[clap(long)]
167 genesis_secret_key_path: PathBuf,
168}
169
170impl SignGenesisSubCommand {
171 pub async fn execute(
172 &self,
173 root_logger: Logger,
174 _config_builder: ConfigBuilder<DefaultState>,
175 ) -> StdResult<()> {
176 debug!(root_logger, "SIGN GENESIS command");
177 println!(
178 "Genesis sign payload from {} to {}",
179 self.to_sign_payload_path.to_string_lossy(),
180 self.target_signed_payload_path.to_string_lossy()
181 );
182
183 GenesisTools::sign_genesis_certificate(
184 &self.to_sign_payload_path,
185 &self.target_signed_payload_path,
186 &self.genesis_secret_key_path,
187 )
188 .await
189 .with_context(|| "genesis-tools: sign error")?;
190
191 Ok(())
192 }
193}
194#[derive(Parser, Debug, Clone)]
195pub struct BootstrapGenesisSubCommand {
196 #[clap(long, env = "GENESIS_SECRET_KEY")]
198 genesis_secret_key: HexEncodedGenesisSecretKey,
199}
200
201impl BootstrapGenesisSubCommand {
202 pub async fn execute(
203 &self,
204 root_logger: Logger,
205 config_builder: ConfigBuilder<DefaultState>,
206 ) -> StdResult<()> {
207 let config: Configuration = config_builder
208 .build()
209 .with_context(|| "configuration build error")?
210 .try_deserialize()
211 .with_context(|| "configuration deserialize error")?;
212 debug!(root_logger, "BOOTSTRAP GENESIS command"; "config" => format!("{config:?}"));
213 println!("Genesis bootstrap for test only!");
214 let mut dependencies_builder =
215 DependenciesBuilder::new(root_logger.clone(), config.clone());
216 let dependencies = dependencies_builder
217 .create_genesis_container()
218 .await
219 .with_context(|| {
220 "Dependencies Builder can not create genesis command dependencies container"
221 })?;
222
223 let genesis_tools = GenesisTools::from_dependencies(dependencies)
224 .await
225 .with_context(|| "genesis-tools: initialization error")?;
226 let genesis_secret_key = ProtocolGenesisSecretKey::from_json_hex(&self.genesis_secret_key)
227 .with_context(|| "json hex decode of genesis secret key failure")?;
228 let genesis_signer = ProtocolGenesisSigner::from_secret_key(genesis_secret_key);
229 genesis_tools
230 .bootstrap_test_genesis_certificate(genesis_signer)
231 .await
232 .with_context(|| "genesis-tools: bootstrap error")?;
233 Ok(())
234 }
235}
236
237#[derive(Parser, Debug, Clone)]
239pub struct GenerateKeypairGenesisSubCommand {
240 #[clap(long)]
242 target_path: PathBuf,
243}
244
245impl GenerateKeypairGenesisSubCommand {
246 pub async fn execute(
247 &self,
248 root_logger: Logger,
249 _config_builder: ConfigBuilder<DefaultState>,
250 ) -> StdResult<()> {
251 debug!(root_logger, "GENERATE KEYPAIR GENESIS command");
252 println!(
253 "Genesis generate keypair to {}",
254 self.target_path.to_string_lossy()
255 );
256
257 GenesisTools::create_and_save_genesis_keypair(&self.target_path)
258 .with_context(|| "genesis-tools: keypair generation error")?;
259
260 Ok(())
261 }
262}