parent
11fc684f3c
commit
e5a7d08966
|
@ -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
|
||||
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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: {:?}",
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue