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