Skip to content

Commit 22ac742

Browse files
committed
Merge #473: Fix max_satisfaction_weight calculations for taproot.
8834b7f Fix `max_satisfaction_weight` calculations for taproot (志宇) Pull request description: * 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. ACKs for top commit: sanket1729: utACK 8834b7f. Thanks for the significant code improvement. LLFourn: ACK 8834b7f apoelstra: ACK 8834b7f Tree-SHA512: e2f7c893bf9f9d13deae047b1d341fef513c8b1e4e0d4285684c5c420baabc89ae84033162534ee1dfd0c98e39bef01451a0e75e400cece37ec9218b2881a16f
2 parents 2d113fb + 8834b7f commit 22ac742

File tree

2 files changed

+35
-25
lines changed

2 files changed

+35
-25
lines changed

examples/taproot.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,11 @@ fn main() {
116116

117117
// Max Satisfaction Weight for compilation, corresponding to the script-path spend
118118
// `multi_a(2,PUBKEY_1,PUBKEY_2) at taptree depth 1, having
119-
// Max Witness Size = scriptSig len + control_block size + varint(script_size) + script_size +
120-
// varint(max satisfaction elements) + max satisfaction size
121-
// = 4 + 65 + 1 + 70 + 1 + 132
119+
// Max Witness Size = scriptSig len + witnessStack len + varint(control_block_size) +
120+
// control_block size + varint(script_size) + script_size + max_satisfaction_size
121+
// = 4 + 1 + 1 + 65 + 1 + 70 + 132 = 274
122122
let max_sat_wt = real_desc.max_satisfaction_weight().unwrap();
123-
assert_eq!(max_sat_wt, 273);
123+
assert_eq!(max_sat_wt, 274);
124124

125125
// Compute the bitcoin address and check if it matches
126126
let network = Network::Bitcoin;

src/descriptor/tr.rs

+31-21
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)