@@ -32,7 +32,8 @@ use std::str::{self, FromStr};
3232
3333use  expression; 
3434use  miniscript; 
35- use  miniscript:: Miniscript ; 
35+ use  miniscript:: context:: ScriptContextError ; 
36+ use  miniscript:: { Legacy ,  Miniscript ,  Segwitv0 } ; 
3637use  Error ; 
3738use  MiniscriptKey ; 
3839use  Satisfier ; 
@@ -50,8 +51,8 @@ pub use self::satisfied_constraints::Stack;
5051/// Script descriptor 
5152#[ derive( Clone ,  PartialEq ,  Eq ,  PartialOrd ,  Ord ) ]  
5253pub  enum  Descriptor < Pk :  MiniscriptKey >  { 
53-     /// A raw scriptpubkey (including pay-to-pubkey) 
54- Bare ( Miniscript < Pk > ) , 
54+     /// A raw scriptpubkey (including pay-to-pubkey) under Legacy context  
55+ Bare ( Miniscript < Pk ,   Legacy > ) , 
5556    /// Pay-to-Pubkey 
5657Pk ( Pk ) , 
5758    /// Pay-to-PubKey-Hash 
@@ -60,16 +61,19 @@ pub enum Descriptor<Pk: MiniscriptKey> {
6061Wpkh ( Pk ) , 
6162    /// Pay-to-Witness-PubKey-Hash inside P2SH 
6263ShWpkh ( Pk ) , 
63-     /// Pay-to-ScriptHash 
64- Sh ( Miniscript < Pk > ) , 
65-     /// Pay-to-Witness-ScriptHash 
66- Wsh ( Miniscript < Pk > ) , 
67-     /// P2SH-P2WSH 
68- ShWsh ( Miniscript < Pk > ) , 
64+     /// Pay-to-ScriptHash with Legacy context  
65+ Sh ( Miniscript < Pk ,   Legacy > ) , 
66+     /// Pay-to-Witness-ScriptHash with Segwitv0 context  
67+ Wsh ( Miniscript < Pk ,   Segwitv0 > ) , 
68+     /// P2SH-P2WSH with Segwitv0 context  
69+ ShWsh ( Miniscript < Pk ,   Segwitv0 > ) , 
6970} 
7071
7172impl < Pk :  MiniscriptKey >  Descriptor < Pk >  { 
7273    /// Convert a descriptor using abstract keys to one using specific keys 
74+ /// This will panic if translatefpk returns an uncompressed key when 
75+ /// converting to a Segwit descriptor. To prevent this panic, ensure 
76+ /// translatefpk returns an error in this case instead. 
7377pub  fn  translate_pk < Fpk ,  Fpkh ,  Q ,  E > ( 
7478        & self , 
7579        mut  translatefpk :  Fpk , 
@@ -86,8 +90,18 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
8690            ) ) , 
8791            Descriptor :: Pk ( ref  pk)  => translatefpk ( pk) . map ( Descriptor :: Pk ) , 
8892            Descriptor :: Pkh ( ref  pk)  => translatefpk ( pk) . map ( Descriptor :: Pkh ) , 
89-             Descriptor :: Wpkh ( ref  pk)  => translatefpk ( pk) . map ( Descriptor :: Wpkh ) , 
90-             Descriptor :: ShWpkh ( ref  pk)  => translatefpk ( pk) . map ( Descriptor :: ShWpkh ) , 
93+             Descriptor :: Wpkh ( ref  pk)  => { 
94+                 if  pk. is_uncompressed ( )  { 
95+                     panic ! ( "Uncompressed pubkeys are not allowed in segwit v0 scripts" ) ; 
96+                 } 
97+                 translatefpk ( pk) . map ( Descriptor :: Wpkh ) 
98+             } 
99+             Descriptor :: ShWpkh ( ref  pk)  => { 
100+                 if  pk. is_uncompressed ( )  { 
101+                     panic ! ( "Uncompressed pubkeys are not allowed in segwit v0 scripts" ) ; 
102+                 } 
103+                 translatefpk ( pk) . map ( Descriptor :: ShWpkh ) 
104+             } 
91105            Descriptor :: Sh ( ref  ms)  => Ok ( Descriptor :: Sh ( 
92106                ms. translate_pk ( & mut  translatefpk,  & mut  translatefpkh) ?, 
93107            ) ) , 
@@ -201,7 +215,8 @@ impl<Pk: MiniscriptKey + ToPublicKey> Descriptor<Pk> {
201215                let  addr = bitcoin:: Address :: p2wpkh ( & pk. to_public_key ( ) ,  bitcoin:: Network :: Bitcoin ) ; 
202216                addr. script_pubkey ( ) 
203217            } 
204-             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 ( ) , 
205220        } 
206221    } 
207222
@@ -396,7 +411,12 @@ where
396411                expression:: terminal ( & top. args [ 0 ] ,  |pk| Pk :: from_str ( pk) . map ( Descriptor :: Pkh ) ) 
397412            } 
398413            ( "wpkh" ,  1 )  => { 
399-                 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+                 } 
400420            } 
401421            ( "sh" ,  1 )  => { 
402422                let  newtop = & top. args [ 0 ] ; 
@@ -409,9 +429,14 @@ where
409429                            Ok ( Descriptor :: ShWsh ( sub) ) 
410430                        } 
411431                    } 
412-                     ( "wpkh" ,  1 )  => expression:: terminal ( & newtop. args [ 0 ] ,  |pk| { 
413-                         Pk :: from_str ( pk) . map ( Descriptor :: ShWpkh ) 
414-                     } ) , 
432+                     ( "wpkh" ,  1 )  => { 
433+                         let  wpkh = expression:: terminal ( & newtop. args [ 0 ] ,  |pk| Pk :: from_str ( pk) ) ?; 
434+                         if  wpkh. is_uncompressed ( )  { 
435+                             Err ( Error :: ContextError ( ScriptContextError :: CompressedOnly ) ) 
436+                         }  else  { 
437+                             Ok ( Descriptor :: ShWpkh ( wpkh) ) 
438+                         } 
439+                     } 
415440                    _ => { 
416441                        let  sub = Miniscript :: from_tree ( & top. args [ 0 ] ) ?; 
417442                        if  sub. ty . corr . base  != miniscript:: types:: Base :: B  { 
@@ -586,6 +611,18 @@ mod tests {
586611        StdDescriptor :: from_str ( "nl:0" ) . unwrap_err ( ) ;  //issue 63 
587612
588613        StdDescriptor :: from_str ( TEST_PK ) . unwrap ( ) ; 
614+ 
615+         let  uncompressed_pk =
616+         "0414fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267be5645686309c6e6736dbd93940707cc9143d3cf29f1b877ff340e2cb2d259cf" ; 
617+ 
618+         // Context tests 
619+         StdDescriptor :: from_str ( & format ! ( "pk({})" ,  uncompressed_pk) ) . unwrap ( ) ; 
620+         StdDescriptor :: from_str ( & format ! ( "pkh({})" ,  uncompressed_pk) ) . unwrap ( ) ; 
621+         StdDescriptor :: from_str ( & format ! ( "sh(pk({}))" ,  uncompressed_pk) ) . unwrap ( ) ; 
622+         StdDescriptor :: from_str ( & format ! ( "wpkh({})" ,  uncompressed_pk) ) . unwrap_err ( ) ; 
623+         StdDescriptor :: from_str ( & format ! ( "sh(wpkh({}))" ,  uncompressed_pk) ) . unwrap_err ( ) ; 
624+         StdDescriptor :: from_str ( & format ! ( "wsh(pk{})" ,  uncompressed_pk) ) . unwrap_err ( ) ; 
625+         StdDescriptor :: from_str ( & format ! ( "sh(wsh(pk{}))" ,  uncompressed_pk) ) . unwrap_err ( ) ; 
589626    } 
590627
591628    #[ test]  
@@ -875,6 +912,8 @@ mod tests {
875912        ) ; 
876913        assert_eq ! ( sh. unsigned_script_sig( ) ,  bitcoin:: Script :: new( ) ) ; 
877914
915+         let  ms = ms_str ! ( "c:pk_k({})" ,  pk) ; 
916+ 
878917        let  wsh = Descriptor :: Wsh ( ms. clone ( ) ) ; 
879918        wsh. satisfy ( & mut  txin,  & satisfier) . expect ( "satisfaction" ) ; 
880919        assert_eq ! ( 
0 commit comments