Skip to content

Commit 8543da9

Browse files
committed
feature: read ancillary verification key from both clap arguments and config files
1 parent 6e09dbc commit 8543da9

File tree

2 files changed

+298
-66
lines changed

2 files changed

+298
-66
lines changed

mithril-client-cli/src/commands/cardano_db/download.rs

Lines changed: 127 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::{
1111

1212
use crate::{
1313
commands::{client_builder, SharedArgs},
14-
configuration::{ConfigError, ConfigSource},
14+
configuration::{ConfigError, ConfigParameters, ConfigSource},
1515
utils::{
1616
self, AncillaryLogMessage, CardanoDbDownloadChecker, CardanoDbUtils, ExpanderUtils,
1717
IndicatifFeedbackReceiver, ProgressOutputType, ProgressPrinter,
@@ -51,7 +51,7 @@ pub struct CardanoDbDownloadCommand {
5151
/// By default, only finalized immutable files are downloaded.
5252
/// The last ledger state snapshot and the last immutable file (the ancillary files) can be
5353
/// downloaded with this option.
54-
#[clap(long, requires = "ancillary_verification_key")]
54+
#[clap(long)]
5555
include_ancillary: bool,
5656

5757
/// Ancillary verification key to verify the ancillary files.
@@ -60,23 +60,50 @@ pub struct CardanoDbDownloadCommand {
6060
}
6161

6262
impl CardanoDbDownloadCommand {
63-
/// Is JSON output enabled
64-
pub fn is_json_output_enabled(&self) -> bool {
65-
self.shared_args.json
66-
}
67-
6863
/// Command execution
6964
pub async fn execute(&self, context: CommandContext) -> MithrilResult<()> {
70-
if self.include_ancillary {
65+
let params = context.config_parameters()?.add_source(self)?;
66+
let prepared_command = self.prepare(&params)?;
67+
68+
prepared_command.execute(context.logger(), params).await
69+
}
70+
71+
fn prepare(&self, params: &ConfigParameters) -> MithrilResult<PreparedCardanoDbDownload> {
72+
let ancillary_verification_key = if self.include_ancillary {
7173
AncillaryLogMessage::warn_ancillary_not_signed_by_mithril();
74+
Some(params.require("ancillary_verification_key")?)
7275
} else {
7376
AncillaryLogMessage::warn_fast_bootstrap_not_available();
74-
}
77+
None
78+
};
7579

76-
let params = context.config_parameters()?.add_source(self)?;
77-
let download_dir: &String = &params.require("download_dir")?;
78-
let db_dir = Path::new(download_dir).join("db");
79-
let logger = context.logger();
80+
Ok(PreparedCardanoDbDownload {
81+
shared_args: self.shared_args.clone(),
82+
digest: self.digest.clone(),
83+
download_dir: params.require("download_dir")?,
84+
include_ancillary: self.include_ancillary,
85+
ancillary_verification_key,
86+
})
87+
}
88+
}
89+
90+
#[derive(Debug, Clone)]
91+
struct PreparedCardanoDbDownload {
92+
shared_args: SharedArgs,
93+
digest: String,
94+
download_dir: String,
95+
include_ancillary: bool,
96+
ancillary_verification_key: Option<String>,
97+
}
98+
99+
impl PreparedCardanoDbDownload {
100+
fn is_json_output_enabled(&self) -> bool {
101+
self.shared_args.json
102+
}
103+
104+
/// Command execution
105+
pub async fn execute(&self, logger: &Logger, params: ConfigParameters) -> MithrilResult<()> {
106+
let db_dir = Path::new(&self.download_dir).join("db");
80107

81108
let progress_output_type = if self.is_json_output_enabled() {
82109
ProgressOutputType::JsonReporter
@@ -358,12 +385,19 @@ impl ConfigSource for CardanoDbDownloadCommand {
358385
);
359386
}
360387

388+
if let Some(ancillary_verification_key) = self.ancillary_verification_key.clone() {
389+
map.insert(
390+
"ancillary_verification_key".to_string(),
391+
ancillary_verification_key,
392+
);
393+
}
394+
361395
Ok(map)
362396
}
363397
}
364-
365398
#[cfg(test)]
366399
mod tests {
400+
use config::ConfigBuilder;
367401
use mithril_client::{
368402
common::{CardanoDbBeacon, ProtocolMessagePartKey, SignedEntityType},
369403
MithrilCertificateMetadata,
@@ -398,14 +432,85 @@ mod tests {
398432
}
399433
}
400434

435+
fn dummy_command() -> CardanoDbDownloadCommand {
436+
CardanoDbDownloadCommand {
437+
shared_args: SharedArgs { json: false },
438+
digest: "whatever_digest".to_string(),
439+
download_dir: Some(std::path::PathBuf::from("whatever_dir")),
440+
genesis_verification_key: "whatever".to_string().into(),
441+
include_ancillary: true,
442+
ancillary_verification_key: "whatever".to_string().into(),
443+
}
444+
}
445+
446+
#[tokio::test]
447+
async fn ancillary_verification_key_is_mandatory_when_include_ancillary_is_true() {
448+
let command = CardanoDbDownloadCommand {
449+
include_ancillary: true,
450+
ancillary_verification_key: None,
451+
..dummy_command()
452+
};
453+
let command_context = CommandContext::new(
454+
ConfigBuilder::default(),
455+
false,
456+
Logger::root(slog::Discard, slog::o!()),
457+
);
458+
459+
let result = command.execute(command_context).await;
460+
461+
assert!(result.is_err());
462+
assert_eq!(
463+
result.unwrap_err().to_string(),
464+
"Parameter 'ancillary_verification_key' is mandatory."
465+
);
466+
}
467+
468+
#[test]
469+
fn ancillary_verification_key_can_be_read_through_configuration_file() {
470+
let command = CardanoDbDownloadCommand {
471+
ancillary_verification_key: None,
472+
..dummy_command()
473+
};
474+
let config = config::Config::builder()
475+
.set_default("ancillary_verification_key", "value from config")
476+
.expect("Failed to build config builder");
477+
let command_context =
478+
CommandContext::new(config, false, Logger::root(slog::Discard, slog::o!()));
479+
let config_parameters = command_context
480+
.config_parameters()
481+
.unwrap()
482+
.add_source(&command)
483+
.unwrap();
484+
485+
let result = command.prepare(&config_parameters);
486+
487+
assert!(result.is_ok());
488+
}
489+
401490
#[test]
402-
fn ancillary_verification_key_is_mandatory_when_include_ancillary_is_true() {
403-
CardanoDbDownloadCommand::try_parse_from([
404-
"cdbv1-command",
405-
"--include-ancillary",
406-
"whatever_digest",
407-
])
408-
.expect_err("The command should fail because ancillary_verification_key is not set");
491+
fn db_download_dir_is_mandatory_to_execute_command() {
492+
let command = CardanoDbDownloadCommand {
493+
download_dir: None,
494+
..dummy_command()
495+
};
496+
let command_context = CommandContext::new(
497+
ConfigBuilder::default(),
498+
false,
499+
Logger::root(slog::Discard, slog::o!()),
500+
);
501+
let config_parameters = command_context
502+
.config_parameters()
503+
.unwrap()
504+
.add_source(&command)
505+
.unwrap();
506+
507+
let result = command.prepare(&config_parameters);
508+
509+
assert!(result.is_err());
510+
assert_eq!(
511+
result.unwrap_err().to_string(),
512+
"Parameter 'download_dir' is mandatory."
513+
);
409514
}
410515

411516
#[tokio::test]
@@ -424,7 +529,7 @@ mod tests {
424529
"verify_cardano_db_signature_should_remove_db_dir_if_messages_mismatch",
425530
);
426531

427-
let result = CardanoDbDownloadCommand::verify_cardano_db_signature(
532+
let result = PreparedCardanoDbDownload::verify_cardano_db_signature(
428533
&Logger::root(slog::Discard, slog::o!()),
429534
1,
430535
&progress_printer,

0 commit comments

Comments
 (0)