@@ -54,16 +54,17 @@ pub mod hardwaresigner;
5454
5555pub use utils:: IsDust ;
5656
57+ use crate :: descriptor;
5758#[ allow( deprecated) ]
5859use coin_selection:: DefaultCoinSelectionAlgorithm ;
5960use signer:: { SignOptions , SignerOrdering , SignersContainer , TransactionSigner } ;
6061use tx_builder:: { BumpFee , CreateTx , FeePolicy , TxBuilder , TxParams } ;
6162use utils:: { check_nsequence_rbf, After , Older , SecpCtx } ;
6263
63- use crate :: descriptor:: policy:: BuildSatisfaction ;
64+ use crate :: descriptor:: policy:: { BuildSatisfaction , PolicyError } ;
6465use crate :: descriptor:: {
65- calc_checksum, into_wallet_descriptor_checked, DerivedDescriptor , DescriptorMeta ,
66- ExtendedDescriptor , ExtractPolicy , IntoWalletDescriptor , Policy , XKeyUtils ,
66+ calc_checksum, into_wallet_descriptor_checked, DerivedDescriptor , DescriptorError ,
67+ DescriptorMeta , ExtendedDescriptor , ExtractPolicy , IntoWalletDescriptor , Policy , XKeyUtils ,
6768} ;
6869use crate :: error:: { Error , MiniscriptPsbtError } ;
6970use crate :: psbt:: PsbtUtils ;
@@ -166,7 +167,7 @@ impl Wallet {
166167pub enum NewError < P > {
167168 /// There was problem with the descriptors passed in
168169 Descriptor ( crate :: descriptor:: DescriptorError ) ,
169- /// We were unable to load the wallet's data from the persistance backend
170+ /// We were unable to load the wallet's data from the persistence backend
170171 Persist ( P ) ,
171172}
172173
@@ -178,7 +179,7 @@ where
178179 match self {
179180 NewError :: Descriptor ( e) => e. fmt ( f) ,
180181 NewError :: Persist ( e) => {
181- write ! ( f, "failed to load wallet from persistance backend: {}" , e)
182+ write ! ( f, "failed to load wallet from persistence backend: {}" , e)
182183 }
183184 }
184185 }
@@ -200,6 +201,60 @@ pub enum InsertTxError {
200201#[ cfg( feature = "std" ) ]
201202impl < P : core:: fmt:: Display + core:: fmt:: Debug > std:: error:: Error for NewError < P > { }
202203
204+ #[ derive( Debug ) ]
205+ /// Error returned from [`Wallet::create_tx`]
206+ pub enum CreateTxError < P > {
207+ /// There was a problem with the descriptors passed in
208+ Descriptor ( DescriptorError ) ,
209+ /// We were unable to write wallet data to the persistence backend
210+ Persist ( P ) ,
211+ /// There was a problem while extracting and manipulating policies
212+ Policy ( PolicyError ) ,
213+ /// TODO: replace this with specific error types
214+ Bdk ( Error ) ,
215+ }
216+
217+ impl < P > fmt:: Display for CreateTxError < P >
218+ where
219+ P : fmt:: Display ,
220+ {
221+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
222+ match self {
223+ Self :: Descriptor ( e) => e. fmt ( f) ,
224+ Self :: Persist ( e) => {
225+ write ! (
226+ f,
227+ "failed to write wallet data to persistence backend: {}" ,
228+ e
229+ )
230+ }
231+ Self :: Bdk ( e) => e. fmt ( f) ,
232+ Self :: Policy ( e) => e. fmt ( f) ,
233+ }
234+ }
235+ }
236+
237+ impl < P > From < descriptor:: error:: Error > for CreateTxError < P > {
238+ fn from ( err : descriptor:: error:: Error ) -> Self {
239+ CreateTxError :: Descriptor ( err)
240+ }
241+ }
242+
243+ impl < P > From < PolicyError > for CreateTxError < P > {
244+ fn from ( err : PolicyError ) -> Self {
245+ CreateTxError :: Policy ( err)
246+ }
247+ }
248+
249+ impl < P > From < Error > for CreateTxError < P > {
250+ fn from ( err : Error ) -> Self {
251+ CreateTxError :: Bdk ( err)
252+ }
253+ }
254+
255+ #[ cfg( feature = "std" ) ]
256+ impl < P : core:: fmt:: Display + core:: fmt:: Debug > std:: error:: Error for CreateTxError < P > { }
257+
203258impl < D > Wallet < D > {
204259 /// Create a wallet from a `descriptor` (and an optional `change_descriptor`) and load related
205260 /// transaction data from `db`.
@@ -596,6 +651,8 @@ impl<D> Wallet<D> {
596651 /// # use std::str::FromStr;
597652 /// # use bitcoin::*;
598653 /// # use bdk::*;
654+ /// # use bdk::wallet::{ChangeSet,CreateTxError};
655+ /// # use bdk_chain::PersistBackend;
599656 /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
600657 /// # let mut wallet = doctest_wallet!();
601658 /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
@@ -607,7 +664,7 @@ impl<D> Wallet<D> {
607664 /// };
608665 ///
609666 /// // sign and broadcast ...
610- /// # Ok::<(), bdk::Error >(())
667+ /// # Ok::<(), CreateTxError<<() as PersistBackend<ChangeSet>>::WriteError> >(())
611668 /// ```
612669 ///
613670 /// [`TxBuilder`]: crate::TxBuilder
@@ -624,7 +681,7 @@ impl<D> Wallet<D> {
624681 & mut self ,
625682 coin_selection : Cs ,
626683 params : TxParams ,
627- ) -> Result < ( psbt:: PartiallySignedTransaction , TransactionDetails ) , Error >
684+ ) -> Result < ( psbt:: PartiallySignedTransaction , TransactionDetails ) , CreateTxError < D :: WriteError > >
628685 where
629686 D : PersistBackend < ChangeSet > ,
630687 {
@@ -659,15 +716,15 @@ impl<D> Wallet<D> {
659716 && external_policy. requires_path ( )
660717 && params. external_policy_path . is_none ( )
661718 {
662- return Err ( Error :: SpendingPolicyRequired ( KeychainKind :: External ) ) ;
719+ return Err ( Error :: SpendingPolicyRequired ( KeychainKind :: External ) . into ( ) ) ;
663720 } ;
664721 // Same for the internal_policy path, if present
665722 if let Some ( internal_policy) = & internal_policy {
666723 if params. change_policy != tx_builder:: ChangeSpendPolicy :: ChangeForbidden
667724 && internal_policy. requires_path ( )
668725 && params. internal_policy_path . is_none ( )
669726 {
670- return Err ( Error :: SpendingPolicyRequired ( KeychainKind :: Internal ) ) ;
727+ return Err ( Error :: SpendingPolicyRequired ( KeychainKind :: Internal ) . into ( ) ) ;
671728 } ;
672729 }
673730
@@ -696,13 +753,14 @@ impl<D> Wallet<D> {
696753
697754 let version = match params. version {
698755 Some ( tx_builder:: Version ( 0 ) ) => {
699- return Err ( Error :: Generic ( "Invalid version `0`" . into ( ) ) )
756+ return Err ( Error :: Generic ( "Invalid version `0`" . into ( ) ) . into ( ) )
700757 }
701758 Some ( tx_builder:: Version ( 1 ) ) if requirements. csv . is_some ( ) => {
702759 return Err ( Error :: Generic (
703760 "TxBuilder requested version `1`, but at least `2` is needed to use OP_CSV"
704761 . into ( ) ,
705- ) )
762+ )
763+ . into ( ) )
706764 }
707765 Some ( tx_builder:: Version ( x) ) => x,
708766 None if requirements. csv . is_some ( ) => 2 ,
@@ -745,7 +803,7 @@ impl<D> Wallet<D> {
745803 // Specific nLockTime required and it's compatible with the constraints
746804 Some ( x) if requirements. timelock . unwrap ( ) . is_same_unit ( x) && x >= requirements. timelock . unwrap ( ) => x,
747805 // Invalid nLockTime required
748- Some ( x) => return Err ( Error :: Generic ( format ! ( "TxBuilder requested timelock of `{:?}`, but at least `{:?}` is required to spend from this script" , x, requirements. timelock. unwrap( ) ) ) )
806+ Some ( x) => return Err ( Error :: Generic ( format ! ( "TxBuilder requested timelock of `{:?}`, but at least `{:?}` is required to spend from this script" , x, requirements. timelock. unwrap( ) ) ) . into ( ) )
749807 } ;
750808
751809 let n_sequence = match ( params. rbf , requirements. csv ) {
@@ -763,7 +821,8 @@ impl<D> Wallet<D> {
763821 ( Some ( tx_builder:: RbfValue :: Value ( rbf) ) , _) if !rbf. is_rbf ( ) => {
764822 return Err ( Error :: Generic (
765823 "Cannot enable RBF with a nSequence >= 0xFFFFFFFE" . into ( ) ,
766- ) )
824+ )
825+ . into ( ) )
767826 }
768827 // RBF with a specific value requested, but the value is incompatible with CSV
769828 ( Some ( tx_builder:: RbfValue :: Value ( rbf) ) , Some ( csv) )
@@ -772,7 +831,8 @@ impl<D> Wallet<D> {
772831 return Err ( Error :: Generic ( format ! (
773832 "Cannot enable RBF with nSequence `{:?}` given a required OP_CSV of `{:?}`" ,
774833 rbf, csv
775- ) ) )
834+ ) )
835+ . into ( ) )
776836 }
777837
778838 // RBF enabled with the default value with CSV also enabled. CSV takes precedence
@@ -793,7 +853,8 @@ impl<D> Wallet<D> {
793853 if * fee < previous_fee. absolute {
794854 return Err ( Error :: FeeTooLow {
795855 required : previous_fee. absolute ,
796- } ) ;
856+ }
857+ . into ( ) ) ;
797858 }
798859 }
799860 ( FeeRate :: from_sat_per_vb ( 0.0 ) , * fee)
@@ -804,7 +865,8 @@ impl<D> Wallet<D> {
804865 if * rate < required_feerate {
805866 return Err ( Error :: FeeRateTooLow {
806867 required : required_feerate,
807- } ) ;
868+ }
869+ . into ( ) ) ;
808870 }
809871 }
810872 ( * rate, 0 )
@@ -819,7 +881,7 @@ impl<D> Wallet<D> {
819881 } ;
820882
821883 if params. manually_selected_only && params. utxos . is_empty ( ) {
822- return Err ( Error :: NoUtxosSelected ) ;
884+ return Err ( Error :: NoUtxosSelected . into ( ) ) ;
823885 }
824886
825887 // we keep it as a float while we accumulate it, and only round it at the end
@@ -833,7 +895,7 @@ impl<D> Wallet<D> {
833895 && value. is_dust ( script_pubkey)
834896 && !script_pubkey. is_provably_unspendable ( )
835897 {
836- return Err ( Error :: OutputBelowDustLimit ( index) ) ;
898+ return Err ( Error :: OutputBelowDustLimit ( index) . into ( ) ) ;
837899 }
838900
839901 if self . is_mine ( script_pubkey) {
@@ -868,7 +930,8 @@ impl<D> Wallet<D> {
868930 {
869931 return Err ( Error :: Generic (
870932 "The `change_policy` can be set only if the wallet has a change_descriptor" . into ( ) ,
871- ) ) ;
933+ )
934+ . into ( ) ) ;
872935 }
873936
874937 let ( required_utxos, optional_utxos) = self . preselect_utxos (
@@ -892,7 +955,7 @@ impl<D> Wallet<D> {
892955 self . indexed_graph . index . mark_used ( & change_keychain, index) ;
893956 self . persist
894957 . stage ( ChangeSet :: from ( IndexedAdditions :: from ( index_additions) ) ) ;
895- self . persist . commit ( ) . expect ( "TODO" ) ;
958+ self . persist . commit ( ) . map_err ( CreateTxError :: Persist ) ? ;
896959 spk
897960 }
898961 } ;
@@ -936,10 +999,11 @@ impl<D> Wallet<D> {
936999 return Err ( Error :: InsufficientFunds {
9371000 needed : * dust_threshold,
9381001 available : remaining_amount. saturating_sub ( * change_fee) ,
939- } ) ;
1002+ }
1003+ . into ( ) ) ;
9401004 }
9411005 } else {
942- return Err ( Error :: NoRecipients ) ;
1006+ return Err ( Error :: NoRecipients . into ( ) ) ;
9431007 }
9441008 }
9451009
@@ -998,6 +1062,8 @@ impl<D> Wallet<D> {
9981062 /// # use std::str::FromStr;
9991063 /// # use bitcoin::*;
10001064 /// # use bdk::*;
1065+ /// # use bdk::wallet::{ChangeSet, CreateTxError};
1066+ /// # use bdk_chain::PersistBackend;
10011067 /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
10021068 /// # let mut wallet = doctest_wallet!();
10031069 /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
@@ -1021,7 +1087,7 @@ impl<D> Wallet<D> {
10211087 /// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
10221088 /// let fee_bumped_tx = psbt.extract_tx();
10231089 /// // broadcast fee_bumped_tx to replace original
1024- /// # Ok::<(), bdk::Error >(())
1090+ /// # Ok::<(), CreateTxError<<() as PersistBackend<ChangeSet>>::WriteError> >(())
10251091 /// ```
10261092 // TODO: support for merging multiple transactions while bumping the fees
10271093 pub fn build_fee_bump (
@@ -1168,6 +1234,8 @@ impl<D> Wallet<D> {
11681234 /// # use std::str::FromStr;
11691235 /// # use bitcoin::*;
11701236 /// # use bdk::*;
1237+ /// # use bdk::wallet::{ChangeSet, CreateTxError};
1238+ /// # use bdk_chain::PersistBackend;
11711239 /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
11721240 /// # let mut wallet = doctest_wallet!();
11731241 /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
@@ -1178,7 +1246,7 @@ impl<D> Wallet<D> {
11781246 /// };
11791247 /// let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
11801248 /// assert!(finalized, "we should have signed all the inputs");
1181- /// # Ok::<(), bdk::Error >(())
1249+ /// # Ok::<(), CreateTxError<<() as PersistBackend<ChangeSet>>::WriteError> >(())
11821250 pub fn sign (
11831251 & self ,
11841252 psbt : & mut psbt:: PartiallySignedTransaction ,
0 commit comments