@@ -27,8 +27,8 @@ use crate::miniscript::{satisfy, Legacy, Miniscript, Segwitv0};
27
27
use crate :: plan:: { AssetProvider , Plan } ;
28
28
use crate :: prelude:: * ;
29
29
use crate :: {
30
- expression, hash256, BareCtx , Error , ForEachKey , FromStrKey , MiniscriptKey , Satisfier ,
31
- ToPublicKey , TranslateErr , Translator ,
30
+ expression, hash256, AnalysisError , BareCtx , Error , ExtParams , ForEachKey , FromStrKey ,
31
+ MiniscriptKey , Satisfier , ToPublicKey , TranslateErr , Translator ,
32
32
} ;
33
33
34
34
mod bare;
@@ -318,6 +318,36 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
318
318
}
319
319
}
320
320
321
+ /// Helper function for Wsh descriptor
322
+ fn ext_check_wsh ( wsh : & Wsh < Pk > , params : & ExtParams ) -> Result < ( ) , AnalysisError > {
323
+ match wsh. as_inner ( ) {
324
+ WshInner :: SortedMulti ( ref smv) => Ok ( ( ) ) ,
325
+ WshInner :: Ms ( ref ms) => ms. ext_check ( params) ,
326
+ }
327
+ }
328
+
329
+ /// Helper function for Sh descriptor
330
+ fn ext_check_sh ( sh : & Sh < Pk > , params : & ExtParams ) -> Result < ( ) , AnalysisError > {
331
+ match sh. as_inner ( ) {
332
+ ShInner :: Wsh ( ref wsh) => Self :: ext_check_wsh ( & wsh, params) ,
333
+ ShInner :: Wpkh ( _) => Ok ( ( ) ) ,
334
+ ShInner :: SortedMulti ( ref smv) => Ok ( ( ) ) ,
335
+ ShInner :: Ms ( ref ms) => ms. ext_check ( params) ,
336
+ }
337
+ }
338
+
339
+ /// Check whether the descriptor is safe under the given extra parameters
340
+ pub fn ext_check ( & self , params : & ExtParams ) -> Result < ( ) , AnalysisError > {
341
+ match * self {
342
+ Descriptor :: Bare ( ref bare) => bare. as_inner ( ) . ext_check ( params) ,
343
+ Descriptor :: Pkh ( _) => Ok ( ( ) ) ,
344
+ Descriptor :: Wpkh ( ref wpkh) => Ok ( ( ) ) ,
345
+ Descriptor :: Wsh ( ref wsh) => Self :: ext_check_wsh ( & wsh, params) ,
346
+ Descriptor :: Sh ( ref sh) => Self :: ext_check_sh ( & sh, params) ,
347
+ Descriptor :: Tr ( ref tr) => tr. ext_check ( params) ,
348
+ }
349
+ }
350
+
321
351
/// Computes an upper bound on the difference between a non-satisfied
322
352
/// `TxIn`'s `segwit_weight` and a satisfied `TxIn`'s `segwit_weight`
323
353
///
@@ -1117,7 +1147,7 @@ mod tests {
1117
1147
StdDescriptor :: from_str ( TEST_PK ) . unwrap ( ) ;
1118
1148
1119
1149
let uncompressed_pk =
1120
- "0414fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267be5645686309c6e6736dbd93940707cc9143d3cf29f1b877ff340e2cb2d259cf" ;
1150
+ "0414fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267be5645686309c6e6736dbd93940707cc9143d3cf29f1b877ff340e2cb2d259cf" ;
1121
1151
1122
1152
// Context tests
1123
1153
StdDescriptor :: from_str ( & format ! ( "pk({})" , uncompressed_pk) ) . unwrap ( ) ;
@@ -1302,6 +1332,29 @@ mod tests {
1302
1332
) ;
1303
1333
}
1304
1334
1335
+ #[ test]
1336
+ fn ext_check ( ) {
1337
+ /// Make sure that default ext_check() catches OP_DROP but
1338
+ /// ext_check() with OP_DROP explicitly allowed does not.
1339
+ fn assert_opdrop_error ( desc : & str ) {
1340
+ let desc = Descriptor :: < PublicKey > :: from_str ( desc) . unwrap ( ) ;
1341
+ assert_eq ! (
1342
+ desc. ext_check( & ExtParams :: default ( ) ) . unwrap_err( ) ,
1343
+ AnalysisError :: ContainsDrop
1344
+ ) ;
1345
+ assert_eq ! ( desc. ext_check( & ExtParams :: default ( ) . drop( ) ) , Ok ( ( ) ) ) ;
1346
+ }
1347
+
1348
+ let secp = secp256k1:: Secp256k1 :: new ( ) ;
1349
+ let sk =
1350
+ secp256k1:: SecretKey :: from_slice ( & b"sally was a secret key, she said" [ ..] ) . unwrap ( ) ;
1351
+ let pk = bitcoin:: PublicKey :: new ( secp256k1:: PublicKey :: from_secret_key ( & secp, & sk) ) ;
1352
+ let inner = format ! ( "and_v(r:after(1),c:pk_k({}))" , pk) ;
1353
+ assert_opdrop_error ( format ! ( "sh({})" , inner) . as_str ( ) ) ;
1354
+ assert_opdrop_error ( format ! ( "wsh({})" , inner) . as_str ( ) ) ;
1355
+ assert_opdrop_error ( format ! ( "sh(wsh({}))" , inner) . as_str ( ) ) ;
1356
+ }
1357
+
1305
1358
#[ test]
1306
1359
fn satisfy ( ) {
1307
1360
let secp = secp256k1:: Secp256k1 :: new ( ) ;
@@ -1648,7 +1701,7 @@ mod tests {
1648
1701
let descriptor = Descriptor :: < PublicKey > :: from_str (
1649
1702
"wsh(multi(2,03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd,03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626))" ,
1650
1703
)
1651
- . unwrap ( ) ;
1704
+ . unwrap ( ) ;
1652
1705
assert_eq ! (
1653
1706
* descriptor
1654
1707
. script_code( ) . unwrap( )
@@ -1679,7 +1732,7 @@ mod tests {
1679
1732
bip32:: ChildNumber :: from_hardened_idx ( 0 ) . unwrap ( ) ,
1680
1733
bip32:: ChildNumber :: from_hardened_idx ( 0 ) . unwrap ( ) ,
1681
1734
] [ ..] )
1682
- . into ( ) ,
1735
+ . into ( ) ,
1683
1736
) ) ,
1684
1737
xkey : bip32:: Xpub :: from_str ( "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL" ) . unwrap ( ) ,
1685
1738
derivation_path : ( & [ bip32:: ChildNumber :: from_normal_idx ( 1 ) . unwrap ( ) ] [ ..] ) . into ( ) ,
@@ -1741,7 +1794,7 @@ mod tests {
1741
1794
key : SinglePubKey :: FullKey ( bitcoin:: PublicKey :: from_str (
1742
1795
"04f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446a" ,
1743
1796
)
1744
- . unwrap ( ) ) ,
1797
+ . unwrap ( ) ) ,
1745
1798
origin : None ,
1746
1799
} ) ;
1747
1800
assert_eq ! ( expected, key. parse( ) . unwrap( ) ) ;
0 commit comments