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