11use bdk_coin_select:: {
22 ChangePolicy , DrainWeights , InsufficientFunds , Replace , Target , TargetFee , TargetOutputs ,
33} ;
4- use bitcoin:: { Amount , FeeRate , ScriptBuf , Transaction , TxOut , Weight } ;
4+ use bitcoin:: { Amount , FeeRate , Transaction , TxOut , Weight } ;
55use miniscript:: bitcoin;
66
7- use crate :: { cs_feerate, DefiniteDescriptor , InputCandidates , InputGroup , Output , Selection } ;
7+ use crate :: { cs_feerate, InputCandidates , InputGroup , Output , ScriptSource , Selection } ;
88use alloc:: vec:: Vec ;
99use core:: fmt;
1010
@@ -15,51 +15,10 @@ pub struct Selector<'c> {
1515 target_outputs : Vec < Output > ,
1616 target : Target ,
1717 change_policy : bdk_coin_select:: ChangePolicy ,
18- change_descriptor : ChangeDescriptor ,
18+ change_source : ScriptSource ,
1919 inner : bdk_coin_select:: CoinSelector < ' c > ,
2020}
2121
22- /// Data source to create a change output if needed
23- #[ derive( Debug , Clone ) ]
24- pub enum ChangeDescriptor {
25- /// Build change output from descriptor
26- Definite ( DefiniteDescriptor ) ,
27- /// Build change output without descriptor
28- Manual {
29- /// The final script pubkey the change output should have
30- script_pubkey : ScriptBuf ,
31- /// The maximum weight to satisfy the script pubkey
32- max_weight_to_satisfy_wu : u64 ,
33- } ,
34- }
35-
36- /// Wrapper methods to unify interface for change outputs
37- impl ChangeDescriptor {
38- /// Get the maximum weight to satisfy the script pubkey of the resultant output
39- pub fn get_max_weight_to_satisfy_wu ( & self ) -> Result < u64 , miniscript:: Error > {
40- use ChangeDescriptor :: * ;
41-
42- match self {
43- Definite ( definite_descriptor) => definite_descriptor
44- . max_weight_to_satisfy ( )
45- . map ( |weight| weight. to_wu ( ) ) ,
46- Manual {
47- max_weight_to_satisfy_wu,
48- ..
49- } => Ok ( * max_weight_to_satisfy_wu) ,
50- }
51- }
52-
53- /// Get the script pubkey the change output should have
54- pub fn get_script_pubkey ( & self ) -> ScriptBuf {
55- use ChangeDescriptor :: * ;
56- match self {
57- Definite ( definite_descriptor) => definite_descriptor. script_pubkey ( ) ,
58- Manual { script_pubkey, .. } => script_pubkey. clone ( ) ,
59- }
60- }
61- }
62-
6322/// Parameters for creating tx.
6423///
6524/// TODO: Create a builder interface on this that does checks. I.e.
@@ -83,7 +42,7 @@ pub struct SelectorParams {
8342 /// To derive change output.
8443 ///
8544 /// Will error if this is unsatisfiable descriptor.
86- pub change_descriptor : ChangeDescriptor ,
45+ pub change_source : ScriptSource ,
8746
8847 /// The policy to determine whether we create a change output.
8948 pub change_policy : ChangePolicyType ,
@@ -181,11 +140,11 @@ impl SelectorParams {
181140 pub fn new (
182141 target_feerate : bitcoin:: FeeRate ,
183142 target_outputs : Vec < Output > ,
184- change_descriptor : ChangeDescriptor ,
143+ change_source : ScriptSource ,
185144 change_policy : ChangePolicyType ,
186145 ) -> Self {
187146 Self {
188- change_descriptor ,
147+ change_source ,
189148 change_policy,
190149 target_feerate,
191150 target_outputs,
@@ -216,32 +175,49 @@ impl SelectorParams {
216175 ///
217176 /// # Error
218177 ///
219- /// Fails if `change_descriptor` cannot be satisfied.
220- pub fn to_cs_change_weights ( & self ) -> Result < bdk_coin_select:: DrainWeights , miniscript:: Error > {
221- Ok ( DrainWeights {
178+ /// Fails if `change_source` cannot be satisfied.
179+ pub fn to_cs_change_weights ( & self ) -> Result < bdk_coin_select:: DrainWeights , SelectorError > {
180+ let ( script_pubkey, spend_weight) = match & self . change_source {
181+ ScriptSource :: Script {
182+ script_pubkey,
183+ max_weight_to_satisfy,
184+ } => {
185+ if let Some ( weight) = max_weight_to_satisfy {
186+ ( script_pubkey. clone ( ) , weight. to_wu ( ) )
187+ } else {
188+ return Err ( SelectorError :: MissingChangeSatisfactionWeight ) ;
189+ }
190+ }
191+ ScriptSource :: Descriptor ( definite_descriptor) => {
192+ let script_pubkey = definite_descriptor. script_pubkey ( ) ;
193+ let weight = definite_descriptor
194+ . max_weight_to_satisfy ( )
195+ . map ( |weight| weight. to_wu ( ) )
196+ . map_err ( SelectorError :: Miniscript ) ?;
197+ ( script_pubkey, weight)
198+ }
199+ } ;
200+ let drain_weight = DrainWeights {
222201 output_weight : ( TxOut {
223- script_pubkey : self . change_descriptor . get_script_pubkey ( ) ,
202+ script_pubkey,
224203 value : Amount :: ZERO ,
225204 } )
226205 . weight ( )
227206 . to_wu ( ) ,
228- spend_weight : self . change_descriptor . get_max_weight_to_satisfy_wu ( ) ? ,
207+ spend_weight,
229208 n_outputs : 1 ,
230- } )
209+ } ;
210+ Ok ( drain_weight)
231211 }
232212
233213 /// To change policy.
234214 ///
235215 /// # Error
236216 ///
237- /// Fails if `change_descriptor ` cannot be satisfied.
238- pub fn to_cs_change_policy ( & self ) -> Result < bdk_coin_select:: ChangePolicy , miniscript :: Error > {
217+ /// Fails if `change_source ` cannot be satisfied.
218+ pub fn to_cs_change_policy ( & self ) -> Result < bdk_coin_select:: ChangePolicy , SelectorError > {
239219 let change_weights = self . to_cs_change_weights ( ) ?;
240- let dust_value = self
241- . change_descriptor
242- . get_script_pubkey ( )
243- . minimal_non_dust ( )
244- . to_sat ( ) ;
220+ let dust_value = self . change_source . script ( ) . minimal_non_dust ( ) . to_sat ( ) ;
245221 Ok ( match self . change_policy {
246222 ChangePolicyType :: NoDust => ChangePolicy :: min_value ( change_weights, dust_value) ,
247223 ChangePolicyType :: NoDustAndLeastWaste { longterm_feerate } => {
@@ -311,11 +287,9 @@ impl<'c> Selector<'c> {
311287 params : SelectorParams ,
312288 ) -> Result < Self , SelectorError > {
313289 let target = params. to_cs_target ( ) ;
314- let change_policy = params
315- . to_cs_change_policy ( )
316- . map_err ( SelectorError :: Miniscript ) ?;
290+ let change_policy = params. to_cs_change_policy ( ) ?;
317291 let target_outputs = params. target_outputs ;
318- let change_descriptor = params. change_descriptor ;
292+ let change_source = params. change_source ;
319293 if target. value ( ) > candidates. groups ( ) . map ( |grp| grp. value ( ) . to_sat ( ) ) . sum ( ) {
320294 return Err ( SelectorError :: CannotMeetTarget ( CannotMeetTarget ) ) ;
321295 }
@@ -328,7 +302,7 @@ impl<'c> Selector<'c> {
328302 target,
329303 target_outputs,
330304 change_policy,
331- change_descriptor ,
305+ change_source ,
332306 inner,
333307 } )
334308 }
@@ -405,10 +379,16 @@ impl<'c> Selector<'c> {
405379 outputs : {
406380 let mut outputs = self . target_outputs . clone ( ) ;
407381 if maybe_change. is_some ( ) {
408- outputs. push ( Output :: with_script (
409- self . change_descriptor . get_script_pubkey ( ) ,
410- Amount :: from_sat ( maybe_change. value ) ,
411- ) ) ;
382+ let change_amount = Amount :: from_sat ( maybe_change. value ) ;
383+ let change_output = match & self . change_source {
384+ ScriptSource :: Descriptor ( definite_descriptor) => {
385+ Output :: with_descriptor ( * definite_descriptor. clone ( ) , change_amount)
386+ }
387+ ScriptSource :: Script { script_pubkey, .. } => {
388+ Output :: with_script ( script_pubkey. clone ( ) , change_amount)
389+ }
390+ } ;
391+ outputs. push ( change_output) ;
412392 }
413393 outputs
414394 } ,
0 commit comments