I was previously reluctant to do parsing checks on the descriptors as it's harder to get the semantics right than when compiling the policy. But the compile-time checks don't achieve much, and we can already check a number of things without much semantics (like the maximum number of keys, check for duplicates).
Also, we already analyze the Unvault descriptor semantic with success to get the threshold, so why not for parsing checks?
|
fn unvault_descriptor_managers_threshold<Pk: MiniscriptKey>( |
|
desc: &Descriptor<Pk>, |
|
) -> Option<usize> { |
|
let ms = match &desc { |
|
Descriptor::Wsh(ref wsh) => match wsh.as_inner() { |
|
WshInner::Ms(ms) => ms, |
|
WshInner::SortedMulti(_) => unreachable!("Unvault descriptor is not a sorted multi"), |
|
}, |
|
_ => unreachable!("Unvault descriptor is always a P2WSH"), |
|
}; |
|
|
|
let policy = ms |
|
.lift() |
|
.expect("Lifting can't fail on a Miniscript") |
|
.normalized(); |
|
|
|
// The Unvault descriptor is always of the form 'or(mans_branch, stks_branch)' |
|
match policy { |
|
SemanticPolicy::Threshold(1, ref subs) => { |
|
assert_eq!(subs.len(), 2); |
|
|
|
// The 'mans_branch' can be identified as the one containing the CSV. It is always an |
|
// 'and()' of CSV + Managers (the latter being potentially a thresh) and optionally |
|
// along with Cosigning Servers |
|
for sub in subs { |
|
match sub { |
|
SemanticPolicy::Threshold(k, ref subs) |
|
if k == &subs.len() |
|
&& subs |
|
.iter() |
|
.any(|sub| matches!(sub, SemanticPolicy::Older(..))) => |
|
{ |
|
// Now, the mans are either a Threshold or directly pks (in the case the |
|
// thresh is an 'and()', pks are flattened in the upper 'and()'). |
|
return subs.iter().find_map(|sub| match sub { |
|
SemanticPolicy::Threshold(k, _) => Some(*k), |
|
_ => None, |
|
}); |
|
} |
|
_ => continue, |
|
} |
|
} |
|
|
|
unreachable!( |
|
"Given an Unvault descriptor which doesn't contain a second-to-top \ |
|
branch with a CSV" |
|
); |
|
} |
|
_ => unreachable!("Given an Unvault descriptor that doesn't contain a 'or()' at the root"), |
|
} |
|
} |
I was previously reluctant to do parsing checks on the descriptors as it's harder to get the semantics right than when compiling the policy. But the compile-time checks don't achieve much, and we can already check a number of things without much semantics (like the maximum number of keys, check for duplicates).
Also, we already analyze the Unvault descriptor semantic with success to get the threshold, so why not for parsing checks?
revault_tx/src/scripts.rs
Lines 510 to 560 in 4bddb1d