@@ -15,8 +15,13 @@ use units::parse::{self, ParseIntError, PrefixedHexError, UnprefixedHexError};
15
15
16
16
use crate :: block:: { BlockHash , Header } ;
17
17
use crate :: consensus:: encode:: { self , Decodable , Encodable } ;
18
+ use crate :: internal_macros:: define_extension_trait;
18
19
use crate :: network:: Params ;
19
20
21
+ #[ rustfmt:: skip] // Keep public re-exports separate.
22
+ #[ doc( inline) ]
23
+ pub use primitives:: CompactTarget ;
24
+
20
25
/// Implement traits and methods shared by `Target` and `Work`.
21
26
macro_rules! do_impl {
22
27
( $ty: ident) => {
@@ -164,7 +169,7 @@ impl Target {
164
169
///
165
170
/// ref: <https://developer.bitcoin.org/reference/block_chain.html#target-nbits>
166
171
pub fn from_compact ( c : CompactTarget ) -> Target {
167
- let bits = c. 0 ;
172
+ let bits = c. to_consensus ( ) ;
168
173
// This is a floating-point "compact" encoding originally used by
169
174
// OpenSSL, which satoshi put into consensus code, so we're stuck
170
175
// with it. The exponent needs to have 3 subtracted from it, hence
@@ -204,7 +209,7 @@ impl Target {
204
209
size += 1 ;
205
210
}
206
211
207
- CompactTarget ( compact | ( size << 24 ) )
212
+ CompactTarget :: from_consensus ( compact | ( size << 24 ) )
208
213
}
209
214
210
215
/// Returns true if block hash is less than or equal to this [`Target`].
@@ -329,118 +334,97 @@ impl Target {
329
334
}
330
335
do_impl ! ( Target ) ;
331
336
332
- /// Encoding of 256-bit target as 32-bit float.
333
- ///
334
- /// This is used to encode a target into the block header. Satoshi made this part of consensus code
335
- /// in the original version of Bitcoin, likely copying an idea from OpenSSL.
336
- ///
337
- /// OpenSSL's bignum (BN) type has an encoding, which is even called "compact" as in bitcoin, which
338
- /// is exactly this format.
339
- ///
340
- /// # Note on order/equality
341
- ///
342
- /// Usage of the ordering and equality traits for this type may be surprising. Converting between
343
- /// `CompactTarget` and `Target` is lossy *in both directions* (there are multiple `CompactTarget`
344
- /// values that map to the same `Target` value). Ordering and equality for this type are defined in
345
- /// terms of the underlying `u32`.
346
- #[ derive( Copy , Clone , Debug , Default , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
347
- #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
348
- pub struct CompactTarget ( u32 ) ;
349
-
350
- impl CompactTarget {
351
- /// Creates a `CompactTarget` from a prefixed hex string.
352
- pub fn from_hex ( s : & str ) -> Result < Self , PrefixedHexError > {
353
- let target = parse:: hex_u32_prefixed ( s) ?;
354
- Ok ( Self :: from_consensus ( target) )
355
- }
337
+ define_extension_trait ! {
338
+ /// Extension functionality for the [`CompactTarget`] type.
339
+ pub trait CompactTargetExt impl for CompactTarget {
340
+ /// Creates a `CompactTarget` from a prefixed hex string.
341
+ fn from_hex( s: & str ) -> Result <CompactTarget , PrefixedHexError > {
342
+ let target = parse:: hex_u32_prefixed( s) ?;
343
+ Ok ( Self :: from_consensus( target) )
344
+ }
356
345
357
- /// Creates a `CompactTarget` from an unprefixed hex string.
358
- pub fn from_unprefixed_hex ( s : & str ) -> Result < Self , UnprefixedHexError > {
359
- let target = parse:: hex_u32_unprefixed ( s) ?;
360
- Ok ( Self :: from_consensus ( target) )
361
- }
346
+ /// Creates a `CompactTarget` from an unprefixed hex string.
347
+ fn from_unprefixed_hex( s: & str ) -> Result <CompactTarget , UnprefixedHexError > {
348
+ let target = parse:: hex_u32_unprefixed( s) ?;
349
+ Ok ( Self :: from_consensus( target) )
350
+ }
362
351
363
- /// Computes the [`CompactTarget`] from a difficulty adjustment.
364
- ///
365
- /// ref: <https://github.com/bitcoin/bitcoin/blob/0503cbea9aab47ec0a87d34611e5453158727169/src/pow.cpp>
366
- ///
367
- /// Given the previous Target, represented as a [`CompactTarget`], the difficulty is adjusted
368
- /// by taking the timespan between them, and multipling the current [`CompactTarget`] by a factor
369
- /// of the net timespan and expected timespan. The [`CompactTarget`] may not adjust by more than
370
- /// a factor of 4, or adjust beyond the maximum threshold for the network.
371
- ///
372
- /// # Note
373
- ///
374
- /// Under the consensus rules, the difference in the number of blocks between the headers does
375
- /// not equate to the `difficulty_adjustment_interval` of [`Params`]. This is due to an off-by-one
376
- /// error, and, the expected number of blocks in between headers is `difficulty_adjustment_interval - 1`
377
- /// when calculating the difficulty adjustment.
378
- ///
379
- /// Take the example of the first difficulty adjustment. Block 2016 introduces a new [`CompactTarget`],
380
- /// which takes the net timespan between Block 2015 and Block 0, and recomputes the difficulty.
381
- ///
382
- /// # Returns
383
- ///
384
- /// The expected [`CompactTarget`] recalculation.
385
- pub fn from_next_work_required (
386
- last : CompactTarget ,
387
- timespan : u64 ,
388
- params : impl AsRef < Params > ,
389
- ) -> CompactTarget {
390
- let params = params. as_ref ( ) ;
391
- if params. no_pow_retargeting {
392
- return last;
352
+ /// Computes the [`CompactTarget`] from a difficulty adjustment.
353
+ ///
354
+ /// ref: <https://github.com/bitcoin/bitcoin/blob/0503cbea9aab47ec0a87d34611e5453158727169/src/pow.cpp>
355
+ ///
356
+ /// Given the previous Target, represented as a [`CompactTarget`], the difficulty is adjusted
357
+ /// by taking the timespan between them, and multipling the current [`CompactTarget`] by a factor
358
+ /// of the net timespan and expected timespan. The [`CompactTarget`] may not adjust by more than
359
+ /// a factor of 4, or adjust beyond the maximum threshold for the network.
360
+ ///
361
+ /// # Note
362
+ ///
363
+ /// Under the consensus rules, the difference in the number of blocks between the headers does
364
+ /// not equate to the `difficulty_adjustment_interval` of [`Params`]. This is due to an off-by-one
365
+ /// error, and, the expected number of blocks in between headers is `difficulty_adjustment_interval - 1`
366
+ /// when calculating the difficulty adjustment.
367
+ ///
368
+ /// Take the example of the first difficulty adjustment. Block 2016 introduces a new [`CompactTarget`],
369
+ /// which takes the net timespan between Block 2015 and Block 0, and recomputes the difficulty.
370
+ ///
371
+ /// # Returns
372
+ ///
373
+ /// The expected [`CompactTarget`] recalculation.
374
+ fn from_next_work_required(
375
+ last: CompactTarget ,
376
+ timespan: u64 ,
377
+ params: impl AsRef <Params >,
378
+ ) -> CompactTarget {
379
+ let params = params. as_ref( ) ;
380
+ if params. no_pow_retargeting {
381
+ return last;
382
+ }
383
+ // Comments relate to the `pow.cpp` file from Core.
384
+ // ref: <https://github.com/bitcoin/bitcoin/blob/0503cbea9aab47ec0a87d34611e5453158727169/src/pow.cpp>
385
+ let min_timespan = params. pow_target_timespan >> 2 ; // Lines 56/57
386
+ let max_timespan = params. pow_target_timespan << 2 ; // Lines 58/59
387
+ let actual_timespan = timespan. clamp( min_timespan, max_timespan) ;
388
+ let prev_target: Target = last. into( ) ;
389
+ let maximum_retarget = prev_target. max_transition_threshold( params) ; // bnPowLimit
390
+ let retarget = prev_target. 0 ; // bnNew
391
+ let retarget = retarget. mul( actual_timespan. into( ) ) ;
392
+ let retarget = retarget. div( params. pow_target_timespan. into( ) ) ;
393
+ let retarget = Target ( retarget) ;
394
+ if retarget. ge( & maximum_retarget) {
395
+ return maximum_retarget. to_compact_lossy( ) ;
396
+ }
397
+ retarget. to_compact_lossy( )
393
398
}
394
- // Comments relate to the `pow.cpp` file from Core.
395
- // ref: <https://github.com/bitcoin/bitcoin/blob/0503cbea9aab47ec0a87d34611e5453158727169/src/pow.cpp>
396
- let min_timespan = params. pow_target_timespan >> 2 ; // Lines 56/57
397
- let max_timespan = params. pow_target_timespan << 2 ; // Lines 58/59
398
- let actual_timespan = timespan. clamp ( min_timespan, max_timespan) ;
399
- let prev_target: Target = last. into ( ) ;
400
- let maximum_retarget = prev_target. max_transition_threshold ( params) ; // bnPowLimit
401
- let retarget = prev_target. 0 ; // bnNew
402
- let retarget = retarget. mul ( actual_timespan. into ( ) ) ;
403
- let retarget = retarget. div ( params. pow_target_timespan . into ( ) ) ;
404
- let retarget = Target ( retarget) ;
405
- if retarget. ge ( & maximum_retarget) {
406
- return maximum_retarget. to_compact_lossy ( ) ;
399
+
400
+ /// Computes the [`CompactTarget`] from a difficulty adjustment,
401
+ /// assuming these are the relevant block headers.
402
+ ///
403
+ /// Given two headers, representing the start and end of a difficulty adjustment epoch,
404
+ /// compute the [`CompactTarget`] based on the net time between them and the current
405
+ /// [`CompactTarget`].
406
+ ///
407
+ /// # Note
408
+ ///
409
+ /// See [`CompactTarget::from_next_work_required`]
410
+ ///
411
+ /// For example, to successfully compute the first difficulty adjustment on the Bitcoin network,
412
+ /// one would pass the header for Block 2015 as `current` and the header for Block 0 as
413
+ /// `last_epoch_boundary`.
414
+ ///
415
+ /// # Returns
416
+ ///
417
+ /// The expected [`CompactTarget`] recalculation.
418
+ fn from_header_difficulty_adjustment(
419
+ last_epoch_boundary: Header ,
420
+ current: Header ,
421
+ params: impl AsRef <Params >,
422
+ ) -> CompactTarget {
423
+ let timespan = current. time - last_epoch_boundary. time;
424
+ let bits = current. bits;
425
+ CompactTarget :: from_next_work_required( bits, timespan. into( ) , params)
407
426
}
408
- retarget. to_compact_lossy ( )
409
427
}
410
-
411
- /// Computes the [`CompactTarget`] from a difficulty adjustment,
412
- /// assuming these are the relevant block headers.
413
- ///
414
- /// Given two headers, representing the start and end of a difficulty adjustment epoch,
415
- /// compute the [`CompactTarget`] based on the net time between them and the current
416
- /// [`CompactTarget`].
417
- ///
418
- /// # Note
419
- ///
420
- /// See [`CompactTarget::from_next_work_required`]
421
- ///
422
- /// For example, to successfully compute the first difficulty adjustment on the Bitcoin network,
423
- /// one would pass the header for Block 2015 as `current` and the header for Block 0 as
424
- /// `last_epoch_boundary`.
425
- ///
426
- /// # Returns
427
- ///
428
- /// The expected [`CompactTarget`] recalculation.
429
- pub fn from_header_difficulty_adjustment (
430
- last_epoch_boundary : Header ,
431
- current : Header ,
432
- params : impl AsRef < Params > ,
433
- ) -> CompactTarget {
434
- let timespan = current. time - last_epoch_boundary. time ;
435
- let bits = current. bits ;
436
- CompactTarget :: from_next_work_required ( bits, timespan. into ( ) , params)
437
- }
438
-
439
- /// Creates a [`CompactTarget`] from a consensus encoded `u32`.
440
- pub fn from_consensus ( bits : u32 ) -> Self { Self ( bits) }
441
-
442
- /// Returns the consensus encoded `u32` representation of this [`CompactTarget`].
443
- pub fn to_consensus ( self ) -> u32 { self . 0 }
444
428
}
445
429
446
430
impl From < CompactTarget > for Target {
@@ -450,27 +434,17 @@ impl From<CompactTarget> for Target {
450
434
impl Encodable for CompactTarget {
451
435
#[ inline]
452
436
fn consensus_encode < W : Write + ?Sized > ( & self , w : & mut W ) -> Result < usize , io:: Error > {
453
- self . 0 . consensus_encode ( w)
437
+ self . to_consensus ( ) . consensus_encode ( w)
454
438
}
455
439
}
456
440
457
441
impl Decodable for CompactTarget {
458
442
#[ inline]
459
443
fn consensus_decode < R : BufRead + ?Sized > ( r : & mut R ) -> Result < Self , encode:: Error > {
460
- u32:: consensus_decode ( r) . map ( CompactTarget )
444
+ u32:: consensus_decode ( r) . map ( CompactTarget :: from_consensus )
461
445
}
462
446
}
463
447
464
- impl fmt:: LowerHex for CompactTarget {
465
- #[ inline]
466
- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result { fmt:: LowerHex :: fmt ( & self . 0 , f) }
467
- }
468
-
469
- impl fmt:: UpperHex for CompactTarget {
470
- #[ inline]
471
- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result { fmt:: UpperHex :: fmt ( & self . 0 , f) }
472
- }
473
-
474
448
/// Big-endian 256 bit integer type.
475
449
// (high, low): u.0 contains the high bits, u.1 contains the low bits.
476
450
#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash , Default ) ]
@@ -1099,8 +1073,12 @@ impl kani::Arbitrary for U256 {
1099
1073
mod tests {
1100
1074
use super :: * ;
1101
1075
1102
- impl < T : Into < u128 > > From < T > for Target {
1103
- fn from ( x : T ) -> Self { Self ( U256 :: from ( x) ) }
1076
+ impl From < u64 > for Target {
1077
+ fn from ( x : u64 ) -> Self { Self ( U256 :: from ( x) ) }
1078
+ }
1079
+
1080
+ impl From < u32 > for Target {
1081
+ fn from ( x : u32 ) -> Self { Self ( U256 :: from ( x) ) }
1104
1082
}
1105
1083
1106
1084
impl < T : Into < u128 > > From < T > for Work {
@@ -1721,25 +1699,25 @@ mod tests {
1721
1699
#[ test]
1722
1700
fn compact_target_from_hex_lower ( ) {
1723
1701
let target = CompactTarget :: from_hex ( "0x010034ab" ) . unwrap ( ) ;
1724
- assert_eq ! ( target, CompactTarget ( 0x010034ab ) ) ;
1702
+ assert_eq ! ( target, CompactTarget :: from_consensus ( 0x010034ab ) ) ;
1725
1703
}
1726
1704
1727
1705
#[ test]
1728
1706
fn compact_target_from_hex_upper ( ) {
1729
1707
let target = CompactTarget :: from_hex ( "0X010034AB" ) . unwrap ( ) ;
1730
- assert_eq ! ( target, CompactTarget ( 0x010034ab ) ) ;
1708
+ assert_eq ! ( target, CompactTarget :: from_consensus ( 0x010034ab ) ) ;
1731
1709
}
1732
1710
1733
1711
#[ test]
1734
1712
fn compact_target_from_unprefixed_hex_lower ( ) {
1735
1713
let target = CompactTarget :: from_unprefixed_hex ( "010034ab" ) . unwrap ( ) ;
1736
- assert_eq ! ( target, CompactTarget ( 0x010034ab ) ) ;
1714
+ assert_eq ! ( target, CompactTarget :: from_consensus ( 0x010034ab ) ) ;
1737
1715
}
1738
1716
1739
1717
#[ test]
1740
1718
fn compact_target_from_unprefixed_hex_upper ( ) {
1741
1719
let target = CompactTarget :: from_unprefixed_hex ( "010034AB" ) . unwrap ( ) ;
1742
- assert_eq ! ( target, CompactTarget ( 0x010034ab ) ) ;
1720
+ assert_eq ! ( target, CompactTarget :: from_consensus ( 0x010034ab ) ) ;
1743
1721
}
1744
1722
1745
1723
#[ test]
@@ -1751,8 +1729,8 @@ mod tests {
1751
1729
1752
1730
#[ test]
1753
1731
fn compact_target_lower_hex_and_upper_hex ( ) {
1754
- assert_eq ! ( format!( "{:08x}" , CompactTarget ( 0x01D0F456 ) ) , "01d0f456" ) ;
1755
- assert_eq ! ( format!( "{:08X}" , CompactTarget ( 0x01d0f456 ) ) , "01D0F456" ) ;
1732
+ assert_eq ! ( format!( "{:08x}" , CompactTarget :: from_consensus ( 0x01D0F456 ) ) , "01d0f456" ) ;
1733
+ assert_eq ! ( format!( "{:08X}" , CompactTarget :: from_consensus ( 0x01d0f456 ) ) , "01D0F456" ) ;
1756
1734
}
1757
1735
1758
1736
#[ test]
0 commit comments