1313//! components of the AST.
1414//!
1515
16- use core:: marker:: PhantomData ;
1716use core:: { fmt, hash, str} ;
1817
1918use bitcoin:: script;
2019use bitcoin:: taproot:: { LeafVersion , TapLeafHash } ;
2120
2221use self :: analyzable:: ExtParams ;
2322pub use self :: context:: { BareCtx , Legacy , Segwitv0 , Tap } ;
24- use crate :: { prelude:: * , MAX_RECURSION_DEPTH } ;
23+ use crate :: prelude:: * ;
2524use crate :: TranslateErr ;
2625
2726pub mod analyzable;
@@ -42,25 +41,70 @@ use self::lex::{lex, TokenIter};
4241use self :: types:: Property ;
4342pub use crate :: miniscript:: context:: ScriptContext ;
4443use crate :: miniscript:: decode:: Terminal ;
45- use crate :: miniscript:: types:: extra_props:: ExtData ;
46- use crate :: miniscript:: types:: Type ;
4744use crate :: { expression, Error , ForEachKey , MiniscriptKey , ToPublicKey , TranslatePk , Translator } ;
4845#[ cfg( test) ]
4946mod ms_tests;
5047
51- /// Top-level script AST type
52- #[ derive( Clone ) ]
53- pub struct Miniscript < Pk : MiniscriptKey , Ctx : ScriptContext > {
54- ///A node in the Abstract Syntax Tree(
55- pub node : Terminal < Pk , Ctx > ,
56- ///The correctness and malleability type information for the AST node
57- pub ty : types:: Type ,
58- ///Additional information helpful for extra analysis.
59- pub ext : types:: extra_props:: ExtData ,
60- /// Context PhantomData. Only accessible inside this crate
61- phantom : PhantomData < Ctx > ,
48+ mod private {
49+ use core:: marker:: PhantomData ;
50+
51+ use super :: types:: { ExtData , Property , Type } ;
52+ pub use crate :: miniscript:: context:: ScriptContext ;
53+ use crate :: miniscript:: types;
54+ use crate :: { Error , MiniscriptKey , Terminal , MAX_RECURSION_DEPTH } ;
55+
56+ /// The top-level miniscript abstract syntax tree (AST).
57+ #[ derive( Clone ) ]
58+ pub struct Miniscript < Pk : MiniscriptKey , Ctx : ScriptContext > {
59+ /// A node in the AST.
60+ pub node : Terminal < Pk , Ctx > ,
61+ /// The correctness and malleability type information for the AST node.
62+ pub ty : types:: Type ,
63+ /// Additional information helpful for extra analysis.
64+ pub ext : types:: extra_props:: ExtData ,
65+ /// Context PhantomData. Only accessible inside this crate
66+ phantom : PhantomData < Ctx > ,
67+ }
68+ impl < Pk : MiniscriptKey , Ctx : ScriptContext > Miniscript < Pk , Ctx > {
69+
70+ /// Add type information(Type and Extdata) to Miniscript based on
71+ /// `AstElem` fragment. Dependent on display and clone because of Error
72+ /// Display code of type_check.
73+ pub fn from_ast ( t : Terminal < Pk , Ctx > ) -> Result < Miniscript < Pk , Ctx > , Error > {
74+ let res = Miniscript {
75+ ty : Type :: type_check ( & t, |_| None ) ?,
76+ ext : ExtData :: type_check ( & t, |_| None ) ?,
77+ node : t,
78+ phantom : PhantomData ,
79+ } ;
80+ // TODO: This recursion depth is based on segwitv0.
81+ // We can relax this in tapscript, but this should be good for almost
82+ // all practical cases and we can revisit this if needed.
83+ // casting to u32 is safe because tree_height will never go more than u32::MAX
84+ if ( res. ext . tree_height as u32 ) > MAX_RECURSION_DEPTH {
85+ return Err ( Error :: MaxRecursiveDepthExceeded ) ;
86+ }
87+ Ctx :: check_global_consensus_validity ( & res) ?;
88+ Ok ( res)
89+ }
90+
91+ /// Create a new `Miniscript` from a `Terminal` node and a `Type` annotation
92+ /// This does not check the typing rules. The user is responsible for ensuring
93+ /// that the type provided is correct.
94+ ///
95+ /// You should almost always use `Miniscript::from_ast` instead of this function.
96+ pub fn from_components_unchecked (
97+ node : Terminal < Pk , Ctx > ,
98+ ty : types:: Type ,
99+ ext : types:: extra_props:: ExtData ,
100+ ) -> Miniscript < Pk , Ctx > {
101+ Miniscript { node, ty, ext, phantom : PhantomData }
102+ }
103+ }
62104}
63105
106+ pub use private:: Miniscript ;
107+
64108/// `PartialOrd` of `Miniscript` must depend only on node and not the type information.
65109/// The type information and extra_properties can be deterministically determined
66110/// by the ast.
@@ -105,54 +149,14 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> hash::Hash for Miniscript<Pk, Ctx> {
105149 }
106150}
107151
108- impl < Pk : MiniscriptKey , Ctx : ScriptContext > Miniscript < Pk , Ctx > {
109- /// Add type information(Type and Extdata) to Miniscript based on
110- /// `AstElem` fragment. Dependent on display and clone because of Error
111- /// Display code of type_check.
112- pub fn from_ast ( t : Terminal < Pk , Ctx > ) -> Result < Miniscript < Pk , Ctx > , Error > {
113- let res = Miniscript {
114- ty : Type :: type_check ( & t, |_| None ) ?,
115- ext : ExtData :: type_check ( & t, |_| None ) ?,
116- node : t,
117- phantom : PhantomData ,
118- } ;
119- // TODO: This recursion depth is based on segwitv0.
120- // We can relax this in tapscript, but this should be good for almost
121- // all practical cases and we can revisit this if needed.
122- // casting to u32 is safe because tree_height will never go more than u32::MAX
123- if ( res. ext . tree_height as u32 ) > MAX_RECURSION_DEPTH {
124- return Err ( Error :: MaxRecursiveDepthExceeded ) ;
125- }
126- Ctx :: check_global_consensus_validity ( & res) ?;
127- Ok ( res)
128- }
129-
130- /// Create a new `Miniscript` from a `Terminal` node and a `Type` annotation
131- /// This does not check the typing rules. The user is responsible for ensuring
132- /// that the type provided is correct.
133- ///
134- /// You should almost always use `Miniscript::from_ast` instead of this function.
135- pub fn from_components_unchecked (
136- node : Terminal < Pk , Ctx > ,
137- ty : types:: Type ,
138- ext : types:: extra_props:: ExtData ,
139- ) -> Miniscript < Pk , Ctx > {
140- Miniscript {
141- node,
142- ty,
143- ext,
144- phantom : PhantomData ,
145- }
146- }
147- }
148-
149152impl < Pk : MiniscriptKey , Ctx : ScriptContext > fmt:: Display for Miniscript < Pk , Ctx > {
150153 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
151154 write ! ( f, "{}" , self . node)
152155 }
153156}
154157
155158impl < Pk : MiniscriptKey , Ctx : ScriptContext > Miniscript < Pk , Ctx > {
159+
156160 /// Extracts the `AstElem` representing the root of the miniscript
157161 pub fn into_inner ( self ) -> Terminal < Pk , Ctx > {
158162 self . node
@@ -481,7 +485,6 @@ pub mod hash256 {
481485#[ cfg( test) ]
482486mod tests {
483487
484- use core:: marker:: PhantomData ;
485488 use core:: str;
486489 use core:: str:: FromStr ;
487490
@@ -492,7 +495,7 @@ mod tests {
492495 use sync:: Arc ;
493496
494497 use super :: { Miniscript , ScriptContext , Segwitv0 , Tap } ;
495- use crate :: miniscript:: types:: { self , ExtData , Property , Type } ;
498+ use crate :: miniscript:: types;
496499 use crate :: miniscript:: Terminal ;
497500 use crate :: policy:: Liftable ;
498501 use crate :: { prelude:: * , Error } ;
@@ -678,21 +681,15 @@ mod tests {
678681 . unwrap ( ) ;
679682 let hash = hash160:: Hash :: from_byte_array ( [ 17 ; 20 ] ) ;
680683
681- let pk_node = Terminal :: Check ( Arc :: new ( Miniscript {
682- node : Terminal :: PkK ( String :: from ( "" ) ) ,
683- ty : Type :: from_pk_k :: < Segwitv0 > ( ) ,
684- ext : types:: extra_props:: ExtData :: from_pk_k :: < Segwitv0 > ( ) ,
685- phantom : PhantomData ,
686- } ) ) ;
684+ let pk_node = Terminal :: Check ( Arc :: new (
685+ Miniscript :: from_ast ( Terminal :: PkK ( String :: from ( "" ) ) ) . unwrap ( ) ,
686+ ) ) ;
687687 let pkk_ms: Miniscript < String , Segwitv0 > = Miniscript :: from_ast ( pk_node) . unwrap ( ) ;
688688 dummy_string_rtt ( pkk_ms, "[B/onduesm]c:[K/onduesm]pk_k(\" \" )" , "pk()" ) ;
689689
690- let pkh_node = Terminal :: Check ( Arc :: new ( Miniscript {
691- node : Terminal :: PkH ( String :: from ( "" ) ) ,
692- ty : Type :: from_pk_h :: < Segwitv0 > ( ) ,
693- ext : types:: extra_props:: ExtData :: from_pk_h :: < Segwitv0 > ( ) ,
694- phantom : PhantomData ,
695- } ) ) ;
690+ let pkh_node = Terminal :: Check ( Arc :: new (
691+ Miniscript :: from_ast ( Terminal :: PkH ( String :: from ( "" ) ) ) . unwrap ( ) ,
692+ ) ) ;
696693 let pkh_ms: Miniscript < String , Segwitv0 > = Miniscript :: from_ast ( pkh_node) . unwrap ( ) ;
697694
698695 let expected_debug = "[B/nduesm]c:[K/nduesm]pk_h(\" \" )" ;
@@ -708,12 +705,7 @@ mod tests {
708705 assert_eq ! ( display, expected) ;
709706 }
710707
711- let pkk_node = Terminal :: Check ( Arc :: new ( Miniscript {
712- node : Terminal :: PkK ( pk) ,
713- ty : Type :: from_pk_k :: < Segwitv0 > ( ) ,
714- ext : types:: extra_props:: ExtData :: from_pk_k :: < Segwitv0 > ( ) ,
715- phantom : PhantomData ,
716- } ) ) ;
708+ let pkk_node = Terminal :: Check ( Arc :: new ( Miniscript :: from_ast ( Terminal :: PkK ( pk) ) . unwrap ( ) ) ) ;
717709 let pkk_ms: Segwitv0Script = Miniscript :: from_ast ( pkk_node) . unwrap ( ) ;
718710
719711 script_rtt (
@@ -722,17 +714,10 @@ mod tests {
722714 202020202ac",
723715 ) ;
724716
725- let pkh_ms: Segwitv0Script = Miniscript {
726- node : Terminal :: Check ( Arc :: new ( Miniscript {
727- node : Terminal :: RawPkH ( hash) ,
728- ty : Type :: from_pk_h :: < Segwitv0 > ( ) ,
729- ext : types:: extra_props:: ExtData :: from_pk_h :: < Segwitv0 > ( ) ,
730- phantom : PhantomData ,
731- } ) ) ,
732- ty : Type :: cast_check ( Type :: from_pk_h :: < Segwitv0 > ( ) ) . unwrap ( ) ,
733- ext : ExtData :: cast_check ( ExtData :: from_pk_h :: < Segwitv0 > ( ) ) . unwrap ( ) ,
734- phantom : PhantomData ,
735- } ;
717+ let pkh_ms: Segwitv0Script = Miniscript :: from_ast ( Terminal :: Check ( Arc :: new (
718+ Miniscript :: from_ast ( Terminal :: RawPkH ( hash) ) . unwrap ( ) ,
719+ ) ) )
720+ . unwrap ( ) ;
736721
737722 script_rtt ( pkh_ms, "76a914111111111111111111111111111111111111111188ac" ) ;
738723 }
@@ -1160,4 +1145,13 @@ mod tests {
11601145 panic ! ( "Unexpected error: {:?}" , err) ;
11611146 }
11621147 }
1148+
1149+ #[ test]
1150+ fn test_script_parse_dos ( ) {
1151+ let mut script = bitcoin:: script:: Builder :: new ( ) . push_opcode ( bitcoin:: opcodes:: OP_TRUE ) ;
1152+ for _ in 0 ..10000 {
1153+ script = script. push_opcode ( bitcoin:: opcodes:: all:: OP_0NOTEQUAL ) ;
1154+ }
1155+ Tapscript :: parse_insane ( & script. into_script ( ) ) . unwrap_err ( ) ;
1156+ }
11631157}
0 commit comments