Skip to content

Commit

Permalink
Add thiserror for better display error formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
yukibtc committed Dec 21, 2022
1 parent 0b768d6 commit 1b90ee4
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 67 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ bitcoin = { version = "0.29.1", features = ["serde", "base64", "rand"] }
serde = { version = "^1.0", features = ["derive"] }
serde_json = { version = "^1.0" }
rand = "^0.8"
thiserror = "^1.0"

# Optional dependencies
sled = { version = "0.34", optional = true }
Expand Down
27 changes: 17 additions & 10 deletions src/blockchain/compact_filters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
//! ```

use std::collections::HashSet;
use std::fmt;
use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
Expand Down Expand Up @@ -534,54 +533,62 @@ impl ConfigurableBlockchain for CompactFiltersBlockchain {
}

/// An error that can occur during sync with a [`CompactFiltersBlockchain`]
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub enum CompactFiltersError {
/// A peer sent an invalid or unexpected response
#[error("A peer sent an invalid or unexpected response")]
InvalidResponse,
/// The headers returned are invalid
#[error("Invalid headers")]
InvalidHeaders,
/// The compact filter headers returned are invalid
#[error("Invalid filter header")]
InvalidFilterHeader,
/// The compact filter returned is invalid
#[error("Invalid filters")]
InvalidFilter,
/// The peer is missing a block in the valid chain
#[error("The peer is missing a block in the valid chain")]
MissingBlock,
/// Block hash at specified height not found
#[error("Block hash not found")]
BlockHashNotFound,
/// The data stored in the block filters storage are corrupted
#[error("The data stored in the block filters storage are corrupted")]
DataCorruption,

/// A peer is not connected
#[error("A peer is not connected")]
NotConnected,
/// A peer took too long to reply to one of our messages
#[error("A peer took too long to reply to one of our messages")]
Timeout,
/// The peer doesn't advertise the [`BLOOM`](bitcoin::network::constants::ServiceFlags::BLOOM) service flag
#[error("Peer doesn't advertise the BLOOM service flag")]
PeerBloomDisabled,

/// No peers have been specified
#[error("No peers have been specified")]
NoPeers,

/// Internal database error
#[error("Internal database error: {0}")]
Db(rocksdb::Error),
/// Internal I/O error
#[error("Internal I/O error: {0}")]
Io(std::io::Error),
/// Invalid BIP158 filter
#[error("Invalid BIP158 filter: {0}")]
Bip158(bitcoin::util::bip158::Error),
/// Internal system time error
#[error("Invalid system time: {0}")]
Time(std::time::SystemTimeError),

/// Wrapper for [`crate::error::Error`]
#[error("Generic error: {0}")]
Global(Box<crate::error::Error>),
}

impl fmt::Display for CompactFiltersError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}

impl std::error::Error for CompactFiltersError {}

impl_error!(rocksdb::Error, Db, CompactFiltersError);
impl_error!(std::io::Error, Io, CompactFiltersError);
impl_error!(bitcoin::util::bip158::Error, Bip158, CompactFiltersError);
Expand Down
21 changes: 12 additions & 9 deletions src/descriptor/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,43 @@
//! Descriptor errors

/// Errors related to the parsing and usage of descriptors
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Invalid HD Key path, such as having a wildcard but a length != 1
#[error("Invalid HD key path")]
InvalidHdKeyPath,
/// The provided descriptor doesn't match its checksum
#[error("The provided descriptor doesn't match its checksum")]
InvalidDescriptorChecksum,
/// The descriptor contains hardened derivation steps on public extended keys
#[error("The descriptor contains hardened derivation steps on public extended keys")]
HardenedDerivationXpub,

/// Error thrown while working with [`keys`](crate::keys)
#[error("Key error: {0}")]
Key(crate::keys::KeyError),
/// Error while extracting and manipulating policies
#[error("Policy error: {0}")]
Policy(crate::descriptor::policy::PolicyError),

/// Invalid byte found in the descriptor checksum
#[error("Invalid descriptor character: {0}")]
InvalidDescriptorCharacter(u8),

/// BIP32 error
#[error("BIP32 error: {0}")]
Bip32(bitcoin::util::bip32::Error),
/// Error during base58 decoding
#[error("Base58 error: {0}")]
Base58(bitcoin::util::base58::Error),
/// Key-related error
#[error("Key-related error: {0}")]
Pk(bitcoin::util::key::Error),
/// Miniscript error
#[error("Miniscript error: {0}")]
Miniscript(miniscript::Error),
/// Hex decoding error
#[error("Hex decoding error: {0}")]
Hex(bitcoin::hashes::hex::Error),
}

Expand All @@ -51,14 +62,6 @@ impl From<crate::keys::KeyError> for Error {
}
}

impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}

impl std::error::Error for Error {}

impl_error!(bitcoin::util::bip32::Error, Bip32);
impl_error!(bitcoin::util::base58::Error, Base58);
impl_error!(bitcoin::util::key::Error, Pk);
Expand Down
17 changes: 7 additions & 10 deletions src/descriptor/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@

use std::cmp::max;
use std::collections::{BTreeMap, HashSet, VecDeque};
use std::fmt;

use serde::ser::SerializeMap;
use serde::{Serialize, Serializer};
Expand Down Expand Up @@ -494,30 +493,28 @@ impl Condition {
}

/// Errors that can happen while extracting and manipulating policies
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
pub enum PolicyError {
/// Not enough items are selected to satisfy a [`SatisfiableItem::Thresh`] or a [`SatisfiableItem::Multisig`]
#[error("Not enought items selected: {0}")]
NotEnoughItemsSelected(String),
/// Index out of range for an item to satisfy a [`SatisfiableItem::Thresh`] or a [`SatisfiableItem::Multisig`]
#[error("Index out of range: {0}")]
IndexOutOfRange(usize),
/// Can not add to an item that is [`Satisfaction::None`] or [`Satisfaction::Complete`]
#[error("Add on leaf")]
AddOnLeaf,
/// Can not add to an item that is [`Satisfaction::PartialComplete`]
#[error("Add on partial complete")]
AddOnPartialComplete,
/// Can not merge CSV or timelock values unless both are less than or both are equal or greater than 500_000_000
#[error("Mixed timelock units")]
MixedTimelockUnits,
/// Incompatible conditions (not currently used)
#[error("Incompatible conditions")]
IncompatibleConditions,
}

impl fmt::Display for PolicyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}

impl std::error::Error for PolicyError {}

impl Policy {
fn new(item: SatisfiableItem) -> Self {
Policy {
Expand Down
59 changes: 49 additions & 10 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,28 @@ use crate::{descriptor, wallet};
use bitcoin::{OutPoint, Txid};

/// Errors that can be thrown by the [`Wallet`](crate::wallet::Wallet)
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Wrong number of bytes found when trying to convert to u32
#[error("Wrong number of bytes found when trying to convert to u32")]
InvalidU32Bytes(Vec<u8>),
/// Generic error
#[error("Generic error: {0}")]
Generic(String),
/// This error is thrown when trying to convert Bare and Public key script to address
#[error("Script doesn't have address form")]
ScriptDoesntHaveAddressForm,
/// Cannot build a tx without recipients
#[error("Cannot build tx without recipients")]
NoRecipients,
/// `manually_selected_only` option is selected but no utxo has been passed
#[error("No UTXO selected")]
NoUtxosSelected,
/// Output created is under the dust limit, 546 satoshis
#[error("Output below the dust limit: {0}")]
OutputBelowDustLimit(usize),
/// Wallet's UTXO set is not enough to cover recipient's requested plus fee
#[error("Insufficient funds: {available} sat available of {needed} sat needed")]
InsufficientFunds {
/// Sats needed for some transaction
needed: u64,
Expand All @@ -39,47 +46,63 @@ pub enum Error {
},
/// Branch and bound coin selection possible attempts with sufficiently big UTXO set could grow
/// exponentially, thus a limit is set, and when hit, this error is thrown
#[error("Branch and bound coin selection: total tries exceeded")]
BnBTotalTriesExceeded,
/// Branch and bound coin selection tries to avoid needing a change by finding the right inputs for
/// the desired outputs plus fee, if there is not such combination this error is thrown
#[error("Branch and bound coin selection: not exact match")]
BnBNoExactMatch,
/// Happens when trying to spend an UTXO that is not in the internal database
#[error("UTXO not found in the internal database")]
UnknownUtxo,
/// Thrown when a tx is not found in the internal database
#[error("Transaction not found in the internal database")]
TransactionNotFound,
/// Happens when trying to bump a transaction that is already confirmed
#[error("Transaction already confirmed")]
TransactionConfirmed,
/// Trying to replace a tx that has a sequence >= `0xFFFFFFFE`
#[error("Transaction can't be replaced")]
IrreplaceableTransaction,
/// When bumping a tx the fee rate requested is lower than required
#[error("Fee rate too low: required {} sat/vbyte", required.as_sat_per_vb())]
FeeRateTooLow {
/// Required fee rate (satoshi/vbyte)
required: crate::types::FeeRate,
},
/// When bumping a tx the absolute fee requested is lower than replaced tx absolute fee
#[error("Fee to low: required {required} sat")]
FeeTooLow {
/// Required fee absolute value (satoshi)
required: u64,
},
/// Node doesn't have data to estimate a fee rate
#[error("Fee rate unavailable")]
FeeRateUnavailable,
/// In order to use the [`TxBuilder::add_global_xpubs`] option every extended
/// key in the descriptor must either be a master key itself (having depth = 0) or have an
/// explicit origin provided
///
/// [`TxBuilder::add_global_xpubs`]: crate::wallet::tx_builder::TxBuilder::add_global_xpubs
#[error("Missing key origin: {0}")]
MissingKeyOrigin(String),
/// Error while working with [`keys`](crate::keys)
#[error("Key error: {0}")]
Key(crate::keys::KeyError),
/// Descriptor checksum mismatch
#[error("Descriptor checksum mismatch")]
ChecksumMismatch,
/// Spending policy is not compatible with this [`KeychainKind`](crate::types::KeychainKind)
#[error("Spending policy required: {0:?}")]
SpendingPolicyRequired(crate::types::KeychainKind),
/// Error while extracting and manipulating policies
#[error("Invalid policy path: {0}")]
InvalidPolicyPathError(crate::descriptor::policy::PolicyError),
/// Signing error
#[error("Signer error: {0}")]
Signer(crate::wallet::signer::SignerError),
/// Invalid network
#[error("Invalid network: requested {} but found {}", requested, found)]
InvalidNetwork {
/// requested network, for example what is given as bdk-cli option
requested: Network,
Expand All @@ -88,34 +111,48 @@ pub enum Error {
},
#[cfg(feature = "verify")]
/// Transaction verification error
#[error("Verification error: {0}")]
Verification(crate::wallet::verify::VerifyError),

/// Progress value must be between `0.0` (included) and `100.0` (included)
#[error("Invalid progress value: {0}")]
InvalidProgressValue(f32),
/// Progress update error (maybe the channel has been closed)
#[error("Progress update error (maybe the channel has been closed)")]
ProgressUpdateError,
/// Requested outpoint doesn't exist in the tx (vout greater than available outputs)
#[error("Requested outpoint doesn't exist in the tx: {0}")]
InvalidOutpoint(OutPoint),

/// Error related to the parsing and usage of descriptors
#[error("Descriptor error: {0}")]
Descriptor(crate::descriptor::error::Error),
/// Encoding error
#[error("Encoding error: {0}")]
Encode(bitcoin::consensus::encode::Error),
/// Miniscript error
#[error("Miniscript error: {0}")]
Miniscript(miniscript::Error),
/// Miniscript PSBT error
#[error("Miniscript PSBT error: {0}")]
MiniscriptPsbt(MiniscriptPsbtError),
/// BIP32 error
#[error("BIP32 error: {0}")]
Bip32(bitcoin::util::bip32::Error),
/// An ECDSA error
#[error("ECDSA error: {0}")]
Secp256k1(bitcoin::secp256k1::Error),
/// Error serializing or deserializing JSON data
#[error("Serialize/Deserialize JSON error: {0}")]
Json(serde_json::Error),
/// Hex decoding error
#[error("Hex decoding error: {0}")]
Hex(bitcoin::hashes::hex::Error),
/// Partially signed bitcoin transaction error
#[error("PSBT error: {0}")]
Psbt(bitcoin::util::psbt::Error),
/// Partially signed bitcoin transaction parse error
#[error("Impossible to parse PSBT: {0}")]
PsbtParse(bitcoin::util::psbt::PsbtParseError),

//KeyMismatch(bitcoin::secp256k1::PublicKey, bitcoin::secp256k1::PublicKey),
Expand All @@ -127,33 +164,43 @@ pub enum Error {
//MissingCachedAddresses,
/// [`crate::blockchain::WalletSync`] sync attempt failed due to missing scripts in cache which
/// are needed to satisfy `stop_gap`.
#[error("Missing cached scripts: {0:?}")]
MissingCachedScripts(MissingCachedScripts),

#[cfg(feature = "electrum")]
/// Electrum client error
#[error("Electrum client error: {0}")]
Electrum(electrum_client::Error),
#[cfg(feature = "esplora")]
/// Esplora client error
#[error("Esplora client error: {0}")]
Esplora(Box<crate::blockchain::esplora::EsploraError>),
#[cfg(feature = "compact_filters")]
/// Compact filters client error)
#[error("Compact filters client error: {0}")]
CompactFilters(crate::blockchain::compact_filters::CompactFiltersError),
#[cfg(feature = "key-value-db")]
/// Sled database error
#[error("Sled database error: {0}")]
Sled(sled::Error),
#[cfg(feature = "rpc")]
/// Rpc client error
#[error("RPC client error: {0}")]
Rpc(bitcoincore_rpc::Error),
#[cfg(feature = "sqlite")]
/// Rusqlite client error
#[error("SQLite error: {0}")]
Rusqlite(rusqlite::Error),
}

/// Errors returned by miniscript when updating inconsistent PSBTs
#[derive(Debug, Clone)]
#[derive(Debug, Clone, thiserror::Error)]
pub enum MiniscriptPsbtError {
#[error("Conversion error: {0}")]
Conversion(miniscript::descriptor::ConversionError),
#[error("UTXO update error: {0}")]
UtxoUpdate(miniscript::psbt::UtxoUpdateError),
#[error("Output update error: {0}")]
OutputUpdate(miniscript::psbt::OutputUpdateError),
}

Expand All @@ -167,14 +214,6 @@ pub struct MissingCachedScripts {
pub missing_count: usize,
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}

impl std::error::Error for Error {}

macro_rules! impl_error {
( $from:ty, $to:ident ) => {
impl_error!($from, $to, Error);
Expand Down
Loading

0 comments on commit 1b90ee4

Please sign in to comment.