Merge rust-bitcoin/rust-bitcoin#1437: Add log2 to Work

df90c50242 Add log2 to Work (Jiri Jakes)

Pull request description:

  Adds method `Work::log2()` providing value equivalent to Bitcoin Core's `log2_work` in its logs. Fixes #1326.

  Questions:

  - The original issue (#1326) also suggests to add log2 to Target but it does not seem to be meaningful, does it? Bitcoin Core, to which the issue refers, also displays only log2 of work.
  - Although work should not be 0, the type allows it. In this case, log2 would return -inf. I think we could leave it like that but if there are suggestions to deal with it in a different way, please let me know.

ACKs for top commit:
  Kixunil:
    ACK df90c50242
  tcharding:
    ACK df90c50242
  apoelstra:
    ACK df90c50242

Tree-SHA512: 24e83c849ea3e16cad6f1636920883967cdac90b1b98ab19e86d1a5d0ac4585079740b54c1315afecabc1943d29a8b94316e3586bd2d10f1b61cc5cf7ad5b273
This commit is contained in:
Andrew Poelstra 2022-12-03 21:03:55 +00:00
commit 4fccd3fb84
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
1 changed files with 37 additions and 0 deletions

View File

@ -110,6 +110,20 @@ impl Work {
/// Converts this [`Work`] to [`Target`].
pub fn to_target(self) -> Target { Target(self.0.inverse()) }
/// Returns log2 of this work.
///
/// The result inherently suffers from a loss of precision and is, therefore, meant to be
/// used mainly for informative and displaying purposes, similarly to Bitcoin Core's
/// `log2_work` output in its logs.
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn log2(self) -> f64 {
let U256(high, low) = self.0;
// 2^128 * high + low
let double = (3402823669209385e23_f64 * high as f64) + (low as f64);
double.log2()
}
}
do_impl!(Work);
@ -1438,6 +1452,29 @@ mod tests {
assert_eq!(back, target)
}
#[cfg(feature = "std")]
#[test]
fn work_log2() {
// Compare work log2 to historical Bitcoin Core values found in Core logs.
let tests: Vec<(u128, f64)> = vec![
// (chainwork, core log2) // height
(0x200020002, 33.000022), // 1
(0xa97d67041c5e51596ee7, 79.405055), // 308004
(0x1dc45d79394baa8ab18b20, 84.895644), // 418141
(0x8c85acb73287e335d525b98, 91.134654), // 596624
(0x2ef447e01d1642c40a184ada, 93.553183), // 738965
];
for (chainwork, core_log2) in tests {
// Core log2 in the logs is rounded to 6 decimal places.
let log2 = (Work::from(chainwork).log2() * 1e6).round() / 1e6;
assert_eq!(log2, core_log2)
}
assert_eq!(Work(U256::ONE).log2(), 0.0);
assert_eq!(Work(U256::MAX).log2(), 256.0);
}
#[test]
fn u256_zero_min_max_inverse() {
assert_eq!(U256::MAX.inverse(), U256::ONE);