Make solana-validator check vote account at start (#6790)
* Make solana-validator check vote account at start * Don't abort tests... * Fix test breakage * Remove extra semicolon * Attempt to fix cluster-tests * rustfmt * Change behavior of vote_account ephemeral pubkeys * save * clean up * clean up * rustfmt && clippy * Reorder for simpler diff * Fix rebase... * Fix message a bit * Still more rebase fixes.... * Fix yet more * Use find_map over filter_map & next and revert message * More through error checks * rustfmt & clippy * Revert * Revert core/src/validator.rs * Cleanup * Cleanup * Cleanup * Rebase fix * Make clippy & rustfmt happy * save * Clean up * Show rpc error detail * Check node lamports only after pubkey matching * rustfmt
This commit is contained in:
parent
361eab1bf7
commit
e5c5f34f9a
|
@ -19,6 +19,7 @@ use solana_ledger::bank_forks::SnapshotConfig;
|
|||
use solana_perf::recycler::enable_recycler_warming;
|
||||
use solana_sdk::clock::Slot;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::{read_keypair_file, Keypair, KeypairUtil};
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, Read};
|
||||
|
@ -168,12 +169,9 @@ fn download_tar_bz2(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn initialize_ledger_path(
|
||||
fn create_rpc_client(
|
||||
entrypoint: &ContactInfo,
|
||||
ledger_path: &Path,
|
||||
no_genesis_fetch: bool,
|
||||
no_snapshot_fetch: bool,
|
||||
) -> Result<Hash, String> {
|
||||
) -> Result<(std::net::SocketAddr, RpcClient), String> {
|
||||
let (nodes, _archivers) = discover(
|
||||
&entrypoint.gossip,
|
||||
Some(1),
|
||||
|
@ -184,9 +182,7 @@ fn initialize_ledger_path(
|
|||
)
|
||||
.map_err(|err| err.to_string())?;
|
||||
|
||||
let rpc_addr = nodes
|
||||
.iter()
|
||||
.filter_map(|contact_info| {
|
||||
let rpc_addr = nodes.iter().find_map(|contact_info| {
|
||||
if contact_info.gossip == entrypoint.gossip
|
||||
&& ContactInfo::is_valid_address(&contact_info.rpc)
|
||||
{
|
||||
|
@ -194,18 +190,78 @@ fn initialize_ledger_path(
|
|||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.next()
|
||||
.unwrap_or_else(|| {
|
||||
error!(
|
||||
"Entrypoint ({:?}) is not running the RPC service",
|
||||
entrypoint.gossip
|
||||
);
|
||||
exit(1);
|
||||
});
|
||||
|
||||
let client = RpcClient::new_socket(rpc_addr);
|
||||
let genesis_hash = client.get_genesis_hash().map_err(|err| err.to_string())?;
|
||||
if let Some(rpc_addr) = rpc_addr {
|
||||
Ok((rpc_addr, RpcClient::new_socket(rpc_addr)))
|
||||
} else {
|
||||
Err(format!(
|
||||
"Entrypoint ({:?}) is not running the RPC service",
|
||||
entrypoint.gossip
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn check_vote_account(
|
||||
rpc_client: &RpcClient,
|
||||
vote_pubkey: &Pubkey,
|
||||
voting_pubkey: &Pubkey,
|
||||
node_pubkey: &Pubkey,
|
||||
) -> Result<(), String> {
|
||||
let found_vote_account = rpc_client
|
||||
.get_account(vote_pubkey)
|
||||
.map_err(|err| format!("Failed to get vote account: {}", err.to_string()))?;
|
||||
|
||||
if found_vote_account.owner != solana_vote_api::id() {
|
||||
return Err(format!(
|
||||
"not a vote account (owned by {}): {}",
|
||||
found_vote_account.owner, vote_pubkey
|
||||
));
|
||||
}
|
||||
|
||||
let found_node_account = rpc_client
|
||||
.get_account(node_pubkey)
|
||||
.map_err(|err| format!("Failed to get identity account: {}", err.to_string()))?;
|
||||
|
||||
let found_vote_account = solana_vote_api::vote_state::VoteState::from(&found_vote_account);
|
||||
if let Some(found_vote_account) = found_vote_account {
|
||||
if found_vote_account.authorized_voter != *voting_pubkey {
|
||||
return Err(format!(
|
||||
"account's authorized voter ({}) does not match to the given voting keypair ({}).",
|
||||
found_vote_account.authorized_voter, voting_pubkey
|
||||
));
|
||||
}
|
||||
if found_vote_account.node_pubkey != *node_pubkey {
|
||||
return Err(format!(
|
||||
"account's node pubkey ({}) does not match to the given identity keypair ({}).",
|
||||
found_vote_account.node_pubkey, node_pubkey
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(format!("invalid vote account data: {}", vote_pubkey));
|
||||
}
|
||||
|
||||
// Maybe we can calculate minimum voting fee; rather than 1 lamport
|
||||
if found_node_account.lamports <= 1 {
|
||||
return Err(format!(
|
||||
"unfunded identity account ({}): only {} lamports (needs more fund to vote)",
|
||||
node_pubkey, found_node_account.lamports
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn initialize_ledger_path(
|
||||
rpc_addr: &std::net::SocketAddr,
|
||||
rpc_client: &RpcClient,
|
||||
ledger_path: &Path,
|
||||
no_genesis_fetch: bool,
|
||||
no_snapshot_fetch: bool,
|
||||
) -> Result<Hash, String> {
|
||||
let genesis_hash = rpc_client
|
||||
.get_genesis_hash()
|
||||
.map_err(|err| err.to_string())?;
|
||||
|
||||
fs::create_dir_all(ledger_path).map_err(|err| err.to_string())?;
|
||||
|
||||
|
@ -228,7 +284,7 @@ fn initialize_ledger_path(
|
|||
.unwrap_or_else(|err| warn!("Unable to fetch snapshot: {:?}", err));
|
||||
}
|
||||
|
||||
match client.get_slot() {
|
||||
match rpc_client.get_slot() {
|
||||
Ok(slot) => info!("Entrypoint currently at slot {}", slot),
|
||||
Err(err) => warn!("Failed to get_slot from entrypoint: {}", err),
|
||||
}
|
||||
|
@ -265,7 +321,7 @@ pub fn main() {
|
|||
.value_name("PATH")
|
||||
.takes_value(true)
|
||||
.validator(is_keypair)
|
||||
.help("File containing the authorized voting keypair. Default is an ephemeral keypair"),
|
||||
.help("File containing the authorized voting keypair. Default is an ephemeral keypair, which may disable voting without --vote-account."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("vote_account")
|
||||
|
@ -273,7 +329,7 @@ pub fn main() {
|
|||
.value_name("PUBKEY")
|
||||
.takes_value(true)
|
||||
.validator(is_pubkey_or_keypair)
|
||||
.help("Public key of the vote account to vote with. Default is the public key of the voting keypair"),
|
||||
.help("Public key of the vote account to vote with. Default is the public key of --voting-keypair"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("storage_keypair")
|
||||
|
@ -448,12 +504,14 @@ pub fn main() {
|
|||
Keypair::new()
|
||||
};
|
||||
|
||||
let mut ephemeral_voting_keypair = false;
|
||||
let voting_keypair = if let Some(identity) = matches.value_of("voting_keypair") {
|
||||
read_keypair_file(identity).unwrap_or_else(|err| {
|
||||
error!("{}: Unable to open keypair file: {}", err, identity);
|
||||
exit(1);
|
||||
})
|
||||
} else {
|
||||
ephemeral_voting_keypair = true;
|
||||
Keypair::new()
|
||||
};
|
||||
let storage_keypair = if let Some(storage_keypair) = matches.value_of("storage_keypair") {
|
||||
|
@ -465,9 +523,6 @@ pub fn main() {
|
|||
Keypair::new()
|
||||
};
|
||||
|
||||
let vote_account =
|
||||
pubkey_of(&matches, "vote_account").unwrap_or_else(|| voting_keypair.pubkey());
|
||||
|
||||
let ledger_path = PathBuf::from(matches.value_of("ledger_path").unwrap());
|
||||
let entrypoint = matches.value_of("entrypoint");
|
||||
let init_complete_file = matches.value_of("init_complete_file");
|
||||
|
@ -481,8 +536,6 @@ pub fn main() {
|
|||
validator_config.dev_sigverify_disabled = matches.is_present("dev_no_sigverify");
|
||||
validator_config.dev_halt_at_slot = value_t!(matches, "dev_halt_at_slot", Slot).ok();
|
||||
|
||||
validator_config.voting_disabled = matches.is_present("no_voting");
|
||||
|
||||
validator_config.rpc_config.enable_validator_exit = matches.is_present("enable_rpc_exit");
|
||||
|
||||
validator_config.rpc_config.drone_addr = matches.value_of("rpc_drone_addr").map(|address| {
|
||||
|
@ -578,6 +631,21 @@ pub fn main() {
|
|||
]
|
||||
.join(","),
|
||||
);
|
||||
|
||||
if matches.is_present("no_voting") {
|
||||
validator_config.voting_disabled = true;
|
||||
}
|
||||
|
||||
let vote_account = pubkey_of(&matches, "vote_account").unwrap_or_else(|| {
|
||||
// Disable voting because normal (=not bootstrapping) validator rejects
|
||||
// non-voting accounts (= ephemeral keypairs).
|
||||
if ephemeral_voting_keypair && entrypoint.is_some() {
|
||||
warn!("Disabled voting due to the use of ephemeral key for vote account");
|
||||
validator_config.voting_disabled = true;
|
||||
};
|
||||
voting_keypair.pubkey()
|
||||
});
|
||||
|
||||
solana_metrics::set_host_id(identity_keypair.pubkey().to_string());
|
||||
solana_metrics::set_panic_hook("validator");
|
||||
|
||||
|
@ -653,8 +721,27 @@ pub fn main() {
|
|||
&udp_sockets,
|
||||
);
|
||||
|
||||
let (rpc_addr, rpc_client) = create_rpc_client(cluster_entrypoint).unwrap_or_else(|err| {
|
||||
error!("unable to create rpc client: {}", err);
|
||||
std::process::exit(1);
|
||||
});
|
||||
|
||||
if !validator_config.voting_disabled {
|
||||
check_vote_account(
|
||||
&rpc_client,
|
||||
&vote_account,
|
||||
&voting_keypair.pubkey(),
|
||||
&identity_keypair.pubkey(),
|
||||
)
|
||||
.unwrap_or_else(|err| {
|
||||
error!("Failed to check vote account: {}", err);
|
||||
exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
let genesis_hash = initialize_ledger_path(
|
||||
cluster_entrypoint,
|
||||
&rpc_addr,
|
||||
&rpc_client,
|
||||
&ledger_path,
|
||||
no_genesis_fetch,
|
||||
no_snapshot_fetch,
|
||||
|
|
Loading…
Reference in New Issue