solana_genesis_utils/
lib.rs

1use {
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    // Sanity check that the RPC node is using the expected genesis hash before
88    // downloading a snapshot from it
89    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}