solana_genesis_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)]
10use {
11 agave_snapshots::unpack_genesis_archive,
12 log::*,
13 solana_download_utils::download_genesis_if_missing,
14 solana_genesis_config::{GenesisConfig, DEFAULT_GENESIS_ARCHIVE},
15 solana_hash::Hash,
16 solana_rpc_client::rpc_client::RpcClient,
17 std::net::SocketAddr,
18};
19
20mod open;
21
22fn check_genesis_hash(
23 genesis_config: &GenesisConfig,
24 expected_genesis_hash: Option<Hash>,
25) -> Result<(), String> {
26 let genesis_hash = genesis_config.hash();
27
28 if let Some(expected_genesis_hash) = expected_genesis_hash {
29 if expected_genesis_hash != genesis_hash {
30 return Err(format!(
31 "Genesis hash mismatch: expected {expected_genesis_hash} but downloaded genesis \
32 hash is {genesis_hash}",
33 ));
34 }
35 }
36
37 Ok(())
38}
39
40fn load_local_genesis(
41 ledger_path: &std::path::Path,
42 expected_genesis_hash: Option<Hash>,
43) -> Result<GenesisConfig, String> {
44 let existing_genesis = GenesisConfig::load(ledger_path)
45 .map_err(|err| format!("Failed to load genesis config: {err}"))?;
46 check_genesis_hash(&existing_genesis, expected_genesis_hash)?;
47
48 Ok(existing_genesis)
49}
50
51fn get_genesis_config(
52 rpc_addr: &SocketAddr,
53 ledger_path: &std::path::Path,
54 expected_genesis_hash: Option<Hash>,
55 max_genesis_archive_unpacked_size: u64,
56 no_genesis_fetch: bool,
57 use_progress_bar: bool,
58) -> Result<GenesisConfig, String> {
59 if no_genesis_fetch {
60 return load_local_genesis(ledger_path, expected_genesis_hash);
61 }
62
63 let genesis_package = ledger_path.join(DEFAULT_GENESIS_ARCHIVE);
64 if let Ok(tmp_genesis_package) =
65 download_genesis_if_missing(rpc_addr, &genesis_package, use_progress_bar)
66 {
67 unpack_genesis_archive(
68 &tmp_genesis_package,
69 ledger_path,
70 max_genesis_archive_unpacked_size,
71 )
72 .map_err(|err| format!("Failed to unpack downloaded genesis config: {err}"))?;
73
74 let downloaded_genesis = GenesisConfig::load(ledger_path)
75 .map_err(|err| format!("Failed to load downloaded genesis config: {err}"))?;
76
77 check_genesis_hash(&downloaded_genesis, expected_genesis_hash)?;
78 std::fs::rename(tmp_genesis_package, genesis_package)
79 .map_err(|err| format!("Unable to rename: {err:?}"))?;
80
81 Ok(downloaded_genesis)
82 } else {
83 load_local_genesis(ledger_path, expected_genesis_hash)
84 }
85}
86
87fn set_and_verify_expected_genesis_hash(
88 genesis_config: GenesisConfig,
89 expected_genesis_hash: &mut Option<Hash>,
90 rpc_client: &RpcClient,
91) -> Result<(), String> {
92 let genesis_hash = genesis_config.hash();
93 if expected_genesis_hash.is_none() {
94 info!("Expected genesis hash set to {genesis_hash}");
95 *expected_genesis_hash = Some(genesis_hash);
96 }
97 let expected_genesis_hash = expected_genesis_hash.unwrap();
98
99 let rpc_genesis_hash = rpc_client
102 .get_genesis_hash()
103 .map_err(|err| format!("Failed to get genesis hash: {err}"))?;
104
105 if expected_genesis_hash != rpc_genesis_hash {
106 return Err(format!(
107 "Genesis hash mismatch: expected {expected_genesis_hash} but RPC node genesis hash is \
108 {rpc_genesis_hash}"
109 ));
110 }
111
112 Ok(())
113}
114
115pub fn download_then_check_genesis_hash(
116 rpc_addr: &SocketAddr,
117 ledger_path: &std::path::Path,
118 expected_genesis_hash: &mut Option<Hash>,
119 max_genesis_archive_unpacked_size: u64,
120 no_genesis_fetch: bool,
121 use_progress_bar: bool,
122 rpc_client: &RpcClient,
123) -> Result<(), String> {
124 let genesis_config = get_genesis_config(
125 rpc_addr,
126 ledger_path,
127 *expected_genesis_hash,
128 max_genesis_archive_unpacked_size,
129 no_genesis_fetch,
130 use_progress_bar,
131 )?;
132
133 set_and_verify_expected_genesis_hash(genesis_config, expected_genesis_hash, rpc_client)
134}
135
136pub use open::{open_genesis_config, OpenGenesisConfigError, MAX_GENESIS_ARCHIVE_UNPACKED_SIZE};