zebra_chain/work/difficulty.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
//! Block difficulty data structures and calculations
//!
//! The block difficulty "target threshold" is stored in the block header as a
//! 32-bit `CompactDifficulty`. The `block::Hash` must be less than or equal
//! to the `ExpandedDifficulty` threshold, when represented as a 256-bit integer
//! in little-endian order.
//!
//! The target threshold is also used to calculate the `Work` for each block.
//! The block work is used to find the chain with the greatest total work. Each
//! block's work value depends on the fixed threshold in the block header, not
//! the actual work represented by the block header hash.
use std::{
cmp::{Ordering, PartialEq, PartialOrd},
fmt,
iter::Sum,
ops::{Add, Div, Mul},
};
use hex::{FromHex, ToHex};
use crate::{block, parameters::Network, BoxError};
pub use crate::work::u256::U256;
#[cfg(any(test, feature = "proptest-impl"))]
mod arbitrary;
#[cfg(test)]
mod tests;
/// A 32-bit "compact bits" value, which represents the difficulty threshold for
/// a block header.
///
/// Used for:
/// - checking the `difficulty_threshold` value in the block header,
/// - calculating the 256-bit `ExpandedDifficulty` threshold, for comparison
/// with the block header hash, and
/// - calculating the block work.
///
/// # Consensus
///
/// This is a floating-point encoding, with a 24-bit signed mantissa,
/// an 8-bit exponent, an offset of 3, and a radix of 256.
/// (IEEE 754 32-bit floating-point values use a separate sign bit, an implicit
/// leading mantissa bit, an offset of 127, and a radix of 2.)
///
/// The precise bit pattern of a `CompactDifficulty` value is
/// consensus-critical, because it is used for the `difficulty_threshold` field,
/// which is:
/// - part of the `BlockHeader`, which is used to create the
/// `block::Hash`, and
/// - bitwise equal to the median `ExpandedDifficulty` value of recent blocks,
/// when encoded to `CompactDifficulty` using the specified conversion
/// function.
///
/// Without these consensus rules, some `ExpandedDifficulty` values would have
/// multiple equivalent `CompactDifficulty` values, due to redundancy in the
/// floating-point format.
///
/// > Deterministic conversions between a target threshold and a “compact" nBits value
/// > are not fully defined in the Bitcoin documentation, and so we define them here:
/// > (see equations in the Zcash Specification [section 7.7.4])
///
/// [section 7.7.4]: https://zips.z.cash/protocol/protocol.pdf#nbits
#[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Default))]
pub struct CompactDifficulty(pub(crate) u32);
/// An invalid CompactDifficulty value, for testing.
pub const INVALID_COMPACT_DIFFICULTY: CompactDifficulty = CompactDifficulty(u32::MAX);
/// A 256-bit unsigned "expanded difficulty" value.
///
/// Used as a target threshold for the difficulty of a `block::Hash`.
///
/// # Consensus
///
/// The precise bit pattern of an `ExpandedDifficulty` value is
/// consensus-critical, because it is compared with the `block::Hash`.
///
/// Note that each `CompactDifficulty` value can be converted from a
/// range of `ExpandedDifficulty` values, because the precision of
/// the floating-point format requires rounding on conversion.
///
/// Therefore, consensus-critical code must perform the specified
/// conversions to `CompactDifficulty`, even if the original
/// `ExpandedDifficulty` values are known.
///
/// Callers should avoid constructing `ExpandedDifficulty` zero
/// values, because they are rejected by the consensus rules,
/// and cause some conversion functions to panic.
///
/// > The difficulty filter is unchanged from Bitcoin, and is calculated using SHA-256d on the
/// > whole block header (including solutionSize and solution). The result is interpreted as a
/// > 256-bit integer represented in little-endian byte order, which MUST be less than or equal
/// > to the target threshold given by ToTarget(nBits).
///
/// Zcash Specification [section 7.7.2].
///
/// [section 7.7.2]: https://zips.z.cash/protocol/protocol.pdf#difficulty
//
// TODO: Use NonZeroU256, when available
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ExpandedDifficulty(U256);
/// A 128-bit unsigned "Work" value.
///
/// Used to calculate the total work for each chain of blocks.
///
/// # Consensus
///
/// The relative value of `Work` is consensus-critical, because it is used to
/// choose the best chain. But its precise value and bit pattern are not
/// consensus-critical.
///
/// We calculate work values according to the Zcash specification, but store
/// them as u128, rather than the implied u256. We don't expect the total chain
/// work to ever exceed 2^128. The current total chain work for Zcash is 2^58,
/// and Bitcoin adds around 2^91 work per year. (Each extra bit represents twice
/// as much work.)
///
/// > a node chooses the “best” block chain visible to it by finding the chain of valid blocks
/// > with the greatest total work. The work of a block with value nBits for the nBits field in
/// > its block header is defined as `floor(2^256 / (ToTarget(nBits) + 1))`.
///
/// Zcash Specification [section 7.7.5].
///
/// [section 7.7.5]: https://zips.z.cash/protocol/protocol.pdf#workdef
#[derive(Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd)]
pub struct Work(u128);
impl Work {
/// Returns a value representing no work.
pub fn zero() -> Self {
Self(0)
}
/// Return the inner `u128` value.
pub fn as_u128(self) -> u128 {
self.0
}
}
impl fmt::Debug for Work {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// There isn't a standard way to show different representations of the
// same value
f.debug_tuple("Work")
// Use hex, because expanded difficulty is in hex.
.field(&format_args!("{:#x}", self.0))
// Use decimal, to compare with zcashd
.field(&format_args!("{}", self.0))
// Use log2, to compare with zcashd
.field(&format_args!("{:.5}", (self.0 as f64).log2()))
.finish()
}
}
impl CompactDifficulty {
/// CompactDifficulty exponent base.
const BASE: u32 = 256;
/// CompactDifficulty exponent offset.
const OFFSET: i32 = 3;
/// CompactDifficulty floating-point precision.
const PRECISION: u32 = 24;
/// CompactDifficulty sign bit, part of the signed mantissa.
const SIGN_BIT: u32 = 1 << (CompactDifficulty::PRECISION - 1);
/// CompactDifficulty unsigned mantissa mask.
///
/// Also the maximum unsigned mantissa value.
const UNSIGNED_MANTISSA_MASK: u32 = CompactDifficulty::SIGN_BIT - 1;
/// Calculate the ExpandedDifficulty for a compact representation.
///
/// See `ToTarget()` in the Zcash Specification, and `CheckProofOfWork()` in
/// zcashd:
/// <https://zips.z.cash/protocol/protocol.pdf#nbits>
///
/// Returns None for negative, zero, and overflow values. (zcashd rejects
/// these values, before comparing the hash.)
#[allow(clippy::unwrap_in_result)]
pub fn to_expanded(self) -> Option<ExpandedDifficulty> {
// The constants for this floating-point representation.
// Alias the struct constants here, so the code is easier to read.
const BASE: u32 = CompactDifficulty::BASE;
const OFFSET: i32 = CompactDifficulty::OFFSET;
const PRECISION: u32 = CompactDifficulty::PRECISION;
const SIGN_BIT: u32 = CompactDifficulty::SIGN_BIT;
const UNSIGNED_MANTISSA_MASK: u32 = CompactDifficulty::UNSIGNED_MANTISSA_MASK;
// Negative values in this floating-point representation.
// 0 if (x & 2^23 == 2^23)
// zcashd rejects negative values without comparing the hash.
if self.0 & SIGN_BIT == SIGN_BIT {
return None;
}
// The components of the result
// The fractional part of the floating-point number
// x & (2^23 - 1)
let mantissa = self.0 & UNSIGNED_MANTISSA_MASK;
// The exponent for the multiplier in the floating-point number
// 256^(floor(x/(2^24)) - 3)
//
// The i32 conversion is safe, because we've just divided self by 2^24.
let exponent = i32::try_from(self.0 >> PRECISION).expect("fits in i32") - OFFSET;
// Normalise the mantissa and exponent before multiplying.
//
// zcashd rejects non-zero overflow values, but accepts overflows where
// all the overflowing bits are zero. It also allows underflows.
let (mantissa, exponent) = match (mantissa, exponent) {
// Overflow: check for non-zero overflow bits
//
// If m is non-zero, overflow. If m is zero, invalid.
(_, e) if (e >= 32) => return None,
// If m is larger than the remaining bytes, overflow.
// Otherwise, avoid overflows in base^exponent.
(m, e) if (e == 31 && m > u8::MAX.into()) => return None,
(m, e) if (e == 31 && m <= u8::MAX.into()) => (m << 16, e - 2),
(m, e) if (e == 30 && m > u16::MAX.into()) => return None,
(m, e) if (e == 30 && m <= u16::MAX.into()) => (m << 8, e - 1),
// Underflow: perform the right shift.
// The abs is safe, because we've just divided by 2^24, and offset
// is small.
(m, e) if (e < 0) => (m >> ((e.abs() * 8) as u32), 0),
(m, e) => (m, e),
};
// Now calculate the result: mantissa*base^exponent
// Earlier code should make sure all these values are in range.
let mantissa: U256 = mantissa.into();
let base: U256 = BASE.into();
let exponent: U256 = exponent.into();
let result = mantissa * base.pow(exponent);
if result == U256::zero() {
// zcashd rejects zero values, without comparing the hash
None
} else {
Some(result.into())
}
}
/// Calculate the Work for a compact representation.
///
/// See `Definition of Work` in the [Zcash Specification], and
/// `GetBlockProof()` in zcashd.
///
/// Returns None if the corresponding ExpandedDifficulty is None.
/// Also returns None on Work overflow, which should be impossible on a
/// valid chain.
///
/// [Zcash Specification]: https://zips.z.cash/protocol/protocol.pdf#workdef
pub fn to_work(self) -> Option<Work> {
let expanded = self.to_expanded()?;
Work::try_from(expanded).ok()
}
/// Return the difficulty bytes in big-endian byte-order.
///
/// Zebra displays difficulties in big-endian byte-order,
/// following the u256 convention set by Bitcoin and zcashd.
pub fn bytes_in_display_order(&self) -> [u8; 4] {
self.0.to_be_bytes()
}
/// Convert bytes in big-endian byte-order into a [`CompactDifficulty`].
///
/// Zebra displays difficulties in big-endian byte-order,
/// following the u256 convention set by Bitcoin and zcashd.
///
/// Returns an error if the difficulty value is invalid.
pub fn from_bytes_in_display_order(
bytes_in_display_order: &[u8; 4],
) -> Result<CompactDifficulty, BoxError> {
let internal_byte_order = u32::from_be_bytes(*bytes_in_display_order);
let difficulty = CompactDifficulty(internal_byte_order);
if difficulty.to_expanded().is_none() {
return Err("invalid difficulty value".into());
}
Ok(difficulty)
}
/// Returns a floating-point number representing a difficulty as a multiple
/// of the minimum difficulty for the provided network.
// Copied from <https://github.com/zcash/zcash/blob/99ad6fdc3a549ab510422820eea5e5ce9f60a5fd/src/rpc/blockchain.cpp#L34-L74>
// TODO: Explain here what this ported code is doing and why, request help to do so with the ECC team.
pub fn relative_to_network(&self, network: &Network) -> f64 {
let network_difficulty = network.target_difficulty_limit().to_compact();
let [mut n_shift, ..] = self.0.to_be_bytes();
let [n_shift_amount, ..] = network_difficulty.0.to_be_bytes();
let mut d_diff = f64::from(network_difficulty.0 << 8) / f64::from(self.0 << 8);
while n_shift < n_shift_amount {
d_diff *= 256.0;
n_shift += 1;
}
while n_shift > n_shift_amount {
d_diff /= 256.0;
n_shift -= 1;
}
d_diff
}
}
impl fmt::Debug for CompactDifficulty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// There isn't a standard way to show different representations of the
// same value
f.debug_tuple("CompactDifficulty")
// Use hex, because it's a float
.field(&format_args!("{:#010x}", self.0))
// Use expanded difficulty, for bitwise difficulty comparisons
.field(&format_args!("{:?}", self.to_expanded()))
.finish()
}
}
impl fmt::Display for CompactDifficulty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.encode_hex::<String>())
}
}
impl ToHex for &CompactDifficulty {
fn encode_hex<T: FromIterator<char>>(&self) -> T {
self.bytes_in_display_order().encode_hex()
}
fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
self.bytes_in_display_order().encode_hex_upper()
}
}
impl ToHex for CompactDifficulty {
fn encode_hex<T: FromIterator<char>>(&self) -> T {
(&self).encode_hex()
}
fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
(&self).encode_hex_upper()
}
}
impl FromHex for CompactDifficulty {
type Error = BoxError;
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
let bytes_in_display_order = <[u8; 4]>::from_hex(hex)?;
CompactDifficulty::from_bytes_in_display_order(&bytes_in_display_order)
}
}
impl TryFrom<ExpandedDifficulty> for Work {
type Error = ();
fn try_from(expanded: ExpandedDifficulty) -> Result<Self, Self::Error> {
// Consensus:
//
// <https://zips.z.cash/protocol/protocol.pdf#workdef>
//
// We need to compute `2^256 / (expanded + 1)`, but we can't represent
// 2^256, as it's too large for a u256. However, as 2^256 is at least as
// large as `expanded + 1`, it is equal to
// `((2^256 - expanded - 1) / (expanded + 1)) + 1`, or
let result = (!expanded.0 / (expanded.0 + 1)) + 1;
if result <= u128::MAX.into() {
Ok(Work(result.as_u128()))
} else {
Err(())
}
}
}
impl From<ExpandedDifficulty> for CompactDifficulty {
fn from(value: ExpandedDifficulty) -> Self {
value.to_compact()
}
}
impl ExpandedDifficulty {
/// Returns the difficulty of the hash.
///
/// Used to implement comparisons between difficulties and hashes.
///
/// Usage:
///
/// Compare the hash with the calculated difficulty value, using Rust's
/// standard comparison operators.
///
/// Hashes are not used to calculate the difficulties of future blocks, so
/// users of this module should avoid converting hashes into difficulties.
pub(super) fn from_hash(hash: &block::Hash) -> ExpandedDifficulty {
U256::from_little_endian(&hash.0).into()
}
/// Calculate the CompactDifficulty for an expanded difficulty.
///
/// # Consensus
///
/// See `ToCompact()` in the Zcash Specification, and `GetCompact()`
/// in zcashd:
/// <https://zips.z.cash/protocol/protocol.pdf#nbits>
///
/// # Panics
///
/// If `self` is zero.
///
/// `ExpandedDifficulty` values are generated in two ways:
/// * conversion from `CompactDifficulty` values, which rejects zeroes, and
/// * difficulty adjustment calculations, which impose a non-zero minimum
/// `target_difficulty_limit`.
///
/// Neither of these methods yield zero values.
pub fn to_compact(self) -> CompactDifficulty {
// The zcashd implementation supports negative and zero compact values.
// These values are rejected by the protocol rules. Zebra is designed so
// that invalid states are not representable. Therefore, this function
// does not produce negative compact values, and panics on zero compact
// values. (The negative compact value code in zcashd is unused.)
assert!(self.0 > 0.into(), "Zero difficulty values are invalid");
// The constants for this floating-point representation.
// Alias the constants here, so the code is easier to read.
const UNSIGNED_MANTISSA_MASK: u32 = CompactDifficulty::UNSIGNED_MANTISSA_MASK;
const OFFSET: i32 = CompactDifficulty::OFFSET;
// Calculate the final size, accounting for the sign bit.
// This is the size *after* applying the sign bit adjustment in `ToCompact()`.
let size = self.0.bits() / 8 + 1;
// Make sure the mantissa is non-negative, by shifting down values that
// would otherwise overflow into the sign bit
let mantissa = if self.0 <= UNSIGNED_MANTISSA_MASK.into() {
// Value is small, shift up if needed
self.0 << (8 * (3 - size))
} else {
// Value is large, shift down
self.0 >> (8 * (size - 3))
};
// This assertion also makes sure that size fits in its 8 bit compact field
assert!(
size < (31 + OFFSET) as _,
"256^size (256^{size}) must fit in a u256, after the sign bit adjustment and offset"
);
let size = u32::try_from(size).expect("a 0-6 bit value fits in a u32");
assert!(
mantissa <= UNSIGNED_MANTISSA_MASK.into(),
"mantissa {mantissa:x?} must fit in its compact field"
);
let mantissa = u32::try_from(mantissa).expect("a 0-23 bit value fits in a u32");
if mantissa > 0 {
CompactDifficulty(mantissa + (size << 24))
} else {
// This check catches invalid mantissas. Overflows and underflows
// should also be unreachable, but they aren't caught here.
unreachable!("converted CompactDifficulty values must be valid")
}
}
/// Return the difficulty bytes in big-endian byte-order,
/// suitable for printing out byte by byte.
///
/// Zebra displays difficulties in big-endian byte-order,
/// following the u256 convention set by Bitcoin and zcashd.
pub fn bytes_in_display_order(&self) -> [u8; 32] {
self.0.to_big_endian()
}
/// Convert bytes in big-endian byte-order into an [`ExpandedDifficulty`].
///
/// Zebra displays difficulties in big-endian byte-order,
/// following the u256 convention set by Bitcoin and zcashd.
///
/// Preserves the exact difficulty value represented by the bytes,
/// even if it can't be generated from a [`CompactDifficulty`].
/// This means a round-trip conversion to [`CompactDifficulty`] can be lossy.
pub fn from_bytes_in_display_order(bytes_in_display_order: &[u8; 32]) -> ExpandedDifficulty {
let internal_byte_order = U256::from_big_endian(bytes_in_display_order);
ExpandedDifficulty(internal_byte_order)
}
}
impl fmt::Display for ExpandedDifficulty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.encode_hex::<String>())
}
}
impl fmt::Debug for ExpandedDifficulty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("ExpandedDifficulty")
.field(&self.encode_hex::<String>())
.finish()
}
}
impl ToHex for &ExpandedDifficulty {
fn encode_hex<T: FromIterator<char>>(&self) -> T {
self.bytes_in_display_order().encode_hex()
}
fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
self.bytes_in_display_order().encode_hex_upper()
}
}
impl ToHex for ExpandedDifficulty {
fn encode_hex<T: FromIterator<char>>(&self) -> T {
(&self).encode_hex()
}
fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
(&self).encode_hex_upper()
}
}
impl FromHex for ExpandedDifficulty {
type Error = <[u8; 32] as FromHex>::Error;
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
let bytes_in_display_order = <[u8; 32]>::from_hex(hex)?;
Ok(ExpandedDifficulty::from_bytes_in_display_order(
&bytes_in_display_order,
))
}
}
impl From<U256> for ExpandedDifficulty {
fn from(value: U256) -> Self {
ExpandedDifficulty(value)
}
}
impl From<ExpandedDifficulty> for U256 {
fn from(value: ExpandedDifficulty) -> Self {
value.0
}
}
impl Sum<ExpandedDifficulty> for ExpandedDifficulty {
fn sum<I: Iterator<Item = ExpandedDifficulty>>(iter: I) -> Self {
iter.map(|d| d.0).fold(U256::zero(), Add::add).into()
}
}
impl<T> Div<T> for ExpandedDifficulty
where
T: Into<U256>,
{
type Output = ExpandedDifficulty;
fn div(self, rhs: T) -> Self::Output {
ExpandedDifficulty(self.0 / rhs)
}
}
impl<T> Mul<T> for ExpandedDifficulty
where
U256: Mul<T>,
<U256 as Mul<T>>::Output: Into<U256>,
{
type Output = ExpandedDifficulty;
fn mul(self, rhs: T) -> ExpandedDifficulty {
ExpandedDifficulty((self.0 * rhs).into())
}
}
impl PartialEq<block::Hash> for ExpandedDifficulty {
/// Is `self` equal to `other`?
///
/// See `partial_cmp` for details.
fn eq(&self, other: &block::Hash) -> bool {
self.partial_cmp(other) == Some(Ordering::Equal)
}
}
impl PartialOrd<block::Hash> for ExpandedDifficulty {
/// # Consensus
///
/// `block::Hash`es are compared with `ExpandedDifficulty` thresholds by
/// converting the hash to a 256-bit integer in little-endian order.
///
/// Greater values represent *less* work. This matches the convention in
/// zcashd and bitcoin.
///
/// <https://zips.z.cash/protocol/protocol.pdf#workdef>
fn partial_cmp(&self, other: &block::Hash) -> Option<Ordering> {
self.partial_cmp(&ExpandedDifficulty::from_hash(other))
}
}
impl PartialEq<ExpandedDifficulty> for block::Hash {
/// Is `self` equal to `other`?
///
/// See `<ExpandedDifficulty as PartialOrd<block::Hash>::partial_cmp`
/// for details.
fn eq(&self, other: &ExpandedDifficulty) -> bool {
other.eq(self)
}
}
impl PartialOrd<ExpandedDifficulty> for block::Hash {
/// How does `self` compare to `other`?
///
/// # Consensus
///
/// See `<ExpandedDifficulty as PartialOrd<block::Hash>::partial_cmp`
/// for details.
#[allow(clippy::unwrap_in_result)]
fn partial_cmp(&self, other: &ExpandedDifficulty) -> Option<Ordering> {
Some(
// Use the canonical implementation, but reverse the order
other
.partial_cmp(self)
.expect("difficulties and hashes have a total order")
.reverse(),
)
}
}
impl std::ops::Add for Work {
type Output = PartialCumulativeWork;
fn add(self, rhs: Work) -> PartialCumulativeWork {
PartialCumulativeWork::from(self) + rhs
}
}
/// Partial work used to track relative work in non-finalized chains
///
/// # Consensus
///
/// Use to choose the best chain with the most work.
///
/// Since it is only relative values that matter, Zebra uses the partial work from a shared
/// fork root block to find the best chain.
///
/// See [`Work`] for details.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct PartialCumulativeWork(u128);
impl PartialCumulativeWork {
/// Returns a value representing no work.
pub fn zero() -> Self {
Self(0)
}
/// Return the inner `u128` value.
pub fn as_u128(self) -> u128 {
self.0
}
/// Returns a floating-point work multiplier that can be used for display.
/// The returned value is the work as a multiple of the target difficulty limit for `network`.
pub fn difficulty_multiplier_for_display(&self, network: Network) -> f64 {
// This calculation is similar to the `getdifficulty` RPC, see that code for details.
let pow_limit = network
.target_difficulty_limit()
.to_compact()
.to_work()
.expect("target difficult limit is valid work");
// Convert to u128 then f64.
let pow_limit = pow_limit.as_u128() as f64;
let work = self.as_u128() as f64;
work / pow_limit
}
/// Returns floating-point work bits that can be used for display.
/// The returned value is the number of hash bits represented by the work.
pub fn difficulty_bits_for_display(&self) -> f64 {
// This calculation is similar to `zcashd`'s bits display in its logs.
// Convert to u128 then f64.
let work = self.as_u128() as f64;
work.log2()
}
}
/// Network methods related to Difficulty
pub trait ParameterDifficulty {
/// Returns the easiest target difficulty allowed on `network`.
///
/// # Consensus
///
/// See `PoWLimit` in the Zcash specification:
/// <https://zips.z.cash/protocol/protocol.pdf#constants>
fn target_difficulty_limit(&self) -> ExpandedDifficulty;
}
impl ParameterDifficulty for Network {
/// Returns the easiest target difficulty allowed on `network`.
/// See [`ParameterDifficulty::target_difficulty_limit`]
fn target_difficulty_limit(&self) -> ExpandedDifficulty {
let limit: U256 = match self {
// Mainnet PoWLimit is defined as `2^243 - 1` on page 73 of the protocol specification:
// <https://zips.z.cash/protocol/protocol.pdf>
Network::Mainnet => (U256::one() << 243) - 1,
// 2^251 - 1 for the default testnet, see `testnet::ParametersBuilder::default`()
Network::Testnet(params) => return params.target_difficulty_limit(),
};
// `zcashd` converts the PoWLimit into a compact representation before
// using it to perform difficulty filter checks.
//
// The Zcash specification converts to compact for the default difficulty
// filter, but not for testnet minimum difficulty blocks. (ZIP 205 and
// ZIP 208 don't specify this conversion either.) See #1277 for details.
ExpandedDifficulty(limit)
.to_compact()
.to_expanded()
.expect("difficulty limits are valid expanded values")
}
}
impl From<Work> for PartialCumulativeWork {
fn from(work: Work) -> Self {
PartialCumulativeWork(work.0)
}
}
impl std::ops::Add<Work> for PartialCumulativeWork {
type Output = PartialCumulativeWork;
fn add(self, rhs: Work) -> Self::Output {
let result = self
.0
.checked_add(rhs.0)
.expect("Work values do not overflow");
PartialCumulativeWork(result)
}
}
impl std::ops::AddAssign<Work> for PartialCumulativeWork {
fn add_assign(&mut self, rhs: Work) {
*self = *self + rhs;
}
}
impl std::ops::Sub<Work> for PartialCumulativeWork {
type Output = PartialCumulativeWork;
fn sub(self, rhs: Work) -> Self::Output {
let result = self.0
.checked_sub(rhs.0)
.expect("PartialCumulativeWork values do not underflow: all subtracted Work values must have been previously added to the PartialCumulativeWork");
PartialCumulativeWork(result)
}
}
impl std::ops::SubAssign<Work> for PartialCumulativeWork {
fn sub_assign(&mut self, rhs: Work) {
*self = *self - rhs;
}
}