24
24
//! components of the AST.
25
25
//!
26
26
27
- use core:: marker:: PhantomData ;
28
27
use core:: { fmt, hash, str} ;
29
28
30
29
use bitcoin:: blockdata:: script;
31
30
use bitcoin:: util:: taproot:: { LeafVersion , TapLeafHash } ;
32
31
33
32
use self :: analyzable:: ExtParams ;
34
33
pub use self :: context:: { BareCtx , Legacy , Segwitv0 , Tap } ;
35
- use crate :: { prelude:: * , MAX_RECURSION_DEPTH } ;
34
+ use crate :: prelude:: * ;
36
35
37
36
pub mod analyzable;
38
37
pub mod astelem;
@@ -53,25 +52,70 @@ use self::lex::{lex, TokenIter};
53
52
use self :: types:: Property ;
54
53
pub use crate :: miniscript:: context:: ScriptContext ;
55
54
use crate :: miniscript:: decode:: Terminal ;
56
- use crate :: miniscript:: types:: extra_props:: ExtData ;
57
- use crate :: miniscript:: types:: Type ;
58
55
use crate :: { expression, Error , ForEachKey , MiniscriptKey , ToPublicKey , TranslatePk , Translator } ;
59
56
#[ cfg( test) ]
60
57
mod ms_tests;
61
58
62
- /// Top-level script AST type
63
- #[ derive( Clone ) ]
64
- pub struct Miniscript < Pk : MiniscriptKey , Ctx : ScriptContext > {
65
- ///A node in the Abstract Syntax Tree(
66
- pub node : Terminal < Pk , Ctx > ,
67
- ///The correctness and malleability type information for the AST node
68
- pub ty : types:: Type ,
69
- ///Additional information helpful for extra analysis.
70
- pub ext : types:: extra_props:: ExtData ,
71
- /// Context PhantomData. Only accessible inside this crate
72
- pub ( crate ) phantom : PhantomData < Ctx > ,
59
+ mod private {
60
+ use core:: marker:: PhantomData ;
61
+
62
+ use super :: types:: { ExtData , Property , Type } ;
63
+ pub use crate :: miniscript:: context:: ScriptContext ;
64
+ use crate :: miniscript:: types;
65
+ use crate :: { Error , MiniscriptKey , Terminal , MAX_RECURSION_DEPTH } ;
66
+
67
+ /// The top-level miniscript abstract syntax tree (AST).
68
+ #[ derive( Clone ) ]
69
+ pub struct Miniscript < Pk : MiniscriptKey , Ctx : ScriptContext > {
70
+ /// A node in the AST.
71
+ pub node : Terminal < Pk , Ctx > ,
72
+ /// The correctness and malleability type information for the AST node.
73
+ pub ty : types:: Type ,
74
+ /// Additional information helpful for extra analysis.
75
+ pub ext : types:: extra_props:: ExtData ,
76
+ /// Context PhantomData. Only accessible inside this crate
77
+ phantom : PhantomData < Ctx > ,
78
+ }
79
+ impl < Pk : MiniscriptKey , Ctx : ScriptContext > Miniscript < Pk , Ctx > {
80
+
81
+ /// Add type information(Type and Extdata) to Miniscript based on
82
+ /// `AstElem` fragment. Dependent on display and clone because of Error
83
+ /// Display code of type_check.
84
+ pub fn from_ast ( t : Terminal < Pk , Ctx > ) -> Result < Miniscript < Pk , Ctx > , Error > {
85
+ let res = Miniscript {
86
+ ty : Type :: type_check ( & t, |_| None ) ?,
87
+ ext : ExtData :: type_check ( & t, |_| None ) ?,
88
+ node : t,
89
+ phantom : PhantomData ,
90
+ } ;
91
+ // TODO: This recursion depth is based on segwitv0.
92
+ // We can relax this in tapscript, but this should be good for almost
93
+ // all practical cases and we can revisit this if needed.
94
+ // casting to u32 is safe because tree_height will never go more than u32::MAX
95
+ if ( res. ext . tree_height as u32 ) > MAX_RECURSION_DEPTH {
96
+ return Err ( Error :: MaxRecursiveDepthExceeded ) ;
97
+ }
98
+ Ctx :: check_global_consensus_validity ( & res) ?;
99
+ Ok ( res)
100
+ }
101
+
102
+ /// Create a new `Miniscript` from a `Terminal` node and a `Type` annotation
103
+ /// This does not check the typing rules. The user is responsible for ensuring
104
+ /// that the type provided is correct.
105
+ ///
106
+ /// You should almost always use `Miniscript::from_ast` instead of this function.
107
+ pub fn from_components_unchecked (
108
+ node : Terminal < Pk , Ctx > ,
109
+ ty : types:: Type ,
110
+ ext : types:: extra_props:: ExtData ,
111
+ ) -> Miniscript < Pk , Ctx > {
112
+ Miniscript { node, ty, ext, phantom : PhantomData }
113
+ }
114
+ }
73
115
}
74
116
117
+ pub use private:: Miniscript ;
118
+
75
119
/// `PartialOrd` of `Miniscript` must depend only on node and not the type information.
76
120
/// The type information and extra_properties can be deterministically determined
77
121
/// by the ast.
@@ -116,36 +160,14 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> hash::Hash for Miniscript<Pk, Ctx> {
116
160
}
117
161
}
118
162
119
- impl < Pk : MiniscriptKey , Ctx : ScriptContext > Miniscript < Pk , Ctx > {
120
- /// Add type information(Type and Extdata) to Miniscript based on
121
- /// `AstElem` fragment. Dependent on display and clone because of Error
122
- /// Display code of type_check.
123
- pub fn from_ast ( t : Terminal < Pk , Ctx > ) -> Result < Miniscript < Pk , Ctx > , Error > {
124
- let res = Miniscript {
125
- ty : Type :: type_check ( & t, |_| None ) ?,
126
- ext : ExtData :: type_check ( & t, |_| None ) ?,
127
- node : t,
128
- phantom : PhantomData ,
129
- } ;
130
- // TODO: This recursion depth is based on segwitv0.
131
- // We can relax this in tapscript, but this should be good for almost
132
- // all practical cases and we can revisit this if needed.
133
- // casting to u32 is safe because tree_height will never go more than u32::MAX
134
- if ( res. ext . tree_height as u32 ) > MAX_RECURSION_DEPTH {
135
- Err ( Error :: MaxRecursiveDepthExceeded )
136
- } else {
137
- Ok ( res)
138
- }
139
- }
140
- }
141
-
142
163
impl < Pk : MiniscriptKey , Ctx : ScriptContext > fmt:: Display for Miniscript < Pk , Ctx > {
143
164
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
144
165
write ! ( f, "{}" , self . node)
145
166
}
146
167
}
147
168
148
169
impl < Pk : MiniscriptKey , Ctx : ScriptContext > Miniscript < Pk , Ctx > {
170
+
149
171
/// Extracts the `AstElem` representing the root of the miniscript
150
172
pub fn into_inner ( self ) -> Terminal < Pk , Ctx > {
151
173
self . node
@@ -338,14 +360,8 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
338
360
T : Translator < Pk , Q , FuncError > ,
339
361
{
340
362
let inner = self . node . real_translate_pk ( t) ?;
341
- let ms = Miniscript {
342
- //directly copying the type and ext is safe because translating public
343
- //key should not change any properties
344
- ty : self . ty ,
345
- ext : self . ext ,
346
- node : inner,
347
- phantom : PhantomData ,
348
- } ;
363
+ let ms = Miniscript :: from_ast ( inner)
364
+ . expect ( "Translator should not change the type of the AST" ) ;
349
365
Ok ( ms)
350
366
}
351
367
}
@@ -455,12 +471,7 @@ impl_from_tree!(
455
471
/// should not be called directly; rather go through the descriptor API.
456
472
fn from_tree( top: & expression:: Tree ) -> Result <Miniscript <Pk , Ctx >, Error > {
457
473
let inner: Terminal <Pk , Ctx > = expression:: FromTree :: from_tree( top) ?;
458
- Ok ( Miniscript {
459
- ty: Type :: type_check( & inner, |_| None ) ?,
460
- ext: ExtData :: type_check( & inner, |_| None ) ?,
461
- node: inner,
462
- phantom: PhantomData ,
463
- } )
474
+ Ok ( Miniscript :: from_ast( inner) ?)
464
475
}
465
476
) ;
466
477
@@ -482,7 +493,6 @@ serde_string_impl_pk!(Miniscript, "a miniscript", Ctx; ScriptContext);
482
493
#[ cfg( test) ]
483
494
mod tests {
484
495
485
- use core:: marker:: PhantomData ;
486
496
use core:: str;
487
497
use core:: str:: FromStr ;
488
498
@@ -493,7 +503,7 @@ mod tests {
493
503
use sync:: Arc ;
494
504
495
505
use super :: { Miniscript , ScriptContext , Segwitv0 , Tap } ;
496
- use crate :: miniscript:: types:: { self , ExtData , Property , Type } ;
506
+ use crate :: miniscript:: types;
497
507
use crate :: miniscript:: Terminal ;
498
508
use crate :: policy:: Liftable ;
499
509
use crate :: { prelude:: * , Error } ;
@@ -679,32 +689,18 @@ mod tests {
679
689
. unwrap ( ) ;
680
690
let hash = hash160:: Hash :: from_inner ( [ 17 ; 20 ] ) ;
681
691
682
- let pkk_ms: Miniscript < DummyKey , Segwitv0 > = Miniscript {
683
- node : Terminal :: Check ( Arc :: new ( Miniscript {
684
- node : Terminal :: PkK ( DummyKey ) ,
685
- ty : Type :: from_pk_k :: < Segwitv0 > ( ) ,
686
- ext : types:: extra_props:: ExtData :: from_pk_k :: < Segwitv0 > ( ) ,
687
- phantom : PhantomData ,
688
- } ) ) ,
689
- ty : Type :: cast_check ( Type :: from_pk_k :: < Segwitv0 > ( ) ) . unwrap ( ) ,
690
- ext : ExtData :: cast_check ( ExtData :: from_pk_k :: < Segwitv0 > ( ) ) . unwrap ( ) ,
691
- phantom : PhantomData ,
692
- } ;
692
+ let pk_node = Terminal :: Check ( Arc :: new (
693
+ Miniscript :: from_ast ( Terminal :: PkK ( DummyKey ) ) . unwrap ( ) ,
694
+ ) ) ;
695
+ let pkk_ms: Miniscript < DummyKey , Segwitv0 > = Miniscript :: from_ast ( pk_node) . unwrap ( ) ;
693
696
dummy_string_rtt ( pkk_ms, "[B/onduesm]c:[K/onduesm]pk_k(DummyKey)" , "pk()" ) ;
694
697
695
- let pkh_ms: Miniscript < DummyKey , Segwitv0 > = Miniscript {
696
- node : Terminal :: Check ( Arc :: new ( Miniscript {
697
- node : Terminal :: PkH ( DummyKey ) ,
698
- ty : Type :: from_pk_h :: < Segwitv0 > ( ) ,
699
- ext : types:: extra_props:: ExtData :: from_pk_h :: < Segwitv0 > ( ) ,
700
- phantom : PhantomData ,
701
- } ) ) ,
702
- ty : Type :: cast_check ( Type :: from_pk_h :: < Segwitv0 > ( ) ) . unwrap ( ) ,
703
- ext : ExtData :: cast_check ( ExtData :: from_pk_h :: < Segwitv0 > ( ) ) . unwrap ( ) ,
704
- phantom : PhantomData ,
705
- } ;
698
+ let pkh_node = Terminal :: Check ( Arc :: new (
699
+ Miniscript :: from_ast ( Terminal :: PkH ( String :: from ( "" ) ) ) . unwrap ( ) ,
700
+ ) ) ;
701
+ let pkh_ms: Miniscript < String , Segwitv0 > = Miniscript :: from_ast ( pkh_node) . unwrap ( ) ;
706
702
707
- let expected_debug = "[B/nduesm]c:[K/nduesm]pk_h(DummyKey )" ;
703
+ let expected_debug = "[B/nduesm]c:[K/nduesm]pk_h(\" \" )" ;
708
704
let expected_display = "pkh()" ;
709
705
710
706
assert_eq ! ( pkh_ms. ty. corr. base, types:: Base :: B ) ;
@@ -717,35 +713,19 @@ mod tests {
717
713
assert_eq ! ( display, expected) ;
718
714
}
719
715
720
- let pkk_ms: Segwitv0Script = Miniscript {
721
- node : Terminal :: Check ( Arc :: new ( Miniscript {
722
- node : Terminal :: PkK ( pk) ,
723
- ty : Type :: from_pk_k :: < Segwitv0 > ( ) ,
724
- ext : types:: extra_props:: ExtData :: from_pk_k :: < Segwitv0 > ( ) ,
725
- phantom : PhantomData ,
726
- } ) ) ,
727
- ty : Type :: cast_check ( Type :: from_pk_k :: < Segwitv0 > ( ) ) . unwrap ( ) ,
728
- ext : ExtData :: cast_check ( ExtData :: from_pk_k :: < Segwitv0 > ( ) ) . unwrap ( ) ,
729
- phantom : PhantomData ,
730
- } ;
716
+ let pkk_node = Terminal :: Check ( Arc :: new ( Miniscript :: from_ast ( Terminal :: PkK ( pk) ) . unwrap ( ) ) ) ;
717
+ let pkk_ms: Segwitv0Script = Miniscript :: from_ast ( pkk_node) . unwrap ( ) ;
731
718
732
719
script_rtt (
733
720
pkk_ms,
734
721
"21020202020202020202020202020202020202020202020202020202020\
735
722
202020202ac",
736
723
) ;
737
724
738
- let pkh_ms: Segwitv0Script = Miniscript {
739
- node : Terminal :: Check ( Arc :: new ( Miniscript {
740
- node : Terminal :: RawPkH ( hash) ,
741
- ty : Type :: from_pk_h :: < Segwitv0 > ( ) ,
742
- ext : types:: extra_props:: ExtData :: from_pk_h :: < Segwitv0 > ( ) ,
743
- phantom : PhantomData ,
744
- } ) ) ,
745
- ty : Type :: cast_check ( Type :: from_pk_h :: < Segwitv0 > ( ) ) . unwrap ( ) ,
746
- ext : ExtData :: cast_check ( ExtData :: from_pk_h :: < Segwitv0 > ( ) ) . unwrap ( ) ,
747
- phantom : PhantomData ,
748
- } ;
725
+ let pkh_ms: Segwitv0Script = Miniscript :: from_ast ( Terminal :: Check ( Arc :: new (
726
+ Miniscript :: from_ast ( Terminal :: RawPkH ( hash) ) . unwrap ( ) ,
727
+ ) ) )
728
+ . unwrap ( ) ;
749
729
750
730
script_rtt ( pkh_ms, "76a914111111111111111111111111111111111111111188ac" ) ;
751
731
}
@@ -1160,4 +1140,13 @@ mod tests {
1160
1140
panic ! ( "Unexpected error: {:?}" , err) ;
1161
1141
}
1162
1142
}
1143
+
1144
+ #[ test]
1145
+ fn test_script_parse_dos ( ) {
1146
+ let mut script = bitcoin:: blockdata:: script:: Builder :: new ( ) . push_opcode ( bitcoin:: blockdata:: opcodes:: OP_TRUE ) ;
1147
+ for _ in 0 ..10000 {
1148
+ script = script. push_opcode ( bitcoin:: blockdata:: opcodes:: all:: OP_0NOTEQUAL ) ;
1149
+ }
1150
+ Tapscript :: parse_insane ( & script. into_script ( ) ) . unwrap_err ( ) ;
1151
+ }
1163
1152
}
0 commit comments