Skip to content

Commit c589508

Browse files
committed
refactor: replace ChangeDescriptor by ScriptSource
1 parent d78768f commit c589508

File tree

2 files changed

+52
-72
lines changed

2 files changed

+52
-72
lines changed

examples/synopsis.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fn main() -> anyhow::Result<()> {
6060
recipient_addr.script_pubkey(),
6161
Amount::from_sat(21_000_000),
6262
)],
63-
bdk_tx::ChangeDescriptor::Definite(internal.at_derivation_index(0)?),
63+
bdk_tx::ScriptSource::Descriptor(Box::new(internal.at_derivation_index(0)?)),
6464
bdk_tx::ChangePolicyType::NoDustAndLeastWaste { longterm_feerate },
6565
),
6666
)?;
@@ -134,9 +134,9 @@ fn main() -> anyhow::Result<()> {
134134
// be less wasteful to have no output, however that will not be a valid tx).
135135
// If you only want to fee bump, put the original txs' recipients here.
136136
target_outputs: vec![],
137-
change_descriptor: bdk_tx::ChangeDescriptor::Definite(
137+
change_source: bdk_tx::ScriptSource::Descriptor(Box::new(
138138
internal.at_derivation_index(1)?,
139-
),
139+
)),
140140
change_policy: ChangePolicyType::NoDustAndLeastWaste { longterm_feerate },
141141
// This ensures that we satisfy mempool-replacement policy rules 4 and 6.
142142
replace: Some(rbf_params),

src/selector.rs

Lines changed: 49 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use 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};
55
use miniscript::bitcoin;
66

7-
use crate::{cs_feerate, DefiniteDescriptor, InputCandidates, InputGroup, Output, Selection};
7+
use crate::{cs_feerate, InputCandidates, InputGroup, Output, ScriptSource, Selection};
88
use alloc::vec::Vec;
99
use 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

Comments
 (0)