Skip to main content

zebra_chain/work/
difficulty.rs

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