From b47b214b317553d4bf0debf85e1d081acb48569f Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 23 Oct 2024 14:13:57 +0800 Subject: [PATCH] feat add from_next_work_required to CompactTarget --- bitcoin/src/consensus/params.rs | 30 +++++++++++++++++++++++++++++ bitcoin/src/pow.rs | 34 +++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/bitcoin/src/consensus/params.rs b/bitcoin/src/consensus/params.rs index ee309349d1..e127824dce 100644 --- a/bitcoin/src/consensus/params.rs +++ b/bitcoin/src/consensus/params.rs @@ -48,6 +48,21 @@ pub struct Params { pub no_pow_retargeting: bool, } +/// The mainnet parameters. +/// +/// Use this for a static reference e.g., `¶ms::MAINNET`. +/// +/// For more on static vs const see The Rust Reference [using-statics-or-consts] section. +/// +/// [using-statics-or-consts]: +pub static MAINNET: Params = Params::MAINNET; +/// The testnet parameters. +pub static TESTNET: Params = Params::TESTNET; +/// The signet parameters. +pub static SIGNET: Params = Params::SIGNET; +/// The regtest parameters. +pub static REGTEST: Params = Params::REGTEST; + impl Params { /// The mainnet parameters (alias for `Params::MAINNET`). pub const BITCOIN: Params = Params::MAINNET; @@ -148,3 +163,18 @@ impl From for &'static Params { impl From<&Network> for &'static Params { fn from(value: &Network) -> Self { value.params() } } + +impl AsRef for Params { + fn as_ref(&self) -> &Params { self } +} + +impl AsRef for Network { + fn as_ref(&self) -> &Params { + match *self { + Network::Bitcoin => &MAINNET, + Network::Testnet => &TESTNET, + Network::Signet => &SIGNET, + Network::Regtest => ®TEST, + } + } +} diff --git a/bitcoin/src/pow.rs b/bitcoin/src/pow.rs index b65b597677..be93209c58 100644 --- a/bitcoin/src/pow.rs +++ b/bitcoin/src/pow.rs @@ -8,7 +8,7 @@ use core::fmt::{self, LowerHex, UpperHex}; use core::ops::{Add, Div, Mul, Not, Rem, Shl, Shr, Sub}; - +use std::cmp; use io::{BufRead, Write}; #[cfg(all(test, mutate))] use mutagen::mutate; @@ -16,7 +16,6 @@ use units::parse; use crate::blockdata::block::BlockHash; use crate::consensus::encode::{self, Decodable, Encodable}; -#[cfg(doc)] use crate::consensus::Params; use crate::error::{PrefixedHexError, UnprefixedHexError, ContainsPrefixError, MissingPrefixError}; use crate::Network; @@ -256,6 +255,11 @@ impl Target { /// The difficulty can only decrease or increase by a factor of 4 max on each difficulty /// adjustment period. pub fn max_difficulty_transition_threshold(&self) -> Self { Self(self.0 << 2) } + + pub fn max_transition_threshold(&self, params: impl AsRef) -> Self { + let max_attainable = params.as_ref().pow_limit; + cmp::min(self.max_difficulty_transition_threshold(), max_attainable) + } } do_impl!(Target); @@ -300,6 +304,32 @@ impl CompactTarget { /// Returns the consensus encoded `u32` representation of this [`CompactTarget`]. pub fn to_consensus(self) -> u32 { self.0 } + + pub fn from_next_work_required( + last: CompactTarget, + timespan: u64, + params: impl AsRef, + ) -> CompactTarget { + let params = params.as_ref(); + if params.no_pow_retargeting { + return last; + } + // Comments relate to the `pow.cpp` file from Core. + // ref: + let min_timespan = params.pow_target_timespan >> 2; // Lines 56/57 + let max_timespan = params.pow_target_timespan << 2; // Lines 58/59 + let actual_timespan = timespan.clamp(min_timespan, max_timespan); + let prev_target: Target = last.into(); + let maximum_retarget = prev_target.max_transition_threshold(params); // bnPowLimit + let retarget = prev_target.0; // bnNew + let retarget = retarget.mul(actual_timespan.into()); + let retarget = retarget.div(params.pow_target_timespan.into()); + let retarget = Target(retarget); + if retarget.ge(&maximum_retarget) { + return maximum_retarget.to_compact_lossy(); + } + retarget.to_compact_lossy() + } } impl From for Target {