Skip to content

Commit 75b8dda

Browse files
committed
tr: Weight calculations for Simplicity
The length of the witness stack is always the same: 3 elements. There is the serialized program+witness, the CMR and the control block. The maximum witness size is trickier, because of the custom encoding that Simplicity uses and because of the existence of disconnect (will be present in asm fragments). There exists no function to compute a bound, and the real witness size would be much smaller than what this function returned. max_satisfaction_size will return an error for Simplicity leaves. We can still choose the best leaf to spend because the spending methods generate a witness from a satisfier, which we _can_ do.
1 parent 597a82c commit 75b8dda

File tree

1 file changed

+33
-10
lines changed

1 file changed

+33
-10
lines changed

src/descriptor/tr.rs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -319,11 +319,10 @@ impl<Pk: MiniscriptKey, Ext: Extension> Tr<Pk, Ext> {
319319
};
320320

321321
tree.iter()
322-
.filter_map(|(depth, ms)| {
323-
let ms = ms.as_miniscript().unwrap();
324-
let script_size = ms.script_size();
325-
let max_sat_elems = ms.max_satisfaction_witness_elements().ok()?;
326-
let max_sat_size = ms.max_satisfaction_size().ok()?;
322+
.filter_map(|(depth, script)| {
323+
let script_size = script.script_size();
324+
let max_sat_elems = script.max_satisfaction_witness_elements().ok()?;
325+
let max_sat_size = script.max_satisfaction_size().ok()?;
327326
let control_block_size = control_block_len(depth);
328327

329328
// stack varint difference (+1 for ctrl block, witness script already included)
@@ -365,11 +364,10 @@ impl<Pk: MiniscriptKey, Ext: Extension> Tr<Pk, Ext> {
365364
};
366365

367366
tree.iter()
368-
.filter_map(|(depth, ms)| {
369-
let ms = ms.as_miniscript().unwrap();
370-
let script_size = ms.script_size();
371-
let max_sat_elems = ms.max_satisfaction_witness_elements().ok()?;
372-
let max_sat_size = ms.max_satisfaction_size().ok()?;
367+
.filter_map(|(depth, script)| {
368+
let script_size = script.script_size();
369+
let max_sat_elems = script.max_satisfaction_witness_elements().ok()?;
370+
let max_sat_size = script.max_satisfaction_size().ok()?;
373371
let control_block_size = control_block_len(depth);
374372
Some(
375373
// scriptSig len byte
@@ -475,6 +473,31 @@ impl<'a, Pk: MiniscriptKey, Ext: Extension> TapLeafScript<'a, Pk, Ext> {
475473
TapLeafScript::Simplicity(..) => simplicity::leaf_version(),
476474
}
477475
}
476+
477+
/// Return the maximum number of witness elements used to satisfied the leaf script,
478+
/// including the witness script itself.
479+
pub fn max_satisfaction_witness_elements(&self) -> Result<usize, Error> {
480+
match self {
481+
TapLeafScript::Miniscript(ms) => ms.max_satisfaction_witness_elements(),
482+
// Simplicity always has one witness element plus leaf script:
483+
// (1) Encoded program+witness
484+
// (2) CMR program
485+
// The third element is the control block, which is not counted by this method.
486+
TapLeafScript::Simplicity(..) => Ok(2),
487+
}
488+
}
489+
490+
/// Return the maximum byte size of a satisfying witness.
491+
pub fn max_satisfaction_size(&self) -> Result<usize, Error> {
492+
match self {
493+
TapLeafScript::Miniscript(ms) => ms.max_satisfaction_size(),
494+
// There is currently no way to bound the Simplicity witness size without producing one
495+
// We mark the witness size as malleable since it depends on the chosen spending path
496+
// TODO: Add method to simplicity::Policy and use it here
497+
TapLeafScript::Simplicity(..) => Err(Error::AnalysisError(crate::AnalysisError::Malleable))
498+
}
499+
}
500+
478501
}
479502

480503
impl<'a, Pk: ToPublicKey, Ext: ParseableExt> TapLeafScript<'a, Pk, Ext> {

0 commit comments

Comments
 (0)