Add --expected-genesis-blockhash validator argument (#6174)

automerge
This commit is contained in:
Michael Vines 2019-09-29 19:09:24 -07:00 committed by Grimes
parent 11fc684f3c
commit e5a7d08966
5 changed files with 71 additions and 17 deletions

View File

@ -152,6 +152,7 @@ startNodes() {
addLogs=true
fi
initCompleteFiles=()
maybeExpectedGenesisBlockhash=
for i in $(seq 0 $((${#nodes[@]} - 1))); do
declare cmd=${nodes[$i]}
@ -160,7 +161,7 @@ startNodes() {
rm -f "$initCompleteFile"
initCompleteFiles+=("$initCompleteFile")
fi
startNode "$i" "$cmd"
startNode "$i" "$cmd $maybeExpectedGenesisBlockhash"
if $addLogs; then
logs+=("$(getNodeLogFile "$i" "$cmd")")
fi
@ -170,6 +171,14 @@ startNodes() {
if [[ "$i" -eq 1 ]]; then
SECONDS=
waitForNodeToInit "$initCompleteFile"
(
source multinode-demo/common.sh
set -x
$solana_cli --keypair config/bootstrap-leader/identity-keypair.json \
--url http://127.0.0.1:8899 get-genesis-blockhash
) | tee genesis-blockhash.log
maybeExpectedGenesisBlockhash="--expected-genesis-blockhash $(tail -n1 genesis-blockhash.log)"
fi
done

View File

@ -96,6 +96,7 @@ pub enum WalletCommand {
ClaimStorageReward(Pubkey, Pubkey),
ShowStorageAccount(Pubkey),
Deploy(String),
GetGenesisBlockhash,
GetSlot,
GetEpochInfo,
GetTransactionCount,
@ -343,6 +344,7 @@ pub fn parse_command(
.unwrap()
.to_string(),
)),
("get-genesis-blockhash", Some(_matches)) => Ok(WalletCommand::GetGenesisBlockhash),
("get-slot", Some(_matches)) => Ok(WalletCommand::GetSlot),
("get-epoch-info", Some(_matches)) => Ok(WalletCommand::GetEpochInfo),
("get-transaction-count", Some(_matches)) => Ok(WalletCommand::GetTransactionCount),
@ -1086,6 +1088,11 @@ fn process_cancel(rpc_client: &RpcClient, config: &WalletConfig, pubkey: &Pubkey
log_instruction_custom_error::<BudgetError>(result)
}
fn process_get_genesis_blockhash(rpc_client: &RpcClient) -> ProcessResult {
let genesis_blockhash = rpc_client.get_genesis_blockhash()?;
Ok(genesis_blockhash.to_string())
}
fn process_get_slot(rpc_client: &RpcClient) -> ProcessResult {
let slot = rpc_client.get_slot()?;
Ok(slot.to_string())
@ -1501,6 +1508,7 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
process_deploy(&rpc_client, config, program_location)
}
WalletCommand::GetGenesisBlockhash => process_get_genesis_blockhash(&rpc_client),
WalletCommand::GetSlot => process_get_slot(&rpc_client),
WalletCommand::GetEpochInfo => process_get_epoch_info(&rpc_client),
WalletCommand::GetTransactionCount => process_get_transaction_count(&rpc_client),
@ -2196,6 +2204,10 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.help("/path/to/program.o"),
), // TODO: Add "loader" argument; current default is bpf_loader
)
.subcommand(
SubCommand::with_name("get-genesis-blockhash")
.about("Get the genesis blockhash"),
)
.subcommand(
SubCommand::with_name("get-slot")
.about("Get current slot"),

View File

@ -497,12 +497,13 @@ pub fn new_banks_from_blocktree(
) {
let genesis_block = GenesisBlock::load(blocktree_path).expect("Failed to load genesis block");
let genesis_blockhash = genesis_block.hash();
info!("genesis blockhash: {}", genesis_blockhash);
if let Some(expected_genesis_blockhash) = expected_genesis_blockhash {
if genesis_blockhash != expected_genesis_blockhash {
error!(
"Genesis blockhash mismatch: expected {} but local genesis blockhash is {}",
expected_genesis_blockhash, genesis_blockhash,
"genesis blockhash mismatch: expected {}",
expected_genesis_blockhash
);
error!(
"Delete the ledger directory to continue: {:?}",

View File

@ -67,6 +67,9 @@ while [[ -n $1 ]]; do
elif [[ $1 = --blockstream ]]; then
args+=("$1" "$2")
shift 2
elif [[ $1 = --expected-genesis-blockhash ]]; then
args+=("$1" "$2")
shift 2
elif [[ $1 = --identity ]]; then
identity_keypair_path=$2
args+=("$1" "$2")

View File

@ -20,6 +20,7 @@ use std::io::{self, Read};
use std::net::{SocketAddr, TcpListener};
use std::path::{Path, PathBuf};
use std::process::exit;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Instant;
@ -31,6 +32,12 @@ fn port_range_validator(port_range: String) -> Result<(), String> {
}
}
fn hash_validator(hash: String) -> Result<(), String> {
Hash::from_str(&hash)
.map(|_| ())
.map_err(|e| format!("{:?}", e))
}
static TRUCK: Emoji = Emoji("🚚 ", "");
static SPARKLE: Emoji = Emoji("", "");
@ -171,7 +178,7 @@ fn initialize_ledger_path(
.map(|addrs| addrs.0)
.find(|rpc_addr| rpc_addr.ip() == entrypoint.gossip.ip())
.unwrap_or_else(|| {
eprintln!(
error!(
"Entrypoint ({:?}) is not running the RPC service",
entrypoint.gossip.ip()
);
@ -199,7 +206,7 @@ fn initialize_ledger_path(
snapshot_package.parent().unwrap(),
false,
)
.unwrap_or_else(|err| eprintln!("Warning: Unable to fetch snapshot: {:?}", err));
.unwrap_or_else(|err| warn!("Unable to fetch snapshot: {:?}", err));
}
match client.get_slot() {
@ -396,6 +403,14 @@ pub fn main() {
.takes_value(false)
.help("Use CUDA"),
)
.arg(
Arg::with_name("expected_genesis_blockhash")
.long("expected-genesis-blockhash")
.value_name("HASH")
.takes_value(true)
.validator(hash_validator)
.help("Require the genesis block have this blockhash"),
)
.get_matches();
if matches.is_present("cuda") {
@ -405,7 +420,7 @@ pub fn main() {
let mut validator_config = ValidatorConfig::default();
let keypair = if let Some(identity) = matches.value_of("identity") {
read_keypair(identity).unwrap_or_else(|err| {
eprintln!("{}: Unable to open keypair file: {}", err, identity);
error!("{}: Unable to open keypair file: {}", err, identity);
exit(1);
})
} else {
@ -414,7 +429,7 @@ pub fn main() {
let voting_keypair = if let Some(identity) = matches.value_of("voting_keypair") {
read_keypair(identity).unwrap_or_else(|err| {
eprintln!("{}: Unable to open keypair file: {}", err, identity);
error!("{}: Unable to open keypair file: {}", err, identity);
exit(1);
})
} else {
@ -422,7 +437,7 @@ pub fn main() {
};
let storage_keypair = if let Some(storage_keypair) = matches.value_of("storage_keypair") {
read_keypair(storage_keypair).unwrap_or_else(|err| {
eprintln!("{}: Unable to open keypair file: {}", err, storage_keypair);
error!("{}: Unable to open keypair file: {}", err, storage_keypair);
exit(1);
})
} else {
@ -471,7 +486,7 @@ pub fn main() {
let snapshot_interval_slots = value_t_or_exit!(matches, "snapshot_interval_slots", usize);
let snapshot_path = ledger_path.clone().join("snapshot");
fs::create_dir_all(&snapshot_path).unwrap_or_else(|err| {
eprintln!(
error!(
"Failed to create snapshots directory {:?}: {}",
snapshot_path, err
);
@ -495,7 +510,7 @@ pub fn main() {
let entrypoint_addr = solana_netutil::parse_host_port(entrypoint)
.expect("failed to parse entrypoint address");
let ip_addr = solana_netutil::get_public_ip_addr(&entrypoint_addr).unwrap_or_else(|err| {
eprintln!(
error!(
"Failed to contact cluster entrypoint {} ({}): {}",
entrypoint, entrypoint_addr, err
);
@ -543,7 +558,7 @@ pub fn main() {
if let Some(port) = matches.value_of("rpc_port") {
let port_number = port.to_string().parse().expect("integer");
if port_number == 0 {
eprintln!("Invalid RPC port requested: {:?}", port);
error!("Invalid RPC port requested: {:?}", port);
exit(1);
}
node.info.rpc = SocketAddr::new(node.info.gossip.ip(), port_number);
@ -551,6 +566,10 @@ pub fn main() {
tcp_ports = vec![port_number, port_number + 1];
};
validator_config.expected_genesis_blockhash = matches
.value_of("expected_genesis_blockhash")
.map(|s| Hash::from_str(&s).unwrap());
if let Some(ref cluster_entrypoint) = cluster_entrypoint {
let udp_sockets = [
&node.sockets.gossip,
@ -583,21 +602,31 @@ pub fn main() {
&udp_sockets,
);
let expected_genesis_blockhash = initialize_ledger_path(
let genesis_blockhash = initialize_ledger_path(
cluster_entrypoint,
&ledger_path,
matches.is_present("no_snapshot_fetch"),
)
.unwrap_or_else(|err| {
eprintln!("Failed to download ledger: {}", err);
error!("Failed to download ledger: {}", err);
exit(1);
});
validator_config.expected_genesis_blockhash = Some(expected_genesis_blockhash);
if let Some(expected_genesis_blockhash) = validator_config.expected_genesis_blockhash {
if expected_genesis_blockhash != genesis_blockhash {
error!(
"Genesis blockhash mismatch: expected {} but local genesis blockhash is {}",
expected_genesis_blockhash, genesis_blockhash,
);
exit(1);
}
}
validator_config.expected_genesis_blockhash = Some(genesis_blockhash);
} else {
// Without a cluster entrypoint, ledger_path must already be present
if !ledger_path.is_dir() {
eprintln!(
"Error: ledger directory does not exist or is not accessible: {:?}",
error!(
"ledger directory does not exist or is not accessible: {:?}",
ledger_path
);
exit(1);
@ -618,7 +647,7 @@ pub fn main() {
if let Some(filename) = init_complete_file {
File::create(filename).unwrap_or_else(|_| {
eprintln!("Unable to create: {}", filename);
error!("Unable to create: {}", filename);
exit(1);
});
}