`solana catchup` now detects when you try to catchup to yourself (#8635)

automerge
This commit is contained in:
Grimes 2020-03-04 14:44:21 -08:00 committed by GitHub
parent f23dc11a86
commit f89c22b5ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 5 deletions

View File

@ -394,6 +394,19 @@ pub fn process_catchup(
)
};
let reported_node_pubkey = node_client.get_identity()?;
if reported_node_pubkey != *node_pubkey {
return Err(format!(
"The identity reported by node RPC URL does not match. Expected: {:?}. Reported: {:?}",
node_pubkey, reported_node_pubkey
)
.into());
}
if rpc_client.get_identity()? == *node_pubkey {
return Err("Both RPC URLs reference the same node, unable to monitor for catchup. Try a different --url".into());
}
let progress_bar = new_spinner_progress_bar();
progress_bar.set_message("Connecting...");

View File

@ -6,8 +6,8 @@ use crate::{
rpc_request::RpcRequest,
rpc_response::{
Response, RpcAccount, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo,
RpcEpochInfo, RpcFeeRateGovernor, RpcKeyedAccount, RpcLeaderSchedule, RpcResponse,
RpcVersionInfo, RpcVoteAccountStatus,
RpcEpochInfo, RpcFeeRateGovernor, RpcIdentity, RpcKeyedAccount, RpcLeaderSchedule,
RpcResponse, RpcVersionInfo, RpcVoteAccountStatus,
},
};
use bincode::serialize;
@ -356,6 +356,34 @@ impl RpcClient {
})
}
pub fn get_identity(&self) -> io::Result<Pubkey> {
let response = self
.client
.send(&RpcRequest::GetIdentity, Value::Null, 0)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetIdentity request failure: {:?}", err),
)
})?;
serde_json::from_value(response)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetIdentity failure: {:?}", err),
)
})
.and_then(|rpc_identity: RpcIdentity| {
rpc_identity.identity.parse::<Pubkey>().map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetIdentity invalid pubkey failure: {:?}", err),
)
})
})
}
pub fn get_inflation(&self) -> io::Result<Inflation> {
let response = self
.client

View File

@ -15,6 +15,7 @@ pub enum RpcRequest {
GetEpochInfo,
GetEpochSchedule,
GetGenesisHash,
GetIdentity,
GetInflation,
GetLeaderSchedule,
GetNumBlocksSinceSignatureConfirmation,
@ -55,6 +56,7 @@ impl RpcRequest {
RpcRequest::GetEpochInfo => "getEpochInfo",
RpcRequest::GetEpochSchedule => "getEpochSchedule",
RpcRequest::GetGenesisHash => "getGenesisHash",
RpcRequest::GetIdentity => "getIdentity",
RpcRequest::GetInflation => "getInflation",
RpcRequest::GetLeaderSchedule => "getLeaderSchedule",
RpcRequest::GetNumBlocksSinceSignatureConfirmation => {

View File

@ -241,6 +241,13 @@ pub struct RpcVersionInfo {
pub solana_core: String,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct RpcIdentity {
/// The current node identity pubkey
pub identity: String,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct RpcVoteAccountStatus {

View File

@ -9,9 +9,9 @@ use jsonrpc_core::{Error, Metadata, Result};
use jsonrpc_derive::rpc;
use solana_client::rpc_response::{
Response, RpcAccount, RpcBlockCommitment, RpcBlockhashFeeCalculator, RpcConfirmedBlock,
RpcContactInfo, RpcEpochInfo, RpcFeeRateGovernor, RpcKeyedAccount, RpcLeaderSchedule,
RpcResponseContext, RpcSignatureConfirmation, RpcStorageTurn, RpcTransactionEncoding,
RpcVersionInfo, RpcVoteAccountInfo, RpcVoteAccountStatus,
RpcContactInfo, RpcEpochInfo, RpcFeeRateGovernor, RpcIdentity, RpcKeyedAccount,
RpcLeaderSchedule, RpcResponseContext, RpcSignatureConfirmation, RpcStorageTurn,
RpcTransactionEncoding, RpcVersionInfo, RpcVoteAccountInfo, RpcVoteAccountStatus,
};
use solana_faucet::faucet::request_airdrop_transaction;
use solana_ledger::{
@ -49,6 +49,7 @@ fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
pub struct JsonRpcConfig {
pub enable_validator_exit: bool,
pub enable_get_confirmed_block: bool,
pub identity_pubkey: Pubkey,
pub faucet_addr: Option<SocketAddr>,
}
@ -594,6 +595,9 @@ pub trait RpcSol {
commitment: Option<CommitmentConfig>,
) -> Result<Option<RpcSignatureConfirmation>>;
#[rpc(meta, name = "getIdentity")]
fn get_identity(&self, meta: Self::Metadata) -> Result<RpcIdentity>;
#[rpc(meta, name = "getVersion")]
fn get_version(&self, meta: Self::Metadata) -> Result<RpcVersionInfo>;
@ -1076,6 +1080,18 @@ impl RpcSol for RpcSolImpl {
meta.request_processor.read().unwrap().validator_exit()
}
fn get_identity(&self, meta: Self::Metadata) -> Result<RpcIdentity> {
Ok(RpcIdentity {
identity: meta
.request_processor
.read()
.unwrap()
.config
.identity_pubkey
.to_string(),
})
}
fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo> {
Ok(RpcVersionInfo {
solana_core: solana_clap_utils::version!().to_string(),
@ -1269,6 +1285,7 @@ pub mod tests {
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
JsonRpcConfig {
enable_get_confirmed_block: true,
identity_pubkey: *pubkey,
..JsonRpcConfig::default()
},
bank_forks.clone(),
@ -1996,6 +2013,27 @@ pub mod tests {
assert_eq!(exit.load(Ordering::Relaxed), true);
}
#[test]
fn test_rpc_get_identity() {
let bob_pubkey = Pubkey::new_rand();
let RpcHandler { io, meta, .. } = start_rpc_handler_with_tx(&bob_pubkey);
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getIdentity"}}"#);
let res = io.handle_request_sync(&req, meta);
let expected = json!({
"jsonrpc": "2.0",
"result": {
"identity": bob_pubkey.to_string()
},
"id": 1
});
let expected: Response =
serde_json::from_value(expected).expect("expected response deserialization");
let result: Response = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
assert_eq!(expected, result);
}
#[test]
fn test_rpc_get_version() {
let bob_pubkey = Pubkey::new_rand();

View File

@ -26,6 +26,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
* [getEpochSchedule](jsonrpc-api.md#getepochschedule)
* [getFeeRateGovernor](jsonrpc-api.md#getfeerategovernor)
* [getGenesisHash](jsonrpc-api.md#getgenesishash)
* [getIdentity](jsonrpc-api.md#getidentity)
* [getInflation](jsonrpc-api.md#getinflation)
* [getLeaderSchedule](jsonrpc-api.md#getleaderschedule)
* [getMinimumBalanceForRentExemption](jsonrpc-api.md#getminimumbalanceforrentexemption)
@ -454,6 +455,29 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
{"jsonrpc":"2.0","result":"GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC","id":1}
```
### getIdentity
Returns the identity pubkey for the current node
#### Parameters:
None
#### Results:
The result field will be a JSON object with the following fields:
* `identity`, the identity pubkey of the current node \(as a base-58 encoded string\)
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getIdentity"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":{"identity": "2r1F4iWqVcb8M1DbAjQuFpebkQHY9hcVU4WuW2DJBppN"},"id":1}
```
### getInflation
Returns the inflation configuration of the cluster

View File

@ -903,6 +903,7 @@ pub fn main() {
rpc_config: JsonRpcConfig {
enable_validator_exit: matches.is_present("enable_rpc_exit"),
enable_get_confirmed_block: matches.is_present("enable_rpc_get_confirmed_block"),
identity_pubkey: identity_keypair.pubkey(),
faucet_addr: matches.value_of("rpc_faucet_addr").map(|address| {
solana_net_utils::parse_host_port(address).expect("failed to parse faucet address")
}),