diff --git a/Cargo.toml b/Cargo.toml index 681da7f07..775588208 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 } diff --git a/src/blockchain/compact_filters/mod.rs b/src/blockchain/compact_filters/mod.rs index 9b47df9cf..0f3c5fd5c 100644 --- a/src/blockchain/compact_filters/mod.rs +++ b/src/blockchain/compact_filters/mod.rs @@ -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}; @@ -534,61 +533,64 @@ 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 - Db(rocksdb::Error), + #[error("Internal database error: {0}")] + Db(#[from] rocksdb::Error), /// Internal I/O error - Io(std::io::Error), + #[error("Internal I/O error: {0}")] + Io(#[from] std::io::Error), /// Invalid BIP158 filter - Bip158(bitcoin::util::bip158::Error), + #[error("Invalid BIP158 filter: {0}")] + Bip158(#[from] bitcoin::util::bip158::Error), /// Internal system time error - Time(std::time::SystemTimeError), + #[error("Invalid system time: {0}")] + Time(#[from] std::time::SystemTimeError), /// Wrapper for [`crate::error::Error`] + #[error("Generic error: {0}")] Global(Box), } -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); -impl_error!(std::time::SystemTimeError, Time, CompactFiltersError); - impl From for CompactFiltersError { fn from(err: crate::error::Error) -> Self { - CompactFiltersError::Global(Box::new(err)) + Self::Global(Box::new(err)) } } diff --git a/src/descriptor/error.rs b/src/descriptor/error.rs index 72141dcbb..c33a02070 100644 --- a/src/descriptor/error.rs +++ b/src/descriptor/error.rs @@ -12,33 +12,44 @@ //! 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 - Policy(crate::descriptor::policy::PolicyError), + #[error("Policy error: {0}")] + Policy(#[from] crate::descriptor::policy::PolicyError), /// Invalid byte found in the descriptor checksum + #[error("Invalid descriptor character: {0}")] InvalidDescriptorCharacter(u8), /// BIP32 error - Bip32(bitcoin::util::bip32::Error), + #[error("BIP32 error: {0}")] + Bip32(#[from] bitcoin::util::bip32::Error), /// Error during base58 decoding - Base58(bitcoin::util::base58::Error), + #[error("Base58 error: {0}")] + Base58(#[from] bitcoin::util::base58::Error), /// Key-related error - Pk(bitcoin::util::key::Error), + #[error("Key-related error: {0}")] + Pk(#[from] bitcoin::util::key::Error), /// Miniscript error - Miniscript(miniscript::Error), + #[error("Miniscript error: {0}")] + Miniscript(#[from] miniscript::Error), /// Hex decoding error - Hex(bitcoin::hashes::hex::Error), + #[error("Hex decoding error: {0}")] + Hex(#[from] bitcoin::hashes::hex::Error), } impl From for Error { @@ -46,22 +57,7 @@ impl From for Error { match key_error { crate::keys::KeyError::Miniscript(inner) => Error::Miniscript(inner), crate::keys::KeyError::Bip32(inner) => Error::Bip32(inner), - e => Error::Key(e), + e => Self::Key(e), } } } - -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); -impl_error!(miniscript::Error, Miniscript); -impl_error!(bitcoin::hashes::hex::Error, Hex); -impl_error!(crate::descriptor::policy::PolicyError, Policy); diff --git a/src/descriptor/policy.rs b/src/descriptor/policy.rs index 964ec2911..22d64119f 100644 --- a/src/descriptor/policy.rs +++ b/src/descriptor/policy.rs @@ -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}; @@ -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 { diff --git a/src/error.rs b/src/error.rs index 4150eadc9..bf1a25345 100644 --- a/src/error.rs +++ b/src/error.rs @@ -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), /// 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, @@ -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 - InvalidPolicyPathError(crate::descriptor::policy::PolicyError), + #[error("Invalid policy path: {0}")] + InvalidPolicyPathError(#[from] crate::descriptor::policy::PolicyError), /// Signing error - Signer(crate::wallet::signer::SignerError), + #[error("Signer error: {0}")] + Signer(#[from] 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, @@ -88,35 +111,49 @@ 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 - Descriptor(crate::descriptor::error::Error), + #[error("Descriptor error: {0}")] + Descriptor(#[from] crate::descriptor::error::Error), /// Encoding error - Encode(bitcoin::consensus::encode::Error), + #[error("Encoding error: {0}")] + Encode(#[from] bitcoin::consensus::encode::Error), /// Miniscript error - Miniscript(miniscript::Error), + #[error("Miniscript error: {0}")] + Miniscript(#[from] miniscript::Error), /// Miniscript PSBT error - MiniscriptPsbt(MiniscriptPsbtError), + #[error("Miniscript PSBT error: {0}")] + MiniscriptPsbt(#[from] MiniscriptPsbtError), /// BIP32 error - Bip32(bitcoin::util::bip32::Error), + #[error("BIP32 error: {0}")] + Bip32(#[from] bitcoin::util::bip32::Error), /// An ECDSA error - Secp256k1(bitcoin::secp256k1::Error), + #[error("ECDSA error: {0}")] + Secp256k1(#[from] bitcoin::secp256k1::Error), /// Error serializing or deserializing JSON data - Json(serde_json::Error), + #[error("Serialize/Deserialize JSON error: {0}")] + Json(#[from] serde_json::Error), /// Hex decoding error - Hex(bitcoin::hashes::hex::Error), + #[error("Hex decoding error: {0}")] + Hex(#[from] bitcoin::hashes::hex::Error), /// Partially signed bitcoin transaction error - Psbt(bitcoin::util::psbt::Error), + #[error("PSBT error: {0}")] + Psbt(#[from] bitcoin::util::psbt::Error), /// Partially signed bitcoin transaction parse error - PsbtParse(bitcoin::util::psbt::PsbtParseError), + #[error("Impossible to parse PSBT: {0}")] + PsbtParse(#[from] bitcoin::util::psbt::PsbtParseError), //KeyMismatch(bitcoin::secp256k1::PublicKey, bitcoin::secp256k1::PublicKey), //MissingInputUTXO(usize), @@ -127,34 +164,44 @@ 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 - Electrum(electrum_client::Error), + #[error("Electrum client error: {0}")] + Electrum(#[from] electrum_client::Error), #[cfg(feature = "esplora")] /// Esplora client error + #[error("Esplora client error: {0}")] Esplora(Box), #[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 - Sled(sled::Error), + #[error("Sled database error: {0}")] + Sled(#[from] sled::Error), #[cfg(feature = "rpc")] /// Rpc client error - Rpc(bitcoincore_rpc::Error), + #[error("RPC client error: {0}")] + Rpc(#[from] bitcoincore_rpc::Error), #[cfg(feature = "sqlite")] /// Rusqlite client error - Rusqlite(rusqlite::Error), + #[error("SQLite error: {0}")] + Rusqlite(#[from] rusqlite::Error), } /// Errors returned by miniscript when updating inconsistent PSBTs -#[derive(Debug, Clone)] +#[derive(Debug, Clone, thiserror::Error)] pub enum MiniscriptPsbtError { - Conversion(miniscript::descriptor::ConversionError), - UtxoUpdate(miniscript::psbt::UtxoUpdateError), - OutputUpdate(miniscript::psbt::OutputUpdateError), + #[error("Conversion error: {0}")] + Conversion(#[from] miniscript::descriptor::ConversionError), + #[error("UTXO update error: {0}")] + UtxoUpdate(#[from] miniscript::psbt::UtxoUpdateError), + #[error("Output update error: {0}")] + OutputUpdate(#[from] miniscript::psbt::OutputUpdateError), } /// Represents the last failed [`crate::blockchain::WalletSync`] sync attempt in which we were short @@ -167,67 +214,23 @@ 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); - }; - ( $from:ty, $to:ident, $impl_for:ty ) => { - impl std::convert::From<$from> for $impl_for { - fn from(err: $from) -> Self { - <$impl_for>::$to(err) - } - } - }; -} - -impl_error!(descriptor::error::Error, Descriptor); -impl_error!(descriptor::policy::PolicyError, InvalidPolicyPathError); -impl_error!(wallet::signer::SignerError, Signer); - impl From for Error { fn from(key_error: crate::keys::KeyError) -> Error { match key_error { crate::keys::KeyError::Miniscript(inner) => Error::Miniscript(inner), crate::keys::KeyError::Bip32(inner) => Error::Bip32(inner), crate::keys::KeyError::InvalidChecksum => Error::ChecksumMismatch, - e => Error::Key(e), + e => Self::Key(e), } } } -impl_error!(bitcoin::consensus::encode::Error, Encode); -impl_error!(miniscript::Error, Miniscript); -impl_error!(MiniscriptPsbtError, MiniscriptPsbt); -impl_error!(bitcoin::util::bip32::Error, Bip32); -impl_error!(bitcoin::secp256k1::Error, Secp256k1); -impl_error!(serde_json::Error, Json); -impl_error!(bitcoin::hashes::hex::Error, Hex); -impl_error!(bitcoin::util::psbt::Error, Psbt); -impl_error!(bitcoin::util::psbt::PsbtParseError, PsbtParse); - -#[cfg(feature = "electrum")] -impl_error!(electrum_client::Error, Electrum); -#[cfg(feature = "key-value-db")] -impl_error!(sled::Error, Sled); -#[cfg(feature = "rpc")] -impl_error!(bitcoincore_rpc::Error, Rpc); -#[cfg(feature = "sqlite")] -impl_error!(rusqlite::Error, Rusqlite); - #[cfg(feature = "compact_filters")] impl From for Error { fn from(other: crate::blockchain::compact_filters::CompactFiltersError) -> Self { match other { crate::blockchain::compact_filters::CompactFiltersError::Global(e) => *e, - err => Error::CompactFilters(err), + err => Self::CompactFilters(err), } } } @@ -237,7 +240,7 @@ impl From for Error { fn from(other: crate::wallet::verify::VerifyError) -> Self { match other { crate::wallet::verify::VerifyError::Global(inner) => *inner, - err => Error::Verification(err), + err => Self::Verification(err), } } } @@ -245,6 +248,6 @@ impl From for Error { #[cfg(feature = "esplora")] impl From for Error { fn from(other: crate::blockchain::esplora::EsploraError) -> Self { - Error::Esplora(Box::new(other)) + Self::Esplora(Box::new(other)) } } diff --git a/src/keys/mod.rs b/src/keys/mod.rs index da541e1c5..1d67e13ac 100644 --- a/src/keys/mod.rs +++ b/src/keys/mod.rs @@ -912,35 +912,30 @@ impl IntoDescriptorKey for PrivateKey { } /// Errors thrown while working with [`keys`](crate::keys) -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum KeyError { /// The key cannot exist in the given script context + #[error("Invalid script context")] InvalidScriptContext, /// The key is not valid for the given network + #[error("Invalid network")] InvalidNetwork, /// The key has an invalid checksum + #[error("Invalid checksum")] InvalidChecksum, /// Custom error message + #[error("{0}")] Message(String), /// BIP32 error - Bip32(bitcoin::util::bip32::Error), + #[error("BIP32 error: {0}")] + Bip32(#[from] bitcoin::util::bip32::Error), /// Miniscript error - Miniscript(miniscript::Error), -} - -impl_error!(miniscript::Error, Miniscript, KeyError); -impl_error!(bitcoin::util::bip32::Error, Bip32, KeyError); - -impl std::fmt::Display for KeyError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } + #[error("Miniscript error: {0}")] + Miniscript(#[from] miniscript::Error), } -impl std::error::Error for KeyError {} - #[cfg(test)] pub mod test { use bitcoin::util::bip32; diff --git a/src/wallet/signer.rs b/src/wallet/signer.rs index 84d38826a..3bd60acc8 100644 --- a/src/wallet/signer.rs +++ b/src/wallet/signer.rs @@ -130,62 +130,56 @@ impl From for SignerId { } /// Signing error -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, thiserror::Error)] pub enum SignerError { /// The private key is missing for the required public key + #[error("Missing private key")] MissingKey, /// The private key in use has the right fingerprint but derives differently than expected + #[error( + "The private key in use has the right fingerprint but derives differently than expected" + )] InvalidKey, /// The user canceled the operation + #[error("The user canceled the operation")] UserCanceled, /// Input index is out of range + #[error("Input index out of range")] InputIndexOutOfRange, /// The `non_witness_utxo` field of the transaction is required to sign this input + #[error("Missing non-witness UTXO")] MissingNonWitnessUtxo, /// The `non_witness_utxo` specified is invalid + #[error("Invalid non-witness UTXO")] InvalidNonWitnessUtxo, /// The `witness_utxo` field of the transaction is required to sign this input + #[error("Missing witness UTXO")] MissingWitnessUtxo, /// The `witness_script` field of the transaction is required to sign this input + #[error("Missing witness script")] MissingWitnessScript, /// The fingerprint and derivation path are missing from the psbt input + #[error("Missing fingerprint and derivation path")] MissingHdKeypath, /// The psbt contains a non-`SIGHASH_ALL` sighash in one of its input and the user hasn't /// explicitly allowed them /// /// To enable signing transactions with non-standard sighashes set /// [`SignOptions::allow_all_sighashes`] to `true`. + #[error("The psbt contains a non standard sighash")] NonStandardSighash, /// Invalid SIGHASH for the signing context in use + #[error("Invalid SIGHASH for the signing context in use")] InvalidSighash, /// Error while computing the hash to sign - SighashError(sighash::Error), + #[error("Error while computing the hash to sign: {0}")] + SighashError(#[from] sighash::Error), /// Error while signing using hardware wallets #[cfg(feature = "hardware-signer")] - HWIError(hwi::error::Error), + #[error("Error while signing using hardware wallets: {0}")] + HWIError(#[from] hwi::error::Error), } -#[cfg(feature = "hardware-signer")] -impl From for SignerError { - fn from(e: hwi::error::Error) -> Self { - SignerError::HWIError(e) - } -} - -impl From for SignerError { - fn from(e: sighash::Error) -> Self { - SignerError::SighashError(e) - } -} - -impl fmt::Display for SignerError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -impl std::error::Error for SignerError {} - /// Signing context /// /// Used by our software signers to determine the type of signatures to make diff --git a/src/wallet/verify.rs b/src/wallet/verify.rs index 084388b91..d730775fa 100644 --- a/src/wallet/verify.rs +++ b/src/wallet/verify.rs @@ -12,7 +12,6 @@ //! Verify transactions against the consensus rules use std::collections::HashMap; -use std::fmt; use bitcoin::consensus::serialize; use bitcoin::{OutPoint, Transaction, Txid}; @@ -73,36 +72,37 @@ pub fn verify_tx( } /// Error during validation of a tx agains the consensus rules -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum VerifyError { /// The transaction being spent is not available in the database or the blockchain client + #[error("The transaction being spent is not available in the database or the blockchain client: {0}")] MissingInputTx(Txid), /// The transaction being spent doesn't have the requested output + #[error("The transaction being spent doesn't have the requested output: {0}")] InvalidInput(OutPoint), /// Consensus error + #[error("Consensus error: {0:?}")] Consensus(bitcoinconsensus::Error), /// Generic error /// /// It has to be wrapped in a `Box` since `Error` has a variant that contains this enum + #[error("Generic error: {0}")] Global(Box), } -impl fmt::Display for VerifyError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) +impl From for VerifyError { + fn from(e: bitcoinconsensus::Error) -> Self { + Self::Consensus(e) } } -impl std::error::Error for VerifyError {} - impl From for VerifyError { fn from(other: Error) -> Self { - VerifyError::Global(Box::new(other)) + Self::Global(Box::new(other)) } } -impl_error!(bitcoinconsensus::Error, Consensus, VerifyError); #[cfg(test)] mod test {