Skip to content

Commit fa2e4e2

Browse files
committed
Fix max_satisfaction_weight calculations for taproot
* Key spend path should take into consideration the scriptSigLen, stackLen and itemLen (for the one and only stack item). * Script spend path should consider `control_block` and `script` to be items on the stack. I also restructured the function to improve readability.
1 parent 2f1535e commit fa2e4e2

File tree

1 file changed

+31
-21
lines changed

1 file changed

+31
-21
lines changed

src/descriptor/tr.rs

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -264,27 +264,37 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
264264
/// # Errors
265265
/// When the descriptor is impossible to safisfy (ex: sh(OP_FALSE)).
266266
pub fn max_satisfaction_weight(&self) -> Result<usize, Error> {
267-
let mut max_wieght = Some(65);
268-
for (depth, ms) in self.iter_scripts() {
269-
let script_size = ms.script_size();
270-
let max_sat_elems = match ms.max_satisfaction_witness_elements() {
271-
Ok(elem) => elem,
272-
Err(..) => continue,
273-
};
274-
let max_sat_size = match ms.max_satisfaction_size() {
275-
Ok(sz) => sz,
276-
Err(..) => continue,
277-
};
278-
let control_block_sz = control_block_len(depth);
279-
let wit_size = 4 + // scriptSig len byte
280-
control_block_sz + // first element control block
281-
varint_len(script_size) +
282-
script_size + // second element script len with prefix
283-
varint_len(max_sat_elems) +
284-
max_sat_size; // witness
285-
max_wieght = cmp::max(max_wieght, Some(wit_size));
286-
}
287-
max_wieght.ok_or(Error::ImpossibleSatisfaction)
267+
let tree = match self.taptree() {
268+
// key spend path:
269+
// scriptSigLen(4) + stackLen(1) + stack[Sig]Len(1) + stack[Sig](65)
270+
None => return Ok(4 + 1 + 1 + 65),
271+
// script path spend..
272+
Some(tree) => tree,
273+
};
274+
275+
tree.iter()
276+
.filter_map(|(depth, ms)| {
277+
let script_size = ms.script_size();
278+
let max_sat_elems = ms.max_satisfaction_witness_elements().ok()?;
279+
let max_sat_size = ms.max_satisfaction_size().ok()?;
280+
let control_block_size = control_block_len(depth);
281+
Some(
282+
// scriptSig len byte
283+
4 +
284+
// witness field stack len (+2 for control block & script)
285+
varint_len(max_sat_elems + 2) +
286+
// size of elements to satisfy script
287+
max_sat_size +
288+
// second to last element: script
289+
varint_len(script_size) +
290+
script_size +
291+
// last element: control block
292+
varint_len(control_block_size) +
293+
control_block_size,
294+
)
295+
})
296+
.max()
297+
.ok_or(Error::ImpossibleSatisfaction)
288298
}
289299
}
290300

0 commit comments

Comments
 (0)