diff --git a/client/src/http_sender.rs b/client/src/http_sender.rs index 9d54eb22cc..43ca3d7d96 100644 --- a/client/src/http_sender.rs +++ b/client/src/http_sender.rs @@ -86,8 +86,8 @@ impl RpcSender for HttpSender { } }, rpc_custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHLY => { - match serde_json::from_value::(json["error"]["data"].clone()) { - Ok(rpc_custom_error::RpcNodeUnhealthyErrorData { num_slots_behind}) => RpcResponseErrorData::NodeUnhealthy {num_slots_behind}, + match serde_json::from_value::(json["error"]["data"].clone()) { + Ok(rpc_custom_error::NodeUnhealthyErrorData {num_slots_behind}) => RpcResponseErrorData::NodeUnhealthy {num_slots_behind}, Err(_err) => { RpcResponseErrorData::Empty } diff --git a/client/src/rpc_custom_error.rs b/client/src/rpc_custom_error.rs index 6d9abf6f3a..582872238b 100644 --- a/client/src/rpc_custom_error.rs +++ b/client/src/rpc_custom_error.rs @@ -26,8 +26,8 @@ pub enum RpcCustomError { BlockNotAvailable { slot: Slot, }, - RpcNodeUnhealthy { - num_slots_behind: Slot, + NodeUnhealthy { + num_slots_behind: Option, }, TransactionPrecompileVerificationFailure(solana_sdk::transaction::TransactionError), SlotSkipped { @@ -38,8 +38,8 @@ pub enum RpcCustomError { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct RpcNodeUnhealthyErrorData { - pub num_slots_behind: Slot, +pub struct NodeUnhealthyErrorData { + pub num_slots_behind: Option, } impl From for Error { @@ -75,10 +75,14 @@ impl From for Error { message: format!("Block not available for slot {}", slot), data: None, }, - RpcCustomError::RpcNodeUnhealthy { num_slots_behind } => Self { + RpcCustomError::NodeUnhealthy { num_slots_behind } => Self { code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_NODE_UNHEALTHLY), - message: format!("RPC node is behind by {} slots", num_slots_behind), - data: Some(serde_json::json!(RpcNodeUnhealthyErrorData { + message: if let Some(num_slots_behind) = num_slots_behind { + format!("Node is behind by {} slots", num_slots_behind) + } else { + "Node is unhealthy".to_string() + }, + data: Some(serde_json::json!(NodeUnhealthyErrorData { num_slots_behind })), }, diff --git a/client/src/rpc_request.rs b/client/src/rpc_request.rs index 1d2c85643e..9a705396a2 100644 --- a/client/src/rpc_request.rs +++ b/client/src/rpc_request.rs @@ -147,7 +147,7 @@ impl RpcRequest { pub enum RpcResponseErrorData { Empty, SendTransactionPreflightFailure(RpcSimulateTransactionResult), - NodeUnhealthy { num_slots_behind: Slot }, + NodeUnhealthy { num_slots_behind: Option }, } impl fmt::Display for RpcResponseErrorData { diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 56a3f68abf..22950b86ae 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -2265,9 +2265,10 @@ impl RpcSol for RpcSolImpl { fn get_health(&self, meta: Self::Metadata) -> Result { match meta.health.check() { RpcHealthStatus::Ok => Ok("ok".to_string()), - RpcHealthStatus::Behind { - num_slots: num_slots_behind, - } => Err(RpcCustomError::RpcNodeUnhealthy { num_slots_behind }.into()), + RpcHealthStatus::Behind { num_slots } => Err(RpcCustomError::NodeUnhealthy { + num_slots_behind: Some(num_slots), + } + .into()), } } @@ -2523,10 +2524,11 @@ impl RpcSol for RpcSolImpl { match meta.health.check() { RpcHealthStatus::Ok => (), - RpcHealthStatus::Behind { - num_slots: num_slots_behind, - } => { - return Err(RpcCustomError::RpcNodeUnhealthy { num_slots_behind }.into()); + RpcHealthStatus::Behind { num_slots } => { + return Err(RpcCustomError::NodeUnhealthy { + num_slots_behind: Some(num_slots), + } + .into()); } } @@ -4570,7 +4572,7 @@ pub mod tests { assert_eq!( res, Some( - r#"{"jsonrpc":"2.0","error":{"code":-32005,"message":"RPC node is behind by 42 slots","data":{"numSlotsBehind":42}},"id":1}"#.to_string(), + r#"{"jsonrpc":"2.0","error":{"code":-32005,"message":"Node is behind by 42 slots","data":{"numSlotsBehind":42}},"id":1}"#.to_string(), ) ); health.stub_set_health_status(None); diff --git a/docs/src/developing/clients/jsonrpc-api.md b/docs/src/developing/clients/jsonrpc-api.md index 71cd1a0cc0..8c29ec96ae 100644 --- a/docs/src/developing/clients/jsonrpc-api.md +++ b/docs/src/developing/clients/jsonrpc-api.md @@ -1294,7 +1294,9 @@ None #### Results: If the node is healthy: "ok" -If the node is unhealthy, a JSON RPC error response is returned indicating how far behind the node is. +If the node is unhealthy, a JSON RPC error response is returned. The specifics +of the error response are **UNSTABLE** and may change in the future + #### Example: @@ -1310,13 +1312,26 @@ Healthy Result: {"jsonrpc":"2.0","result": "ok","id":1} ``` -Unhealthy Result: +Unhealthy Result (generic): ```json { "jsonrpc": "2.0", "error": { "code": -32005, - "message": "RPC node is behind by 42 slots", + "message": "Node is unhealthy", + "data": {} + }, + "id": 1 +} +``` + +Unhealthy Result (if additional information is available) +```json +{ + "jsonrpc": "2.0", + "error": { + "code": -32005, + "message": "Node is behind by 42 slots", "data": { "numSlotsBehind": 42 } diff --git a/validator/src/bin/solana-test-validator.rs b/validator/src/bin/solana-test-validator.rs index a6a9cc1dbf..efc55f49df 100644 --- a/validator/src/bin/solana-test-validator.rs +++ b/validator/src/bin/solana-test-validator.rs @@ -358,7 +358,9 @@ fn main() { code: _, message: _, data: - rpc_request::RpcResponseErrorData::NodeUnhealthy { num_slots_behind }, + rpc_request::RpcResponseErrorData::NodeUnhealthy { + num_slots_behind: Some(num_slots_behind), + }, }, ) = &err.kind {