From 14d793b22c1571fb092d5822189d5b64f32605e6 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 12 Oct 2020 18:06:10 -0700 Subject: [PATCH] Cleanly handle RPC servers that don't have --enable-rpc-transaction-history enabled --- cli/src/stake.rs | 28 ++++++++++++++++++++++++---- client/src/client_error.rs | 4 ++-- client/src/rpc_custom_error.rs | 30 ++++++++++++++++++------------ 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/cli/src/stake.rs b/cli/src/stake.rs index e0c8059e7..8d56e44c0 100644 --- a/cli/src/stake.rs +++ b/cli/src/stake.rs @@ -23,8 +23,12 @@ use solana_cli_output::{ CliStakeType, }; use solana_client::{ - blockhash_query::BlockhashQuery, nonce_utils, rpc_client::RpcClient, - rpc_request::DELINQUENT_VALIDATOR_SLOT_DISTANCE, + blockhash_query::BlockhashQuery, + client_error::{ClientError, ClientErrorKind}, + nonce_utils, + rpc_client::RpcClient, + rpc_custom_error, + rpc_request::{self, DELINQUENT_VALIDATOR_SLOT_DISTANCE}, }; use solana_remote_wallet::remote_wallet::RemoteWalletManager; use solana_sdk::{ @@ -1605,10 +1609,26 @@ pub(crate) fn fetch_epoch_rewards( .get(0) .ok_or_else(|| format!("Unable to fetch first confirmed block for epoch {}", epoch))?; - let first_confirmed_block = rpc_client.get_confirmed_block_with_encoding( + let first_confirmed_block = match rpc_client.get_confirmed_block_with_encoding( first_confirmed_block_in_epoch, solana_transaction_status::UiTransactionEncoding::Base64, - )?; + ) { + Ok(first_confirmed_block) => first_confirmed_block, + Err(ClientError { + kind: + ClientErrorKind::RpcError(rpc_request::RpcError::RpcResponseError { + code: rpc_custom_error::JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE, + message: _, + }), + request: _, + }) => { + // RPC node doesn't have this block + break; + } + Err(err) => { + return Err(err.into()); + } + }; let epoch_start_time = if let Some(block_time) = first_confirmed_block.block_time { block_time diff --git a/client/src/client_error.rs b/client/src/client_error.rs index 7397ec5ea..417d58301 100644 --- a/client/src/client_error.rs +++ b/client/src/client_error.rs @@ -50,10 +50,10 @@ impl Into for ClientErrorKind { #[derive(Error, Debug)] #[error("{kind}")] pub struct ClientError { - request: Option, + pub request: Option, #[source] - kind: ClientErrorKind, + pub kind: ClientErrorKind, } impl ClientError { diff --git a/client/src/rpc_custom_error.rs b/client/src/rpc_custom_error.rs index 1cd206bbb..b28fac9a6 100644 --- a/client/src/rpc_custom_error.rs +++ b/client/src/rpc_custom_error.rs @@ -4,12 +4,12 @@ use crate::rpc_response::RpcSimulateTransactionResult; use jsonrpc_core::{Error, ErrorCode}; use solana_sdk::clock::Slot; -const JSON_RPC_SERVER_ERROR_1: i64 = -32001; -const JSON_RPC_SERVER_ERROR_2: i64 = -32002; -const JSON_RPC_SERVER_ERROR_3: i64 = -32003; -const JSON_RPC_SERVER_ERROR_4: i64 = -32004; -const JSON_RPC_SERVER_ERROR_5: i64 = -32005; -const JSON_RPC_SERVER_ERROR_6: i64 = -32006; +pub const JSON_RPC_SERVER_ERROR_BLOCK_CLEANED_UP: i64 = -32001; +pub const JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE: i64 = -32002; +pub const JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE: i64 = -32003; +pub const JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE: i64 = -32004; +pub const JSON_RPC_SERVER_ERROR_NODE_UNHEALTHLY: i64 = -32005; +pub const JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: i64 = -32006; pub enum RpcCustomError { BlockCleanedUp { @@ -35,7 +35,7 @@ impl From for Error { slot, first_available_block, } => Self { - code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_1), + code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_BLOCK_CLEANED_UP), message: format!( "Block {} cleaned up, does not exist on node. First available block: {}", slot, first_available_block, @@ -43,27 +43,33 @@ impl From for Error { data: None, }, RpcCustomError::SendTransactionPreflightFailure { message, result } => Self { - code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_2), + code: ErrorCode::ServerError( + JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE, + ), message, data: Some(serde_json::json!(result)), }, RpcCustomError::TransactionSignatureVerificationFailure => Self { - code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_3), + code: ErrorCode::ServerError( + JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE, + ), message: "Transaction signature verification failure".to_string(), data: None, }, RpcCustomError::BlockNotAvailable { slot } => Self { - code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_4), + code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE), message: format!("Block not available for slot {}", slot), data: None, }, RpcCustomError::RpcNodeUnhealthy => Self { - code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_5), + code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_NODE_UNHEALTHLY), message: "RPC node is unhealthy".to_string(), data: None, }, RpcCustomError::TransactionPrecompileVerificationFailure(e) => Self { - code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_6), + code: ErrorCode::ServerError( + JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE, + ), message: format!("Transaction precompile verification failure {:?}", e), data: None, },