Support reading keypair from stdin in `solana-validator set-identity`/`solana-validator authorized-voter add` (#26056)

* Add keypair reading from stdin in `validator set-identity`

* Add keypair reading from stdin in `validator authorized-voter add`
This commit is contained in:
Ivan Mironov 2022-06-24 21:21:03 +05:00 committed by GitHub
parent fbcb4d8216
commit 1884275882
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 187 additions and 63 deletions

View File

@ -152,6 +152,10 @@ pub trait AdminRpc {
#[rpc(meta, name = "addAuthorizedVoter")]
fn add_authorized_voter(&self, meta: Self::Metadata, keypair_file: String) -> Result<()>;
#[rpc(meta, name = "addAuthorizedVoterFromBytes")]
fn add_authorized_voter_from_bytes(&self, meta: Self::Metadata, keypair: Vec<u8>)
-> Result<()>;
#[rpc(meta, name = "removeAllAuthorizedVoters")]
fn remove_all_authorized_voters(&self, meta: Self::Metadata) -> Result<()>;
@ -163,6 +167,14 @@ pub trait AdminRpc {
require_tower: bool,
) -> Result<()>;
#[rpc(meta, name = "setIdentityFromBytes")]
fn set_identity_from_bytes(
&self,
meta: Self::Metadata,
identity_keypair: Vec<u8>,
require_tower: bool,
) -> Result<()>;
#[rpc(meta, name = "contactInfo")]
fn contact_info(&self, meta: Self::Metadata) -> Result<AdminRpcContactInfo>;
}
@ -220,19 +232,24 @@ impl AdminRpc for AdminRpcImpl {
let authorized_voter = read_keypair_file(keypair_file)
.map_err(|err| jsonrpc_core::error::Error::invalid_params(format!("{}", err)))?;
let mut authorized_voter_keypairs = meta.authorized_voter_keypairs.write().unwrap();
AdminRpcImpl::add_authorized_voter_keypair(meta, authorized_voter)
}
if authorized_voter_keypairs
.iter()
.any(|x| x.pubkey() == authorized_voter.pubkey())
{
Err(jsonrpc_core::error::Error::invalid_params(
"Authorized voter already present",
fn add_authorized_voter_from_bytes(
&self,
meta: Self::Metadata,
keypair: Vec<u8>,
) -> Result<()> {
debug!("add_authorized_voter_from_bytes request received");
let authorized_voter = Keypair::from_bytes(&keypair).map_err(|err| {
jsonrpc_core::error::Error::invalid_params(format!(
"Failed to read authorized voter keypair from provided byte array: {}",
err
))
} else {
authorized_voter_keypairs.push(Arc::new(authorized_voter));
Ok(())
}
})?;
AdminRpcImpl::add_authorized_voter_keypair(meta, authorized_voter)
}
fn remove_all_authorized_voters(&self, meta: Self::Metadata) -> Result<()> {
@ -256,6 +273,57 @@ impl AdminRpc for AdminRpcImpl {
))
})?;
AdminRpcImpl::set_identity_keypair(meta, identity_keypair, require_tower)
}
fn set_identity_from_bytes(
&self,
meta: Self::Metadata,
identity_keypair: Vec<u8>,
require_tower: bool,
) -> Result<()> {
debug!("set_identity_from_bytes request received");
let identity_keypair = Keypair::from_bytes(&identity_keypair).map_err(|err| {
jsonrpc_core::error::Error::invalid_params(format!(
"Failed to read identity keypair from provided byte array: {}",
err
))
})?;
AdminRpcImpl::set_identity_keypair(meta, identity_keypair, require_tower)
}
fn contact_info(&self, meta: Self::Metadata) -> Result<AdminRpcContactInfo> {
meta.with_post_init(|post_init| Ok(post_init.cluster_info.my_contact_info().into()))
}
}
impl AdminRpcImpl {
fn add_authorized_voter_keypair(
meta: AdminRpcRequestMetadata,
authorized_voter: Keypair,
) -> Result<()> {
let mut authorized_voter_keypairs = meta.authorized_voter_keypairs.write().unwrap();
if authorized_voter_keypairs
.iter()
.any(|x| x.pubkey() == authorized_voter.pubkey())
{
Err(jsonrpc_core::error::Error::invalid_params(
"Authorized voter already present",
))
} else {
authorized_voter_keypairs.push(Arc::new(authorized_voter));
Ok(())
}
}
fn set_identity_keypair(
meta: AdminRpcRequestMetadata,
identity_keypair: Keypair,
require_tower: bool,
) -> Result<()> {
meta.with_post_init(|post_init| {
if require_tower {
let _ = Tower::restore(meta.tower_storage.as_ref(), &identity_keypair.pubkey())
@ -276,10 +344,6 @@ impl AdminRpc for AdminRpcImpl {
Ok(())
})
}
fn contact_info(&self, meta: Self::Metadata) -> Result<AdminRpcContactInfo> {
meta.with_post_init(|post_init| Ok(post_init.cluster_info.my_contact_info().into()))
}
}
// Start the Admin RPC interface

View File

@ -66,7 +66,7 @@ use {
commitment_config::CommitmentConfig,
hash::Hash,
pubkey::Pubkey,
signature::{Keypair, Signer},
signature::{read_keypair, Keypair, Signer},
},
solana_send_transaction_service::send_transaction_service::{
self, MAX_BATCH_SEND_RATE_MS, MAX_TRANSACTION_BATCH_SIZE,
@ -1822,9 +1822,11 @@ pub fn main() {
Arg::with_name("authorized_voter_keypair")
.index(1)
.value_name("KEYPAIR")
.required(false)
.takes_value(true)
.validator(is_keypair)
.help("Keypair of the authorized voter to add"),
.help("Path to keypair of the authorized voter to add \
[default: read JSON keypair from stdin]"),
)
.after_help("Note: the new authorized voter only applies to the \
currently running validator instance")
@ -1867,9 +1869,11 @@ pub fn main() {
Arg::with_name("identity")
.index(1)
.value_name("KEYPAIR")
.required(false)
.takes_value(true)
.validator(is_keypair)
.help("Validator identity keypair")
.help("Path to validator identity keypair \
[default: read JSON keypair from stdin]")
)
.arg(
clap::Arg::with_name("require_tower")
@ -1938,36 +1942,64 @@ pub fn main() {
("authorized-voter", Some(authorized_voter_subcommand_matches)) => {
match authorized_voter_subcommand_matches.subcommand() {
("add", Some(subcommand_matches)) => {
let authorized_voter_keypair =
value_t_or_exit!(subcommand_matches, "authorized_voter_keypair", String);
if let Some(authorized_voter_keypair) =
value_t!(subcommand_matches, "authorized_voter_keypair", String).ok()
{
let authorized_voter_keypair = fs::canonicalize(&authorized_voter_keypair)
.unwrap_or_else(|err| {
println!(
"Unable to access path: {}: {:?}",
authorized_voter_keypair, err
);
exit(1);
});
println!(
"Adding authorized voter path: {}",
authorized_voter_keypair.display()
);
let authorized_voter_keypair = fs::canonicalize(&authorized_voter_keypair)
.unwrap_or_else(|err| {
println!(
"Unable to access path: {}: {:?}",
authorized_voter_keypair, err
);
exit(1);
});
println!(
"Adding authorized voter: {}",
authorized_voter_keypair.display()
);
let admin_client = admin_rpc_service::connect(&ledger_path);
admin_rpc_service::runtime()
.block_on(async move {
admin_client
.await?
.add_authorized_voter(
authorized_voter_keypair.display().to_string(),
)
.await
})
.unwrap_or_else(|err| {
println!("addAuthorizedVoter request failed: {}", err);
exit(1);
});
} else {
let mut stdin = std::io::stdin();
let authorized_voter_keypair =
read_keypair(&mut stdin).unwrap_or_else(|err| {
println!("Unable to read JSON keypair from stdin: {:?}", err);
exit(1);
});
println!(
"Adding authorized voter: {}",
authorized_voter_keypair.pubkey()
);
let admin_client = admin_rpc_service::connect(&ledger_path);
admin_rpc_service::runtime()
.block_on(async move {
admin_client
.await?
.add_authorized_voter_from_bytes(Vec::from(
authorized_voter_keypair.to_bytes(),
))
.await
})
.unwrap_or_else(|err| {
println!("addAuthorizedVoterFromBytes request failed: {}", err);
exit(1);
});
}
let admin_client = admin_rpc_service::connect(&ledger_path);
admin_rpc_service::runtime()
.block_on(async move {
admin_client
.await?
.add_authorized_voter(
authorized_voter_keypair.display().to_string(),
)
.await
})
.unwrap_or_else(|err| {
println!("addAuthorizedVoter request failed: {}", err);
exit(1);
});
return;
}
("remove-all", _) => {
@ -2049,26 +2081,54 @@ pub fn main() {
}
("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| {
println!("Unable to access path: {}: {:?}", identity_keypair, err);
exit(1);
});
println!("Validator identity: {}", identity_keypair.display());
let admin_client = admin_rpc_service::connect(&ledger_path);
admin_rpc_service::runtime()
.block_on(async move {
admin_client
.await?
.set_identity(identity_keypair.display().to_string(), require_tower)
.await
})
.unwrap_or_else(|err| {
println!("setIdentity request failed: {}", err);
if let Some(identity_keypair) = value_t!(subcommand_matches, "identity", String).ok() {
let identity_keypair = fs::canonicalize(&identity_keypair).unwrap_or_else(|err| {
println!("Unable to access path: {}: {:?}", identity_keypair, err);
exit(1);
});
println!(
"New validator identity path: {}",
identity_keypair.display()
);
let admin_client = admin_rpc_service::connect(&ledger_path);
admin_rpc_service::runtime()
.block_on(async move {
admin_client
.await?
.set_identity(identity_keypair.display().to_string(), require_tower)
.await
})
.unwrap_or_else(|err| {
println!("setIdentity request failed: {}", err);
exit(1);
});
} else {
let mut stdin = std::io::stdin();
let identity_keypair = read_keypair(&mut stdin).unwrap_or_else(|err| {
println!("Unable to read JSON keypair from stdin: {:?}", err);
exit(1);
});
println!("New validator identity: {}", identity_keypair.pubkey());
let admin_client = admin_rpc_service::connect(&ledger_path);
admin_rpc_service::runtime()
.block_on(async move {
admin_client
.await?
.set_identity_from_bytes(
Vec::from(identity_keypair.to_bytes()),
require_tower,
)
.await
})
.unwrap_or_else(|err| {
println!("setIdentityFromBytes request failed: {}", err);
exit(1);
});
};
return;
}
("set-log-filter", Some(subcommand_matches)) => {