What changed, and why it matters
This commit changes a single timing parameter in the Bitcoin network rules code from a 64-bit integer to a 32-bit integer. The value represents the expected seconds between blocks. The change simplifies the code by removing casts, but it slightly reduces the maximum value that parameter can hold. For all real Bitcoin networks this is harmless because the value is small (600 seconds for Bitcoin mainnet, 120 in the example). There is no direct security fix or vulnerability being patched.
No immediate action required. Reviewers may want to confirm that no downstream code or custom network parameters rely on `pow_target_spacing` being `u64` or holding values larger than `u32::MAX` (~4.29 billion seconds, or ~136 years, which is far beyond any realistic block spacing).
Security signals we found
Type narrowing from u64 to u32 in consensus-adjacent parameters
Removal of fallible conversion code (try_from/unwrap) for the spacing value
Change is described by the author as a simplification, not a security fix
Evidence from the diff
The commit changes Params::pow_target_spacing from u64 to u32. This removes several u32::try_from/as u32 casts in bitcoin/src/pow.rs and makes difficulty_adjustment_interval() return u32 directly. The value is only used as a divisor for pow_target_timespan (already u32) or in arithmetic with u32 block timestamps. The commit message explicitly states the precision loss is acceptable for simplicity. No overflow or correctness issue is introduced for realistic parameter values.
Changed components
bitcoin/src/network/params.rsbitcoin/src/pow.rsInspect captured patch +7 / −10
diff --git a/bitcoin/src/network/params.rs b/bitcoin/src/network/params.rs
index 03c911c9..b5f9af7c 100644
--- a/bitcoin/src/network/params.rs
+++ b/bitcoin/src/network/params.rs
@@ -14,7 +14,7 @@
//! use bitcoin::network::Params;
//! use bitcoin::{WitnessScript, WitnessScriptBuf, Network, Target};
//!
-//! const POW_TARGET_SPACING: u64 = 120; // Two minutes.
+//! const POW_TARGET_SPACING: u32 = 120; // Two minutes.
//!
//! pub struct CustomParams {
//! params: Params,
@@ -104,7 +104,7 @@ pub struct Params {
/// compact-expressible values between Bitcoin Core's and the limit expressed here.
pub max_attainable_target: Target,
/// Expected amount of time to mine one block.
- pub pow_target_spacing: u64,
+ pub pow_target_spacing: u32,
/// Difficulty recalculation interval.
pub pow_target_timespan: u32,
/// Determines whether minimal difficulty may be used for blocks or not.
@@ -260,8 +260,8 @@ impl Params {
}
/// Calculates the number of blocks between difficulty adjustments.
- pub fn difficulty_adjustment_interval(&self) -> u64 {
- u64::from(self.pow_target_timespan) / self.pow_target_spacing
+ pub fn difficulty_adjustment_interval(&self) -> u32 {
+ self.pow_target_timespan / self.pow_target_spacing
}
}
diff --git a/bitcoin/src/pow.rs b/bitcoin/src/pow.rs
index 0128fd49..89006be3 100644
--- a/bitcoin/src/pow.rs
+++ b/bitcoin/src/pow.rs
@@ -431,8 +431,7 @@ pub fn next_target_after<F, E>(
where
F: FnMut(BlockHeight) -> Result<Header, E>,
{
- // explicitly dropping the high bits because they make no sense since block height is only u32
- let adjustment_interval = params.difficulty_adjustment_interval() as u32;
+ let adjustment_interval = params.difficulty_adjustment_interval();
// if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
if !is_retarget_height(current_height.saturating_add(1.into()), adjustment_interval) {
@@ -444,11 +443,9 @@ where
// Special difficulty rule for testnet: If the new block's timestamp is more
// than 2*10 minutes then allow mining of a min-difficulty block.
let pow_limit = params.max_attainable_target.to_compact_lossy();
- let pow_target_spacing =
- u32::try_from(params.pow_target_spacing & u64::from(u32::MAX)).unwrap();
// if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2)
- if new_block_timestamp > current_header.time.to_u32() + pow_target_spacing * 2 {
+ if new_block_timestamp > current_header.time.to_u32() + params.pow_target_spacing * 2 {
Ok(pow_limit)
} else {
let mut header = current_header;
@@ -2605,7 +2602,7 @@ mod tests {
let want = CompactTarget::from_consensus(0x1d00_ffff);
// Current header is at a retarget boundary (height divisible by 2016) with pow_limit bits
- let adjustment_interval = u32::try_from(params.difficulty_adjustment_interval()).unwrap();
+ let adjustment_interval = params.difficulty_adjustment_interval();
let current_height = BlockHeight::from_u32(adjustment_interval * 5);
let current_header = Header {
Why this scored 19/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.