* RPC sendTransaction now returns transaction logs on simulation failure (cherry picked from commit749208fa32
) # Conflicts: # core/src/rpc.rs * Remove stale comment (cherry picked from commitc6eea94edc
) # Conflicts: # core/src/rpc.rs * Resolve merge conflicts Co-authored-by: Michael Vines <mvines@gmail.com>
This commit is contained in:
@ -1737,7 +1737,7 @@ fn _send_transaction(
|
||||
last_valid_slot: Slot,
|
||||
) -> Result<String> {
|
||||
if transaction.signatures.is_empty() {
|
||||
return Err(RpcCustomError::SendTransactionIsNotSigned.into());
|
||||
return Err(RpcCustomError::TransactionSignatureVerificationFailure.into());
|
||||
}
|
||||
let signature = transaction.signatures[0];
|
||||
meta.send_transaction_service
|
||||
@ -2141,33 +2141,26 @@ impl RpcSol for RpcSolImpl {
|
||||
|
||||
if !config.skip_preflight {
|
||||
if transaction.verify().is_err() {
|
||||
return Err(RpcCustomError::SendTransactionPreflightFailure {
|
||||
message: "Transaction signature verification failed".into(),
|
||||
}
|
||||
.into());
|
||||
return Err(RpcCustomError::TransactionSignatureVerificationFailure.into());
|
||||
}
|
||||
|
||||
if meta.health.check() != RpcHealthStatus::Ok {
|
||||
return Err(RpcCustomError::SendTransactionPreflightFailure {
|
||||
message: "RPC node is unhealthy, unable to simulate transaction".into(),
|
||||
}
|
||||
.into());
|
||||
return Err(RpcCustomError::RpcNodeUnhealthy.into());
|
||||
}
|
||||
|
||||
let preflight_commitment = config
|
||||
.preflight_commitment
|
||||
.map(|commitment| CommitmentConfig { commitment });
|
||||
let preflight_bank = &*meta.bank(preflight_commitment)?;
|
||||
if let (Err(err), _log_output) =
|
||||
if let (Err(err), logs) =
|
||||
run_transaction_simulation(&preflight_bank, transaction.clone())
|
||||
{
|
||||
// Note: it's possible that the transaction simulation failed but the actual
|
||||
// transaction would succeed, such as when a transaction depends on an earlier
|
||||
// transaction that has yet to reach max confirmations. In these cases the user
|
||||
// should use the config.skip_preflight flag, and potentially in the future
|
||||
// additional controls over what bank is used for preflight should be exposed.
|
||||
return Err(RpcCustomError::SendTransactionPreflightFailure {
|
||||
message: format!("Transaction simulation failed: {}", err),
|
||||
result: RpcSimulateTransactionResult {
|
||||
err: Some(err),
|
||||
logs: Some(logs),
|
||||
},
|
||||
}
|
||||
.into());
|
||||
}
|
||||
@ -4059,7 +4052,7 @@ pub mod tests {
|
||||
assert_eq!(
|
||||
res,
|
||||
Some(
|
||||
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: TransactionError::BlockhashNotFound"},"id":1}"#.to_string(),
|
||||
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: TransactionError::BlockhashNotFound","data":{"err":"BlockhashNotFound","logs":[]}},"id":1}"#.to_string(),
|
||||
)
|
||||
);
|
||||
|
||||
@ -4075,7 +4068,7 @@ pub mod tests {
|
||||
assert_eq!(
|
||||
res,
|
||||
Some(
|
||||
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: TransactionError::SanitizeFailure"},"id":1}"#.to_string(),
|
||||
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: TransactionError::SanitizeFailure","data":{"err":"SanitizeFailure","logs":[]}},"id":1}"#.to_string(),
|
||||
)
|
||||
);
|
||||
let mut bad_transaction =
|
||||
@ -4091,7 +4084,7 @@ pub mod tests {
|
||||
assert_eq!(
|
||||
res,
|
||||
Some(
|
||||
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"RPC node is unhealthy, unable to simulate transaction"},"id":1}"#.to_string(),
|
||||
r#"{"jsonrpc":"2.0","error":{"code":-32005,"message":"RPC node is unhealthy"},"id":1}"#.to_string(),
|
||||
)
|
||||
);
|
||||
health.stub_set_health_status(None);
|
||||
@ -4107,7 +4100,7 @@ pub mod tests {
|
||||
assert_eq!(
|
||||
res,
|
||||
Some(
|
||||
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction signature verification failed"},"id":1}"#.to_string(),
|
||||
r#"{"jsonrpc":"2.0","error":{"code":-32003,"message":"Transaction signature verification failure"},"id":1}"#.to_string(),
|
||||
)
|
||||
);
|
||||
|
||||
@ -4136,7 +4129,7 @@ pub mod tests {
|
||||
assert_eq!(
|
||||
res,
|
||||
Some(
|
||||
r#"{"jsonrpc":"2.0","error":{"code":-32003,"message":"Transaction is not signed"},"id":1}"#.to_string(),
|
||||
r#"{"jsonrpc":"2.0","error":{"code":-32003,"message":"Transaction signature verification failure"},"id":1}"#.to_string(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use jsonrpc_core::{Error, ErrorCode};
|
||||
use solana_client::rpc_response::RpcSimulateTransactionResult;
|
||||
use solana_sdk::clock::Slot;
|
||||
|
||||
const JSON_RPC_SERVER_ERROR_0: i64 = -32000;
|
||||
@ -6,6 +7,7 @@ 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;
|
||||
|
||||
pub enum RpcCustomError {
|
||||
NonexistentClusterRoot {
|
||||
@ -18,11 +20,13 @@ pub enum RpcCustomError {
|
||||
},
|
||||
SendTransactionPreflightFailure {
|
||||
message: String,
|
||||
result: RpcSimulateTransactionResult,
|
||||
},
|
||||
SendTransactionIsNotSigned,
|
||||
TransactionSignatureVerificationFailure,
|
||||
BlockNotAvailable {
|
||||
slot: Slot,
|
||||
},
|
||||
RpcNodeUnhealthy,
|
||||
}
|
||||
|
||||
impl From<RpcCustomError> for Error {
|
||||
@ -50,14 +54,14 @@ impl From<RpcCustomError> for Error {
|
||||
),
|
||||
data: None,
|
||||
},
|
||||
RpcCustomError::SendTransactionPreflightFailure { message } => Self {
|
||||
RpcCustomError::SendTransactionPreflightFailure { message, result } => Self {
|
||||
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_2),
|
||||
message,
|
||||
data: None,
|
||||
data: Some(serde_json::json!(result)),
|
||||
},
|
||||
RpcCustomError::SendTransactionIsNotSigned => Self {
|
||||
RpcCustomError::TransactionSignatureVerificationFailure => Self {
|
||||
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_3),
|
||||
message: "Transaction is not signed".to_string(),
|
||||
message: "Transaction signature verification failure".to_string(),
|
||||
data: None,
|
||||
},
|
||||
RpcCustomError::BlockNotAvailable { slot } => Self {
|
||||
@ -65,6 +69,11 @@ impl From<RpcCustomError> for Error {
|
||||
message: format!("Block not available for slot {}", slot,),
|
||||
data: None,
|
||||
},
|
||||
RpcCustomError::RpcNodeUnhealthy => Self {
|
||||
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_5),
|
||||
message: "RPC node is unhealthy".to_string(),
|
||||
data: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user