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:
parent
fbcb4d8216
commit
1884275882
|
@ -152,6 +152,10 @@ pub trait AdminRpc {
|
||||||
#[rpc(meta, name = "addAuthorizedVoter")]
|
#[rpc(meta, name = "addAuthorizedVoter")]
|
||||||
fn add_authorized_voter(&self, meta: Self::Metadata, keypair_file: String) -> Result<()>;
|
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")]
|
#[rpc(meta, name = "removeAllAuthorizedVoters")]
|
||||||
fn remove_all_authorized_voters(&self, meta: Self::Metadata) -> Result<()>;
|
fn remove_all_authorized_voters(&self, meta: Self::Metadata) -> Result<()>;
|
||||||
|
|
||||||
|
@ -163,6 +167,14 @@ pub trait AdminRpc {
|
||||||
require_tower: bool,
|
require_tower: bool,
|
||||||
) -> Result<()>;
|
) -> 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")]
|
#[rpc(meta, name = "contactInfo")]
|
||||||
fn contact_info(&self, meta: Self::Metadata) -> Result<AdminRpcContactInfo>;
|
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)
|
let authorized_voter = read_keypair_file(keypair_file)
|
||||||
.map_err(|err| jsonrpc_core::error::Error::invalid_params(format!("{}", err)))?;
|
.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
|
fn add_authorized_voter_from_bytes(
|
||||||
.iter()
|
&self,
|
||||||
.any(|x| x.pubkey() == authorized_voter.pubkey())
|
meta: Self::Metadata,
|
||||||
{
|
keypair: Vec<u8>,
|
||||||
Err(jsonrpc_core::error::Error::invalid_params(
|
) -> Result<()> {
|
||||||
"Authorized voter already present",
|
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<()> {
|
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| {
|
meta.with_post_init(|post_init| {
|
||||||
if require_tower {
|
if require_tower {
|
||||||
let _ = Tower::restore(meta.tower_storage.as_ref(), &identity_keypair.pubkey())
|
let _ = Tower::restore(meta.tower_storage.as_ref(), &identity_keypair.pubkey())
|
||||||
|
@ -276,10 +344,6 @@ impl AdminRpc for AdminRpcImpl {
|
||||||
Ok(())
|
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
|
// Start the Admin RPC interface
|
||||||
|
|
|
@ -66,7 +66,7 @@ use {
|
||||||
commitment_config::CommitmentConfig,
|
commitment_config::CommitmentConfig,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{read_keypair, Keypair, Signer},
|
||||||
},
|
},
|
||||||
solana_send_transaction_service::send_transaction_service::{
|
solana_send_transaction_service::send_transaction_service::{
|
||||||
self, MAX_BATCH_SEND_RATE_MS, MAX_TRANSACTION_BATCH_SIZE,
|
self, MAX_BATCH_SEND_RATE_MS, MAX_TRANSACTION_BATCH_SIZE,
|
||||||
|
@ -1822,9 +1822,11 @@ pub fn main() {
|
||||||
Arg::with_name("authorized_voter_keypair")
|
Arg::with_name("authorized_voter_keypair")
|
||||||
.index(1)
|
.index(1)
|
||||||
.value_name("KEYPAIR")
|
.value_name("KEYPAIR")
|
||||||
|
.required(false)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.validator(is_keypair)
|
.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 \
|
.after_help("Note: the new authorized voter only applies to the \
|
||||||
currently running validator instance")
|
currently running validator instance")
|
||||||
|
@ -1867,9 +1869,11 @@ pub fn main() {
|
||||||
Arg::with_name("identity")
|
Arg::with_name("identity")
|
||||||
.index(1)
|
.index(1)
|
||||||
.value_name("KEYPAIR")
|
.value_name("KEYPAIR")
|
||||||
|
.required(false)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.validator(is_keypair)
|
.validator(is_keypair)
|
||||||
.help("Validator identity keypair")
|
.help("Path to validator identity keypair \
|
||||||
|
[default: read JSON keypair from stdin]")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
clap::Arg::with_name("require_tower")
|
clap::Arg::with_name("require_tower")
|
||||||
|
@ -1938,36 +1942,64 @@ pub fn main() {
|
||||||
("authorized-voter", Some(authorized_voter_subcommand_matches)) => {
|
("authorized-voter", Some(authorized_voter_subcommand_matches)) => {
|
||||||
match authorized_voter_subcommand_matches.subcommand() {
|
match authorized_voter_subcommand_matches.subcommand() {
|
||||||
("add", Some(subcommand_matches)) => {
|
("add", Some(subcommand_matches)) => {
|
||||||
let authorized_voter_keypair =
|
if let Some(authorized_voter_keypair) =
|
||||||
value_t_or_exit!(subcommand_matches, "authorized_voter_keypair", String);
|
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)
|
let admin_client = admin_rpc_service::connect(&ledger_path);
|
||||||
.unwrap_or_else(|err| {
|
admin_rpc_service::runtime()
|
||||||
println!(
|
.block_on(async move {
|
||||||
"Unable to access path: {}: {:?}",
|
admin_client
|
||||||
authorized_voter_keypair, err
|
.await?
|
||||||
);
|
.add_authorized_voter(
|
||||||
exit(1);
|
authorized_voter_keypair.display().to_string(),
|
||||||
});
|
)
|
||||||
println!(
|
.await
|
||||||
"Adding authorized voter: {}",
|
})
|
||||||
authorized_voter_keypair.display()
|
.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;
|
return;
|
||||||
}
|
}
|
||||||
("remove-all", _) => {
|
("remove-all", _) => {
|
||||||
|
@ -2049,26 +2081,54 @@ pub fn main() {
|
||||||
}
|
}
|
||||||
("set-identity", Some(subcommand_matches)) => {
|
("set-identity", Some(subcommand_matches)) => {
|
||||||
let require_tower = subcommand_matches.is_present("require_tower");
|
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| {
|
if let Some(identity_keypair) = value_t!(subcommand_matches, "identity", String).ok() {
|
||||||
println!("Unable to access path: {}: {:?}", identity_keypair, err);
|
let identity_keypair = fs::canonicalize(&identity_keypair).unwrap_or_else(|err| {
|
||||||
exit(1);
|
println!("Unable to access path: {}: {:?}", identity_keypair, err);
|
||||||
});
|
|
||||||
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);
|
|
||||||
exit(1);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
("set-log-filter", Some(subcommand_matches)) => {
|
("set-log-filter", Some(subcommand_matches)) => {
|
||||||
|
|
Loading…
Reference in New Issue