From a7af24bf3c7cb65718fea0841b60906f01734792 Mon Sep 17 00:00:00 2001 From: John Cantrell Date: Tue, 28 Feb 2023 11:39:29 -0500 Subject: [PATCH] Surface bitcoind rpc error code Users of the RpcClient had no way to access the error code returned by bitcoind's rpc. We embed a new RpcError struct as the inner error for the returned io::Error. Users can access both the code and the message using this inner struct. --- lightning-block-sync/src/rpc.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/lightning-block-sync/src/rpc.rs b/lightning-block-sync/src/rpc.rs index f0476956..6b4397a6 100644 --- a/lightning-block-sync/src/rpc.rs +++ b/lightning-block-sync/src/rpc.rs @@ -13,8 +13,27 @@ use serde_json; use std::convert::TryFrom; use std::convert::TryInto; +use std::error::Error; +use std::fmt; use std::sync::atomic::{AtomicUsize, Ordering}; +/// An error returned by the RPC server. +#[derive(Debug)] +pub struct RpcError { + /// The error code. + pub code: i64, + /// The error message. + pub message: String, +} + +impl fmt::Display for RpcError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "RPC error {}: {}", self.code, self.message) + } +} + +impl Error for RpcError {} + /// A simple RPC client for calling methods using HTTP `POST`. pub struct RpcClient { basic_auth: String, @@ -69,8 +88,11 @@ impl RpcClient { let error = &response["error"]; if !error.is_null() { // TODO: Examine error code for a more precise std::io::ErrorKind. - let message = error["message"].as_str().unwrap_or("unknown error"); - return Err(std::io::Error::new(std::io::ErrorKind::Other, message)); + let rpc_error = RpcError { + code: error["code"].as_i64().unwrap_or(-1), + message: error["message"].as_str().unwrap_or("unknown error").to_string() + }; + return Err(std::io::Error::new(std::io::ErrorKind::Other, rpc_error)); } let result = &mut response["result"]; @@ -163,7 +185,9 @@ mod tests { match client.call_method::("getblock", &[invalid_block_hash]).await { Err(e) => { assert_eq!(e.kind(), std::io::ErrorKind::Other); - assert_eq!(e.get_ref().unwrap().to_string(), "invalid parameter"); + let rpc_error: Box = e.into_inner().unwrap().downcast().unwrap(); + assert_eq!(rpc_error.code, -8); + assert_eq!(rpc_error.message, "invalid parameter"); }, Ok(_) => panic!("Expected error"), } -- 2.30.2