@@ -86,9 +86,7 @@ mod private {
86
86
/// and they can call `Miniscript::clone`.
87
87
fn clone ( & self ) -> Self {
88
88
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 ( ) {
92
90
let new_term = match item. node . node {
93
91
Terminal :: PkK ( ref p) => Terminal :: PkK ( p. clone ( ) ) ,
94
92
Terminal :: PkH ( ref p) => Terminal :: PkH ( p. clone ( ) ) ,
@@ -101,23 +99,31 @@ mod private {
101
99
Terminal :: Hash160 ( ref x) => Terminal :: Hash160 ( x. clone ( ) ) ,
102
100
Terminal :: True => Terminal :: True ,
103
101
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 ( ) ,
120
119
) ,
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
+ }
121
127
Terminal :: Multi ( ref thresh) => Terminal :: Multi ( thresh. clone ( ) ) ,
122
128
Terminal :: MultiA ( ref thresh) => Terminal :: MultiA ( thresh. clone ( ) ) ,
123
129
} ;
@@ -130,6 +136,7 @@ mod private {
130
136
} ) ) ;
131
137
}
132
138
139
+ assert_eq ! ( stack. len( ) , 1 ) ;
133
140
Arc :: try_unwrap ( stack. pop ( ) . unwrap ( ) ) . unwrap ( )
134
141
}
135
142
}
@@ -536,9 +543,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
536
543
T : Translator < Pk , Q , FuncError > ,
537
544
{
538
545
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 ( ) {
542
547
let new_term = match data. node . node {
543
548
Terminal :: PkK ( ref p) => Terminal :: PkK ( t. pk ( p) ?) ,
544
549
Terminal :: PkH ( ref p) => Terminal :: PkH ( t. pk ( p) ?) ,
@@ -551,23 +556,39 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
551
556
Terminal :: Hash160 ( ref x) => Terminal :: Hash160 ( t. hash160 ( x) ?) ,
552
557
Terminal :: True => Terminal :: True ,
553
558
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 ( ) ,
570
576
) ,
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
+ }
571
592
Terminal :: Multi ( ref thresh) => Terminal :: Multi ( thresh. translate_ref ( |k| t. pk ( k) ) ?) ,
572
593
Terminal :: MultiA ( ref thresh) => {
573
594
Terminal :: MultiA ( thresh. translate_ref ( |k| t. pk ( k) ) ?)
@@ -582,22 +603,58 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
582
603
583
604
/// Substitutes raw public keys hashes with the public keys as provided by map.
584
605
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 ( ) ) )
591
644
}
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 ( ) ) ,
594
647
} ;
595
648
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
+ ) ) ) ;
598
654
}
599
655
600
- Arc :: try_unwrap ( translated. pop ( ) . unwrap ( ) ) . unwrap ( )
656
+ assert_eq ! ( stack. len( ) , 1 ) ;
657
+ Arc :: try_unwrap ( stack. pop ( ) . unwrap ( ) ) . unwrap ( )
601
658
}
602
659
}
603
660
@@ -822,6 +879,7 @@ mod tests {
822
879
}
823
880
let roundtrip = Miniscript :: from_str ( & display) . expect ( "parse string serialization" ) ;
824
881
assert_eq ! ( roundtrip, script) ;
882
+ assert_eq ! ( roundtrip. clone( ) , script) ;
825
883
}
826
884
827
885
fn string_display_debug_test < Ctx : ScriptContext > (
@@ -1373,8 +1431,12 @@ mod tests {
1373
1431
#[ test]
1374
1432
fn expr_features ( ) {
1375
1433
// 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) ;
1378
1440
type SegwitMs = Miniscript < bitcoin:: PublicKey , Segwitv0 > ;
1379
1441
1380
1442
// Test that parsing raw hash160 from string does not work without extra features
@@ -1387,6 +1449,12 @@ mod tests {
1387
1449
SegwitMs :: parse ( & script) . unwrap_err ( ) ;
1388
1450
SegwitMs :: parse_insane ( & script) . unwrap_err ( ) ;
1389
1451
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) , ) ;
1390
1458
}
1391
1459
1392
1460
#[ test]
@@ -1408,6 +1476,56 @@ mod tests {
1408
1476
ms. translate_pk ( & mut t) . unwrap_err ( ) ;
1409
1477
}
1410
1478
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
+
1411
1529
#[ test]
1412
1530
fn template_timelocks ( ) {
1413
1531
use crate :: { AbsLockTime , RelLockTime } ;
0 commit comments