Skip to content

Commit b4d73ec

Browse files
committed
refactor: remove SortedMultiVec and use Terminal::SortedMulti
- Utilize the Miniscript parsing to handle sortedmulti as a Terminal. - Deleted sortedmulti.rs (SortedMultiVec) - Refactor Wsh to only wrap a Miniscript now that SortedMultiVec isn't used. - Refactor ShInner to remove SortedMulti variant and only use the Ms variant for sortedmulti scripts
1 parent b2f21d2 commit b4d73ec

23 files changed

Lines changed: 225 additions & 459 deletions

File tree

bitcoind-tests/tests/test_cpp.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,7 @@ pub fn test_from_cpp_ms(cl: &Client, testdata: &TestData) {
147147
for i in 0..psbts.len() {
148148
let wsh_derived = desc_vec[i].derived_descriptor(&secp);
149149
let ms = if let Descriptor::Wsh(wsh) = &wsh_derived {
150-
match wsh.as_inner() {
151-
miniscript::descriptor::WshInner::Ms(ms) => ms,
152-
_ => unreachable!(),
153-
}
150+
wsh.as_inner()
154151
} else {
155152
unreachable!("Only Wsh descriptors are supported");
156153
};

bitcoind-tests/tests/test_desc.rs

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -225,29 +225,15 @@ pub fn test_desc_satisfy(
225225
Descriptor::Pkh(pk) => find_sk_single_key(*pk.as_inner(), testdata),
226226
Descriptor::Wpkh(pk) => find_sk_single_key(*pk.as_inner(), testdata),
227227
Descriptor::Sh(sh) => match sh.as_inner() {
228-
miniscript::descriptor::ShInner::Wsh(wsh) => match wsh.as_inner() {
229-
miniscript::descriptor::WshInner::SortedMulti(ref smv) => {
230-
let ms = Miniscript::from_ast(smv.sorted_node()).unwrap();
231-
find_sks_ms(&ms, testdata)
232-
}
233-
miniscript::descriptor::WshInner::Ms(ref ms) => find_sks_ms(ms, testdata),
234-
},
228+
miniscript::descriptor::ShInner::Wsh(wsh) => {
229+
find_sks_ms(wsh.as_inner(), testdata)
230+
}
235231
miniscript::descriptor::ShInner::Wpkh(pk) => {
236232
find_sk_single_key(*pk.as_inner(), testdata)
237233
}
238-
miniscript::descriptor::ShInner::SortedMulti(smv) => {
239-
let ms = Miniscript::from_ast(smv.sorted_node()).unwrap();
240-
find_sks_ms(&ms, testdata)
241-
}
242234
miniscript::descriptor::ShInner::Ms(ms) => find_sks_ms(ms, testdata),
243235
},
244-
Descriptor::Wsh(wsh) => match wsh.as_inner() {
245-
miniscript::descriptor::WshInner::SortedMulti(ref smv) => {
246-
let ms = Miniscript::from_ast(smv.sorted_node()).unwrap();
247-
find_sks_ms(&ms, testdata)
248-
}
249-
miniscript::descriptor::WshInner::Ms(ref ms) => find_sks_ms(ms, testdata),
250-
},
236+
Descriptor::Wsh(wsh) => find_sks_ms(wsh.as_inner(), testdata),
251237
Descriptor::Tr(_tr) => unreachable!("Tr checked earlier"),
252238
};
253239
let msg = psbt
@@ -319,8 +305,7 @@ fn find_sks_ms<Ctx: ScriptContext>(
319305
) -> Vec<secp256k1::SecretKey> {
320306
let sks = &testdata.secretdata.sks;
321307
let pks = &testdata.pubdata.pks;
322-
let sks = ms
323-
.iter_pk()
308+
let sks = ms.iter_pk()
324309
.filter_map(|pk| {
325310
let i = pks.iter().position(|&x| x.to_public_key() == pk);
326311
i.map(|idx| sks[idx])

src/descriptor/mod.rs

Lines changed: 69 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,13 @@ mod bare;
3636
mod iter;
3737
mod segwitv0;
3838
mod sh;
39-
mod sortedmulti;
4039
mod tr;
4140

4241
// Descriptor Exports
4342
pub use self::bare::{Bare, Pkh};
4443
pub use self::iter::PkIter;
45-
pub use self::segwitv0::{Wpkh, Wsh, WshInner};
44+
pub use self::segwitv0::{Wpkh, Wsh};
4645
pub use self::sh::{Sh, ShInner};
47-
pub use self::sortedmulti::SortedMultiVec;
4846
pub use self::tr::{
4947
TapTree, TapTreeDepthError, TapTreeIter, TapTreeIterItem, Tr, TrSpendInfo, TrSpendInfoIter,
5048
TrSpendInfoIterItem,
@@ -256,18 +254,31 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
256254
Descriptor::Pkh(ref pk) => PkIter::from_key(pk.as_inner().clone()),
257255
Descriptor::Wpkh(ref pk) => PkIter::from_key(pk.as_inner().clone()),
258256
Descriptor::Sh(ref sh) => match *sh.as_inner() {
259-
ShInner::Wsh(ref wsh) => match wsh.as_inner() {
260-
WshInner::SortedMulti(ref sorted) => PkIter::from_sortedmulti(sorted.pks()),
261-
WshInner::Ms(ref ms) => PkIter::from_miniscript_segwit(ms),
262-
},
257+
ShInner::Wsh(ref wsh) => {
258+
let ms = wsh.as_inner();
259+
if let Terminal::SortedMulti(ref thresh) = ms.node {
260+
PkIter::from_sortedmulti(thresh.data())
261+
} else {
262+
PkIter::from_miniscript_segwit(ms)
263+
}
264+
}
263265
ShInner::Wpkh(ref pk) => PkIter::from_key(pk.as_inner().clone()),
264-
ShInner::SortedMulti(ref sorted) => PkIter::from_sortedmulti(sorted.pks()),
265-
ShInner::Ms(ref ms) => PkIter::from_miniscript_legacy(ms),
266-
},
267-
Descriptor::Wsh(ref wsh) => match wsh.as_inner() {
268-
WshInner::SortedMulti(ref sorted) => PkIter::from_sortedmulti(sorted.pks()),
269-
WshInner::Ms(ref ms) => PkIter::from_miniscript_segwit(ms),
266+
ShInner::Ms(ref ms) => {
267+
if let Terminal::SortedMulti(ref thresh) = ms.node {
268+
PkIter::from_sortedmulti(thresh.data())
269+
} else {
270+
PkIter::from_miniscript_legacy(ms)
271+
}
272+
}
270273
},
274+
Descriptor::Wsh(ref wsh) => {
275+
let ms = wsh.as_inner();
276+
if let Terminal::SortedMulti(ref thresh) = ms.node {
277+
PkIter::from_sortedmulti(thresh.data())
278+
} else {
279+
PkIter::from_miniscript_segwit(ms)
280+
}
281+
}
271282
Descriptor::Tr(ref tr) => PkIter::from_tr(tr),
272283
}
273284
}
@@ -313,18 +324,29 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
313324
Descriptor::Pkh(ref _pkh) => DescriptorType::Pkh,
314325
Descriptor::Wpkh(ref _wpkh) => DescriptorType::Wpkh,
315326
Descriptor::Sh(ref sh) => match sh.as_inner() {
316-
ShInner::Wsh(ref wsh) => match wsh.as_inner() {
317-
WshInner::SortedMulti(ref _smv) => DescriptorType::ShWshSortedMulti,
318-
WshInner::Ms(ref _ms) => DescriptorType::ShWsh,
319-
},
327+
ShInner::Wsh(ref wsh) => {
328+
if let Terminal::SortedMulti(..) = wsh.as_inner().node {
329+
DescriptorType::ShWshSortedMulti
330+
} else {
331+
DescriptorType::ShWsh
332+
}
333+
}
320334
ShInner::Wpkh(ref _wpkh) => DescriptorType::ShWpkh,
321-
ShInner::SortedMulti(ref _smv) => DescriptorType::ShSortedMulti,
322-
ShInner::Ms(ref _ms) => DescriptorType::Sh,
323-
},
324-
Descriptor::Wsh(ref wsh) => match wsh.as_inner() {
325-
WshInner::SortedMulti(ref _smv) => DescriptorType::WshSortedMulti,
326-
WshInner::Ms(ref _ms) => DescriptorType::Wsh,
335+
ShInner::Ms(ref ms) => {
336+
if let Terminal::SortedMulti(..) = ms.node {
337+
DescriptorType::ShSortedMulti
338+
} else {
339+
DescriptorType::Sh
340+
}
341+
}
327342
},
343+
Descriptor::Wsh(ref wsh) => {
344+
if let Terminal::SortedMulti(..) = wsh.as_inner().node {
345+
DescriptorType::WshSortedMulti
346+
} else {
347+
DescriptorType::Wsh
348+
}
349+
}
328350
Descriptor::Tr(ref _tr) => DescriptorType::Tr,
329351
}
330352
}
@@ -1208,6 +1230,7 @@ mod tests {
12081230

12091231
use super::{checksum, *};
12101232
use crate::hex_script;
1233+
use crate::miniscript::context::ScriptContextError;
12111234
#[cfg(feature = "compiler")]
12121235
use crate::policy;
12131236

@@ -1257,7 +1280,7 @@ mod tests {
12571280
StdDescriptor::from_str("sh(sortedmulti)")
12581281
.unwrap_err()
12591282
.to_string(),
1260-
"sortedmulti must have at least 1 children, but found 0"
1283+
"expected threshold, found terminal"
12611284
); //issue 202
12621285
assert_eq!(
12631286
StdDescriptor::from_str(&format!("sh(sortedmulti(2,{}))", &TEST_PK[3..69]))
@@ -2884,4 +2907,26 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
28842907
let definite: Result<Descriptor<DefiniteDescriptorKey>, _> = desc.try_into();
28852908
assert!(matches!(definite, Err(NonDefiniteKeyError::Wildcard)));
28862909
}
2910+
2911+
#[test]
2912+
fn too_many_pubkeys_for_p2sh() {
2913+
// Arbitrary 65-byte public key (66 with length prefix).
2914+
let pk = PublicKey::from_str(
2915+
"0400232a2acfc9b43fa89f1b4f608fde335d330d7114f70ea42bfb4a41db368a3e3be6934a4097dd25728438ef73debb1f2ffdb07fec0f18049df13bdc5285dc5b",
2916+
)
2917+
.unwrap();
2918+
2919+
// This is legal for CHECKMULTISIG, but the 8 keys consume the whole 520 bytes
2920+
// allowed by P2SH, meaning that the full script goes over the limit.
2921+
let thresh = Threshold::new(2, vec![pk; 8]).expect("the thresh is ok..");
2922+
let script = Miniscript::<_, Legacy>::sortedmulti(thresh).encode();
2923+
let res = Miniscript::<_, Legacy>::decode(&script);
2924+
2925+
let error = res.expect_err("decoding should err");
2926+
2927+
match error {
2928+
Error::ContextError(ScriptContextError::MaxRedeemScriptSizeExceeded { .. }) => {} // ok
2929+
other => panic!("unexpected error: {:?}", other),
2930+
}
2931+
}
28872932
}

0 commit comments

Comments
 (0)