`solana-validator set-identity` now supports the `--require-tower` flag
This commit is contained in:
parent
6ae87109d2
commit
a6d736572c
|
@ -297,6 +297,7 @@ pub struct Validator {
|
|||
tvu: Tvu,
|
||||
ip_echo_server: Option<solana_net_utils::IpEchoServer>,
|
||||
pub cluster_info: Arc<ClusterInfo>,
|
||||
pub bank_forks: Arc<RwLock<BankForks>>,
|
||||
accountsdb_repl_service: Option<AccountsDbReplService>,
|
||||
accountsdb_plugin_service: Option<AccountsDbPluginService>,
|
||||
}
|
||||
|
@ -897,7 +898,7 @@ impl Validator {
|
|||
&exit,
|
||||
node.info.shred_version,
|
||||
vote_tracker,
|
||||
bank_forks,
|
||||
bank_forks.clone(),
|
||||
verified_vote_sender,
|
||||
gossip_verified_vote_hash_sender,
|
||||
replay_vote_receiver,
|
||||
|
@ -934,6 +935,7 @@ impl Validator {
|
|||
ip_echo_server,
|
||||
validator_exit: config.validator_exit.clone(),
|
||||
cluster_info,
|
||||
bank_forks,
|
||||
accountsdb_repl_service,
|
||||
accountsdb_plugin_service,
|
||||
}
|
||||
|
@ -975,6 +977,7 @@ impl Validator {
|
|||
}
|
||||
|
||||
pub fn join(self) {
|
||||
drop(self.bank_forks);
|
||||
drop(self.cluster_info);
|
||||
|
||||
self.poh_service.join().expect("poh_service");
|
||||
|
|
|
@ -16,7 +16,7 @@ use {
|
|||
solana_net_utils::PortRange,
|
||||
solana_rpc::{rpc::JsonRpcConfig, rpc_pubsub_service::PubSubConfig},
|
||||
solana_runtime::{
|
||||
genesis_utils::create_genesis_config_with_leader_ex,
|
||||
bank_forks::BankForks, genesis_utils::create_genesis_config_with_leader_ex,
|
||||
hardened_unpack::MAX_GENESIS_ARCHIVE_UNPACKED_SIZE, snapshot_config::SnapshotConfig,
|
||||
},
|
||||
solana_sdk::{
|
||||
|
@ -833,6 +833,10 @@ impl TestValidator {
|
|||
pub fn cluster_info(&self) -> Arc<ClusterInfo> {
|
||||
self.validator.as_ref().unwrap().cluster_info.clone()
|
||||
}
|
||||
|
||||
pub fn bank_forks(&self) -> Arc<RwLock<BankForks>> {
|
||||
self.validator.as_ref().unwrap().bank_forks.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestValidator {
|
||||
|
|
|
@ -10,8 +10,10 @@ use {
|
|||
consensus::Tower, tower_storage::TowerStorage, validator::ValidatorStartProgress,
|
||||
},
|
||||
solana_gossip::{cluster_info::ClusterInfo, contact_info::ContactInfo},
|
||||
solana_runtime::bank_forks::BankForks,
|
||||
solana_sdk::{
|
||||
exit::Exit,
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, Keypair, Signer},
|
||||
},
|
||||
std::{
|
||||
|
@ -24,6 +26,13 @@ use {
|
|||
},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AdminRpcRequestMetadataPostInit {
|
||||
pub cluster_info: Arc<ClusterInfo>,
|
||||
pub bank_forks: Arc<RwLock<BankForks>>,
|
||||
pub vote_account: Pubkey,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AdminRpcRequestMetadata {
|
||||
pub rpc_addr: Option<SocketAddr>,
|
||||
|
@ -31,11 +40,26 @@ pub struct AdminRpcRequestMetadata {
|
|||
pub start_progress: Arc<RwLock<ValidatorStartProgress>>,
|
||||
pub validator_exit: Arc<RwLock<Exit>>,
|
||||
pub authorized_voter_keypairs: Arc<RwLock<Vec<Arc<Keypair>>>>,
|
||||
pub cluster_info: Arc<RwLock<Option<Arc<ClusterInfo>>>>,
|
||||
pub tower_storage: Arc<dyn TowerStorage>,
|
||||
pub post_init: Arc<RwLock<Option<AdminRpcRequestMetadataPostInit>>>,
|
||||
}
|
||||
impl Metadata for AdminRpcRequestMetadata {}
|
||||
|
||||
impl AdminRpcRequestMetadata {
|
||||
fn with_post_init<F, R>(&self, func: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(&AdminRpcRequestMetadataPostInit) -> Result<R>,
|
||||
{
|
||||
if let Some(post_init) = self.post_init.read().unwrap().as_ref() {
|
||||
func(post_init)
|
||||
} else {
|
||||
Err(jsonrpc_core::error::Error::invalid_params(
|
||||
"Retry once validator start up is complete",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct AdminRpcContactInfo {
|
||||
pub id: String,
|
||||
|
@ -132,7 +156,12 @@ pub trait AdminRpc {
|
|||
fn remove_all_authorized_voters(&self, meta: Self::Metadata) -> Result<()>;
|
||||
|
||||
#[rpc(meta, name = "setIdentity")]
|
||||
fn set_identity(&self, meta: Self::Metadata, keypair_file: String) -> Result<()>;
|
||||
fn set_identity(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
keypair_file: String,
|
||||
require_tower: bool,
|
||||
) -> Result<()>;
|
||||
|
||||
#[rpc(meta, name = "contactInfo")]
|
||||
fn contact_info(&self, meta: Self::Metadata) -> Result<AdminRpcContactInfo>;
|
||||
|
@ -212,7 +241,12 @@ impl AdminRpc for AdminRpcImpl {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn set_identity(&self, meta: Self::Metadata, keypair_file: String) -> Result<()> {
|
||||
fn set_identity(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
keypair_file: String,
|
||||
require_tower: bool,
|
||||
) -> Result<()> {
|
||||
debug!("set_identity request received");
|
||||
|
||||
let identity_keypair = read_keypair_file(&keypair_file).map_err(|err| {
|
||||
|
@ -222,35 +256,55 @@ impl AdminRpc for AdminRpcImpl {
|
|||
))
|
||||
})?;
|
||||
|
||||
// Ensure a Tower exists for the new identity and exit gracefully.
|
||||
// ReplayStage will be less forgiving if it fails to load the new tower.
|
||||
Tower::restore(meta.tower_storage.as_ref(), &identity_keypair.pubkey()).map_err(|err| {
|
||||
jsonrpc_core::error::Error::invalid_params(format!(
|
||||
"Unable to load tower file for new identity: {}",
|
||||
err
|
||||
))
|
||||
})?;
|
||||
meta.with_post_init(|post_init| {
|
||||
// Ensure a Tower exists for the new identity and exit gracefully.
|
||||
// ReplayStage will be less forgiving if it fails to load the new tower.
|
||||
if let Err(err) =
|
||||
Tower::restore(meta.tower_storage.as_ref(), &identity_keypair.pubkey()).map_err(
|
||||
|err| {
|
||||
jsonrpc_core::error::Error::invalid_params(format!(
|
||||
"Unable to load tower file for identity {}: {}",
|
||||
identity_keypair.pubkey(),
|
||||
err
|
||||
))
|
||||
},
|
||||
)
|
||||
{
|
||||
if require_tower {
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
let root_bank = post_init.bank_forks.read().unwrap().root_bank();
|
||||
let mut tower = Tower::new(
|
||||
&identity_keypair.pubkey(),
|
||||
&post_init.vote_account,
|
||||
root_bank.slot(),
|
||||
&root_bank,
|
||||
);
|
||||
// Forge a single vote to pacify `Tower::adjust_lockouts_after_replay` when its called
|
||||
// by replay_stage
|
||||
tower.record_bank_vote(&root_bank, &post_init.vote_account);
|
||||
tower
|
||||
.save(meta.tower_storage.as_ref(), &identity_keypair)
|
||||
.map_err(|err| {
|
||||
jsonrpc_core::error::Error::invalid_params(format!(
|
||||
"Unable to create default tower file for ephemeral identity: {}",
|
||||
err
|
||||
))
|
||||
})?;
|
||||
}
|
||||
|
||||
if let Some(cluster_info) = meta.cluster_info.read().unwrap().as_ref() {
|
||||
solana_metrics::set_host_id(identity_keypair.pubkey().to_string());
|
||||
cluster_info.set_keypair(Arc::new(identity_keypair));
|
||||
warn!("Identity set to {}", cluster_info.id());
|
||||
post_init
|
||||
.cluster_info
|
||||
.set_keypair(Arc::new(identity_keypair));
|
||||
warn!("Identity set to {}", post_init.cluster_info.id());
|
||||
Ok(())
|
||||
} else {
|
||||
Err(jsonrpc_core::error::Error::invalid_params(
|
||||
"Retry once validator start up is complete",
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn contact_info(&self, meta: Self::Metadata) -> Result<AdminRpcContactInfo> {
|
||||
if let Some(cluster_info) = meta.cluster_info.read().unwrap().as_ref() {
|
||||
Ok(cluster_info.my_contact_info().into())
|
||||
} else {
|
||||
Err(jsonrpc_core::error::Error::invalid_params(
|
||||
"Retry once validator start up is complete",
|
||||
))
|
||||
}
|
||||
meta.with_post_init(|post_init| Ok(post_init.cluster_info.my_contact_info().into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -589,7 +589,7 @@ fn main() {
|
|||
|
||||
let tower_storage = Arc::new(FileTowerStorage::new(ledger_path.clone()));
|
||||
|
||||
let admin_service_cluster_info = Arc::new(RwLock::new(None));
|
||||
let admin_service_post_init = Arc::new(RwLock::new(None));
|
||||
admin_rpc_service::run(
|
||||
&ledger_path,
|
||||
admin_rpc_service::AdminRpcRequestMetadata {
|
||||
|
@ -601,7 +601,7 @@ fn main() {
|
|||
start_time: std::time::SystemTime::now(),
|
||||
validator_exit: genesis.validator_exit.clone(),
|
||||
authorized_voter_keypairs: genesis.authorized_voter_keypairs.clone(),
|
||||
cluster_info: admin_service_cluster_info.clone(),
|
||||
post_init: admin_service_post_init.clone(),
|
||||
tower_storage: tower_storage.clone(),
|
||||
},
|
||||
);
|
||||
|
@ -695,7 +695,12 @@ fn main() {
|
|||
|
||||
match genesis.start_with_mint_address(mint_address, socket_addr_space) {
|
||||
Ok(test_validator) => {
|
||||
*admin_service_cluster_info.write().unwrap() = Some(test_validator.cluster_info());
|
||||
*admin_service_post_init.write().unwrap() =
|
||||
Some(admin_rpc_service::AdminRpcRequestMetadataPostInit {
|
||||
bank_forks: test_validator.bank_forks(),
|
||||
cluster_info: test_validator.cluster_info(),
|
||||
vote_account: test_validator.vote_account_address(),
|
||||
});
|
||||
if let Some(dashboard) = dashboard {
|
||||
dashboard.run(Duration::from_millis(250));
|
||||
}
|
||||
|
|
|
@ -1668,6 +1668,12 @@ pub fn main() {
|
|||
.validator(is_keypair)
|
||||
.help("Validator identity keypair")
|
||||
)
|
||||
.arg(
|
||||
clap::Arg::with_name("require_tower")
|
||||
.long("require-tower")
|
||||
.takes_value(false)
|
||||
.help("Refuse to set the validator identity if saved tower state is not found"),
|
||||
)
|
||||
.after_help("Note: the new identity only applies to the \
|
||||
currently running validator instance")
|
||||
)
|
||||
|
@ -1839,6 +1845,7 @@ pub fn main() {
|
|||
return;
|
||||
}
|
||||
("set-identity", Some(subcommand_matches)) => {
|
||||
let require_tower = subcommand_matches.is_present("require_tower");
|
||||
let identity_keypair = value_t_or_exit!(subcommand_matches, "identity", String);
|
||||
|
||||
let identity_keypair = fs::canonicalize(&identity_keypair).unwrap_or_else(|err| {
|
||||
|
@ -1852,7 +1859,7 @@ pub fn main() {
|
|||
.block_on(async move {
|
||||
admin_client
|
||||
.await?
|
||||
.set_identity(identity_keypair.display().to_string())
|
||||
.set_identity(identity_keypair.display().to_string(), require_tower)
|
||||
.await
|
||||
})
|
||||
.unwrap_or_else(|err| {
|
||||
|
@ -2504,7 +2511,7 @@ pub fn main() {
|
|||
let _ledger_write_guard = lock_ledger(&ledger_path, &mut ledger_lock);
|
||||
|
||||
let start_progress = Arc::new(RwLock::new(ValidatorStartProgress::default()));
|
||||
let admin_service_cluster_info = Arc::new(RwLock::new(None));
|
||||
let admin_service_post_init = Arc::new(RwLock::new(None));
|
||||
admin_rpc_service::run(
|
||||
&ledger_path,
|
||||
admin_rpc_service::AdminRpcRequestMetadata {
|
||||
|
@ -2513,7 +2520,7 @@ pub fn main() {
|
|||
validator_exit: validator_config.validator_exit.clone(),
|
||||
start_progress: start_progress.clone(),
|
||||
authorized_voter_keypairs: authorized_voter_keypairs.clone(),
|
||||
cluster_info: admin_service_cluster_info.clone(),
|
||||
post_init: admin_service_post_init.clone(),
|
||||
tower_storage: validator_config.tower_storage.clone(),
|
||||
},
|
||||
);
|
||||
|
@ -2658,7 +2665,12 @@ pub fn main() {
|
|||
start_progress,
|
||||
socket_addr_space,
|
||||
);
|
||||
*admin_service_cluster_info.write().unwrap() = Some(validator.cluster_info.clone());
|
||||
*admin_service_post_init.write().unwrap() =
|
||||
Some(admin_rpc_service::AdminRpcRequestMetadataPostInit {
|
||||
bank_forks: validator.bank_forks.clone(),
|
||||
cluster_info: validator.cluster_info.clone(),
|
||||
vote_account,
|
||||
});
|
||||
|
||||
if let Some(filename) = init_complete_file {
|
||||
File::create(filename).unwrap_or_else(|_| {
|
||||
|
|
Loading…
Reference in New Issue