solana catchup
now detects when you try to catchup to yourself (#8635)
automerge
This commit is contained in:
@ -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();
|
let progress_bar = new_spinner_progress_bar();
|
||||||
progress_bar.set_message("Connecting...");
|
progress_bar.set_message("Connecting...");
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@ use crate::{
|
|||||||
rpc_request::RpcRequest,
|
rpc_request::RpcRequest,
|
||||||
rpc_response::{
|
rpc_response::{
|
||||||
Response, RpcAccount, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo,
|
Response, RpcAccount, RpcBlockhashFeeCalculator, RpcConfirmedBlock, RpcContactInfo,
|
||||||
RpcEpochInfo, RpcFeeRateGovernor, RpcKeyedAccount, RpcLeaderSchedule, RpcResponse,
|
RpcEpochInfo, RpcFeeRateGovernor, RpcIdentity, RpcKeyedAccount, RpcLeaderSchedule,
|
||||||
RpcVersionInfo, RpcVoteAccountStatus,
|
RpcResponse, RpcVersionInfo, RpcVoteAccountStatus,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use bincode::serialize;
|
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> {
|
pub fn get_inflation(&self) -> io::Result<Inflation> {
|
||||||
let response = self
|
let response = self
|
||||||
.client
|
.client
|
||||||
|
@ -15,6 +15,7 @@ pub enum RpcRequest {
|
|||||||
GetEpochInfo,
|
GetEpochInfo,
|
||||||
GetEpochSchedule,
|
GetEpochSchedule,
|
||||||
GetGenesisHash,
|
GetGenesisHash,
|
||||||
|
GetIdentity,
|
||||||
GetInflation,
|
GetInflation,
|
||||||
GetLeaderSchedule,
|
GetLeaderSchedule,
|
||||||
GetNumBlocksSinceSignatureConfirmation,
|
GetNumBlocksSinceSignatureConfirmation,
|
||||||
@ -55,6 +56,7 @@ impl RpcRequest {
|
|||||||
RpcRequest::GetEpochInfo => "getEpochInfo",
|
RpcRequest::GetEpochInfo => "getEpochInfo",
|
||||||
RpcRequest::GetEpochSchedule => "getEpochSchedule",
|
RpcRequest::GetEpochSchedule => "getEpochSchedule",
|
||||||
RpcRequest::GetGenesisHash => "getGenesisHash",
|
RpcRequest::GetGenesisHash => "getGenesisHash",
|
||||||
|
RpcRequest::GetIdentity => "getIdentity",
|
||||||
RpcRequest::GetInflation => "getInflation",
|
RpcRequest::GetInflation => "getInflation",
|
||||||
RpcRequest::GetLeaderSchedule => "getLeaderSchedule",
|
RpcRequest::GetLeaderSchedule => "getLeaderSchedule",
|
||||||
RpcRequest::GetNumBlocksSinceSignatureConfirmation => {
|
RpcRequest::GetNumBlocksSinceSignatureConfirmation => {
|
||||||
|
@ -241,6 +241,13 @@ pub struct RpcVersionInfo {
|
|||||||
pub solana_core: String,
|
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)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcVoteAccountStatus {
|
pub struct RpcVoteAccountStatus {
|
||||||
|
@ -9,9 +9,9 @@ use jsonrpc_core::{Error, Metadata, Result};
|
|||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
use solana_client::rpc_response::{
|
use solana_client::rpc_response::{
|
||||||
Response, RpcAccount, RpcBlockCommitment, RpcBlockhashFeeCalculator, RpcConfirmedBlock,
|
Response, RpcAccount, RpcBlockCommitment, RpcBlockhashFeeCalculator, RpcConfirmedBlock,
|
||||||
RpcContactInfo, RpcEpochInfo, RpcFeeRateGovernor, RpcKeyedAccount, RpcLeaderSchedule,
|
RpcContactInfo, RpcEpochInfo, RpcFeeRateGovernor, RpcIdentity, RpcKeyedAccount,
|
||||||
RpcResponseContext, RpcSignatureConfirmation, RpcStorageTurn, RpcTransactionEncoding,
|
RpcLeaderSchedule, RpcResponseContext, RpcSignatureConfirmation, RpcStorageTurn,
|
||||||
RpcVersionInfo, RpcVoteAccountInfo, RpcVoteAccountStatus,
|
RpcTransactionEncoding, RpcVersionInfo, RpcVoteAccountInfo, RpcVoteAccountStatus,
|
||||||
};
|
};
|
||||||
use solana_faucet::faucet::request_airdrop_transaction;
|
use solana_faucet::faucet::request_airdrop_transaction;
|
||||||
use solana_ledger::{
|
use solana_ledger::{
|
||||||
@ -49,6 +49,7 @@ fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
|
|||||||
pub struct JsonRpcConfig {
|
pub struct JsonRpcConfig {
|
||||||
pub enable_validator_exit: bool,
|
pub enable_validator_exit: bool,
|
||||||
pub enable_get_confirmed_block: bool,
|
pub enable_get_confirmed_block: bool,
|
||||||
|
pub identity_pubkey: Pubkey,
|
||||||
pub faucet_addr: Option<SocketAddr>,
|
pub faucet_addr: Option<SocketAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,6 +595,9 @@ pub trait RpcSol {
|
|||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> Result<Option<RpcSignatureConfirmation>>;
|
) -> Result<Option<RpcSignatureConfirmation>>;
|
||||||
|
|
||||||
|
#[rpc(meta, name = "getIdentity")]
|
||||||
|
fn get_identity(&self, meta: Self::Metadata) -> Result<RpcIdentity>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getVersion")]
|
#[rpc(meta, name = "getVersion")]
|
||||||
fn get_version(&self, meta: Self::Metadata) -> Result<RpcVersionInfo>;
|
fn get_version(&self, meta: Self::Metadata) -> Result<RpcVersionInfo>;
|
||||||
|
|
||||||
@ -1076,6 +1080,18 @@ impl RpcSol for RpcSolImpl {
|
|||||||
meta.request_processor.read().unwrap().validator_exit()
|
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> {
|
fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo> {
|
||||||
Ok(RpcVersionInfo {
|
Ok(RpcVersionInfo {
|
||||||
solana_core: solana_clap_utils::version!().to_string(),
|
solana_core: solana_clap_utils::version!().to_string(),
|
||||||
@ -1269,6 +1285,7 @@ pub mod tests {
|
|||||||
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
|
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
|
||||||
JsonRpcConfig {
|
JsonRpcConfig {
|
||||||
enable_get_confirmed_block: true,
|
enable_get_confirmed_block: true,
|
||||||
|
identity_pubkey: *pubkey,
|
||||||
..JsonRpcConfig::default()
|
..JsonRpcConfig::default()
|
||||||
},
|
},
|
||||||
bank_forks.clone(),
|
bank_forks.clone(),
|
||||||
@ -1996,6 +2013,27 @@ pub mod tests {
|
|||||||
assert_eq!(exit.load(Ordering::Relaxed), true);
|
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]
|
#[test]
|
||||||
fn test_rpc_get_version() {
|
fn test_rpc_get_version() {
|
||||||
let bob_pubkey = Pubkey::new_rand();
|
let bob_pubkey = Pubkey::new_rand();
|
||||||
|
@ -26,6 +26,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
|
|||||||
* [getEpochSchedule](jsonrpc-api.md#getepochschedule)
|
* [getEpochSchedule](jsonrpc-api.md#getepochschedule)
|
||||||
* [getFeeRateGovernor](jsonrpc-api.md#getfeerategovernor)
|
* [getFeeRateGovernor](jsonrpc-api.md#getfeerategovernor)
|
||||||
* [getGenesisHash](jsonrpc-api.md#getgenesishash)
|
* [getGenesisHash](jsonrpc-api.md#getgenesishash)
|
||||||
|
* [getIdentity](jsonrpc-api.md#getidentity)
|
||||||
* [getInflation](jsonrpc-api.md#getinflation)
|
* [getInflation](jsonrpc-api.md#getinflation)
|
||||||
* [getLeaderSchedule](jsonrpc-api.md#getleaderschedule)
|
* [getLeaderSchedule](jsonrpc-api.md#getleaderschedule)
|
||||||
* [getMinimumBalanceForRentExemption](jsonrpc-api.md#getminimumbalanceforrentexemption)
|
* [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}
|
{"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
|
### getInflation
|
||||||
|
|
||||||
Returns the inflation configuration of the cluster
|
Returns the inflation configuration of the cluster
|
||||||
|
@ -903,6 +903,7 @@ pub fn main() {
|
|||||||
rpc_config: JsonRpcConfig {
|
rpc_config: JsonRpcConfig {
|
||||||
enable_validator_exit: matches.is_present("enable_rpc_exit"),
|
enable_validator_exit: matches.is_present("enable_rpc_exit"),
|
||||||
enable_get_confirmed_block: matches.is_present("enable_rpc_get_confirmed_block"),
|
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| {
|
faucet_addr: matches.value_of("rpc_faucet_addr").map(|address| {
|
||||||
solana_net_utils::parse_host_port(address).expect("failed to parse faucet address")
|
solana_net_utils::parse_host_port(address).expect("failed to parse faucet address")
|
||||||
}),
|
}),
|
||||||
|
Reference in New Issue
Block a user