@@ -69,7 +69,7 @@ struct BlockValue {
6969 #[ cfg( not( feature = "liquid" ) ) ]
7070 bits : u32 ,
7171 #[ cfg( not( feature = "liquid" ) ) ]
72- difficulty : u64 ,
72+ difficulty : f64 ,
7373
7474 #[ cfg( feature = "liquid" ) ]
7575 #[ serde( skip_serializing_if = "Option::is_none" ) ]
@@ -78,7 +78,7 @@ struct BlockValue {
7878
7979impl BlockValue {
8080 #[ cfg_attr( feature = "liquid" , allow( unused_variables) ) ]
81- fn new ( blockhm : BlockHeaderMeta , network : Network ) -> Self {
81+ fn new ( blockhm : BlockHeaderMeta ) -> Self {
8282 let header = blockhm. header_entry . header ( ) ;
8383 BlockValue {
8484 id : header. block_hash ( ) . to_hex ( ) ,
@@ -106,14 +106,35 @@ impl BlockValue {
106106 #[ cfg( not( feature = "liquid" ) ) ]
107107 nonce : header. nonce ,
108108 #[ cfg( not( feature = "liquid" ) ) ]
109- difficulty : header . difficulty ( bitcoin :: Network :: from ( network ) ) ,
109+ difficulty : difficulty_new ( header ) ,
110110
111111 #[ cfg( feature = "liquid" ) ]
112112 ext : Some ( json ! ( header. ext) ) ,
113113 }
114114 }
115115}
116116
117+ /// Calculate the difficulty of a BlockHeader
118+ /// using Bitcoin Core code ported to Rust.
119+ ///
120+ /// https://github.com/bitcoin/bitcoin/blob/v25.0/src/rpc/blockchain.cpp#L75-L97
121+ #[ cfg_attr( feature = "liquid" , allow( dead_code) ) ]
122+ fn difficulty_new ( bh : & bitcoin:: BlockHeader ) -> f64 {
123+ let mut n_shift = bh. bits >> 24 & 0xff ;
124+ let mut d_diff = ( 0x0000ffff as f64 ) / ( ( bh. bits & 0x00ffffff ) as f64 ) ;
125+
126+ while n_shift < 29 {
127+ d_diff *= 256.0 ;
128+ n_shift += 1 ;
129+ }
130+ while n_shift > 29 {
131+ d_diff /= 256.0 ;
132+ n_shift -= 1 ;
133+ }
134+
135+ d_diff
136+ }
137+
117138#[ derive( Serialize , Deserialize ) ]
118139struct TransactionValue {
119140 txid : Txid ,
@@ -681,7 +702,7 @@ fn handle_request(
681702 . chain ( )
682703 . get_block_with_meta ( & hash)
683704 . ok_or_else ( || HttpError :: not_found ( "Block not found" . to_string ( ) ) ) ?;
684- let block_value = BlockValue :: new ( blockhm, config . network_type ) ;
705+ let block_value = BlockValue :: new ( blockhm) ;
685706 json_response ( block_value, TTL_LONG )
686707 }
687708 ( & Method :: GET , Some ( & "block" ) , Some ( hash) , Some ( & "status" ) , None , None ) => {
@@ -1325,7 +1346,7 @@ fn blocks(
13251346 current_hash = blockhm. header_entry . header ( ) . prev_blockhash ;
13261347
13271348 #[ allow( unused_mut) ]
1328- let mut value = BlockValue :: new ( blockhm, config . network_type ) ;
1349+ let mut value = BlockValue :: new ( blockhm) ;
13291350
13301351 #[ cfg( feature = "liquid" ) ]
13311352 {
@@ -1533,4 +1554,128 @@ mod tests {
15331554
15341555 assert ! ( err. is_err( ) ) ;
15351556 }
1557+
1558+ #[ test]
1559+ fn test_difficulty_new ( ) {
1560+ use super :: difficulty_new;
1561+
1562+ let vectors = [
1563+ (
1564+ // bits in header
1565+ 0x17053894 ,
1566+ // expected output (Rust)
1567+ 53911173001054.586 ,
1568+ // Block hash where found (for getblockheader)
1569+ "0000000000000000000050b050758dd2ccb0ba96ad5e95db84efd2f6c05e4e90" ,
1570+ // difficulty returned by Bitcoin Core v25
1571+ "53911173001054.59" ,
1572+ ) ,
1573+ (
1574+ 0x1a0c2a12 ,
1575+ 1379192.2882280778 ,
1576+ "0000000000000bc7636ffbc1cf90cf4a2674de7fcadbc6c9b63d31f07cb3c2c2" ,
1577+ "1379192.288228078" ,
1578+ ) ,
1579+ (
1580+ 0x19262222 ,
1581+ 112628548.66634709 ,
1582+ "000000000000000996b1f06771a81bcf7b15c5f859b6f8329016f01b0442ca72" ,
1583+ "112628548.6663471" ,
1584+ ) ,
1585+ (
1586+ 0x1d00c428 ,
1587+ 1.3050621315915245 ,
1588+ "0000000034014d731a3e1ad6078662ce19b08179dcc7ec0f5f717d4b58060736" ,
1589+ "1.305062131591525" ,
1590+ ) ,
1591+ (
1592+ 0 ,
1593+ f64:: INFINITY ,
1594+ "[No Blockhash]" ,
1595+ "[No Core difficulty, just checking edge cases]" ,
1596+ ) ,
1597+ (
1598+ 0x00000001 ,
1599+ 4.523059468369196e74 ,
1600+ "[No Blockhash]" ,
1601+ "[No Core difficulty, just checking edge cases]" ,
1602+ ) ,
1603+ (
1604+ 0x1d00ffff ,
1605+ 1.0 ,
1606+ "[No Blockhash]" ,
1607+ "[No Core difficulty, just checking MAX_TARGET]" ,
1608+ ) ,
1609+ (
1610+ 0x1c7fff80 ,
1611+ 2.0 ,
1612+ "[No Blockhash]" ,
1613+ "[No Core difficulty, just checking MAX_TARGET >> 1]" ,
1614+ ) ,
1615+ (
1616+ 0x1b00ffff ,
1617+ 65536.0 ,
1618+ "[No Blockhash]" ,
1619+ "[No Core difficulty, just checking MAX_TARGET >> 16]" ,
1620+ ) ,
1621+ (
1622+ 0x1a7fff80 ,
1623+ 131072.0 ,
1624+ "[No Blockhash]" ,
1625+ "[No Core difficulty, just checking MAX_TARGET >> 17]" ,
1626+ ) ,
1627+ (
1628+ 0x1d01fffe ,
1629+ 0.5 ,
1630+ "[No Blockhash]" ,
1631+ "[No Core difficulty, just checking MAX_TARGET << 1]" ,
1632+ ) ,
1633+ (
1634+ 0x1f000080 ,
1635+ 0.007812380790710449 ,
1636+ "[No Blockhash]" ,
1637+ "[No Core difficulty, just checking 2**255]" ,
1638+ ) ,
1639+ (
1640+ 0x1e00ffff ,
1641+ 0.00390625 , // 2.0**-8
1642+ "[No Blockhash]" ,
1643+ "[No Core difficulty, just checking MAX_TARGET << 8]" ,
1644+ ) ,
1645+ (
1646+ 0x1e00ff00 ,
1647+ 0.0039215087890625 ,
1648+ "[No Blockhash]" ,
1649+ "[No Core difficulty, just checking MAX_TARGET << 8 - two `f` chars]" ,
1650+ ) ,
1651+ (
1652+ 0x1f0000ff ,
1653+ 0.0039215087890625 ,
1654+ "[No Blockhash]" ,
1655+ "[No Core difficulty, just checking MAX_TARGET << 8]" ,
1656+ ) ,
1657+ ] ;
1658+
1659+ let to_bh = |b| bitcoin:: BlockHeader {
1660+ version : 1 ,
1661+ prev_blockhash : "0000000000000000000000000000000000000000000000000000000000000000"
1662+ . parse ( )
1663+ . unwrap ( ) ,
1664+ merkle_root : "0000000000000000000000000000000000000000000000000000000000000000"
1665+ . parse ( )
1666+ . unwrap ( ) ,
1667+ time : 0 ,
1668+ bits : b,
1669+ nonce : 0 ,
1670+ } ;
1671+
1672+ for ( bits, expected, hash, core_difficulty) in vectors {
1673+ let result = difficulty_new ( & to_bh ( bits) ) ;
1674+ assert_eq ! (
1675+ result, expected,
1676+ "Block {} difficulty is {} but Core difficulty is {}" ,
1677+ hash, result, core_difficulty,
1678+ ) ;
1679+ }
1680+ }
15361681}
0 commit comments