@@ -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,12 +61,12 @@ 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 > {
@@ -74,29 +75,43 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
7475 & self ,
7576 mut translatefpk : Fpk ,
7677 mut translatefpkh : Fpkh ,
77- ) -> Result < Descriptor < Q > , E >
78+ ) -> Result < Result < Descriptor < Q > , Error > , E >
7879 where
7980 Fpk : FnMut ( & Pk ) -> Result < Q , E > ,
8081 Fpkh : FnMut ( & Pk :: Hash ) -> Result < Q :: Hash , E > ,
8182 Q : MiniscriptKey ,
8283 {
8384 match * self {
84- Descriptor :: Bare ( ref ms) => Ok ( Descriptor :: Bare (
85- ms. translate_pk ( & mut translatefpk, & mut translatefpkh) ?,
86- ) ) ,
87- Descriptor :: Pk ( ref pk) => translatefpk ( pk) . map ( Descriptor :: Pk ) ,
88- 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 ) ,
91- Descriptor :: Sh ( ref ms) => Ok ( Descriptor :: Sh (
92- ms. translate_pk ( & mut translatefpk, & mut translatefpkh) ?,
93- ) ) ,
94- Descriptor :: Wsh ( ref ms) => Ok ( Descriptor :: Wsh (
95- ms. translate_pk ( & mut translatefpk, & mut translatefpkh) ?,
96- ) ) ,
97- Descriptor :: ShWsh ( ref ms) => Ok ( Descriptor :: ShWsh (
98- ms. translate_pk ( & mut translatefpk, & mut translatefpkh) ?,
99- ) ) ,
85+ Descriptor :: Bare ( ref ms) => Ok ( ms
86+ . translate_pk ( & mut translatefpk, & mut translatefpkh) ?
87+ . map ( Descriptor :: Bare ) ) ,
88+ Descriptor :: Pk ( ref pk) => translatefpk ( pk) . map ( Descriptor :: Pk ) . map ( Ok ) ,
89+ Descriptor :: Pkh ( ref pk) => translatefpk ( pk) . map ( Descriptor :: Pkh ) . map ( Ok ) ,
90+ Descriptor :: Wpkh ( ref pk) => {
91+ //uncompressed pubkeys not allowed in segwit descriptors
92+ if pk. is_uncompressed ( ) {
93+ Ok ( Err ( Error :: ContextError ( ScriptContextError :: CompressedOnly ) ) )
94+ } else {
95+ translatefpk ( pk) . map ( Descriptor :: Wpkh ) . map ( Ok )
96+ }
97+ }
98+ Descriptor :: ShWpkh ( ref pk) => {
99+ //uncompressed pubkeys not allowed in segwit descriptors
100+ if pk. is_uncompressed ( ) {
101+ Ok ( Err ( Error :: ContextError ( ScriptContextError :: CompressedOnly ) ) )
102+ } else {
103+ translatefpk ( pk) . map ( Descriptor :: ShWpkh ) . map ( Ok )
104+ }
105+ }
106+ Descriptor :: Sh ( ref ms) => Ok ( ms
107+ . translate_pk ( & mut translatefpk, & mut translatefpkh) ?
108+ . map ( Descriptor :: Sh ) ) ,
109+ Descriptor :: Wsh ( ref ms) => Ok ( ms
110+ . translate_pk ( & mut translatefpk, & mut translatefpkh) ?
111+ . map ( Descriptor :: Wsh ) ) ,
112+ Descriptor :: ShWsh ( ref ms) => Ok ( ms
113+ . translate_pk ( & mut translatefpk, & mut translatefpkh) ?
114+ . map ( Descriptor :: ShWsh ) ) ,
100115 }
101116 }
102117}
@@ -201,7 +216,8 @@ impl<Pk: MiniscriptKey + ToPublicKey> Descriptor<Pk> {
201216 let addr = bitcoin:: Address :: p2wpkh ( & pk. to_public_key ( ) , bitcoin:: Network :: Bitcoin ) ;
202217 addr. script_pubkey ( )
203218 }
204- Descriptor :: Sh ( ref d) | Descriptor :: Wsh ( ref d) | Descriptor :: ShWsh ( ref d) => d. encode ( ) ,
219+ Descriptor :: Sh ( ref d) => d. encode ( ) ,
220+ Descriptor :: Wsh ( ref d) | Descriptor :: ShWsh ( ref d) => d. encode ( ) ,
205221 }
206222 }
207223
@@ -396,7 +412,12 @@ where
396412 expression:: terminal ( & top. args [ 0 ] , |pk| Pk :: from_str ( pk) . map ( Descriptor :: Pkh ) )
397413 }
398414 ( "wpkh" , 1 ) => {
399- expression:: terminal ( & top. args [ 0 ] , |pk| Pk :: from_str ( pk) . map ( Descriptor :: Wpkh ) )
415+ let wpkh = expression:: terminal ( & top. args [ 0 ] , |pk| Pk :: from_str ( pk) ) ?;
416+ if wpkh. is_uncompressed ( ) {
417+ Err ( Error :: ContextError ( ScriptContextError :: CompressedOnly ) )
418+ } else {
419+ Ok ( Descriptor :: Wpkh ( wpkh) )
420+ }
400421 }
401422 ( "sh" , 1 ) => {
402423 let newtop = & top. args [ 0 ] ;
@@ -409,9 +430,14 @@ where
409430 Ok ( Descriptor :: ShWsh ( sub) )
410431 }
411432 }
412- ( "wpkh" , 1 ) => expression:: terminal ( & newtop. args [ 0 ] , |pk| {
413- Pk :: from_str ( pk) . map ( Descriptor :: ShWpkh )
414- } ) ,
433+ ( "wpkh" , 1 ) => {
434+ let wpkh = expression:: terminal ( & newtop. args [ 0 ] , |pk| Pk :: from_str ( pk) ) ?;
435+ if wpkh. is_uncompressed ( ) {
436+ Err ( Error :: ContextError ( ScriptContextError :: CompressedOnly ) )
437+ } else {
438+ Ok ( Descriptor :: ShWpkh ( wpkh) )
439+ }
440+ }
415441 _ => {
416442 let sub = Miniscript :: from_tree ( & top. args [ 0 ] ) ?;
417443 if sub. ty . corr . base != miniscript:: types:: Base :: B {
@@ -585,6 +611,18 @@ mod tests {
585611 StdDescriptor :: from_str ( "nl:0" ) . unwrap_err ( ) ; //issue 63
586612
587613 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 ( ) ;
588626 }
589627
590628 #[ test]
@@ -874,6 +912,8 @@ mod tests {
874912 ) ;
875913 assert_eq ! ( sh. unsigned_script_sig( ) , bitcoin:: Script :: new( ) ) ;
876914
915+ let ms = ms_str ! ( "c:pk_k({})" , pk) ;
916+
877917 let wsh = Descriptor :: Wsh ( ms. clone ( ) ) ;
878918 wsh. satisfy ( & mut txin, & satisfier) . expect ( "satisfaction" ) ;
879919 assert_eq ! (
0 commit comments