Skip to content

Commit 680a476

Browse files
committed
[WIP]feat(client-cli): execute the snapshot-converter binary
1 parent 9b0408f commit 680a476

File tree

1 file changed

+268
-0
lines changed

1 file changed

+268
-0
lines changed

mithril-client-cli/src/commands/tools/snapshot_converter.rs

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// - Add logs.
33
// - Remove the temporary directory in all cases (error or success).
44
use std::path::Path;
5+
use std::process::Command;
56
use std::{env, fmt, path::PathBuf};
67

78
use anyhow::{anyhow, Context};
@@ -23,6 +24,14 @@ const PRERELEASE_DISTRIBUTION_TAG: &str = "prerelease";
2324

2425
const CARDANO_DISTRIBUTION_TEMP_DIR: &str = "cardano-node-distribution-tmp";
2526

27+
const SNAPSHOT_CONVERTER_BIN_DIR: &str = "bin";
28+
const SNAPSHOT_CONVERTER_BIN_NAME_UNIX: &str = "snapshot-converter";
29+
const SNAPSHOT_CONVERTER_BIN_NAME_WINDOWS: &str = "snapshot-converter.exe";
30+
const SNAPSHOT_CONVERTER_CONFIG_DIR: &str = "share";
31+
const SNAPSHOT_CONVERTER_CONFIG_FILE: &str = "config.json";
32+
33+
const LEDGER_DIR: &str = "ledger";
34+
2635
#[derive(Debug, Clone, ValueEnum)]
2736
enum UTxOHDFlavor {
2837
#[clap(name = "Legacy")]
@@ -40,6 +49,23 @@ impl fmt::Display for UTxOHDFlavor {
4049
}
4150
}
4251

52+
#[derive(Debug, Clone, ValueEnum)]
53+
enum CardanoNetwork {
54+
Preview,
55+
Preprod,
56+
Mainnet,
57+
}
58+
59+
impl fmt::Display for CardanoNetwork {
60+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61+
match self {
62+
Self::Preview => write!(f, "preview"),
63+
Self::Preprod => write!(f, "preprod"),
64+
Self::Mainnet => write!(f, "mainnet"),
65+
}
66+
}
67+
}
68+
4369
/// Clap command to convert a restored `InMemory` Mithril snapshot to another flavor.
4470
#[derive(Parser, Debug, Clone)]
4571
pub struct SnapshotConverterCommand {
@@ -53,6 +79,10 @@ pub struct SnapshotConverterCommand {
5379
#[clap(long)]
5480
cardano_node_version: String,
5581

82+
/// Cardano network.
83+
#[clap(long)]
84+
cardano_network: CardanoNetwork,
85+
5686
/// UTxO-HD flavor to convert the ledger snapshot to.
5787
#[clap(long)]
5888
utxo_hd_flavor: UTxOHDFlavor,
@@ -88,6 +118,19 @@ impl SnapshotConverterCommand {
88118
)
89119
})?;
90120

121+
Self::convert_ledger_snapshot(
122+
&self.db_directory,
123+
&self.cardano_network,
124+
&distribution_temp_dir,
125+
&self.utxo_hd_flavor,
126+
)
127+
.with_context(|| {
128+
format!(
129+
"Failed to convert ledger snapshot to flavor: {}",
130+
self.utxo_hd_flavor
131+
)
132+
})?;
133+
91134
Ok(())
92135
}
93136

@@ -141,6 +184,120 @@ impl SnapshotConverterCommand {
141184

142185
Ok(())
143186
}
187+
188+
// 1. Find the `snapshot-converter` binary
189+
// 2. Find the configuration file
190+
// 3. Find the less recent ledger snapshot in the db directory
191+
// 4. Copy the ledger snapshot to the distribution directory (backup)
192+
// 5. Run the `snapshot-converter` command with the appropriate arguments
193+
// - Legacy: snapshot-converter Mem <PATH-IN> Legacy <PATH-OUT> cardano --config <CONFIG>
194+
// - LMDB: snapshot-converter Mem <PATH-IN> LMDB <PATH-OUT> cardano --config <CONFIG>
195+
fn convert_ledger_snapshot(
196+
db_dir: &Path,
197+
cardano_network: &CardanoNetwork,
198+
distribution_dir: &Path,
199+
utxo_hd_flavor: &UTxOHDFlavor,
200+
) -> MithrilResult<()> {
201+
let snapshot_converter_bin_path =
202+
Self::get_snapshot_converter_binary_path(distribution_dir, env::consts::OS)?;
203+
// TODO: check if this configuration file is enough to convert the snapshot.
204+
let config_path =
205+
Self::get_snapshot_converter_config_path(distribution_dir, cardano_network);
206+
207+
let (slot_number, ledger_snapshot_path) = Self::find_less_recent_ledger_snapshot(db_dir)?;
208+
let snapshot_backup_path = distribution_dir.join(ledger_snapshot_path.file_name().unwrap());
209+
std::fs::copy(ledger_snapshot_path.clone(), snapshot_backup_path.clone())?;
210+
211+
let snapshot_converted_output_path = distribution_dir
212+
.join(slot_number.to_string())
213+
.join(utxo_hd_flavor.to_string().to_lowercase());
214+
215+
// TODO: verify if the paths are correct, the command needs relative path.
216+
Command::new(snapshot_converter_bin_path.clone())
217+
.arg("Mem")
218+
.arg(snapshot_backup_path)
219+
.arg(utxo_hd_flavor.to_string())
220+
.arg(snapshot_converted_output_path)
221+
.arg("cardano")
222+
.arg("--config")
223+
.arg(config_path)
224+
.status()
225+
.with_context(|| {
226+
format!(
227+
"Failed to get help of snapshot-converter: {}",
228+
snapshot_converter_bin_path.display()
229+
)
230+
})?;
231+
232+
println!(
233+
"Snapshot converter executed successfully. The ledger snapshot has been converted to {} flavor in {}.",
234+
utxo_hd_flavor,
235+
distribution_dir.display()
236+
);
237+
Ok(())
238+
}
239+
240+
fn get_snapshot_converter_binary_path(
241+
distribution_dir: &Path,
242+
target_os: &str,
243+
) -> MithrilResult<PathBuf> {
244+
let base_path = distribution_dir.join(SNAPSHOT_CONVERTER_BIN_DIR);
245+
246+
let binary_name = match target_os {
247+
"linux" | "macos" => SNAPSHOT_CONVERTER_BIN_NAME_UNIX,
248+
"windows" => SNAPSHOT_CONVERTER_BIN_NAME_WINDOWS,
249+
_ => return Err(anyhow!("Unsupported platform: {}", target_os)),
250+
};
251+
252+
Ok(base_path.join(binary_name))
253+
}
254+
255+
fn get_snapshot_converter_config_path(
256+
distribution_dir: &Path,
257+
network: &CardanoNetwork,
258+
) -> PathBuf {
259+
distribution_dir
260+
.join(SNAPSHOT_CONVERTER_CONFIG_DIR)
261+
.join(network.to_string())
262+
.join(SNAPSHOT_CONVERTER_CONFIG_FILE)
263+
}
264+
265+
// TODO: quick dirty code to go further in `convert_ledger_snapshot` function, must be enhanced and tested.
266+
fn find_less_recent_ledger_snapshot(db_dir: &Path) -> MithrilResult<(u64, PathBuf)> {
267+
let ledger_dir = db_dir.join(LEDGER_DIR);
268+
269+
let entries = std::fs::read_dir(&ledger_dir).with_context(|| {
270+
format!("Failed to read ledger directory: {}", ledger_dir.display())
271+
})?;
272+
273+
let mut min_slot: Option<(u64, PathBuf)> = None;
274+
275+
for entry in entries {
276+
let entry = entry?;
277+
let file_name = entry.file_name();
278+
let file_name_str = file_name.to_str().unwrap();
279+
280+
let slot = match file_name_str.parse::<u64>() {
281+
Ok(n) => n,
282+
Err(_) => continue,
283+
};
284+
285+
let path = entry.path();
286+
if path.is_dir() {
287+
match &min_slot {
288+
Some((current_min, _)) if *current_min <= slot => {}
289+
_ => min_slot = Some((slot, path)),
290+
}
291+
}
292+
}
293+
294+
min_slot.ok_or_else(|| {
295+
anyhow!(
296+
"No valid ledger snapshot found in: {}",
297+
ledger_dir.display()
298+
)
299+
})
300+
}
144301
}
145302

146303
#[cfg(test)]
@@ -257,4 +414,115 @@ mod tests {
257414
.await
258415
.unwrap();
259416
}
417+
418+
#[test]
419+
fn get_snapshot_converter_binary_path_linux() {
420+
let distribution_dir = PathBuf::from("/path/to/distribution");
421+
422+
let binary_path = SnapshotConverterCommand::get_snapshot_converter_binary_path(
423+
&distribution_dir,
424+
"linux",
425+
)
426+
.unwrap();
427+
428+
assert_eq!(
429+
binary_path,
430+
distribution_dir
431+
.join(SNAPSHOT_CONVERTER_BIN_DIR)
432+
.join(SNAPSHOT_CONVERTER_BIN_NAME_UNIX)
433+
);
434+
}
435+
436+
#[test]
437+
fn get_snapshot_converter_binary_path_macos() {
438+
let distribution_dir = PathBuf::from("/path/to/distribution");
439+
440+
let binary_path = SnapshotConverterCommand::get_snapshot_converter_binary_path(
441+
&distribution_dir,
442+
"macos",
443+
)
444+
.unwrap();
445+
446+
assert_eq!(
447+
binary_path,
448+
distribution_dir
449+
.join(SNAPSHOT_CONVERTER_BIN_DIR)
450+
.join(SNAPSHOT_CONVERTER_BIN_NAME_UNIX)
451+
);
452+
}
453+
454+
#[test]
455+
fn get_snapshot_converter_binary_path_windows() {
456+
let distribution_dir = PathBuf::from("/path/to/distribution");
457+
458+
let binary_path = SnapshotConverterCommand::get_snapshot_converter_binary_path(
459+
&distribution_dir,
460+
"windows",
461+
)
462+
.unwrap();
463+
464+
assert_eq!(
465+
binary_path,
466+
distribution_dir
467+
.join(SNAPSHOT_CONVERTER_BIN_DIR)
468+
.join(SNAPSHOT_CONVERTER_BIN_NAME_WINDOWS)
469+
);
470+
}
471+
472+
#[test]
473+
fn get_snapshot_converter_config_path_mainnet() {
474+
let distribution_dir = PathBuf::from("/path/to/distribution");
475+
let network = CardanoNetwork::Mainnet;
476+
477+
let config_path = SnapshotConverterCommand::get_snapshot_converter_config_path(
478+
&distribution_dir,
479+
&network,
480+
);
481+
482+
assert_eq!(
483+
config_path,
484+
distribution_dir
485+
.join(SNAPSHOT_CONVERTER_CONFIG_DIR)
486+
.join(network.to_string())
487+
.join(SNAPSHOT_CONVERTER_CONFIG_FILE)
488+
);
489+
}
490+
491+
#[test]
492+
fn get_snapshot_converter_config_path_preprod() {
493+
let distribution_dir = PathBuf::from("/path/to/distribution");
494+
let network = CardanoNetwork::Preprod;
495+
496+
let config_path = SnapshotConverterCommand::get_snapshot_converter_config_path(
497+
&distribution_dir,
498+
&network,
499+
);
500+
501+
assert_eq!(
502+
config_path,
503+
distribution_dir
504+
.join(SNAPSHOT_CONVERTER_CONFIG_DIR)
505+
.join(network.to_string())
506+
.join(SNAPSHOT_CONVERTER_CONFIG_FILE)
507+
);
508+
}
509+
510+
#[test]
511+
fn get_snapshot_converter_config_path_preview() {
512+
let distribution_dir = PathBuf::from("/path/to/distribution");
513+
let network = CardanoNetwork::Preview;
514+
515+
let config_path = SnapshotConverterCommand::get_snapshot_converter_config_path(
516+
&distribution_dir,
517+
&network,
518+
);
519+
520+
assert_eq!(
521+
config_path,
522+
distribution_dir
523+
.join(SNAPSHOT_CONVERTER_CONFIG_DIR)
524+
.join(network.to_string())
525+
.join(SNAPSHOT_CONVERTER_CONFIG_FILE)
526+
);
527+
}
260528
}

0 commit comments

Comments
 (0)