diff --git a/core/src/rpc.rs b/core/src/rpc.rs index dc05a64f52..70625a0cfb 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -1737,7 +1737,7 @@ fn _send_transaction( last_valid_slot: Slot, ) -> Result { 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(), ) ); } diff --git a/core/src/rpc_error.rs b/core/src/rpc_error.rs index 6eea764fa4..d1796ee449 100644 --- a/core/src/rpc_error.rs +++ b/core/src/rpc_error.rs @@ -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 for Error { @@ -50,14 +54,14 @@ impl From 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 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, + }, } } }