@@ -45,13 +45,13 @@ pub struct LegacyBitcoinAddress {
45
45
pub bytes : Hash160 ,
46
46
}
47
47
48
- /// Segwit address. The bool member is "mainnet" ( to determine the hrp)
48
+ /// Segwit address. The [`BitcoinNetworkType`] member allows to to determine the HRP
49
49
/// New in 2.1
50
50
#[ derive( Debug , PartialEq , Eq , Clone , Serialize , Deserialize ) ]
51
51
pub enum SegwitBitcoinAddress {
52
- P2WPKH ( bool , [ u8 ; 20 ] ) ,
53
- P2WSH ( bool , [ u8 ; 32 ] ) ,
54
- P2TR ( bool , [ u8 ; 32 ] ) ,
52
+ P2WPKH ( BitcoinNetworkType , [ u8 ; 20 ] ) ,
53
+ P2WSH ( BitcoinNetworkType , [ u8 ; 32 ] ) ,
54
+ P2TR ( BitcoinNetworkType , [ u8 ; 32 ] ) ,
55
55
}
56
56
57
57
#[ derive( Debug , PartialEq , Eq , Clone , Serialize , Deserialize ) ]
@@ -81,6 +81,7 @@ pub const ADDRESS_VERSION_TESTNET_MULTISIG: u8 = 196;
81
81
// segwit hrps
82
82
pub const SEGWIT_MAINNET_HRP : & str = "bc" ;
83
83
pub const SEGWIT_TESTNET_HRP : & str = "tb" ;
84
+ pub const SEGWIT_REGTEST_HRP : & str = "bcrt" ;
84
85
85
86
// segwit witnes versions
86
87
pub const SEGWIT_V0 : u8 = 0 ;
@@ -155,15 +156,6 @@ pub fn to_b58_version_byte(version: u8) -> Option<u8> {
155
156
}
156
157
}
157
158
158
- /// Get the HRP for a segwit address based on whether or not we're in mainnet
159
- pub fn segwit_hrp ( mainnet : bool ) -> & ' static str {
160
- if mainnet {
161
- SEGWIT_MAINNET_HRP
162
- } else {
163
- SEGWIT_TESTNET_HRP
164
- }
165
- }
166
-
167
159
impl LegacyBitcoinAddress {
168
160
fn to_versioned_bytes ( & self ) -> [ u8 ; 21 ] {
169
161
let mut ret = [ 0 ; 21 ] ;
@@ -269,11 +261,26 @@ impl SegwitBitcoinAddress {
269
261
version_bytes
270
262
}
271
263
264
+ /// Returns `true` if this Segwit address belongs to the Mainnet network.
272
265
pub fn is_mainnet ( & self ) -> bool {
266
+ self . network ( ) . is_mainnet ( )
267
+ }
268
+
269
+ /// Returns the Bitcoin network type associated with this Segwit address.
270
+ pub fn network ( & self ) -> BitcoinNetworkType {
273
271
match * self {
274
- SegwitBitcoinAddress :: P2WPKH ( ref mainnet, _) => * mainnet,
275
- SegwitBitcoinAddress :: P2WSH ( ref mainnet, _) => * mainnet,
276
- SegwitBitcoinAddress :: P2TR ( ref mainnet, _) => * mainnet,
272
+ SegwitBitcoinAddress :: P2WPKH ( ref network, _)
273
+ | SegwitBitcoinAddress :: P2WSH ( ref network, _)
274
+ | SegwitBitcoinAddress :: P2TR ( ref network, _) => * network,
275
+ }
276
+ }
277
+
278
+ /// Returns the HRP string associated with address network
279
+ pub fn hrp ( & self ) -> & ' static str {
280
+ match self . network ( ) {
281
+ BitcoinNetworkType :: Mainnet => SEGWIT_MAINNET_HRP ,
282
+ BitcoinNetworkType :: Testnet => SEGWIT_TESTNET_HRP ,
283
+ BitcoinNetworkType :: Regtest => SEGWIT_REGTEST_HRP ,
277
284
}
278
285
}
279
286
@@ -295,28 +302,28 @@ impl SegwitBitcoinAddress {
295
302
}
296
303
297
304
pub fn to_bech32 ( & self ) -> String {
298
- let hrp = segwit_hrp ( self . is_mainnet ( ) ) ;
299
- self . to_bech32_hrp ( hrp)
305
+ self . to_bech32_hrp ( self . hrp ( ) )
300
306
}
301
307
302
308
pub fn from_bech32 ( s : & str ) -> Option < SegwitBitcoinAddress > {
303
309
let ( hrp, quintets, variant) = bech32:: decode ( s)
304
310
. inspect_err ( |_e| {
305
- test_debug ! ( "Failed to decode '{s}': {_e:?}" ) ;
311
+ println ! ( "Failed to decode '{s}': {_e:?}" ) ;
306
312
} )
307
313
. ok ( ) ?;
308
314
309
- let mainnet = if hrp == SEGWIT_MAINNET_HRP {
310
- Some ( true )
311
- } else if hrp == SEGWIT_TESTNET_HRP {
312
- Some ( false )
313
- } else {
314
- test_debug ! ( "Unrecognized hrp '{:?}'" , & hrp) ;
315
- None
316
- } ?;
315
+ let network_type = match hrp. as_str ( ) {
316
+ SEGWIT_MAINNET_HRP => BitcoinNetworkType :: Mainnet ,
317
+ SEGWIT_TESTNET_HRP => BitcoinNetworkType :: Testnet ,
318
+ SEGWIT_REGTEST_HRP => BitcoinNetworkType :: Regtest ,
319
+ _ => {
320
+ println ! ( "Unrecognized hrp '{:?}'" , & hrp) ;
321
+ return None ;
322
+ }
323
+ } ;
317
324
318
325
if quintets. is_empty ( ) || quintets. len ( ) > 65 {
319
- test_debug ! ( "Invalid prog length: {}" , quintets. len( ) ) ;
326
+ println ! ( "Invalid prog length: {}" , quintets. len( ) ) ;
320
327
return None ;
321
328
}
322
329
@@ -326,25 +333,25 @@ impl SegwitBitcoinAddress {
326
333
327
334
let bytes = Vec :: from_base32 ( & prog)
328
335
. inspect_err ( |_e| {
329
- test_debug ! ( "Failed to decode quintets: {_e:?}" ) ;
336
+ println ! ( "Failed to decode quintets: {_e:?}" ) ;
330
337
} )
331
338
. ok ( ) ?;
332
339
333
340
match ( variant, version, bytes. len ( ) ) {
334
341
( bech32:: Variant :: Bech32 , SEGWIT_V0 , 20 ) => {
335
342
let bytes_20 = bytes. try_into ( ) . ok ( ) ?;
336
- Some ( SegwitBitcoinAddress :: P2WPKH ( mainnet , bytes_20) )
343
+ Some ( SegwitBitcoinAddress :: P2WPKH ( network_type , bytes_20) )
337
344
}
338
345
( bech32:: Variant :: Bech32 , SEGWIT_V0 , 32 ) => {
339
346
let bytes_32 = bytes. try_into ( ) . ok ( ) ?;
340
- Some ( SegwitBitcoinAddress :: P2WSH ( mainnet , bytes_32) )
347
+ Some ( SegwitBitcoinAddress :: P2WSH ( network_type , bytes_32) )
341
348
}
342
349
( bech32:: Variant :: Bech32m , SEGWIT_V1 , 32 ) => {
343
350
let bytes_32 = bytes. try_into ( ) . ok ( ) ?;
344
- Some ( SegwitBitcoinAddress :: P2TR ( mainnet , bytes_32) )
351
+ Some ( SegwitBitcoinAddress :: P2TR ( network_type , bytes_32) )
345
352
}
346
353
( _, _, _) => {
347
- test_debug ! (
354
+ println ! (
348
355
"Unrecognized segwit address {}: ({:?}, {}, [u8; {}])" ,
349
356
s,
350
357
& variant,
@@ -437,9 +444,8 @@ impl BitcoinAddress {
437
444
. try_into ( )
438
445
. map_err ( |_| btc_error:: InvalidByteSequence ) ?;
439
446
440
- let mainnet = network_id == BitcoinNetworkType :: Mainnet ;
441
447
Ok ( BitcoinAddress :: Segwit ( SegwitBitcoinAddress :: P2WPKH (
442
- mainnet , * my_bytes,
448
+ network_id , * my_bytes,
443
449
) ) )
444
450
}
445
451
@@ -480,9 +486,8 @@ impl BitcoinAddress {
480
486
// segwit p2wpkh
481
487
let witness_program: & [ u8 ; 20 ] = scriptpubkey. get ( 2 ..22 ) ?. try_into ( ) . ok ( ) ?;
482
488
483
- let mainnet = network_id == BitcoinNetworkType :: Mainnet ;
484
489
Some ( BitcoinAddress :: Segwit ( SegwitBitcoinAddress :: P2WPKH (
485
- mainnet ,
490
+ network_id ,
486
491
* witness_program,
487
492
) ) )
488
493
} else if scriptpubkey. len ( ) == 34
@@ -491,9 +496,8 @@ impl BitcoinAddress {
491
496
// segwit p2wsh
492
497
let witness_program: & [ u8 ; 32 ] = scriptpubkey. get ( 2 ..34 ) ?. try_into ( ) . ok ( ) ?;
493
498
494
- let mainnet = network_id == BitcoinNetworkType :: Mainnet ;
495
499
Some ( BitcoinAddress :: Segwit ( SegwitBitcoinAddress :: P2WSH (
496
- mainnet ,
500
+ network_id ,
497
501
* witness_program,
498
502
) ) )
499
503
} else if scriptpubkey. len ( ) == 34
@@ -502,9 +506,8 @@ impl BitcoinAddress {
502
506
// segwit p2tr
503
507
let witness_program: & [ u8 ; 32 ] = scriptpubkey. get ( 2 ..34 ) ?. try_into ( ) . ok ( ) ?;
504
508
505
- let mainnet = network_id == BitcoinNetworkType :: Mainnet ;
506
509
Some ( BitcoinAddress :: Segwit ( SegwitBitcoinAddress :: P2TR (
507
- mainnet ,
510
+ network_id ,
508
511
* witness_program,
509
512
) ) )
510
513
} else {
@@ -771,7 +774,7 @@ mod tests {
771
774
AddressFixture {
772
775
addr: "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4" . to_owned( ) ,
773
776
result: Some ( BitcoinAddress :: Segwit ( SegwitBitcoinAddress :: P2WPKH (
774
- true ,
777
+ BitcoinNetworkType :: Mainnet ,
775
778
[
776
779
0x75 , 0x1e , 0x76 , 0xe8 , 0x19 , 0x91 , 0x96 , 0xd4 , 0x54 , 0x94 , 0x1c , 0x45 ,
777
780
0xd1 , 0xb3 , 0xa3 , 0x23 , 0xf1 , 0x43 , 0x3b , 0xd6 ,
@@ -781,7 +784,7 @@ mod tests {
781
784
AddressFixture {
782
785
addr: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7" . to_owned( ) ,
783
786
result: Some ( BitcoinAddress :: Segwit ( SegwitBitcoinAddress :: P2WSH (
784
- false ,
787
+ BitcoinNetworkType :: Testnet ,
785
788
[
786
789
0x18 , 0x63 , 0x14 , 0x3c , 0x14 , 0xc5 , 0x16 , 0x68 , 0x04 , 0xbd , 0x19 , 0x20 ,
787
790
0x33 , 0x56 , 0xda , 0x13 , 0x6c , 0x98 , 0x56 , 0x78 , 0xcd , 0x4d , 0x27 , 0xa1 ,
@@ -808,7 +811,7 @@ mod tests {
808
811
AddressFixture {
809
812
addr: "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy" . to_owned( ) ,
810
813
result: Some ( BitcoinAddress :: Segwit ( SegwitBitcoinAddress :: P2WSH (
811
- false ,
814
+ BitcoinNetworkType :: Testnet ,
812
815
[
813
816
0x00 , 0x00 , 0x00 , 0xc4 , 0xa5 , 0xca , 0xd4 , 0x62 , 0x21 , 0xb2 , 0xa1 , 0x87 ,
814
817
0x90 , 0x5e , 0x52 , 0x66 , 0x36 , 0x2b , 0x99 , 0xd5 , 0xe9 , 0x1c , 0x6c , 0xe2 ,
@@ -942,7 +945,7 @@ mod tests {
942
945
. unwrap( )
943
946
. to_vec( ) ,
944
947
result: Some ( BitcoinAddress :: Segwit ( SegwitBitcoinAddress :: P2WPKH (
945
- true ,
948
+ BitcoinNetworkType :: Mainnet ,
946
949
[
947
950
0x75 , 0x1e , 0x76 , 0xe8 , 0x19 , 0x91 , 0x96 , 0xd4 , 0x54 , 0x94 , 0x1c , 0x45 ,
948
951
0xd1 , 0xb3 , 0xa3 , 0x23 , 0xf1 , 0x43 , 0x3b , 0xd6 ,
@@ -957,7 +960,7 @@ mod tests {
957
960
. unwrap( )
958
961
. to_vec( ) ,
959
962
result: Some ( BitcoinAddress :: Segwit ( SegwitBitcoinAddress :: P2WSH (
960
- true ,
963
+ BitcoinNetworkType :: Mainnet ,
961
964
[
962
965
0x18 , 0x63 , 0x14 , 0x3c , 0x14 , 0xc5 , 0x16 , 0x68 , 0x04 , 0xbd , 0x19 , 0x20 ,
963
966
0x33 , 0x56 , 0xda , 0x13 , 0x6c , 0x98 , 0x56 , 0x78 , 0xcd , 0x4d , 0x27 , 0xa1 ,
@@ -973,7 +976,7 @@ mod tests {
973
976
. unwrap( )
974
977
. to_vec( ) ,
975
978
result: Some ( BitcoinAddress :: Segwit ( SegwitBitcoinAddress :: P2WSH (
976
- true ,
979
+ BitcoinNetworkType :: Mainnet ,
977
980
[
978
981
0x00 , 0x00 , 0x00 , 0xc4 , 0xa5 , 0xca , 0xd4 , 0x62 , 0x21 , 0xb2 , 0xa1 , 0x87 ,
979
982
0x90 , 0x5e , 0x52 , 0x66 , 0x36 , 0x2b , 0x99 , 0xd5 , 0xe9 , 0x1c , 0x6c , 0xe2 ,
@@ -990,7 +993,7 @@ mod tests {
990
993
. unwrap( )
991
994
. to_vec( ) ,
992
995
result: Some ( BitcoinAddress :: Segwit ( SegwitBitcoinAddress :: P2TR (
993
- true ,
996
+ BitcoinNetworkType :: Mainnet ,
994
997
[
995
998
0x33 , 0x9c , 0xe7 , 0xe1 , 0x65 , 0xe6 , 0x7d , 0x93 , 0xad , 0xb3 , 0xfe , 0xf8 ,
996
999
0x8a , 0x6d , 0x4b , 0xee , 0xd3 , 0x3f , 0x01 , 0xfa , 0x87 , 0x6f , 0x05 , 0xa2 ,
0 commit comments