Skip to content

Commit 45a2ae0

Browse files
committed
Add from_str_insane
1 parent b106a06 commit 45a2ae0

File tree

5 files changed

+43
-26
lines changed

5 files changed

+43
-26
lines changed

src/descriptor/satisfied_constraints.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,6 @@ mod tests {
11041104
StackElement,
11051105
};
11061106
use miniscript::context::{Any, Legacy};
1107-
use std::str::FromStr;
11081107
use BitcoinSig;
11091108
use Miniscript;
11101109
use MiniscriptKey;

src/macros.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/// `ms_str!("c:or_i(pk({}),pk({}))", pk1, pk2)`
77
#[cfg(test)]
88
macro_rules! ms_str {
9-
($($arg:tt)*) => (Miniscript::from_str(&format!($($arg)*)).unwrap())
9+
($($arg:tt)*) => (Miniscript::from_str_insane(&format!($($arg)*)).unwrap())
1010
}
1111

1212
/// Allows tests to create a descriptor directly from string as

src/miniscript/context.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,6 @@ mod private {
512512
#[cfg(test)]
513513
mod tests {
514514
use super::{Any, Bare, Legacy, Segwitv0};
515-
use std::str::FromStr;
516515

517516
use {DummyKey, Miniscript};
518517
type Segwitv0Script = Miniscript<DummyKey, Segwitv0>;
@@ -522,9 +521,9 @@ mod tests {
522521
//miri test for unsafe code
523522
#[test]
524523
fn miri_test_context_transform() {
525-
let segwit_ms = Segwitv0Script::from_str("andor(pk(),or_i(and_v(vc:pk_h(),hash160(1111111111111111111111111111111111111111)),older(1008)),pk())").unwrap();
526-
let legacy_ms = LegacyScript::from_str("andor(pk(),or_i(and_v(vc:pk_h(),hash160(1111111111111111111111111111111111111111)),older(1008)),pk())").unwrap();
527-
let bare_ms = BareScript::from_str("multi(2,,,)").unwrap();
524+
let segwit_ms = Segwitv0Script::from_str_insane("andor(pk(),or_i(and_v(vc:pk_h(),hash160(1111111111111111111111111111111111111111)),older(1008)),pk())").unwrap();
525+
let legacy_ms = LegacyScript::from_str_insane("andor(pk(),or_i(and_v(vc:pk_h(),hash160(1111111111111111111111111111111111111111)),older(1008)),pk())").unwrap();
526+
let bare_ms = BareScript::from_str_insane("multi(2,,,)").unwrap();
528527

529528
let _any = Any::from_legacy(&legacy_ms);
530529
let _any = Any::from_segwitv0(&segwit_ms);

src/miniscript/iter.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,6 @@ pub mod test {
438438
use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
439439
use bitcoin::secp256k1;
440440
use miniscript::context::Segwitv0;
441-
use std::str::FromStr;
442441

443442
pub type TestData = (
444443
Miniscript<bitcoin::PublicKey, Segwitv0>,

src/miniscript/mod.rs

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,34 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
275275
};
276276
Ok(ms)
277277
}
278+
279+
/// Attempt to parse an insane(scripts don't clear sanity checks)
280+
/// from string into a Miniscript representation.
281+
/// Use this to parse scripts with repeated pubkeys, timelock mixing, malleable
282+
/// scripts without sig or scripts that can exceed resource limits.
283+
/// Some of the analysis gurantees of miniscript are lost when dealing with
284+
/// insane scripts. In general, in a multi-party setting users should only
285+
/// accept sane scripts.
286+
pub fn from_str_insane(s: &str) -> Result<Miniscript<Pk, Ctx>, Error>
287+
where
288+
<Pk as str::FromStr>::Err: ToString,
289+
<<Pk as MiniscriptKey>::Hash as str::FromStr>::Err: ToString,
290+
{
291+
for ch in s.as_bytes() {
292+
if *ch < 20 || *ch > 127 {
293+
return Err(Error::Unprintable(*ch));
294+
}
295+
}
296+
297+
let top = expression::Tree::from_str(s)?;
298+
let ms: Miniscript<Pk, Ctx> = expression::FromTree::from_tree(&top)?;
299+
300+
if ms.ty.corr.base != types::Base::B {
301+
Err(Error::NonTopLevel(format!("{:?}", ms)))
302+
} else {
303+
Ok(ms)
304+
}
305+
}
278306
}
279307

280308
impl<Pk, Ctx> expression::FromTree for Arc<Miniscript<Pk, Ctx>>
@@ -318,21 +346,13 @@ where
318346
{
319347
type Err = Error;
320348

349+
/// Parse a Miniscript from string and perform sanity checks
350+
/// See [fn.from_str_insane] to parse scripts from string that
351+
/// do not clear the [fn.analyzable.sanity_check] checks.
321352
fn from_str(s: &str) -> Result<Miniscript<Pk, Ctx>, Error> {
322-
for ch in s.as_bytes() {
323-
if *ch < 20 || *ch > 127 {
324-
return Err(Error::Unprintable(*ch));
325-
}
326-
}
327-
328-
let top = expression::Tree::from_str(s)?;
329-
let ms: Miniscript<Pk, Ctx> = expression::FromTree::from_tree(&top)?;
330-
331-
if ms.ty.corr.base != types::Base::B {
332-
Err(Error::NonTopLevel(format!("{:?}", ms)))
333-
} else {
334-
Ok(ms)
335-
}
353+
let ms = Self::from_str_insane(s)?;
354+
ms.sanity_check()?;
355+
Ok(ms)
336356
}
337357
}
338358

@@ -440,7 +460,7 @@ mod tests {
440460
ops: usize,
441461
_stack: usize,
442462
) {
443-
let ms: Result<Segwitv0Script, _> = Miniscript::from_str(ms);
463+
let ms: Result<Segwitv0Script, _> = Miniscript::from_str_insane(ms);
444464
match (ms, valid) {
445465
(Ok(ms), true) => {
446466
assert_eq!(format!("{:x}", ms.encode(NullCtx)), expected_hex);
@@ -591,19 +611,19 @@ mod tests {
591611
#[test]
592612
fn verify_parse() {
593613
let ms = "and_v(v:hash160(20195b5a3d650c17f0f29f91c33f8f6335193d07),or_d(sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),older(16)))";
594-
let ms: Segwitv0Script = Miniscript::from_str(ms).unwrap();
614+
let ms: Segwitv0Script = Miniscript::from_str_insane(ms).unwrap();
595615
assert_eq!(ms, Miniscript::parse_insane(&ms.encode(NullCtx)).unwrap());
596616

597617
let ms = "and_v(v:sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),or_d(sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),older(16)))";
598-
let ms: Segwitv0Script = Miniscript::from_str(ms).unwrap();
618+
let ms: Segwitv0Script = Miniscript::from_str_insane(ms).unwrap();
599619
assert_eq!(ms, Miniscript::parse_insane(&ms.encode(NullCtx)).unwrap());
600620

601621
let ms = "and_v(v:ripemd160(20195b5a3d650c17f0f29f91c33f8f6335193d07),or_d(sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),older(16)))";
602-
let ms: Segwitv0Script = Miniscript::from_str(ms).unwrap();
622+
let ms: Segwitv0Script = Miniscript::from_str_insane(ms).unwrap();
603623
assert_eq!(ms, Miniscript::parse_insane(&ms.encode(NullCtx)).unwrap());
604624

605625
let ms = "and_v(v:hash256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),or_d(sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),older(16)))";
606-
let ms: Segwitv0Script = Miniscript::from_str(ms).unwrap();
626+
let ms: Segwitv0Script = Miniscript::from_str_insane(ms).unwrap();
607627
assert_eq!(ms, Miniscript::parse_insane(&ms.encode(NullCtx)).unwrap());
608628
}
609629

0 commit comments

Comments
 (0)