solana_download_utils/
lib.rs1#![cfg_attr(
2 not(feature = "agave-unstable-api"),
3 deprecated(
4 since = "3.1.0",
5 note = "This crate has been marked for formal inclusion in the Agave Unstable API. From \
6 v4.0.0 onward, the `agave-unstable-api` crate feature must be specified to \
7 acknowledge use of an interface that may break without warning."
8 )
9)]
10pub use solana_file_download::DownloadProgressRecord;
11use {
12 agave_snapshots::{
13 paths as snapshot_paths, snapshot_hash::SnapshotHash, ArchiveFormat, SnapshotKind,
14 ZstdConfig,
15 },
16 log::*,
17 solana_clock::Slot,
18 solana_file_download::{download_file, DownloadProgressCallbackOption},
19 solana_genesis_config::DEFAULT_GENESIS_ARCHIVE,
20 solana_runtime::snapshot_utils,
21 std::{
22 fs,
23 net::SocketAddr,
24 num::NonZeroUsize,
25 path::{Path, PathBuf},
26 },
27};
28
29pub fn download_genesis_if_missing(
30 rpc_addr: &SocketAddr,
31 genesis_package: &Path,
32 use_progress_bar: bool,
33) -> Result<PathBuf, String> {
34 if !genesis_package.exists() {
35 let tmp_genesis_path = genesis_package.parent().unwrap().join("tmp-genesis");
36 let tmp_genesis_package = tmp_genesis_path.join(DEFAULT_GENESIS_ARCHIVE);
37
38 let _ignored = fs::remove_dir_all(&tmp_genesis_path);
39 download_file(
40 &format!("http://{rpc_addr}/{DEFAULT_GENESIS_ARCHIVE}"),
41 &tmp_genesis_package,
42 use_progress_bar,
43 &mut None,
44 )?;
45
46 Ok(tmp_genesis_package)
47 } else {
48 Err("genesis already exists".to_string())
49 }
50}
51
52pub fn download_snapshot_archive(
55 rpc_addr: &SocketAddr,
56 full_snapshot_archives_dir: &Path,
57 incremental_snapshot_archives_dir: &Path,
58 desired_snapshot_hash: (Slot, SnapshotHash),
59 snapshot_kind: SnapshotKind,
60 maximum_full_snapshot_archives_to_retain: NonZeroUsize,
61 maximum_incremental_snapshot_archives_to_retain: NonZeroUsize,
62 use_progress_bar: bool,
63 progress_notify_callback: &mut DownloadProgressCallbackOption<'_>,
64) -> Result<(), String> {
65 snapshot_utils::purge_old_snapshot_archives(
66 full_snapshot_archives_dir,
67 incremental_snapshot_archives_dir,
68 maximum_full_snapshot_archives_to_retain,
69 maximum_incremental_snapshot_archives_to_retain,
70 );
71
72 let snapshot_archives_remote_dir =
73 snapshot_paths::build_snapshot_archives_remote_dir(match snapshot_kind {
74 SnapshotKind::FullSnapshot => full_snapshot_archives_dir,
75 SnapshotKind::IncrementalSnapshot(_) => incremental_snapshot_archives_dir,
76 });
77 fs::create_dir_all(&snapshot_archives_remote_dir).unwrap();
78
79 for archive_format in [
80 ArchiveFormat::TarZstd {
81 config: ZstdConfig::default(),
82 },
83 ArchiveFormat::TarLz4,
84 ] {
85 let destination_path = match snapshot_kind {
86 SnapshotKind::FullSnapshot => snapshot_paths::build_full_snapshot_archive_path(
87 &snapshot_archives_remote_dir,
88 desired_snapshot_hash.0,
89 &desired_snapshot_hash.1,
90 archive_format,
91 ),
92 SnapshotKind::IncrementalSnapshot(base_slot) => {
93 snapshot_paths::build_incremental_snapshot_archive_path(
94 &snapshot_archives_remote_dir,
95 base_slot,
96 desired_snapshot_hash.0,
97 &desired_snapshot_hash.1,
98 archive_format,
99 )
100 }
101 };
102
103 if destination_path.is_file() {
104 return Ok(());
105 }
106
107 match download_file(
108 &format!(
109 "http://{}/{}",
110 rpc_addr,
111 destination_path.file_name().unwrap().to_str().unwrap()
112 ),
113 &destination_path,
114 use_progress_bar,
115 progress_notify_callback,
116 ) {
117 Ok(()) => return Ok(()),
118 Err(err) => info!("{err}"),
119 }
120 }
121 Err(format!(
122 "Failed to download a snapshot archive for slot {} from {}",
123 desired_snapshot_hash.0, rpc_addr
124 ))
125}