@@ -6,9 +6,25 @@ use miniscript::{
66 descriptor:: DescriptorPublicKey ,
77 DefiniteDescriptorKey , Descriptor ,
88} ;
9+ use tracing:: info;
910
1011pub use errors:: Error ;
1112
13+ /// Testnet extended key prefixes (BIP32/BIP49/BIP84).
14+ /// These indicate the key is for testnet/regtest, not mainnet.
15+ const TESTNET_KEY_PREFIXES : & [ & str ] = & [
16+ "tpub" , "tprv" , // BIP32 testnet
17+ "upub" , "uprv" , // BIP49 testnet (P2WPKH-P2SH)
18+ "vpub" , "vprv" , // BIP84 testnet (P2WPKH native)
19+ ] ;
20+
21+ /// Returns true if the descriptor string contains any testnet extended key prefixes.
22+ fn descriptor_uses_testnet_keys ( descriptor : & str ) -> bool {
23+ TESTNET_KEY_PREFIXES
24+ . iter ( )
25+ . any ( |prefix| descriptor. contains ( prefix) )
26+ }
27+
1228/// Coinbase output transaction.
1329///
1430/// Typically used for parsing coinbase outputs defined in SRI role configuration files.
@@ -52,9 +68,23 @@ impl CoinbaseRewardScript {
5268 . at_derivation_index ( 0 )
5369 . map_err ( |e| Error :: Miniscript ( miniscript:: Error :: Unexpected ( e. to_string ( ) ) ) ) ?;
5470
71+ // Detect if this is a testnet key based on the key prefix
72+ let uses_testnet_keys = descriptor_uses_testnet_keys ( s) ;
73+ let ok_for_mainnet = !uses_testnet_keys;
74+
75+ if uses_testnet_keys {
76+ info ! (
77+ "Coinbase descriptor uses testnet keys (tpub/upub/vpub) - not valid for mainnet"
78+ ) ;
79+ } else {
80+ info ! (
81+ "Coinbase descriptor uses mainnet keys (xpub/ypub/zpub) - valid for mainnet"
82+ ) ;
83+ }
84+
5585 return Ok ( Self {
5686 script_pubkey : definite. script_pubkey ( ) ,
57- ok_for_mainnet : true ,
87+ ok_for_mainnet,
5888 wildcard_descriptor_str : Some ( s. to_string ( ) ) ,
5989 } ) ;
6090 }
@@ -482,7 +512,38 @@ mod tests {
482512 ) . unwrap ( ) ;
483513
484514 assert ! ( desc. has_wildcard( ) ) ;
485- // Mainnet xpubs are allowed
515+ // Mainnet xpubs are valid for mainnet
486516 assert ! ( desc. ok_for_mainnet( ) ) ;
487517 }
518+
519+ #[ test]
520+ fn test_testnet_tpub_wildcard_not_ok_for_mainnet ( ) {
521+ // Testnet tpub with wildcard - should NOT be ok for mainnet
522+ let desc = CoinbaseRewardScript :: from_descriptor (
523+ "wpkh(tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp/0/*)"
524+ ) . unwrap ( ) ;
525+
526+ assert ! ( desc. has_wildcard( ) ) ;
527+ // Testnet tpubs are NOT valid for mainnet
528+ assert ! ( !desc. ok_for_mainnet( ) ) ;
529+ }
530+
531+ #[ test]
532+ fn test_testnet_key_detection ( ) {
533+ // Test the testnet key detection helper
534+ assert ! ( super :: descriptor_uses_testnet_keys( "wpkh(tpub.../0/*)" ) ) ;
535+ assert ! ( super :: descriptor_uses_testnet_keys( "wpkh(tprv.../0/*)" ) ) ;
536+ assert ! ( super :: descriptor_uses_testnet_keys( "wpkh(upub.../0/*)" ) ) ;
537+ assert ! ( super :: descriptor_uses_testnet_keys( "wpkh(uprv.../0/*)" ) ) ;
538+ assert ! ( super :: descriptor_uses_testnet_keys( "wpkh(vpub.../0/*)" ) ) ;
539+ assert ! ( super :: descriptor_uses_testnet_keys( "wpkh(vprv.../0/*)" ) ) ;
540+
541+ // Mainnet keys should return false
542+ assert ! ( !super :: descriptor_uses_testnet_keys( "wpkh(xpub.../0/*)" ) ) ;
543+ assert ! ( !super :: descriptor_uses_testnet_keys( "wpkh(xprv.../0/*)" ) ) ;
544+ assert ! ( !super :: descriptor_uses_testnet_keys( "wpkh(ypub.../0/*)" ) ) ;
545+ assert ! ( !super :: descriptor_uses_testnet_keys( "wpkh(yprv.../0/*)" ) ) ;
546+ assert ! ( !super :: descriptor_uses_testnet_keys( "wpkh(zpub.../0/*)" ) ) ;
547+ assert ! ( !super :: descriptor_uses_testnet_keys( "wpkh(zprv.../0/*)" ) ) ;
548+ }
488549}
0 commit comments