@@ -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,61 @@ 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+ #[ cfg( feature = "std" ) ]
218+ impl < P > fmt:: Display for CreateTxError < P >
219+ where
220+ P : fmt:: Display ,
221+ {
222+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
223+ match self {
224+ Self :: Descriptor ( e) => e. fmt ( f) ,
225+ Self :: Persist ( e) => {
226+ write ! (
227+ f,
228+ "failed to write wallet data to persistence backend: {}" ,
229+ e
230+ )
231+ }
232+ Self :: Bdk ( e) => e. fmt ( f) ,
233+ Self :: Policy ( e) => e. fmt ( f) ,
234+ }
235+ }
236+ }
237+
238+ impl < P > From < descriptor:: error:: Error > for CreateTxError < P > {
239+ fn from ( err : descriptor:: error:: Error ) -> Self {
240+ CreateTxError :: Descriptor ( err)
241+ }
242+ }
243+
244+ impl < P > From < PolicyError > for CreateTxError < P > {
245+ fn from ( err : PolicyError ) -> Self {
246+ CreateTxError :: Policy ( err)
247+ }
248+ }
249+
250+ impl < P > From < Error > for CreateTxError < P > {
251+ fn from ( err : Error ) -> Self {
252+ CreateTxError :: Bdk ( err)
253+ }
254+ }
255+
256+ #[ cfg( feature = "std" ) ]
257+ impl < P : core:: fmt:: Display + core:: fmt:: Debug > std:: error:: Error for CreateTxError < P > { }
258+
203259impl < D > Wallet < D > {
204260 /// Create a wallet from a `descriptor` (and an optional `change_descriptor`) and load related
205261 /// transaction data from `db`.
@@ -596,6 +652,8 @@ impl<D> Wallet<D> {
596652 /// # use std::str::FromStr;
597653 /// # use bitcoin::*;
598654 /// # use bdk::*;
655+ /// # use bdk::wallet::{ChangeSet,CreateTxError};
656+ /// # use bdk_chain::PersistBackend;
599657 /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
600658 /// # let mut wallet = doctest_wallet!();
601659 /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
@@ -607,7 +665,7 @@ impl<D> Wallet<D> {
607665 /// };
608666 ///
609667 /// // sign and broadcast ...
610- /// # Ok::<(), bdk::Error >(())
668+ /// # Ok::<(), CreateTxError<<() as PersistBackend<ChangeSet>>::WriteError> >(())
611669 /// ```
612670 ///
613671 /// [`TxBuilder`]: crate::TxBuilder
@@ -624,7 +682,7 @@ impl<D> Wallet<D> {
624682 & mut self ,
625683 coin_selection : Cs ,
626684 params : TxParams ,
627- ) -> Result < ( psbt:: PartiallySignedTransaction , TransactionDetails ) , Error >
685+ ) -> Result < ( psbt:: PartiallySignedTransaction , TransactionDetails ) , CreateTxError < D :: WriteError > >
628686 where
629687 D : PersistBackend < ChangeSet > ,
630688 {
@@ -659,15 +717,15 @@ impl<D> Wallet<D> {
659717 && external_policy. requires_path ( )
660718 && params. external_policy_path . is_none ( )
661719 {
662- return Err ( Error :: SpendingPolicyRequired ( KeychainKind :: External ) ) ;
720+ return Err ( Error :: SpendingPolicyRequired ( KeychainKind :: External ) . into ( ) ) ;
663721 } ;
664722 // Same for the internal_policy path, if present
665723 if let Some ( internal_policy) = & internal_policy {
666724 if params. change_policy != tx_builder:: ChangeSpendPolicy :: ChangeForbidden
667725 && internal_policy. requires_path ( )
668726 && params. internal_policy_path . is_none ( )
669727 {
670- return Err ( Error :: SpendingPolicyRequired ( KeychainKind :: Internal ) ) ;
728+ return Err ( Error :: SpendingPolicyRequired ( KeychainKind :: Internal ) . into ( ) ) ;
671729 } ;
672730 }
673731
@@ -696,13 +754,14 @@ impl<D> Wallet<D> {
696754
697755 let version = match params. version {
698756 Some ( tx_builder:: Version ( 0 ) ) => {
699- return Err ( Error :: Generic ( "Invalid version `0`" . into ( ) ) )
757+ return Err ( Error :: Generic ( "Invalid version `0`" . into ( ) ) . into ( ) )
700758 }
701759 Some ( tx_builder:: Version ( 1 ) ) if requirements. csv . is_some ( ) => {
702760 return Err ( Error :: Generic (
703761 "TxBuilder requested version `1`, but at least `2` is needed to use OP_CSV"
704762 . into ( ) ,
705- ) )
763+ )
764+ . into ( ) )
706765 }
707766 Some ( tx_builder:: Version ( x) ) => x,
708767 None if requirements. csv . is_some ( ) => 2 ,
@@ -745,7 +804,7 @@ impl<D> Wallet<D> {
745804 // Specific nLockTime required and it's compatible with the constraints
746805 Some ( x) if requirements. timelock . unwrap ( ) . is_same_unit ( x) && x >= requirements. timelock . unwrap ( ) => x,
747806 // 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( ) ) ) )
807+ 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 ( ) )
749808 } ;
750809
751810 let n_sequence = match ( params. rbf , requirements. csv ) {
@@ -763,7 +822,8 @@ impl<D> Wallet<D> {
763822 ( Some ( tx_builder:: RbfValue :: Value ( rbf) ) , _) if !rbf. is_rbf ( ) => {
764823 return Err ( Error :: Generic (
765824 "Cannot enable RBF with a nSequence >= 0xFFFFFFFE" . into ( ) ,
766- ) )
825+ )
826+ . into ( ) )
767827 }
768828 // RBF with a specific value requested, but the value is incompatible with CSV
769829 ( Some ( tx_builder:: RbfValue :: Value ( rbf) ) , Some ( csv) )
@@ -772,7 +832,8 @@ impl<D> Wallet<D> {
772832 return Err ( Error :: Generic ( format ! (
773833 "Cannot enable RBF with nSequence `{:?}` given a required OP_CSV of `{:?}`" ,
774834 rbf, csv
775- ) ) )
835+ ) )
836+ . into ( ) )
776837 }
777838
778839 // RBF enabled with the default value with CSV also enabled. CSV takes precedence
@@ -793,7 +854,8 @@ impl<D> Wallet<D> {
793854 if * fee < previous_fee. absolute {
794855 return Err ( Error :: FeeTooLow {
795856 required : previous_fee. absolute ,
796- } ) ;
857+ }
858+ . into ( ) ) ;
797859 }
798860 }
799861 ( FeeRate :: from_sat_per_vb ( 0.0 ) , * fee)
@@ -804,7 +866,8 @@ impl<D> Wallet<D> {
804866 if * rate < required_feerate {
805867 return Err ( Error :: FeeRateTooLow {
806868 required : required_feerate,
807- } ) ;
869+ }
870+ . into ( ) ) ;
808871 }
809872 }
810873 ( * rate, 0 )
@@ -819,7 +882,7 @@ impl<D> Wallet<D> {
819882 } ;
820883
821884 if params. manually_selected_only && params. utxos . is_empty ( ) {
822- return Err ( Error :: NoUtxosSelected ) ;
885+ return Err ( Error :: NoUtxosSelected . into ( ) ) ;
823886 }
824887
825888 // we keep it as a float while we accumulate it, and only round it at the end
@@ -833,7 +896,7 @@ impl<D> Wallet<D> {
833896 && value. is_dust ( script_pubkey)
834897 && !script_pubkey. is_provably_unspendable ( )
835898 {
836- return Err ( Error :: OutputBelowDustLimit ( index) ) ;
899+ return Err ( Error :: OutputBelowDustLimit ( index) . into ( ) ) ;
837900 }
838901
839902 if self . is_mine ( script_pubkey) {
@@ -868,7 +931,8 @@ impl<D> Wallet<D> {
868931 {
869932 return Err ( Error :: Generic (
870933 "The `change_policy` can be set only if the wallet has a change_descriptor" . into ( ) ,
871- ) ) ;
934+ )
935+ . into ( ) ) ;
872936 }
873937
874938 let ( required_utxos, optional_utxos) = self . preselect_utxos (
@@ -892,7 +956,7 @@ impl<D> Wallet<D> {
892956 self . indexed_graph . index . mark_used ( & change_keychain, index) ;
893957 self . persist
894958 . stage ( ChangeSet :: from ( IndexedAdditions :: from ( index_additions) ) ) ;
895- self . persist . commit ( ) . expect ( "TODO" ) ;
959+ self . persist . commit ( ) . map_err ( CreateTxError :: Persist ) ? ;
896960 spk
897961 }
898962 } ;
@@ -936,10 +1000,11 @@ impl<D> Wallet<D> {
9361000 return Err ( Error :: InsufficientFunds {
9371001 needed : * dust_threshold,
9381002 available : remaining_amount. saturating_sub ( * change_fee) ,
939- } ) ;
1003+ }
1004+ . into ( ) ) ;
9401005 }
9411006 } else {
942- return Err ( Error :: NoRecipients ) ;
1007+ return Err ( Error :: NoRecipients . into ( ) ) ;
9431008 }
9441009 }
9451010
@@ -998,6 +1063,8 @@ impl<D> Wallet<D> {
9981063 /// # use std::str::FromStr;
9991064 /// # use bitcoin::*;
10001065 /// # use bdk::*;
1066+ /// # use bdk::wallet::{ChangeSet, CreateTxError};
1067+ /// # use bdk_chain::PersistBackend;
10011068 /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
10021069 /// # let mut wallet = doctest_wallet!();
10031070 /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
@@ -1021,7 +1088,7 @@ impl<D> Wallet<D> {
10211088 /// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
10221089 /// let fee_bumped_tx = psbt.extract_tx();
10231090 /// // broadcast fee_bumped_tx to replace original
1024- /// # Ok::<(), bdk::Error >(())
1091+ /// # Ok::<(), CreateTxError<<() as PersistBackend<ChangeSet>>::WriteError> >(())
10251092 /// ```
10261093 // TODO: support for merging multiple transactions while bumping the fees
10271094 pub fn build_fee_bump (
@@ -1168,6 +1235,8 @@ impl<D> Wallet<D> {
11681235 /// # use std::str::FromStr;
11691236 /// # use bitcoin::*;
11701237 /// # use bdk::*;
1238+ /// # use bdk::wallet::{ChangeSet, CreateTxError};
1239+ /// # use bdk_chain::PersistBackend;
11711240 /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
11721241 /// # let mut wallet = doctest_wallet!();
11731242 /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
@@ -1178,7 +1247,7 @@ impl<D> Wallet<D> {
11781247 /// };
11791248 /// let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
11801249 /// assert!(finalized, "we should have signed all the inputs");
1181- /// # Ok::<(), bdk::Error >(())
1250+ /// # Ok::<(), CreateTxError<<() as PersistBackend<ChangeSet>>::WriteError> >(())
11821251 pub fn sign (
11831252 & self ,
11841253 psbt : & mut psbt:: PartiallySignedTransaction ,
0 commit comments