Surface transaction logs in rpc client

This commit is contained in:
Michael Vines 2020-11-03 14:37:41 -08:00
parent 04c5e6cc48
commit 6d9ca0ae15
4 changed files with 81 additions and 13 deletions

View File

@ -1618,9 +1618,9 @@ pub(crate) fn fetch_epoch_rewards(
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;

View File

@ -1,6 +1,8 @@
use crate::{
client_error::Result,
rpc_request::{RpcError, RpcRequest},
rpc_custom_error,
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData},
rpc_response::RpcSimulateTransactionResult,
rpc_sender::RpcSender,
};
use log::*;
@ -31,7 +33,7 @@ impl HttpSender {
struct RpcErrorObject {
code: i64,
message: String,
/*data field omitted*/
data: serde_json::Value,
}
impl RpcSender for HttpSender {
@ -72,11 +74,27 @@ impl RpcSender for HttpSender {
if json["error"].is_object() {
return match serde_json::from_value::<RpcErrorObject>(json["error"].clone())
{
Ok(rpc_error_object) => Err(RpcError::RpcResponseError {
code: rpc_error_object.code,
message: rpc_error_object.message,
Ok(rpc_error_object) => {
let data = match rpc_error_object.code {
rpc_custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE => {
match serde_json::from_value::<RpcSimulateTransactionResult>(json["error"]["data"].clone()) {
Ok(data) => RpcResponseErrorData::SendTransactionPreflightFailure(data),
Err(err) => {
debug!("Failed to deserialize RpcSimulateTransactionResult: {:?}", err);
RpcResponseErrorData::Empty
}
}
},
_ => RpcResponseErrorData::Empty
};
Err(RpcError::RpcResponseError {
code: rpc_error_object.code,
message: rpc_error_object.message,
data,
}
.into())
}
.into()),
Err(err) => Err(RpcError::RpcRequestError(format!(
"Failed to deserialize RPC error response: {} [{}]",
serde_json::to_string(&json["error"]).unwrap(),

View File

@ -8,7 +8,7 @@ use crate::{
RpcProgramAccountsConfig, RpcSendTransactionConfig, RpcSimulateTransactionConfig,
RpcTokenAccountsFilter,
},
rpc_request::{RpcError, RpcRequest, TokenAccountsFilter},
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData, TokenAccountsFilter},
rpc_response::*,
rpc_sender::RpcSender,
};
@ -171,10 +171,33 @@ impl RpcClient {
..config
};
let serialized_encoded = serialize_encode_transaction(transaction, encoding)?;
let signature_base58_str: String = self.send(
let signature_base58_str: String = match self.send(
RpcRequest::SendTransaction,
json!([serialized_encoded, config]),
)?;
) {
Ok(signature_base58_str) => signature_base58_str,
Err(err) => {
if let ClientErrorKind::RpcError(RpcError::RpcResponseError {
code,
message,
data,
}) = &err.kind
{
debug!("{} {}", code, message);
if let RpcResponseErrorData::SendTransactionPreflightFailure(
RpcSimulateTransactionResult {
logs: Some(logs), ..
},
) = data
{
for (i, log) in logs.iter().enumerate() {
debug!("{:>3}: {}", i + 1, log);
}
}
}
return Err(err);
}
};
let signature = signature_base58_str
.parse::<Signature>()

View File

@ -1,3 +1,4 @@
use crate::rpc_response::RpcSimulateTransactionResult;
use serde_json::{json, Value};
use solana_sdk::pubkey::Pubkey;
use std::fmt;
@ -138,12 +139,38 @@ impl RpcRequest {
}
}
#[derive(Debug)]
pub enum RpcResponseErrorData {
Empty,
SendTransactionPreflightFailure(RpcSimulateTransactionResult),
}
impl fmt::Display for RpcResponseErrorData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RpcResponseErrorData::SendTransactionPreflightFailure(
RpcSimulateTransactionResult {
logs: Some(logs), ..
},
) => {
// Give the user a hint that there is more useful logging information available...
write!(f, "{} log messages", logs.len())
}
_ => Ok(()),
}
}
}
#[derive(Debug, Error)]
pub enum RpcError {
#[error("RPC request error: {0}")]
RpcRequestError(String),
#[error("RPC response error {code}: {message}")]
RpcResponseError { code: i64, message: String },
#[error("RPC response error {code}: {message} [{data}]")]
RpcResponseError {
code: i64,
message: String,
data: RpcResponseErrorData,
},
#[error("parse error: expected {0}")]
ParseError(String), /* "expected" */
// Anything in a `ForUser` needs to die. The caller should be