@@ -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
5657 Pk ( Pk ) ,
5758 /// Pay-to-PubKey-Hash
@@ -60,16 +61,18 @@ pub enum Descriptor<Pk: MiniscriptKey> {
6061 Wpkh ( Pk ) ,
6162 /// Pay-to-Witness-PubKey-Hash inside P2SH
6263 ShWpkh ( 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 while converting to Segwit descriptor using
75+ /// using uncompressed pubkeys.
7376 pub fn translate_pk < Fpk , Fpkh , Q , E > (
7477 & self ,
7578 mut translatefpk : Fpk ,
@@ -86,8 +89,18 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
8689 ) ) ,
8790 Descriptor :: Pk ( ref pk) => translatefpk ( pk) . map ( Descriptor :: Pk ) ,
8891 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 ) ,
92+ Descriptor :: Wpkh ( ref pk) => {
93+ if pk. is_uncompressed ( ) {
94+ panic ! ( "Uncompressed pubkeys are not allowed in segwit v0 scripts" ) ;
95+ }
96+ translatefpk ( pk) . map ( Descriptor :: Wpkh )
97+ }
98+ Descriptor :: ShWpkh ( ref pk) => {
99+ if pk. is_uncompressed ( ) {
100+ panic ! ( "Uncompressed pubkeys are not allowed in segwit v0 scripts" ) ;
101+ }
102+ translatefpk ( pk) . map ( Descriptor :: ShWpkh )
103+ }
91104 Descriptor :: Sh ( ref ms) => Ok ( Descriptor :: Sh (
92105 ms. translate_pk ( & mut translatefpk, & mut translatefpkh) ?,
93106 ) ) ,
@@ -201,7 +214,8 @@ impl<Pk: MiniscriptKey + ToPublicKey> Descriptor<Pk> {
201214 let addr = bitcoin:: Address :: p2wpkh ( & pk. to_public_key ( ) , bitcoin:: Network :: Bitcoin ) ;
202215 addr. script_pubkey ( )
203216 }
204- Descriptor :: Sh ( ref d) | Descriptor :: Wsh ( ref d) | Descriptor :: ShWsh ( ref d) => d. encode ( ) ,
217+ Descriptor :: Sh ( ref d) => d. encode ( ) ,
218+ Descriptor :: Wsh ( ref d) | Descriptor :: ShWsh ( ref d) => d. encode ( ) ,
205219 }
206220 }
207221
@@ -396,7 +410,12 @@ where
396410 expression:: terminal ( & top. args [ 0 ] , |pk| Pk :: from_str ( pk) . map ( Descriptor :: Pkh ) )
397411 }
398412 ( "wpkh" , 1 ) => {
399- expression:: terminal ( & top. args [ 0 ] , |pk| Pk :: from_str ( pk) . map ( Descriptor :: Wpkh ) )
413+ let wpkh = expression:: terminal ( & top. args [ 0 ] , |pk| Pk :: from_str ( pk) ) ?;
414+ if wpkh. is_uncompressed ( ) {
415+ Err ( Error :: ContextError ( ScriptContextError :: CompressedOnly ) )
416+ } else {
417+ Ok ( Descriptor :: Wpkh ( wpkh) )
418+ }
400419 }
401420 ( "sh" , 1 ) => {
402421 let newtop = & top. args [ 0 ] ;
@@ -409,9 +428,14 @@ where
409428 Ok ( Descriptor :: ShWsh ( sub) )
410429 }
411430 }
412- ( "wpkh" , 1 ) => expression:: terminal ( & newtop. args [ 0 ] , |pk| {
413- Pk :: from_str ( pk) . map ( Descriptor :: ShWpkh )
414- } ) ,
431+ ( "wpkh" , 1 ) => {
432+ let wpkh = expression:: terminal ( & newtop. args [ 0 ] , |pk| Pk :: from_str ( pk) ) ?;
433+ if wpkh. is_uncompressed ( ) {
434+ Err ( Error :: ContextError ( ScriptContextError :: CompressedOnly ) )
435+ } else {
436+ Ok ( Descriptor :: ShWpkh ( wpkh) )
437+ }
438+ }
415439 _ => {
416440 let sub = Miniscript :: from_tree ( & top. args [ 0 ] ) ?;
417441 if sub. ty . corr . base != miniscript:: types:: Base :: B {
@@ -586,6 +610,18 @@ mod tests {
586610 StdDescriptor :: from_str ( "nl:0" ) . unwrap_err ( ) ; //issue 63
587611
588612 StdDescriptor :: from_str ( TEST_PK ) . unwrap ( ) ;
613+
614+ let uncompressed_pk =
615+ "0414fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267be5645686309c6e6736dbd93940707cc9143d3cf29f1b877ff340e2cb2d259cf" ;
616+
617+ // Context tests
618+ StdDescriptor :: from_str ( & format ! ( "pk({})" , uncompressed_pk) ) . unwrap ( ) ;
619+ StdDescriptor :: from_str ( & format ! ( "pkh({})" , uncompressed_pk) ) . unwrap ( ) ;
620+ StdDescriptor :: from_str ( & format ! ( "sh(pk({}))" , uncompressed_pk) ) . unwrap ( ) ;
621+ StdDescriptor :: from_str ( & format ! ( "wpkh({})" , uncompressed_pk) ) . unwrap_err ( ) ;
622+ StdDescriptor :: from_str ( & format ! ( "sh(wpkh({}))" , uncompressed_pk) ) . unwrap_err ( ) ;
623+ StdDescriptor :: from_str ( & format ! ( "wsh(pk{})" , uncompressed_pk) ) . unwrap_err ( ) ;
624+ StdDescriptor :: from_str ( & format ! ( "sh(wsh(pk{}))" , uncompressed_pk) ) . unwrap_err ( ) ;
589625 }
590626
591627 #[ test]
@@ -875,6 +911,8 @@ mod tests {
875911 ) ;
876912 assert_eq ! ( sh. unsigned_script_sig( ) , bitcoin:: Script :: new( ) ) ;
877913
914+ let ms = ms_str ! ( "c:pk_k({})" , pk) ;
915+
878916 let wsh = Descriptor :: Wsh ( ms. clone ( ) ) ;
879917 wsh. satisfy ( & mut txin, & satisfier) . expect ( "satisfaction" ) ;
880918 assert_eq ! (
0 commit comments