@@ -31,7 +31,8 @@ use std::fmt;
3131use std:: str:: { self , FromStr } ;
3232
3333use expression;
34- use miniscript:: Miniscript ;
34+ use miniscript:: context:: ScriptContextError ;
35+ use miniscript:: { Legacy , Miniscript , Segwitv0 } ;
3536use Error ;
3637use MiniscriptKey ;
3738use Satisfier ;
@@ -49,8 +50,8 @@ pub use self::satisfied_constraints::Stack;
4950/// Script descriptor
5051#[ derive( Clone , PartialEq , Eq , PartialOrd , Ord ) ]
5152pub enum Descriptor < Pk : MiniscriptKey > {
52- /// A raw scriptpubkey (including pay-to-pubkey)
53- Bare ( Miniscript < Pk > ) ,
53+ /// A raw scriptpubkey (including pay-to-pubkey) under Legacy context
54+ Bare ( Miniscript < Pk , Legacy > ) ,
5455 /// Pay-to-Pubkey
5556 Pk ( Pk ) ,
5657 /// Pay-to-PubKey-Hash
@@ -59,12 +60,12 @@ pub enum Descriptor<Pk: MiniscriptKey> {
5960 Wpkh ( Pk ) ,
6061 /// Pay-to-Witness-PubKey-Hash inside P2SH
6162 ShWpkh ( Pk ) ,
62- /// Pay-to-ScriptHash
63- Sh ( Miniscript < Pk > ) ,
64- /// Pay-to-Witness-ScriptHash
65- Wsh ( Miniscript < Pk > ) ,
66- /// P2SH-P2WSH
67- ShWsh ( Miniscript < Pk > ) ,
63+ /// Pay-to-ScriptHash with Legacy context
64+ Sh ( Miniscript < Pk , Legacy > ) ,
65+ /// Pay-to-Witness-ScriptHash with Segwitv0 context
66+ Wsh ( Miniscript < Pk , Segwitv0 > ) ,
67+ /// P2SH-P2WSH with Segwitv0 context
68+ ShWsh ( Miniscript < Pk , Segwitv0 > ) ,
6869}
6970
7071impl < Pk : MiniscriptKey > Descriptor < Pk > {
@@ -73,29 +74,43 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
7374 & self ,
7475 mut translatefpk : Fpk ,
7576 mut translatefpkh : Fpkh ,
76- ) -> Result < Descriptor < Q > , E >
77+ ) -> Result < Result < Descriptor < Q > , Error > , E >
7778 where
7879 Fpk : FnMut ( & Pk ) -> Result < Q , E > ,
7980 Fpkh : FnMut ( & Pk :: Hash ) -> Result < Q :: Hash , E > ,
8081 Q : MiniscriptKey ,
8182 {
8283 match * self {
83- Descriptor :: Bare ( ref ms) => Ok ( Descriptor :: Bare (
84- ms. translate_pk ( & mut translatefpk, & mut translatefpkh) ?,
85- ) ) ,
86- Descriptor :: Pk ( ref pk) => translatefpk ( pk) . map ( Descriptor :: Pk ) ,
87- Descriptor :: Pkh ( ref pk) => translatefpk ( pk) . map ( Descriptor :: Pkh ) ,
88- Descriptor :: Wpkh ( ref pk) => translatefpk ( pk) . map ( Descriptor :: Wpkh ) ,
89- Descriptor :: ShWpkh ( ref pk) => translatefpk ( pk) . map ( Descriptor :: ShWpkh ) ,
90- Descriptor :: Sh ( ref ms) => Ok ( Descriptor :: Sh (
91- ms. translate_pk ( & mut translatefpk, & mut translatefpkh) ?,
92- ) ) ,
93- Descriptor :: Wsh ( ref ms) => Ok ( Descriptor :: Wsh (
94- ms. translate_pk ( & mut translatefpk, & mut translatefpkh) ?,
95- ) ) ,
96- Descriptor :: ShWsh ( ref ms) => Ok ( Descriptor :: ShWsh (
97- ms. translate_pk ( & mut translatefpk, & mut translatefpkh) ?,
98- ) ) ,
84+ Descriptor :: Bare ( ref ms) => Ok ( ms
85+ . translate_pk ( & mut translatefpk, & mut translatefpkh) ?
86+ . map ( Descriptor :: Bare ) ) ,
87+ Descriptor :: Pk ( ref pk) => translatefpk ( pk) . map ( Descriptor :: Pk ) . map ( Ok ) ,
88+ Descriptor :: Pkh ( ref pk) => translatefpk ( pk) . map ( Descriptor :: Pkh ) . map ( Ok ) ,
89+ Descriptor :: Wpkh ( ref pk) => {
90+ //uncompressed pubkeys not allowed in segwit descriptors
91+ if pk. is_uncompressed ( ) {
92+ Ok ( Err ( Error :: ContextError ( ScriptContextError :: CompressedOnly ) ) )
93+ } else {
94+ translatefpk ( pk) . map ( Descriptor :: Wpkh ) . map ( Ok )
95+ }
96+ }
97+ Descriptor :: ShWpkh ( ref pk) => {
98+ //uncompressed pubkeys not allowed in segwit descriptors
99+ if pk. is_uncompressed ( ) {
100+ Ok ( Err ( Error :: ContextError ( ScriptContextError :: CompressedOnly ) ) )
101+ } else {
102+ translatefpk ( pk) . map ( Descriptor :: ShWpkh ) . map ( Ok )
103+ }
104+ }
105+ Descriptor :: Sh ( ref ms) => Ok ( ms
106+ . translate_pk ( & mut translatefpk, & mut translatefpkh) ?
107+ . map ( Descriptor :: Sh ) ) ,
108+ Descriptor :: Wsh ( ref ms) => Ok ( ms
109+ . translate_pk ( & mut translatefpk, & mut translatefpkh) ?
110+ . map ( Descriptor :: Wsh ) ) ,
111+ Descriptor :: ShWsh ( ref ms) => Ok ( ms
112+ . translate_pk ( & mut translatefpk, & mut translatefpkh) ?
113+ . map ( Descriptor :: ShWsh ) ) ,
99114 }
100115 }
101116}
@@ -200,7 +215,8 @@ impl<Pk: MiniscriptKey + ToPublicKey> Descriptor<Pk> {
200215 let addr = bitcoin:: Address :: p2wpkh ( & pk. to_public_key ( ) , bitcoin:: Network :: Bitcoin ) ;
201216 addr. script_pubkey ( )
202217 }
203- Descriptor :: Sh ( ref d) | Descriptor :: Wsh ( ref d) | Descriptor :: ShWsh ( ref d) => d. encode ( ) ,
218+ Descriptor :: Sh ( ref d) => d. encode ( ) ,
219+ Descriptor :: Wsh ( ref d) | Descriptor :: ShWsh ( ref d) => d. encode ( ) ,
204220 }
205221 }
206222
@@ -395,25 +411,29 @@ where
395411 expression:: terminal ( & top. args [ 0 ] , |pk| Pk :: from_str ( pk) . map ( Descriptor :: Pkh ) )
396412 }
397413 ( "wpkh" , 1 ) => {
398- expression:: terminal ( & top. args [ 0 ] , |pk| Pk :: from_str ( pk) . map ( Descriptor :: Wpkh ) )
414+ let wpkh = expression:: terminal ( & top. args [ 0 ] , |pk| Pk :: from_str ( pk) ) ?;
415+ if wpkh. is_uncompressed ( ) {
416+ Err ( Error :: ContextError ( ScriptContextError :: CompressedOnly ) )
417+ } else {
418+ Ok ( Descriptor :: Wpkh ( wpkh) )
419+ }
399420 }
400421 ( "sh" , 1 ) => {
401422 let newtop = & top. args [ 0 ] ;
402423 match ( newtop. name , newtop. args . len ( ) ) {
403- ( "wsh" , 1 ) => {
404- let sub = Miniscript :: from_tree ( & newtop. args [ 0 ] ) ?;
405- Ok ( Descriptor :: ShWsh ( sub) )
406- }
407- ( "wpkh" , 1 ) => expression:: terminal ( & newtop. args [ 0 ] , |pk| {
408- Pk :: from_str ( pk) . map ( Descriptor :: ShWpkh )
409- } ) ,
410- _ => {
411- let sub = Miniscript :: from_tree ( & top. args [ 0 ] ) ?;
412- Ok ( Descriptor :: Sh ( sub) )
424+ ( "wsh" , 1 ) => Miniscript :: from_tree ( & newtop. args [ 0 ] ) . map ( Descriptor :: ShWsh ) ,
425+ ( "wpkh" , 1 ) => {
426+ let wpkh = expression:: terminal ( & newtop. args [ 0 ] , |pk| Pk :: from_str ( pk) ) ?;
427+ if wpkh. is_uncompressed ( ) {
428+ Err ( Error :: ContextError ( ScriptContextError :: CompressedOnly ) )
429+ } else {
430+ Ok ( Descriptor :: ShWpkh ( wpkh) )
431+ }
413432 }
433+ _ => Miniscript :: from_tree ( & top. args [ 0 ] ) . map ( Descriptor :: Sh ) ,
414434 }
415435 }
416- ( "wsh" , 1 ) => expression :: unary ( top, Descriptor :: Wsh ) ,
436+ ( "wsh" , 1 ) => Miniscript :: from_tree ( & top. args [ 0 ] ) . map ( Descriptor :: Wsh ) ,
417437 _ => {
418438 let sub = expression:: FromTree :: from_tree ( & top) ?;
419439 Ok ( Descriptor :: Bare ( sub) )
@@ -563,6 +583,18 @@ mod tests {
563583 StdDescriptor :: from_str ( "pk()" ) . unwrap_err ( ) ;
564584
565585 StdDescriptor :: from_str ( TEST_PK ) . unwrap ( ) ;
586+
587+ let uncompressed_pk =
588+ "0414fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267be5645686309c6e6736dbd93940707cc9143d3cf29f1b877ff340e2cb2d259cf" ;
589+
590+ // Context tests
591+ StdDescriptor :: from_str ( & format ! ( "pk({})" , uncompressed_pk) ) . unwrap ( ) ;
592+ StdDescriptor :: from_str ( & format ! ( "pkh({})" , uncompressed_pk) ) . unwrap ( ) ;
593+ StdDescriptor :: from_str ( & format ! ( "sh(pk({}))" , uncompressed_pk) ) . unwrap ( ) ;
594+ StdDescriptor :: from_str ( & format ! ( "wpkh({})" , uncompressed_pk) ) . unwrap_err ( ) ;
595+ StdDescriptor :: from_str ( & format ! ( "sh(wpkh({}))" , uncompressed_pk) ) . unwrap_err ( ) ;
596+ StdDescriptor :: from_str ( & format ! ( "wsh(pk{})" , uncompressed_pk) ) . unwrap_err ( ) ;
597+ StdDescriptor :: from_str ( & format ! ( "sh(wsh(pk{}))" , uncompressed_pk) ) . unwrap_err ( ) ;
566598 }
567599
568600 #[ test]
@@ -852,6 +884,8 @@ mod tests {
852884 ) ;
853885 assert_eq ! ( sh. unsigned_script_sig( ) , bitcoin:: Script :: new( ) ) ;
854886
887+ let ms = ms_str ! ( "c:pk_k({})" , pk) ;
888+
855889 let wsh = Descriptor :: Wsh ( ms. clone ( ) ) ;
856890 wsh. satisfy ( & mut txin, & satisfier) . expect ( "satisfaction" ) ;
857891 assert_eq ! (
0 commit comments