diff --git a/bdk-ffi/src/bdk.udl b/bdk-ffi/src/bdk.udl index 0dd8dd7b..41450564 100644 --- a/bdk-ffi/src/bdk.udl +++ b/bdk-ffi/src/bdk.udl @@ -99,6 +99,24 @@ interface DescriptorError { Hex(string e); }; +[Error] +interface SignerError { + MissingKey(); + InvalidKey(); + UserCanceled(); + InputIndexOutOfRange(); + MissingNonWitnessUtxo(); + InvalidNonWitnessUtxo(); + MissingWitnessUtxo(); + MissingWitnessScript(); + MissingHdKeypath(); + NonStandardSighash(); + InvalidSighash(); + SighashError(string e); + MiniscriptPsbt(string e); + External(string e); +}; + [Error] interface TxidParseError { InvalidTxid(string txid); @@ -213,8 +231,8 @@ interface Wallet { boolean is_mine([ByRef] Script script); - [Throws=Alpha3Error] - boolean sign(Psbt psbt); + [Throws=SignerError] + boolean sign2(Psbt psbt); SentAndReceivedValues sent_and_received([ByRef] Transaction tx); diff --git a/bdk-ffi/src/error.rs b/bdk-ffi/src/error.rs index 1d630a0b..622e9fb4 100644 --- a/bdk-ffi/src/error.rs +++ b/bdk-ffi/src/error.rs @@ -5,6 +5,7 @@ use bdk::bitcoin::Network; use bdk::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError; use bdk::descriptor::DescriptorError as BdkDescriptorError; use bdk::wallet::error::{BuildFeeBumpError, CreateTxError}; +use bdk::wallet::signer::SignerError as BdkSignerError; use bdk::wallet::tx_builder::{AddUtxoError, AllowShrinkingError}; use bdk::wallet::{NewError, NewOrLoadError}; use bdk_esplora::esplora_client::{Error as BdkEsploraError, Error}; @@ -233,6 +234,51 @@ pub enum DescriptorError { Hex { e: String }, } +#[derive(Debug, thiserror::Error)] +pub enum SignerError { + #[error("Missing key for signing")] + MissingKey, + + #[error("Invalid key provided")] + InvalidKey, + + #[error("User canceled operation")] + UserCanceled, + + #[error("Input index out of range")] + InputIndexOutOfRange, + + #[error("Missing non-witness UTXO information")] + MissingNonWitnessUtxo, + + #[error("Invalid non-witness UTXO information provided")] + InvalidNonWitnessUtxo, + + #[error("Missing witness UTXO")] + MissingWitnessUtxo, + + #[error("Missing witness script")] + MissingWitnessScript, + + #[error("Missing HD keypath")] + MissingHdKeypath, + + #[error("Non-standard sighash type used")] + NonStandardSighash, + + #[error("Invalid sighash type provided")] + InvalidSighash, + + #[error("Error with sighash computation: {e}")] + SighashError { e: String }, + + #[error("Miniscript Psbt error: {e}")] + MiniscriptPsbt { e: String }, + + #[error("External error: {e}")] + External { e: String }, +} + #[derive(Debug, thiserror::Error)] pub enum ExtractTxError { #[error("an absurdly high fee rate of {fee_rate} sat/vbyte")] @@ -275,6 +321,29 @@ impl From for DescriptorError { } } +impl From for SignerError { + fn from(error: BdkSignerError) -> Self { + match error { + BdkSignerError::MissingKey => SignerError::MissingKey, + BdkSignerError::InvalidKey => SignerError::InvalidKey, + BdkSignerError::UserCanceled => SignerError::UserCanceled, + BdkSignerError::InputIndexOutOfRange => SignerError::InputIndexOutOfRange, + BdkSignerError::MissingNonWitnessUtxo => SignerError::MissingNonWitnessUtxo, + BdkSignerError::InvalidNonWitnessUtxo => SignerError::InvalidNonWitnessUtxo, + BdkSignerError::MissingWitnessUtxo => SignerError::MissingWitnessUtxo, + BdkSignerError::MissingWitnessScript => SignerError::MissingWitnessScript, + BdkSignerError::MissingHdKeypath => SignerError::MissingHdKeypath, + BdkSignerError::NonStandardSighash => SignerError::NonStandardSighash, + BdkSignerError::InvalidSighash => SignerError::InvalidSighash, + BdkSignerError::SighashError(e) => SignerError::SighashError { e: e.to_string() }, + BdkSignerError::MiniscriptPsbt(e) => SignerError::MiniscriptPsbt { + e: format!("{:?}", e), + }, + BdkSignerError::External(e) => SignerError::External { e }, + } + } +} + impl From for PsbtParseError { fn from(error: BdkPsbtParseError) -> Self { match error { @@ -509,6 +578,7 @@ mod test { use crate::error::{EsploraError, PersistenceError, WalletCreationError}; use crate::CalculateFeeError; use crate::OutPoint; + use crate::SignerError; use bdk::bitcoin::Network; #[test] @@ -672,4 +742,55 @@ mod test { "loaded network type is not bitcoin, got Some(Testnet)" ); } + + #[test] + fn test_signer_errors() { + let errors = vec![ + (SignerError::MissingKey, "Missing key for signing"), + (SignerError::InvalidKey, "Invalid key provided"), + (SignerError::UserCanceled, "User canceled operation"), + ( + SignerError::InputIndexOutOfRange, + "Input index out of range", + ), + ( + SignerError::MissingNonWitnessUtxo, + "Missing non-witness UTXO information", + ), + ( + SignerError::InvalidNonWitnessUtxo, + "Invalid non-witness UTXO information provided", + ), + (SignerError::MissingWitnessUtxo, "Missing witness UTXO"), + (SignerError::MissingWitnessScript, "Missing witness script"), + (SignerError::MissingHdKeypath, "Missing HD keypath"), + ( + SignerError::NonStandardSighash, + "Non-standard sighash type used", + ), + (SignerError::InvalidSighash, "Invalid sighash type provided"), + ( + SignerError::SighashError { + e: "dummy error".into(), + }, + "Error with sighash computation: dummy error", + ), + ( + SignerError::MiniscriptPsbt { + e: "psbt issue".into(), + }, + "Miniscript Psbt error: psbt issue", + ), + ( + SignerError::External { + e: "external error".into(), + }, + "External error: external error", + ), + ]; + + for (error, message) in errors { + assert_eq!(error.to_string(), message); + } + } } diff --git a/bdk-ffi/src/lib.rs b/bdk-ffi/src/lib.rs index 0dbf3526..f995e1d3 100644 --- a/bdk-ffi/src/lib.rs +++ b/bdk-ffi/src/lib.rs @@ -22,6 +22,7 @@ use crate::error::ExtractTxError; use crate::error::FeeRateError; use crate::error::PersistenceError; use crate::error::PsbtParseError; +use crate::error::SignerError; use crate::error::TransactionError; use crate::error::TxidParseError; use crate::error::WalletCreationError; diff --git a/bdk-ffi/src/wallet.rs b/bdk-ffi/src/wallet.rs index f2e50a53..b3cb82e2 100644 --- a/bdk-ffi/src/wallet.rs +++ b/bdk-ffi/src/wallet.rs @@ -1,7 +1,8 @@ use crate::bitcoin::{OutPoint, Psbt, Script, Transaction}; use crate::descriptor::Descriptor; use crate::error::{ - Alpha3Error, CalculateFeeError, PersistenceError, TxidParseError, WalletCreationError, + Alpha3Error, CalculateFeeError, PersistenceError, SignerError, TxidParseError, + WalletCreationError, }; use crate::types::{ AddressIndex, AddressInfo, Balance, CanonicalTx, FeeRate, LocalOutput, ScriptAmount, @@ -89,15 +90,15 @@ impl Wallet { self.get_wallet().is_mine(&script.0) } - pub(crate) fn sign( + pub(crate) fn sign2( &self, psbt: Arc, // sign_options: Option, - ) -> Result { + ) -> Result { let mut psbt = psbt.inner.lock().unwrap(); self.get_wallet() .sign(&mut psbt, SignOptions::default()) - .map_err(|_| Alpha3Error::Generic) + .map_err(SignerError::from) //.map_err(|_| Alpha3Error::Generic) } pub fn sent_and_received(&self, tx: &Transaction) -> SentAndReceivedValues {