From 405928713f7554d578b68eca12a66adda618e6c9 Mon Sep 17 00:00:00 2001 From: scilio Date: Mon, 22 Aug 2022 13:03:10 -0400 Subject: [PATCH] switch to thiserror for node --- src/error.rs | 11 ++++++++++ src/node.rs | 62 ++++++++++++++++++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/error.rs b/src/error.rs index eb8f485..fd0c021 100644 --- a/src/error.rs +++ b/src/error.rs @@ -38,6 +38,9 @@ pub enum ErrorKind { /// Wallet error #[fail(display = "wallet error: {}", _0)] WalletError(crate::wallet::WalletError), + /// Wallet error + #[fail(display = "node error: {}", _0)] + NodeError(crate::node::NodeError), } impl std::error::Error for Error {} @@ -145,3 +148,11 @@ impl From for Error { } } } + +impl From for Error { + fn from(e: crate::node::NodeError) -> Error { + Error { + inner: Context::new(ErrorKind::NodeError(e)), + } + } +} diff --git a/src/node.rs b/src/node.rs index a32ea22..c4941cc 100644 --- a/src/node.rs +++ b/src/node.rs @@ -1,4 +1,3 @@ -use crate::error::{ErrorKind, Result}; use crate::secp::Commitment; use grin_api::client; @@ -11,20 +10,32 @@ use grin_util::ToHex; use serde_json::json; use std::net::SocketAddr; use std::sync::Arc; +use thiserror::Error; pub trait GrinNode: Send + Sync { /// Retrieves the unspent output with a matching commitment - fn get_utxo(&self, output_commit: &Commitment) -> Result>; + fn get_utxo(&self, output_commit: &Commitment) -> Result, NodeError>; /// Gets the height of the chain tip - fn get_chain_height(&self) -> Result; + fn get_chain_height(&self) -> Result; /// Posts a transaction to the grin node - fn post_tx(&self, tx: &Transaction) -> Result<()>; + fn post_tx(&self, tx: &Transaction) -> Result<(), NodeError>; +} + +/// Error types for interacting with nodes +#[derive(Error, Debug)] +pub enum NodeError { + #[error("Error decoding JSON response: {0:?}")] + DecodeResponseError(serde_json::Error), + #[error("JSON-RPC API communication error: {0:?}")] + ApiCommError(grin_api::Error), + #[error("Error decoding JSON-RPC response: {0:?}")] + ResponseParseError(grin_api::json_rpc::Error), } /// Checks if a commitment is in the UTXO set -pub fn is_unspent(node: &Arc, commit: &Commitment) -> Result { +pub fn is_unspent(node: &Arc, commit: &Commitment) -> Result { let utxo = node.get_utxo(&commit)?; Ok(utxo.is_some()) } @@ -34,7 +45,7 @@ pub fn is_spendable( node: &Arc, output_commit: &Commitment, next_block_height: u64, -) -> Result { +) -> Result { let output = node.get_utxo(&output_commit)?; if let Some(out) = output { let is_coinbase = match out.output_type { @@ -59,7 +70,10 @@ pub fn is_spendable( } /// Builds an input for an unspent output commitment -pub fn build_input(node: &Arc, output_commit: &Commitment) -> Result> { +pub fn build_input( + node: &Arc, + output_commit: &Commitment, +) -> Result, NodeError> { let output = node.get_utxo(&output_commit)?; if let Some(out) = output { @@ -96,18 +110,22 @@ impl HttpGrinNode { &self, method: &str, params: &serde_json::Value, - ) -> Result { + ) -> Result { let url = format!("http://{}{}", self.node_url, ENDPOINT); let req = build_request(method, params); let res = - client::post::(url.as_str(), self.node_api_secret.clone(), &req)?; - let parsed = res.clone().into_result()?; + client::post::(url.as_str(), self.node_api_secret.clone(), &req) + .map_err(NodeError::ApiCommError)?; + let parsed = res + .clone() + .into_result() + .map_err(NodeError::ResponseParseError)?; Ok(parsed) } } impl GrinNode for HttpGrinNode { - fn get_utxo(&self, output_commit: &Commitment) -> Result> { + fn get_utxo(&self, output_commit: &Commitment) -> Result, NodeError> { let commits: Vec = vec![output_commit.to_hex()]; let start_height: Option = None; let end_height: Option = None; @@ -129,17 +147,17 @@ impl GrinNode for HttpGrinNode { Ok(Some(outputs[0].clone())) } - fn get_chain_height(&self) -> Result { + fn get_chain_height(&self) -> Result { let params = json!([]); let tip_json = self.send_json_request::("get_tip", ¶ms)?; - let tip: Result = serde_json::from_value(tip_json["Ok"].clone()) - .map_err(|e| ErrorKind::SerdeJsonError(e.to_string()).into()); + let tip = serde_json::from_value::(tip_json["Ok"].clone()) + .map_err(NodeError::DecodeResponseError)?; - Ok(tip?.height) + Ok(tip.height) } - fn post_tx(&self, tx: &Transaction) -> Result<()> { + fn post_tx(&self, tx: &Transaction) -> Result<(), NodeError> { let params = json!([tx, true]); self.send_json_request::("push_transaction", ¶ms)?; Ok(()) @@ -148,8 +166,7 @@ impl GrinNode for HttpGrinNode { #[cfg(test)] pub mod mock { - use super::GrinNode; - use crate::error::Result; + use super::{GrinNode, NodeError}; use crate::secp::Commitment; use grin_api::{OutputPrintable, OutputType}; @@ -198,7 +215,10 @@ pub mod mock { } impl GrinNode for MockGrinNode { - fn get_utxo(&self, output_commit: &Commitment) -> Result> { + fn get_utxo( + &self, + output_commit: &Commitment, + ) -> Result, NodeError> { if let Some(utxo) = self.utxos.get(&output_commit) { return Ok(Some(utxo.clone())); } @@ -206,11 +226,11 @@ pub mod mock { Ok(None) } - fn get_chain_height(&self) -> Result { + fn get_chain_height(&self) -> Result { Ok(100) } - fn post_tx(&self, tx: &Transaction) -> Result<()> { + fn post_tx(&self, tx: &Transaction) -> Result<(), NodeError> { let mut write = self.txns_posted.write().unwrap(); write.push(tx.clone()); Ok(())