Refactor genesis download/load/check functions (#17276)

* Refactor genesis ingest functions

* Consolidate genesis.bin/genesis.tar.bz2 references
This commit is contained in:
sakridge
2021-05-24 16:45:36 +02:00
committed by GitHub
parent 9d112cf41f
commit a8dca3976b
11 changed files with 158 additions and 100 deletions

10
Cargo.lock generated
View File

@ -4549,6 +4549,15 @@ dependencies = [
"tempfile", "tempfile",
] ]
[[package]]
name = "solana-genesis-utils"
version = "1.7.0"
dependencies = [
"solana-download-utils",
"solana-runtime",
"solana-sdk",
]
[[package]] [[package]]
name = "solana-gossip" name = "solana-gossip"
version = "1.7.0" version = "1.7.0"
@ -5442,6 +5451,7 @@ dependencies = [
"solana-core", "solana-core",
"solana-download-utils", "solana-download-utils",
"solana-faucet", "solana-faucet",
"solana-genesis-utils",
"solana-ledger", "solana-ledger",
"solana-logger 1.7.0", "solana-logger 1.7.0",
"solana-metrics", "solana-metrics",

View File

@ -21,6 +21,7 @@ members = [
"perf", "perf",
"validator", "validator",
"genesis", "genesis",
"genesis-utils",
"gossip", "gossip",
"install", "install",
"keygen", "keygen",

View File

@ -26,7 +26,10 @@ use solana_runtime::{
commitment::BlockCommitmentCache, commitment::BlockCommitmentCache,
snapshot_utils, snapshot_utils,
}; };
use solana_sdk::{hash::Hash, native_token::lamports_to_sol, pubkey::Pubkey}; use solana_sdk::{
genesis_config::DEFAULT_GENESIS_DOWNLOAD_PATH, hash::Hash, native_token::lamports_to_sol,
pubkey::Pubkey,
};
use std::{ use std::{
collections::HashSet, collections::HashSet,
net::SocketAddr, net::SocketAddr,
@ -101,7 +104,7 @@ impl RpcRequestMiddleware {
fn is_file_get_path(&self, path: &str) -> bool { fn is_file_get_path(&self, path: &str) -> bool {
match path { match path {
"/genesis.tar.bz2" => true, DEFAULT_GENESIS_DOWNLOAD_PATH => true,
_ => { _ => {
if self.snapshot_config.is_some() { if self.snapshot_config.is_some() {
self.snapshot_archive_path_regex.is_match(path) self.snapshot_archive_path_regex.is_match(path)
@ -136,7 +139,7 @@ impl RpcRequestMiddleware {
let stem = path.split_at(1).1; // Drop leading '/' from path let stem = path.split_at(1).1; // Drop leading '/' from path
let filename = { let filename = {
match path { match path {
"/genesis.tar.bz2" => { DEFAULT_GENESIS_DOWNLOAD_PATH => {
inc_new_counter_info!("rpc-get_genesis", 1); inc_new_counter_info!("rpc-get_genesis", 1);
self.ledger_path.join(stem) self.ledger_path.join(stem)
} }
@ -488,7 +491,10 @@ mod tests {
bank::Bank, bank_forks::ArchiveFormat, snapshot_utils::SnapshotVersion, bank::Bank, bank_forks::ArchiveFormat, snapshot_utils::SnapshotVersion,
snapshot_utils::DEFAULT_MAX_SNAPSHOTS_TO_RETAIN, snapshot_utils::DEFAULT_MAX_SNAPSHOTS_TO_RETAIN,
}; };
use solana_sdk::{genesis_config::ClusterType, signature::Signer}; use solana_sdk::{
genesis_config::{ClusterType, DEFAULT_GENESIS_ARCHIVE},
signature::Signer,
};
use std::io::Write; use std::io::Write;
use std::net::{IpAddr, Ipv4Addr}; use std::net::{IpAddr, Ipv4Addr};
@ -592,8 +598,8 @@ mod tests {
RpcHealth::stub(), RpcHealth::stub(),
); );
assert!(rrm.is_file_get_path("/genesis.tar.bz2")); assert!(rrm.is_file_get_path(DEFAULT_GENESIS_DOWNLOAD_PATH));
assert!(!rrm.is_file_get_path("genesis.tar.bz2")); assert!(!rrm.is_file_get_path(DEFAULT_GENESIS_ARCHIVE));
assert!(!rrm.is_file_get_path("/snapshot.tar.bz2")); // This is a redirect assert!(!rrm.is_file_get_path("/snapshot.tar.bz2")); // This is a redirect
@ -629,7 +635,7 @@ mod tests {
let ledger_path = get_tmp_ledger_path!(); let ledger_path = get_tmp_ledger_path!();
std::fs::create_dir(&ledger_path).unwrap(); std::fs::create_dir(&ledger_path).unwrap();
let genesis_path = ledger_path.join("genesis.tar.bz2"); let genesis_path = ledger_path.join(DEFAULT_GENESIS_ARCHIVE);
let rrm = RpcRequestMiddleware::new( let rrm = RpcRequestMiddleware::new(
ledger_path.clone(), ledger_path.clone(),
None, None,
@ -638,7 +644,7 @@ mod tests {
); );
// File does not exist => request should fail. // File does not exist => request should fail.
let action = rrm.process_file_get("/genesis.tar.bz2"); let action = rrm.process_file_get(DEFAULT_GENESIS_DOWNLOAD_PATH);
if let RequestMiddlewareAction::Respond { response, .. } = action { if let RequestMiddlewareAction::Respond { response, .. } = action {
let response = runtime.block_on(response); let response = runtime.block_on(response);
let response = response.unwrap(); let response = response.unwrap();
@ -653,7 +659,7 @@ mod tests {
} }
// Normal file exist => request should succeed. // Normal file exist => request should succeed.
let action = rrm.process_file_get("/genesis.tar.bz2"); let action = rrm.process_file_get(DEFAULT_GENESIS_DOWNLOAD_PATH);
if let RequestMiddlewareAction::Respond { response, .. } = action { if let RequestMiddlewareAction::Respond { response, .. } = action {
let response = runtime.block_on(response); let response = runtime.block_on(response);
let response = response.unwrap(); let response = response.unwrap();
@ -672,7 +678,7 @@ mod tests {
symlink::symlink_file("wrong", &genesis_path).unwrap(); symlink::symlink_file("wrong", &genesis_path).unwrap();
// File is a symbolic link => request should fail. // File is a symbolic link => request should fail.
let action = rrm.process_file_get("/genesis.tar.bz2"); let action = rrm.process_file_get(DEFAULT_GENESIS_DOWNLOAD_PATH);
if let RequestMiddlewareAction::Respond { response, .. } = action { if let RequestMiddlewareAction::Respond { response, .. } = action {
let response = runtime.block_on(response); let response = runtime.block_on(response);
let response = response.unwrap(); let response = response.unwrap();

View File

@ -3,8 +3,7 @@ use console::Emoji;
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
use log::*; use log::*;
use solana_runtime::{bank_forks::ArchiveFormat, snapshot_utils}; use solana_runtime::{bank_forks::ArchiveFormat, snapshot_utils};
use solana_sdk::clock::Slot; use solana_sdk::{clock::Slot, genesis_config::DEFAULT_GENESIS_ARCHIVE, hash::Hash};
use solana_sdk::hash::Hash;
use std::fs::{self, File}; use std::fs::{self, File};
use std::io; use std::io;
use std::io::Read; use std::io::Read;
@ -158,11 +157,11 @@ pub fn download_genesis_if_missing(
) -> Result<PathBuf, String> { ) -> Result<PathBuf, String> {
if !genesis_package.exists() { if !genesis_package.exists() {
let tmp_genesis_path = genesis_package.parent().unwrap().join("tmp-genesis"); let tmp_genesis_path = genesis_package.parent().unwrap().join("tmp-genesis");
let tmp_genesis_package = tmp_genesis_path.join("genesis.tar.bz2"); let tmp_genesis_package = tmp_genesis_path.join(DEFAULT_GENESIS_ARCHIVE);
let _ignored = fs::remove_dir_all(&tmp_genesis_path); let _ignored = fs::remove_dir_all(&tmp_genesis_path);
download_file( download_file(
&format!("http://{}/{}", rpc_addr, "genesis.tar.bz2"), &format!("http://{}/{}", rpc_addr, DEFAULT_GENESIS_ARCHIVE),
&tmp_genesis_package, &tmp_genesis_package,
use_progress_bar, use_progress_bar,
)?; )?;

22
genesis-utils/Cargo.toml Normal file
View File

@ -0,0 +1,22 @@
[package]
name = "solana-genesis-utils"
version = "1.7.0"
description = "Solana Genesis Utils"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-download-utils"
edition = "2018"
[dependencies]
solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-download-utils = { path = "../download-utils", version = "=1.7.0" }
solana-runtime = { path = "../runtime", version = "=1.7.0" }
[lib]
crate-type = ["lib"]
name = "solana_genesis_utils"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

75
genesis-utils/src/lib.rs Normal file
View File

@ -0,0 +1,75 @@
use solana_download_utils::download_genesis_if_missing;
use solana_runtime::hardened_unpack::unpack_genesis_archive;
use solana_sdk::{
genesis_config::{GenesisConfig, DEFAULT_GENESIS_ARCHIVE},
hash::Hash,
};
use std::net::SocketAddr;
fn check_genesis_hash(
genesis_config: &GenesisConfig,
expected_genesis_hash: Option<Hash>,
) -> Result<(), String> {
let genesis_hash = genesis_config.hash();
if let Some(expected_genesis_hash) = expected_genesis_hash {
if expected_genesis_hash != genesis_hash {
return Err(format!(
"Genesis hash mismatch: expected {} but downloaded genesis hash is {}",
expected_genesis_hash, genesis_hash,
));
}
}
Ok(())
}
fn load_local_genesis(
ledger_path: &std::path::Path,
expected_genesis_hash: Option<Hash>,
) -> Result<GenesisConfig, String> {
let existing_genesis = GenesisConfig::load(&ledger_path)
.map_err(|err| format!("Failed to load genesis config: {}", err))?;
check_genesis_hash(&existing_genesis, expected_genesis_hash)?;
Ok(existing_genesis)
}
pub fn download_then_check_genesis_hash(
rpc_addr: &SocketAddr,
ledger_path: &std::path::Path,
expected_genesis_hash: Option<Hash>,
max_genesis_archive_unpacked_size: u64,
no_genesis_fetch: bool,
use_progress_bar: bool,
) -> Result<GenesisConfig, String> {
if no_genesis_fetch {
let genesis_config = load_local_genesis(ledger_path, expected_genesis_hash)?;
return Ok(genesis_config);
}
let genesis_package = ledger_path.join(DEFAULT_GENESIS_ARCHIVE);
let genesis_config = if let Ok(tmp_genesis_package) =
download_genesis_if_missing(rpc_addr, &genesis_package, use_progress_bar)
{
unpack_genesis_archive(
&tmp_genesis_package,
&ledger_path,
max_genesis_archive_unpacked_size,
)
.map_err(|err| format!("Failed to unpack downloaded genesis config: {}", err))?;
let downloaded_genesis = GenesisConfig::load(&ledger_path)
.map_err(|err| format!("Failed to load downloaded genesis config: {}", err))?;
check_genesis_hash(&downloaded_genesis, expected_genesis_hash)?;
std::fs::rename(tmp_genesis_package, genesis_package)
.map_err(|err| format!("Unable to rename: {:?}", err))?;
downloaded_genesis
} else {
load_local_genesis(ledger_path, expected_genesis_hash)?
};
Ok(genesis_config)
}

View File

@ -28,7 +28,7 @@ use solana_rayon_threadlimit::get_thread_count;
use solana_runtime::hardened_unpack::{unpack_genesis_archive, MAX_GENESIS_ARCHIVE_UNPACKED_SIZE}; use solana_runtime::hardened_unpack::{unpack_genesis_archive, MAX_GENESIS_ARCHIVE_UNPACKED_SIZE};
use solana_sdk::{ use solana_sdk::{
clock::{Slot, UnixTimestamp, DEFAULT_TICKS_PER_SECOND, MS_PER_TICK}, clock::{Slot, UnixTimestamp, DEFAULT_TICKS_PER_SECOND, MS_PER_TICK},
genesis_config::GenesisConfig, genesis_config::{GenesisConfig, DEFAULT_GENESIS_ARCHIVE, DEFAULT_GENESIS_FILE},
hash::Hash, hash::Hash,
pubkey::Pubkey, pubkey::Pubkey,
sanitize::Sanitize, sanitize::Sanitize,
@ -3434,13 +3434,13 @@ pub fn create_new_ledger(
// Explicitly close the blockstore before we create the archived genesis file // Explicitly close the blockstore before we create the archived genesis file
drop(blockstore); drop(blockstore);
let archive_path = ledger_path.join("genesis.tar.bz2"); let archive_path = ledger_path.join(DEFAULT_GENESIS_ARCHIVE);
let args = vec![ let args = vec![
"jcfhS", "jcfhS",
archive_path.to_str().unwrap(), archive_path.to_str().unwrap(),
"-C", "-C",
ledger_path.to_str().unwrap(), ledger_path.to_str().unwrap(),
"genesis.bin", DEFAULT_GENESIS_FILE,
"rocksdb", "rocksdb",
]; ];
let output = std::process::Command::new("tar") let output = std::process::Command::new("tar")
@ -3478,18 +3478,24 @@ pub fn create_new_ledger(
let mut error_messages = String::new(); let mut error_messages = String::new();
fs::rename( fs::rename(
&ledger_path.join("genesis.tar.bz2"), &ledger_path.join(DEFAULT_GENESIS_ARCHIVE),
ledger_path.join("genesis.tar.bz2.failed"), ledger_path.join(format!("{}.failed", DEFAULT_GENESIS_ARCHIVE)),
) )
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
error_messages += &format!("/failed to stash problematic genesis.tar.bz2: {}", e) error_messages += &format!(
"/failed to stash problematic {}: {}",
DEFAULT_GENESIS_ARCHIVE, e
)
}); });
fs::rename( fs::rename(
&ledger_path.join("genesis.bin"), &ledger_path.join(DEFAULT_GENESIS_FILE),
ledger_path.join("genesis.bin.failed"), ledger_path.join(format!("{}.failed", DEFAULT_GENESIS_FILE)),
) )
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
error_messages += &format!("/failed to stash problematic genesis.bin: {}", e) error_messages += &format!(
"/failed to stash problematic {}: {}",
DEFAULT_GENESIS_FILE, e
)
}); });
fs::rename( fs::rename(
&ledger_path.join("rocksdb"), &ledger_path.join("rocksdb"),

View File

@ -1,3 +1,4 @@
use solana_sdk::genesis_config::{DEFAULT_GENESIS_ARCHIVE, DEFAULT_GENESIS_FILE};
use { use {
bzip2::bufread::BzDecoder, bzip2::bufread::BzDecoder,
log::*, log::*,
@ -280,7 +281,7 @@ pub fn open_genesis_config(
max_genesis_archive_unpacked_size: u64, max_genesis_archive_unpacked_size: u64,
) -> GenesisConfig { ) -> GenesisConfig {
GenesisConfig::load(&ledger_path).unwrap_or_else(|load_err| { GenesisConfig::load(&ledger_path).unwrap_or_else(|load_err| {
let genesis_package = ledger_path.join("genesis.tar.bz2"); let genesis_package = ledger_path.join(DEFAULT_GENESIS_ARCHIVE);
unpack_genesis_archive( unpack_genesis_archive(
&genesis_package, &genesis_package,
ledger_path, ledger_path,
@ -348,8 +349,8 @@ fn is_valid_genesis_archive_entry(parts: &[&str], kind: tar::EntryType) -> bool
trace!("validating: {:?} {:?}", parts, kind); trace!("validating: {:?} {:?}", parts, kind);
#[allow(clippy::match_like_matches_macro)] #[allow(clippy::match_like_matches_macro)]
match (parts, kind) { match (parts, kind) {
(["genesis.bin"], GNUSparse) => true, ([DEFAULT_GENESIS_FILE], GNUSparse) => true,
(["genesis.bin"], Regular) => true, ([DEFAULT_GENESIS_FILE], Regular) => true,
(["rocksdb"], Directory) => true, (["rocksdb"], Directory) => true,
(["rocksdb", _], GNUSparse) => true, (["rocksdb", _], GNUSparse) => true,
(["rocksdb", _], Regular) => true, (["rocksdb", _], Regular) => true,

View File

@ -32,6 +32,10 @@ use std::{
time::{SystemTime, UNIX_EPOCH}, time::{SystemTime, UNIX_EPOCH},
}; };
pub const DEFAULT_GENESIS_FILE: &str = "genesis.bin";
pub const DEFAULT_GENESIS_ARCHIVE: &str = "genesis.tar.bz2";
pub const DEFAULT_GENESIS_DOWNLOAD_PATH: &str = "/genesis.tar.bz2";
// deprecated default that is no longer used // deprecated default that is no longer used
pub const UNUSED_DEFAULT: u64 = 1024; pub const UNUSED_DEFAULT: u64 = 1024;
@ -152,7 +156,7 @@ impl GenesisConfig {
} }
fn genesis_filename(ledger_path: &Path) -> PathBuf { fn genesis_filename(ledger_path: &Path) -> PathBuf {
Path::new(ledger_path).join("genesis.bin") Path::new(ledger_path).join(DEFAULT_GENESIS_FILE)
} }
pub fn load(ledger_path: &Path) -> Result<Self, std::io::Error> { pub fn load(ledger_path: &Path) -> Result<Self, std::io::Error> {

View File

@ -34,6 +34,7 @@ solana-client = { path = "../client", version = "=1.7.0" }
solana-core = { path = "../core", version = "=1.7.0" } solana-core = { path = "../core", version = "=1.7.0" }
solana-download-utils = { path = "../download-utils", version = "=1.7.0" } solana-download-utils = { path = "../download-utils", version = "=1.7.0" }
solana-faucet = { path = "../faucet", version = "=1.7.0" } solana-faucet = { path = "../faucet", version = "=1.7.0" }
solana-genesis-utils = { path = "../genesis-utils", version = "=1.7.0" }
solana-ledger = { path = "../ledger", version = "=1.7.0" } solana-ledger = { path = "../ledger", version = "=1.7.0" }
solana-logger = { path = "../logger", version = "=1.7.0" } solana-logger = { path = "../logger", version = "=1.7.0" }
solana-metrics = { path = "../metrics", version = "=1.7.0" } solana-metrics = { path = "../metrics", version = "=1.7.0" }

View File

@ -34,7 +34,8 @@ use {
is_snapshot_config_invalid, Validator, ValidatorConfig, ValidatorStartProgress, is_snapshot_config_invalid, Validator, ValidatorConfig, ValidatorStartProgress,
}, },
}, },
solana_download_utils::{download_genesis_if_missing, download_snapshot}, solana_download_utils::download_snapshot,
solana_genesis_utils::download_then_check_genesis_hash,
solana_ledger::blockstore_db::BlockstoreRecoveryMode, solana_ledger::blockstore_db::BlockstoreRecoveryMode,
solana_perf::recycler::enable_recycler_warming, solana_perf::recycler::enable_recycler_warming,
solana_rpc::rpc_pubsub_service::PubSubConfig, solana_rpc::rpc_pubsub_service::PubSubConfig,
@ -43,13 +44,12 @@ use {
AccountIndex, AccountSecondaryIndexes, AccountSecondaryIndexesIncludeExclude, AccountIndex, AccountSecondaryIndexes, AccountSecondaryIndexesIncludeExclude,
}, },
bank_forks::{ArchiveFormat, SnapshotConfig, SnapshotVersion}, bank_forks::{ArchiveFormat, SnapshotConfig, SnapshotVersion},
hardened_unpack::{unpack_genesis_archive, MAX_GENESIS_ARCHIVE_UNPACKED_SIZE}, hardened_unpack::MAX_GENESIS_ARCHIVE_UNPACKED_SIZE,
snapshot_utils::{get_highest_snapshot_archive_path, DEFAULT_MAX_SNAPSHOTS_TO_RETAIN}, snapshot_utils::{get_highest_snapshot_archive_path, DEFAULT_MAX_SNAPSHOTS_TO_RETAIN},
}, },
solana_sdk::{ solana_sdk::{
clock::{Slot, DEFAULT_S_PER_SLOT}, clock::{Slot, DEFAULT_S_PER_SLOT},
commitment_config::CommitmentConfig, commitment_config::CommitmentConfig,
genesis_config::GenesisConfig,
hash::Hash, hash::Hash,
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
@ -648,74 +648,6 @@ fn validators_set(
} }
} }
fn check_genesis_hash(
genesis_config: &GenesisConfig,
expected_genesis_hash: Option<Hash>,
) -> Result<(), String> {
let genesis_hash = genesis_config.hash();
if let Some(expected_genesis_hash) = expected_genesis_hash {
if expected_genesis_hash != genesis_hash {
return Err(format!(
"Genesis hash mismatch: expected {} but downloaded genesis hash is {}",
expected_genesis_hash, genesis_hash,
));
}
}
Ok(())
}
fn load_local_genesis(
ledger_path: &std::path::Path,
expected_genesis_hash: Option<Hash>,
) -> Result<GenesisConfig, String> {
let existing_genesis = GenesisConfig::load(&ledger_path)
.map_err(|err| format!("Failed to load genesis config: {}", err))?;
check_genesis_hash(&existing_genesis, expected_genesis_hash)?;
Ok(existing_genesis)
}
fn download_then_check_genesis_hash(
rpc_addr: &SocketAddr,
ledger_path: &std::path::Path,
expected_genesis_hash: Option<Hash>,
max_genesis_archive_unpacked_size: u64,
no_genesis_fetch: bool,
use_progress_bar: bool,
) -> Result<Hash, String> {
if no_genesis_fetch {
let genesis_config = load_local_genesis(ledger_path, expected_genesis_hash)?;
return Ok(genesis_config.hash());
}
let genesis_package = ledger_path.join("genesis.tar.bz2");
let genesis_config = if let Ok(tmp_genesis_package) =
download_genesis_if_missing(rpc_addr, &genesis_package, use_progress_bar)
{
unpack_genesis_archive(
&tmp_genesis_package,
&ledger_path,
max_genesis_archive_unpacked_size,
)
.map_err(|err| format!("Failed to unpack downloaded genesis config: {}", err))?;
let downloaded_genesis = GenesisConfig::load(&ledger_path)
.map_err(|err| format!("Failed to load downloaded genesis config: {}", err))?;
check_genesis_hash(&downloaded_genesis, expected_genesis_hash)?;
std::fs::rename(tmp_genesis_package, genesis_package)
.map_err(|err| format!("Unable to rename: {:?}", err))?;
downloaded_genesis
} else {
load_local_genesis(ledger_path, expected_genesis_hash)?
};
Ok(genesis_config.hash())
}
fn verify_reachable_ports( fn verify_reachable_ports(
node: &Node, node: &Node,
cluster_entrypoint: &ContactInfo, cluster_entrypoint: &ContactInfo,
@ -872,7 +804,7 @@ fn rpc_bootstrap(
Err(err) => Err(format!("Failed to get RPC node version: {}", err)), Err(err) => Err(format!("Failed to get RPC node version: {}", err)),
} }
.and_then(|_| { .and_then(|_| {
let genesis_hash = download_then_check_genesis_hash( let genesis_config = download_then_check_genesis_hash(
&rpc_contact_info.rpc, &rpc_contact_info.rpc,
&ledger_path, &ledger_path,
validator_config.expected_genesis_hash, validator_config.expected_genesis_hash,
@ -881,7 +813,8 @@ fn rpc_bootstrap(
use_progress_bar, use_progress_bar,
); );
if let Ok(genesis_hash) = genesis_hash { if let Ok(genesis_config) = genesis_config {
let genesis_hash = genesis_config.hash();
if validator_config.expected_genesis_hash.is_none() { if validator_config.expected_genesis_hash.is_none() {
info!("Expected genesis hash set to {}", genesis_hash); info!("Expected genesis hash set to {}", genesis_hash);
validator_config.expected_genesis_hash = Some(genesis_hash); validator_config.expected_genesis_hash = Some(genesis_hash);