@@ -86,9 +86,7 @@ mod private {
8686 /// and they can call `Miniscript::clone`.
8787 fn clone ( & self ) -> Self {
8888 let mut stack = vec ! [ ] ;
89- for item in self . post_order_iter ( ) {
90- let child_n = |n| Arc :: clone ( & stack[ item. child_indices [ n] ] ) ;
91-
89+ for item in self . rtl_post_order_iter ( ) {
9290 let new_term = match item. node . node {
9391 Terminal :: PkK ( ref p) => Terminal :: PkK ( p. clone ( ) ) ,
9492 Terminal :: PkH ( ref p) => Terminal :: PkH ( p. clone ( ) ) ,
@@ -101,23 +99,31 @@ mod private {
10199 Terminal :: Hash160 ( ref x) => Terminal :: Hash160 ( x. clone ( ) ) ,
102100 Terminal :: True => Terminal :: True ,
103101 Terminal :: False => Terminal :: False ,
104- Terminal :: Alt ( ..) => Terminal :: Alt ( child_n ( 0 ) ) ,
105- Terminal :: Swap ( ..) => Terminal :: Swap ( child_n ( 0 ) ) ,
106- Terminal :: Check ( ..) => Terminal :: Check ( child_n ( 0 ) ) ,
107- Terminal :: DupIf ( ..) => Terminal :: DupIf ( child_n ( 0 ) ) ,
108- Terminal :: Verify ( ..) => Terminal :: Verify ( child_n ( 0 ) ) ,
109- Terminal :: NonZero ( ..) => Terminal :: NonZero ( child_n ( 0 ) ) ,
110- Terminal :: ZeroNotEqual ( ..) => Terminal :: ZeroNotEqual ( child_n ( 0 ) ) ,
111- Terminal :: AndV ( ..) => Terminal :: AndV ( child_n ( 0 ) , child_n ( 1 ) ) ,
112- Terminal :: AndB ( ..) => Terminal :: AndB ( child_n ( 0 ) , child_n ( 1 ) ) ,
113- Terminal :: AndOr ( ..) => Terminal :: AndOr ( child_n ( 0 ) , child_n ( 1 ) , child_n ( 2 ) ) ,
114- Terminal :: OrB ( ..) => Terminal :: OrB ( child_n ( 0 ) , child_n ( 1 ) ) ,
115- Terminal :: OrD ( ..) => Terminal :: OrD ( child_n ( 0 ) , child_n ( 1 ) ) ,
116- Terminal :: OrC ( ..) => Terminal :: OrC ( child_n ( 0 ) , child_n ( 1 ) ) ,
117- Terminal :: OrI ( ..) => Terminal :: OrI ( child_n ( 0 ) , child_n ( 1 ) ) ,
118- Terminal :: Thresh ( ref thresh) => Terminal :: Thresh (
119- thresh. map_from_post_order_iter ( & item. child_indices , & stack) ,
102+ Terminal :: Alt ( ..) => Terminal :: Alt ( stack. pop ( ) . unwrap ( ) ) ,
103+ Terminal :: Swap ( ..) => Terminal :: Swap ( stack. pop ( ) . unwrap ( ) ) ,
104+ Terminal :: Check ( ..) => Terminal :: Check ( stack. pop ( ) . unwrap ( ) ) ,
105+ Terminal :: DupIf ( ..) => Terminal :: DupIf ( stack. pop ( ) . unwrap ( ) ) ,
106+ Terminal :: Verify ( ..) => Terminal :: Verify ( stack. pop ( ) . unwrap ( ) ) ,
107+ Terminal :: NonZero ( ..) => Terminal :: NonZero ( stack. pop ( ) . unwrap ( ) ) ,
108+ Terminal :: ZeroNotEqual ( ..) => Terminal :: ZeroNotEqual ( stack. pop ( ) . unwrap ( ) ) ,
109+ Terminal :: AndV ( ..) => {
110+ Terminal :: AndV ( stack. pop ( ) . unwrap ( ) , stack. pop ( ) . unwrap ( ) )
111+ }
112+ Terminal :: AndB ( ..) => {
113+ Terminal :: AndB ( stack. pop ( ) . unwrap ( ) , stack. pop ( ) . unwrap ( ) )
114+ }
115+ Terminal :: AndOr ( ..) => Terminal :: AndOr (
116+ stack. pop ( ) . unwrap ( ) ,
117+ stack. pop ( ) . unwrap ( ) ,
118+ stack. pop ( ) . unwrap ( ) ,
120119 ) ,
120+ Terminal :: OrB ( ..) => Terminal :: OrB ( stack. pop ( ) . unwrap ( ) , stack. pop ( ) . unwrap ( ) ) ,
121+ Terminal :: OrD ( ..) => Terminal :: OrD ( stack. pop ( ) . unwrap ( ) , stack. pop ( ) . unwrap ( ) ) ,
122+ Terminal :: OrC ( ..) => Terminal :: OrC ( stack. pop ( ) . unwrap ( ) , stack. pop ( ) . unwrap ( ) ) ,
123+ Terminal :: OrI ( ..) => Terminal :: OrI ( stack. pop ( ) . unwrap ( ) , stack. pop ( ) . unwrap ( ) ) ,
124+ Terminal :: Thresh ( ref thresh) => {
125+ Terminal :: Thresh ( thresh. map_ref ( |_| stack. pop ( ) . unwrap ( ) ) )
126+ }
121127 Terminal :: Multi ( ref thresh) => Terminal :: Multi ( thresh. clone ( ) ) ,
122128 Terminal :: MultiA ( ref thresh) => Terminal :: MultiA ( thresh. clone ( ) ) ,
123129 } ;
@@ -130,6 +136,7 @@ mod private {
130136 } ) ) ;
131137 }
132138
139+ assert_eq ! ( stack. len( ) , 1 ) ;
133140 Arc :: try_unwrap ( stack. pop ( ) . unwrap ( ) ) . unwrap ( )
134141 }
135142 }
@@ -536,9 +543,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
536543 T : Translator < Pk , Q , FuncError > ,
537544 {
538545 let mut translated = vec ! [ ] ;
539- for data in Arc :: new ( self . clone ( ) ) . post_order_iter ( ) {
540- let child_n = |n| Arc :: clone ( & translated[ data. child_indices [ n] ] ) ;
541-
546+ for data in self . rtl_post_order_iter ( ) {
542547 let new_term = match data. node . node {
543548 Terminal :: PkK ( ref p) => Terminal :: PkK ( t. pk ( p) ?) ,
544549 Terminal :: PkH ( ref p) => Terminal :: PkH ( t. pk ( p) ?) ,
@@ -551,23 +556,39 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
551556 Terminal :: Hash160 ( ref x) => Terminal :: Hash160 ( t. hash160 ( x) ?) ,
552557 Terminal :: True => Terminal :: True ,
553558 Terminal :: False => Terminal :: False ,
554- Terminal :: Alt ( ..) => Terminal :: Alt ( child_n ( 0 ) ) ,
555- Terminal :: Swap ( ..) => Terminal :: Swap ( child_n ( 0 ) ) ,
556- Terminal :: Check ( ..) => Terminal :: Check ( child_n ( 0 ) ) ,
557- Terminal :: DupIf ( ..) => Terminal :: DupIf ( child_n ( 0 ) ) ,
558- Terminal :: Verify ( ..) => Terminal :: Verify ( child_n ( 0 ) ) ,
559- Terminal :: NonZero ( ..) => Terminal :: NonZero ( child_n ( 0 ) ) ,
560- Terminal :: ZeroNotEqual ( ..) => Terminal :: ZeroNotEqual ( child_n ( 0 ) ) ,
561- Terminal :: AndV ( ..) => Terminal :: AndV ( child_n ( 0 ) , child_n ( 1 ) ) ,
562- Terminal :: AndB ( ..) => Terminal :: AndB ( child_n ( 0 ) , child_n ( 1 ) ) ,
563- Terminal :: AndOr ( ..) => Terminal :: AndOr ( child_n ( 0 ) , child_n ( 1 ) , child_n ( 2 ) ) ,
564- Terminal :: OrB ( ..) => Terminal :: OrB ( child_n ( 0 ) , child_n ( 1 ) ) ,
565- Terminal :: OrD ( ..) => Terminal :: OrD ( child_n ( 0 ) , child_n ( 1 ) ) ,
566- Terminal :: OrC ( ..) => Terminal :: OrC ( child_n ( 0 ) , child_n ( 1 ) ) ,
567- Terminal :: OrI ( ..) => Terminal :: OrI ( child_n ( 0 ) , child_n ( 1 ) ) ,
568- Terminal :: Thresh ( ref thresh) => Terminal :: Thresh (
569- thresh. map_from_post_order_iter ( & data. child_indices , & translated) ,
559+ Terminal :: Alt ( ..) => Terminal :: Alt ( translated. pop ( ) . unwrap ( ) ) ,
560+ Terminal :: Swap ( ..) => Terminal :: Swap ( translated. pop ( ) . unwrap ( ) ) ,
561+ Terminal :: Check ( ..) => Terminal :: Check ( translated. pop ( ) . unwrap ( ) ) ,
562+ Terminal :: DupIf ( ..) => Terminal :: DupIf ( translated. pop ( ) . unwrap ( ) ) ,
563+ Terminal :: Verify ( ..) => Terminal :: Verify ( translated. pop ( ) . unwrap ( ) ) ,
564+ Terminal :: NonZero ( ..) => Terminal :: NonZero ( translated. pop ( ) . unwrap ( ) ) ,
565+ Terminal :: ZeroNotEqual ( ..) => Terminal :: ZeroNotEqual ( translated. pop ( ) . unwrap ( ) ) ,
566+ Terminal :: AndV ( ..) => {
567+ Terminal :: AndV ( translated. pop ( ) . unwrap ( ) , translated. pop ( ) . unwrap ( ) )
568+ }
569+ Terminal :: AndB ( ..) => {
570+ Terminal :: AndB ( translated. pop ( ) . unwrap ( ) , translated. pop ( ) . unwrap ( ) )
571+ }
572+ Terminal :: AndOr ( ..) => Terminal :: AndOr (
573+ translated. pop ( ) . unwrap ( ) ,
574+ translated. pop ( ) . unwrap ( ) ,
575+ translated. pop ( ) . unwrap ( ) ,
570576 ) ,
577+ Terminal :: OrB ( ..) => {
578+ Terminal :: OrB ( translated. pop ( ) . unwrap ( ) , translated. pop ( ) . unwrap ( ) )
579+ }
580+ Terminal :: OrD ( ..) => {
581+ Terminal :: OrD ( translated. pop ( ) . unwrap ( ) , translated. pop ( ) . unwrap ( ) )
582+ }
583+ Terminal :: OrC ( ..) => {
584+ Terminal :: OrC ( translated. pop ( ) . unwrap ( ) , translated. pop ( ) . unwrap ( ) )
585+ }
586+ Terminal :: OrI ( ..) => {
587+ Terminal :: OrI ( translated. pop ( ) . unwrap ( ) , translated. pop ( ) . unwrap ( ) )
588+ }
589+ Terminal :: Thresh ( ref thresh) => {
590+ Terminal :: Thresh ( thresh. map_ref ( |_| translated. pop ( ) . unwrap ( ) ) )
591+ }
571592 Terminal :: Multi ( ref thresh) => Terminal :: Multi ( thresh. translate_ref ( |k| t. pk ( k) ) ?) ,
572593 Terminal :: MultiA ( ref thresh) => {
573594 Terminal :: MultiA ( thresh. translate_ref ( |k| t. pk ( k) ) ?)
@@ -582,22 +603,58 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
582603
583604 /// Substitutes raw public keys hashes with the public keys as provided by map.
584605 pub fn substitute_raw_pkh ( & self , pk_map : & BTreeMap < hash160:: Hash , Pk > ) -> Miniscript < Pk , Ctx > {
585- let mut translated = vec ! [ ] ;
586- for data in Arc :: new ( self . clone ( ) ) . post_order_iter ( ) {
587- let new_term = if let Terminal :: RawPkH ( ref p) = data. node . node {
588- match pk_map. get ( p) {
589- Some ( pk) => Terminal :: PkH ( pk. clone ( ) ) ,
590- None => Terminal :: RawPkH ( * p) ,
606+ let mut stack = vec ! [ ] ;
607+ for item in self . rtl_post_order_iter ( ) {
608+ let new_term = match item. node . node {
609+ Terminal :: PkK ( ref p) => Terminal :: PkK ( p. clone ( ) ) ,
610+ Terminal :: PkH ( ref p) => Terminal :: PkH ( p. clone ( ) ) ,
611+ // This algorithm is identical to Clone::clone except for this line.
612+ Terminal :: RawPkH ( ref hash) => match pk_map. get ( hash) {
613+ Some ( p) => Terminal :: PkH ( p. clone ( ) ) ,
614+ None => Terminal :: RawPkH ( * hash) ,
615+ } ,
616+ Terminal :: After ( ref n) => Terminal :: After ( * n) ,
617+ Terminal :: Older ( ref n) => Terminal :: Older ( * n) ,
618+ Terminal :: Sha256 ( ref x) => Terminal :: Sha256 ( x. clone ( ) ) ,
619+ Terminal :: Hash256 ( ref x) => Terminal :: Hash256 ( x. clone ( ) ) ,
620+ Terminal :: Ripemd160 ( ref x) => Terminal :: Ripemd160 ( x. clone ( ) ) ,
621+ Terminal :: Hash160 ( ref x) => Terminal :: Hash160 ( x. clone ( ) ) ,
622+ Terminal :: True => Terminal :: True ,
623+ Terminal :: False => Terminal :: False ,
624+ Terminal :: Alt ( ..) => Terminal :: Alt ( stack. pop ( ) . unwrap ( ) ) ,
625+ Terminal :: Swap ( ..) => Terminal :: Swap ( stack. pop ( ) . unwrap ( ) ) ,
626+ Terminal :: Check ( ..) => Terminal :: Check ( stack. pop ( ) . unwrap ( ) ) ,
627+ Terminal :: DupIf ( ..) => Terminal :: DupIf ( stack. pop ( ) . unwrap ( ) ) ,
628+ Terminal :: Verify ( ..) => Terminal :: Verify ( stack. pop ( ) . unwrap ( ) ) ,
629+ Terminal :: NonZero ( ..) => Terminal :: NonZero ( stack. pop ( ) . unwrap ( ) ) ,
630+ Terminal :: ZeroNotEqual ( ..) => Terminal :: ZeroNotEqual ( stack. pop ( ) . unwrap ( ) ) ,
631+ Terminal :: AndV ( ..) => Terminal :: AndV ( stack. pop ( ) . unwrap ( ) , stack. pop ( ) . unwrap ( ) ) ,
632+ Terminal :: AndB ( ..) => Terminal :: AndB ( stack. pop ( ) . unwrap ( ) , stack. pop ( ) . unwrap ( ) ) ,
633+ Terminal :: AndOr ( ..) => Terminal :: AndOr (
634+ stack. pop ( ) . unwrap ( ) ,
635+ stack. pop ( ) . unwrap ( ) ,
636+ stack. pop ( ) . unwrap ( ) ,
637+ ) ,
638+ Terminal :: OrB ( ..) => Terminal :: OrB ( stack. pop ( ) . unwrap ( ) , stack. pop ( ) . unwrap ( ) ) ,
639+ Terminal :: OrD ( ..) => Terminal :: OrD ( stack. pop ( ) . unwrap ( ) , stack. pop ( ) . unwrap ( ) ) ,
640+ Terminal :: OrC ( ..) => Terminal :: OrC ( stack. pop ( ) . unwrap ( ) , stack. pop ( ) . unwrap ( ) ) ,
641+ Terminal :: OrI ( ..) => Terminal :: OrI ( stack. pop ( ) . unwrap ( ) , stack. pop ( ) . unwrap ( ) ) ,
642+ Terminal :: Thresh ( ref thresh) => {
643+ Terminal :: Thresh ( thresh. map_ref ( |_| stack. pop ( ) . unwrap ( ) ) )
591644 }
592- } else {
593- data . node . node . clone ( )
645+ Terminal :: Multi ( ref thresh ) => Terminal :: Multi ( thresh . clone ( ) ) ,
646+ Terminal :: MultiA ( ref thresh ) => Terminal :: MultiA ( thresh . clone ( ) ) ,
594647 } ;
595648
596- let new_ms = Miniscript :: from_ast ( new_term) . expect ( "typeck" ) ;
597- translated. push ( Arc :: new ( new_ms) ) ;
649+ stack. push ( Arc :: new ( Miniscript :: from_components_unchecked (
650+ new_term,
651+ item. node . ty ,
652+ item. node . ext ,
653+ ) ) ) ;
598654 }
599655
600- Arc :: try_unwrap ( translated. pop ( ) . unwrap ( ) ) . unwrap ( )
656+ assert_eq ! ( stack. len( ) , 1 ) ;
657+ Arc :: try_unwrap ( stack. pop ( ) . unwrap ( ) ) . unwrap ( )
601658 }
602659}
603660
@@ -822,6 +879,7 @@ mod tests {
822879 }
823880 let roundtrip = Miniscript :: from_str ( & display) . expect ( "parse string serialization" ) ;
824881 assert_eq ! ( roundtrip, script) ;
882+ assert_eq ! ( roundtrip. clone( ) , script) ;
825883 }
826884
827885 fn string_display_debug_test < Ctx : ScriptContext > (
@@ -1373,8 +1431,12 @@ mod tests {
13731431 #[ test]
13741432 fn expr_features ( ) {
13751433 // test that parsing raw hash160 does not work with
1376- let hash160_str = "e9f171df53e04b270fa6271b42f66b0f4a99c5a2" ;
1377- let ms_str = & format ! ( "c:expr_raw_pkh({})" , hash160_str) ;
1434+ let pk = bitcoin:: PublicKey :: from_str (
1435+ "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c" ,
1436+ )
1437+ . unwrap ( ) ;
1438+ let hash160 = pk. pubkey_hash ( ) . to_raw_hash ( ) ;
1439+ let ms_str = & format ! ( "c:expr_raw_pkh({})" , hash160) ;
13781440 type SegwitMs = Miniscript < bitcoin:: PublicKey , Segwitv0 > ;
13791441
13801442 // Test that parsing raw hash160 from string does not work without extra features
@@ -1387,6 +1449,12 @@ mod tests {
13871449 SegwitMs :: parse ( & script) . unwrap_err ( ) ;
13881450 SegwitMs :: parse_insane ( & script) . unwrap_err ( ) ;
13891451 SegwitMs :: parse_with_ext ( & script, & ExtParams :: allow_all ( ) ) . unwrap ( ) ;
1452+
1453+ // Try replacing the raw_pkh with a pkh
1454+ let mut map = BTreeMap :: new ( ) ;
1455+ map. insert ( hash160, pk) ;
1456+ let ms_no_raw = ms. substitute_raw_pkh ( & map) ;
1457+ assert_eq ! ( ms_no_raw. to_string( ) , format!( "pkh({})" , pk) , ) ;
13901458 }
13911459
13921460 #[ test]
@@ -1408,6 +1476,56 @@ mod tests {
14081476 ms. translate_pk ( & mut t) . unwrap_err ( ) ;
14091477 }
14101478
1479+ #[ test]
1480+ fn duplicate_keys ( ) {
1481+ // You cannot parse a Miniscript that has duplicate keys
1482+ let err = Miniscript :: < String , Segwitv0 > :: from_str ( "and_v(v:pk(A),pk(A))" ) . unwrap_err ( ) ;
1483+ assert_eq ! ( err, Error :: AnalysisError ( crate :: AnalysisError :: RepeatedPubkeys ) ) ;
1484+
1485+ // ...though you can parse one with from_str_insane
1486+ let ok_insane =
1487+ Miniscript :: < String , Segwitv0 > :: from_str_insane ( "and_v(v:pk(A),pk(A))" ) . unwrap ( ) ;
1488+ // ...but this cannot be sanity checked.
1489+ assert_eq ! ( ok_insane. sanity_check( ) . unwrap_err( ) , crate :: AnalysisError :: RepeatedPubkeys ) ;
1490+ // ...it can be lifted, though it's unclear whether this is a deliberate
1491+ // choice or just an accident. It seems weird given that duplicate public
1492+ // keys are forbidden in several other places.
1493+ ok_insane. lift ( ) . unwrap ( ) ;
1494+ }
1495+
1496+ #[ test]
1497+ fn mixed_timelocks ( ) {
1498+ // You cannot parse a Miniscript that mixes timelocks.
1499+ let err = Miniscript :: < String , Segwitv0 > :: from_str (
1500+ "and_v(v:and_v(v:older(4194304),pk(A)),and_v(v:older(1),pk(B)))" ,
1501+ )
1502+ . unwrap_err ( ) ;
1503+ assert_eq ! ( err, Error :: AnalysisError ( crate :: AnalysisError :: HeightTimelockCombination ) ) ;
1504+
1505+ // Though you can in an or() rather than and()
1506+ let ok_or = Miniscript :: < String , Segwitv0 > :: from_str (
1507+ "or_i(and_v(v:older(4194304),pk(A)),and_v(v:older(1),pk(B)))" ,
1508+ )
1509+ . unwrap ( ) ;
1510+ ok_or. sanity_check ( ) . unwrap ( ) ;
1511+ ok_or. lift ( ) . unwrap ( ) ;
1512+
1513+ // ...and you can parse one with from_str_insane
1514+ let ok_insane = Miniscript :: < String , Segwitv0 > :: from_str_insane (
1515+ "and_v(v:and_v(v:older(4194304),pk(A)),and_v(v:older(1),pk(B)))" ,
1516+ )
1517+ . unwrap ( ) ;
1518+ // ...but this cannot be sanity checked or lifted
1519+ assert_eq ! (
1520+ ok_insane. sanity_check( ) . unwrap_err( ) ,
1521+ crate :: AnalysisError :: HeightTimelockCombination
1522+ ) ;
1523+ assert_eq ! (
1524+ ok_insane. lift( ) . unwrap_err( ) ,
1525+ Error :: LiftError ( crate :: policy:: LiftError :: HeightTimelockCombination )
1526+ ) ;
1527+ }
1528+
14111529 #[ test]
14121530 fn template_timelocks ( ) {
14131531 use crate :: { AbsLockTime , RelLockTime } ;
0 commit comments