1212//! components of the AST.
1313//!
1414
15- use core:: marker:: PhantomData ;
1615use core:: { fmt, hash, str} ;
1716
1817use bitcoin:: hashes:: hash160;
@@ -23,7 +22,7 @@ use self::analyzable::ExtParams;
2322pub use self :: context:: { BareCtx , Legacy , Segwitv0 , Tap } ;
2423use crate :: iter:: TreeLike ;
2524use crate :: prelude:: * ;
26- use crate :: { script_num_size, TranslateErr , MAX_RECURSION_DEPTH } ;
25+ use crate :: { script_num_size, TranslateErr } ;
2726
2827pub mod analyzable;
2928pub mod astelem;
@@ -42,79 +41,89 @@ use sync::Arc;
4241use self :: lex:: { lex, TokenIter } ;
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 :: {
4845 expression, plan, Error , ForEachKey , FromStrKey , MiniscriptKey , ToPublicKey , TranslatePk ,
4946 Translator ,
5047} ;
5148#[ cfg( test) ]
5249mod ms_tests;
5350
54- /// The top-level miniscript abstract syntax tree (AST).
55- #[ derive( Clone ) ]
56- pub struct Miniscript < Pk : MiniscriptKey , Ctx : ScriptContext > {
57- /// A node in the AST.
58- pub node : Terminal < Pk , Ctx > ,
59- /// The correctness and malleability type information for the AST node.
60- pub ty : types:: Type ,
61- /// Additional information helpful for extra analysis.
62- pub ext : types:: extra_props:: ExtData ,
63- /// Context PhantomData. Only accessible inside this crate
64- phantom : PhantomData < Ctx > ,
65- }
51+ mod private {
52+ use core:: marker:: PhantomData ;
6653
67- impl < Pk : MiniscriptKey , Ctx : ScriptContext > Miniscript < Pk , Ctx > {
68- /// The `1` combinator.
69- pub const TRUE : Self = Miniscript {
70- node : Terminal :: True ,
71- ty : types:: Type :: TRUE ,
72- ext : types:: extra_props:: ExtData :: TRUE ,
73- phantom : PhantomData ,
74- } ;
75-
76- /// The `0` combinator.
77- pub const FALSE : Self = Miniscript {
78- node : Terminal :: False ,
79- ty : types:: Type :: FALSE ,
80- ext : types:: extra_props:: ExtData :: FALSE ,
81- phantom : PhantomData ,
82- } ;
83-
84- /// Add type information(Type and Extdata) to Miniscript based on
85- /// `AstElem` fragment. Dependent on display and clone because of Error
86- /// Display code of type_check.
87- pub fn from_ast ( t : Terminal < Pk , Ctx > ) -> Result < Miniscript < Pk , Ctx > , Error > {
88- let res = Miniscript {
89- ty : Type :: type_check ( & t) ?,
90- ext : ExtData :: type_check ( & t) ?,
91- node : t,
54+ use super :: types:: { ExtData , Type } ;
55+ pub use crate :: miniscript:: context:: ScriptContext ;
56+ use crate :: miniscript:: types;
57+ use crate :: { Error , MiniscriptKey , Terminal , MAX_RECURSION_DEPTH } ;
58+
59+ /// The top-level miniscript abstract syntax tree (AST).
60+ #[ derive( Clone ) ]
61+ pub struct Miniscript < Pk : MiniscriptKey , Ctx : ScriptContext > {
62+ /// A node in the AST.
63+ pub node : Terminal < Pk , Ctx > ,
64+ /// The correctness and malleability type information for the AST node.
65+ pub ty : types:: Type ,
66+ /// Additional information helpful for extra analysis.
67+ pub ext : types:: extra_props:: ExtData ,
68+ /// Context PhantomData. Only accessible inside this crate
69+ phantom : PhantomData < Ctx > ,
70+ }
71+ impl < Pk : MiniscriptKey , Ctx : ScriptContext > Miniscript < Pk , Ctx > {
72+ /// The `1` combinator.
73+ pub const TRUE : Self = Miniscript {
74+ node : Terminal :: True ,
75+ ty : types:: Type :: TRUE ,
76+ ext : types:: extra_props:: ExtData :: TRUE ,
9277 phantom : PhantomData ,
9378 } ;
94- // TODO: This recursion depth is based on segwitv0.
95- // We can relax this in tapscript, but this should be good for almost
96- // all practical cases and we can revisit this if needed.
97- // casting to u32 is safe because tree_height will never go more than u32::MAX
98- if ( res. ext . tree_height as u32 ) > MAX_RECURSION_DEPTH {
99- return Err ( Error :: MaxRecursiveDepthExceeded ) ;
79+
80+ /// The `0` combinator.
81+ pub const FALSE : Self = Miniscript {
82+ node : Terminal :: False ,
83+ ty : types:: Type :: FALSE ,
84+ ext : types:: extra_props:: ExtData :: FALSE ,
85+ phantom : PhantomData ,
86+ } ;
87+
88+ /// Add type information(Type and Extdata) to Miniscript based on
89+ /// `AstElem` fragment. Dependent on display and clone because of Error
90+ /// Display code of type_check.
91+ pub fn from_ast ( t : Terminal < Pk , Ctx > ) -> Result < Miniscript < Pk , Ctx > , Error > {
92+ let res = Miniscript {
93+ ty : Type :: type_check ( & t) ?,
94+ ext : ExtData :: type_check ( & t) ?,
95+ node : t,
96+ phantom : PhantomData ,
97+ } ;
98+ // TODO: This recursion depth is based on segwitv0.
99+ // We can relax this in tapscript, but this should be good for almost
100+ // all practical cases and we can revisit this if needed.
101+ // casting to u32 is safe because tree_height will never go more than u32::MAX
102+ if ( res. ext . tree_height as u32 ) > MAX_RECURSION_DEPTH {
103+ return Err ( Error :: MaxRecursiveDepthExceeded ) ;
104+ }
105+ Ctx :: check_global_consensus_validity ( & res) ?;
106+ Ok ( res)
100107 }
101- Ctx :: check_global_consensus_validity ( & res) ?;
102- Ok ( res)
103- }
104108
105- /// Create a new `Miniscript` from a `Terminal` node and a `Type` annotation
106- /// This does not check the typing rules. The user is responsible for ensuring
107- /// that the type provided is correct.
108- ///
109- /// You should almost always use `Miniscript::from_ast` instead of this function.
110- pub fn from_components_unchecked (
111- node : Terminal < Pk , Ctx > ,
112- ty : types:: Type ,
113- ext : types:: extra_props:: ExtData ,
114- ) -> Miniscript < Pk , Ctx > {
115- Miniscript { node, ty, ext, phantom : PhantomData }
109+ /// Create a new `Miniscript` from a `Terminal` node and a `Type` annotation
110+ /// This does not check the typing rules. The user is responsible for ensuring
111+ /// that the type provided is correct.
112+ ///
113+ /// You should almost always use `Miniscript::from_ast` instead of this function.
114+ pub fn from_components_unchecked (
115+ node : Terminal < Pk , Ctx > ,
116+ ty : types:: Type ,
117+ ext : types:: extra_props:: ExtData ,
118+ ) -> Miniscript < Pk , Ctx > {
119+ Miniscript { node, ty, ext, phantom : PhantomData }
120+ }
116121 }
122+ }
117123
124+ pub use private:: Miniscript ;
125+
126+ impl < Pk : MiniscriptKey , Ctx : ScriptContext > Miniscript < Pk , Ctx > {
118127 /// Extracts the `AstElem` representing the root of the miniscript
119128 pub fn into_inner ( self ) -> Terminal < Pk , Ctx > { self . node }
120129
@@ -700,7 +709,6 @@ pub mod hash256 {
700709#[ cfg( test) ]
701710mod tests {
702711
703- use core:: marker:: PhantomData ;
704712 use core:: str;
705713 use core:: str:: FromStr ;
706714
@@ -710,8 +718,7 @@ mod tests {
710718 use sync:: Arc ;
711719
712720 use super :: { Miniscript , ScriptContext , Segwitv0 , Tap } ;
713- use crate :: miniscript:: types:: { self , ExtData , Type } ;
714- use crate :: miniscript:: Terminal ;
721+ use crate :: miniscript:: { types, Terminal } ;
715722 use crate :: policy:: Liftable ;
716723 use crate :: prelude:: * ;
717724 use crate :: test_utils:: { StrKeyTranslator , StrXOnlyKeyTranslator } ;
@@ -896,21 +903,15 @@ mod tests {
896903 . unwrap ( ) ;
897904 let hash = hash160:: Hash :: from_byte_array ( [ 17 ; 20 ] ) ;
898905
899- let pk_node = Terminal :: Check ( Arc :: new ( Miniscript {
900- node : Terminal :: PkK ( String :: from ( "" ) ) ,
901- ty : Type :: pk_k ( ) ,
902- ext : types:: extra_props:: ExtData :: pk_k :: < Segwitv0 > ( ) ,
903- phantom : PhantomData ,
904- } ) ) ;
906+ let pk_node = Terminal :: Check ( Arc :: new (
907+ Miniscript :: from_ast ( Terminal :: PkK ( String :: from ( "" ) ) ) . unwrap ( ) ,
908+ ) ) ;
905909 let pkk_ms: Miniscript < String , Segwitv0 > = Miniscript :: from_ast ( pk_node) . unwrap ( ) ;
906910 dummy_string_rtt ( pkk_ms, "[B/onduesm]pk(\" \" )" , "pk()" ) ;
907911
908- let pkh_node = Terminal :: Check ( Arc :: new ( Miniscript {
909- node : Terminal :: PkH ( String :: from ( "" ) ) ,
910- ty : Type :: pk_h ( ) ,
911- ext : types:: extra_props:: ExtData :: pk_h :: < Segwitv0 > ( ) ,
912- phantom : PhantomData ,
913- } ) ) ;
912+ let pkh_node = Terminal :: Check ( Arc :: new (
913+ Miniscript :: from_ast ( Terminal :: PkH ( String :: from ( "" ) ) ) . unwrap ( ) ,
914+ ) ) ;
914915 let pkh_ms: Miniscript < String , Segwitv0 > = Miniscript :: from_ast ( pkh_node) . unwrap ( ) ;
915916
916917 let expected_debug = "[B/nduesm]pkh(\" \" )" ;
@@ -926,12 +927,7 @@ mod tests {
926927 assert_eq ! ( display, expected) ;
927928 }
928929
929- let pkk_node = Terminal :: Check ( Arc :: new ( Miniscript {
930- node : Terminal :: PkK ( pk) ,
931- ty : Type :: pk_k ( ) ,
932- ext : types:: extra_props:: ExtData :: pk_k :: < Segwitv0 > ( ) ,
933- phantom : PhantomData ,
934- } ) ) ;
930+ let pkk_node = Terminal :: Check ( Arc :: new ( Miniscript :: from_ast ( Terminal :: PkK ( pk) ) . unwrap ( ) ) ) ;
935931 let pkk_ms: Segwitv0Script = Miniscript :: from_ast ( pkk_node) . unwrap ( ) ;
936932
937933 script_rtt (
@@ -940,17 +936,10 @@ mod tests {
940936 202020202ac",
941937 ) ;
942938
943- let pkh_ms: Segwitv0Script = Miniscript {
944- node : Terminal :: Check ( Arc :: new ( Miniscript {
945- node : Terminal :: RawPkH ( hash) ,
946- ty : Type :: pk_h ( ) ,
947- ext : types:: extra_props:: ExtData :: pk_h :: < Segwitv0 > ( ) ,
948- phantom : PhantomData ,
949- } ) ) ,
950- ty : Type :: cast_check ( Type :: pk_h ( ) ) . unwrap ( ) ,
951- ext : ExtData :: cast_check ( ExtData :: pk_h :: < Segwitv0 > ( ) ) ,
952- phantom : PhantomData ,
953- } ;
939+ let pkh_ms: Segwitv0Script = Miniscript :: from_ast ( Terminal :: Check ( Arc :: new (
940+ Miniscript :: from_ast ( Terminal :: RawPkH ( hash) ) . unwrap ( ) ,
941+ ) ) )
942+ . unwrap ( ) ;
954943
955944 script_rtt ( pkh_ms, "76a914111111111111111111111111111111111111111188ac" ) ;
956945 }
@@ -1462,6 +1451,15 @@ mod tests {
14621451 Err ( Error :: MaxRecursiveDepthExceeded )
14631452 ) ;
14641453 }
1454+
1455+ #[ test]
1456+ fn test_script_parse_dos ( ) {
1457+ let mut script = bitcoin:: script:: Builder :: new ( ) . push_opcode ( bitcoin:: opcodes:: OP_TRUE ) ;
1458+ for _ in 0 ..10000 {
1459+ script = script. push_opcode ( bitcoin:: opcodes:: all:: OP_0NOTEQUAL ) ;
1460+ }
1461+ Tapscript :: parse_insane ( & script. into_script ( ) ) . unwrap_err ( ) ;
1462+ }
14651463}
14661464
14671465#[ cfg( bench) ]
0 commit comments