Skip to content

Commit 2c77295

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 78254b2 commit 2c77295

20 files changed

Lines changed: 196 additions & 423 deletions

File tree

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
}
@@ -1121,6 +1143,7 @@ mod tests {
11211143

11221144
use super::{checksum, *};
11231145
use crate::hex_script;
1146+
use crate::miniscript::context::ScriptContextError;
11241147
#[cfg(feature = "compiler")]
11251148
use crate::policy;
11261149

@@ -1170,7 +1193,7 @@ mod tests {
11701193
StdDescriptor::from_str("sh(sortedmulti)")
11711194
.unwrap_err()
11721195
.to_string(),
1173-
"sortedmulti must have at least 1 children, but found 0"
1196+
"expected threshold, found terminal"
11741197
); //issue 202
11751198
assert_eq!(
11761199
StdDescriptor::from_str(&format!("sh(sortedmulti(2,{}))", &TEST_PK[3..69]))
@@ -2698,4 +2721,26 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
26982721
);
26992722
}
27002723
}
2724+
2725+
#[test]
2726+
fn too_many_pubkeys_for_p2sh() {
2727+
// Arbitrary 65-byte public key (66 with length prefix).
2728+
let pk = PublicKey::from_str(
2729+
"0400232a2acfc9b43fa89f1b4f608fde335d330d7114f70ea42bfb4a41db368a3e3be6934a4097dd25728438ef73debb1f2ffdb07fec0f18049df13bdc5285dc5b",
2730+
)
2731+
.unwrap();
2732+
2733+
// This is legal for CHECKMULTISIG, but the 8 keys consume the whole 520 bytes
2734+
// allowed by P2SH, meaning that the full script goes over the limit.
2735+
let thresh = Threshold::new(2, vec![pk; 8]).expect("the thresh is ok..");
2736+
let script = Miniscript::<_, Legacy>::sortedmulti(thresh).encode();
2737+
let res = Miniscript::<_, Legacy>::decode(&script);
2738+
2739+
let error = res.expect_err("decoding should err");
2740+
2741+
match error {
2742+
Error::ContextError(ScriptContextError::MaxRedeemScriptSizeExceeded { .. }) => {} // ok
2743+
other => panic!("unexpected error: {:?}", other),
2744+
}
2745+
}
27012746
}

0 commit comments

Comments
 (0)