Skip to content

Commit

Permalink
Merge of #5837
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Dec 13, 2022
2 parents 29818a9 + fa8ec61 commit 2d96189
Show file tree
Hide file tree
Showing 20 changed files with 925 additions and 539 deletions.
6 changes: 3 additions & 3 deletions zebra-chain/src/block/hash.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use std::{fmt, io, sync::Arc};

use hex::{FromHex, ToHex};

#[cfg(any(test, feature = "proptest-impl"))]
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};

use crate::serialization::{
Expand All @@ -12,6 +9,9 @@ use crate::serialization::{

use super::Header;

#[cfg(any(test, feature = "proptest-impl"))]
use proptest_derive::Arbitrary;

/// A hash of a block, used to identify blocks and link blocks into a chain. ⛓️
///
/// Technically, this is the (SHA256d) hash of a block *header*, but since the
Expand Down
7 changes: 7 additions & 0 deletions zebra-chain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,10 @@ pub mod work;

#[cfg(any(test, feature = "proptest-impl"))]
pub use block::LedgerState;

/// Error type alias to make working with generic errors easier.
///
/// Note: the 'static lifetime bound means that the *type* cannot have any
/// non-'static lifetimes, (e.g., when a type contains a borrow and is
/// parameterized by 'a), *not* that the object itself has 'static lifetime.
pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
9 changes: 6 additions & 3 deletions zebra-chain/src/parameters/network_upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ pub(crate) const CONSENSUS_BRANCH_IDS: &[(NetworkUpgrade, ConsensusBranchId)] =
const PRE_BLOSSOM_POW_TARGET_SPACING: i64 = 150;

/// The target block spacing after Blossom activation.
pub const POST_BLOSSOM_POW_TARGET_SPACING: i64 = 75;
pub const POST_BLOSSOM_POW_TARGET_SPACING: u32 = 75;

/// The averaging window for difficulty threshold arithmetic mean calculations.
///
Expand Down Expand Up @@ -337,7 +337,7 @@ impl NetworkUpgrade {
pub fn target_spacing(&self) -> Duration {
let spacing_seconds = match self {
Genesis | BeforeOverwinter | Overwinter | Sapling => PRE_BLOSSOM_POW_TARGET_SPACING,
Blossom | Heartwood | Canopy | Nu5 => POST_BLOSSOM_POW_TARGET_SPACING,
Blossom | Heartwood | Canopy | Nu5 => POST_BLOSSOM_POW_TARGET_SPACING.into(),
};

Duration::seconds(spacing_seconds)
Expand All @@ -354,7 +354,10 @@ impl NetworkUpgrade {
pub fn target_spacings(network: Network) -> impl Iterator<Item = (block::Height, Duration)> {
[
(NetworkUpgrade::Genesis, PRE_BLOSSOM_POW_TARGET_SPACING),
(NetworkUpgrade::Blossom, POST_BLOSSOM_POW_TARGET_SPACING),
(
NetworkUpgrade::Blossom,
POST_BLOSSOM_POW_TARGET_SPACING.into(),
),
]
.into_iter()
.map(move |(upgrade, spacing_seconds)| {
Expand Down
9 changes: 3 additions & 6 deletions zebra-chain/src/serialization/date_time.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
//! DateTime types with specific serialization invariants.
use std::{
convert::{TryFrom, TryInto},
fmt,
num::TryFromIntError,
};
use std::{fmt, num::TryFromIntError};

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use chrono::{TimeZone, Utc};

use super::{SerializationError, ZcashDeserialize, ZcashSerialize};

/// A date and time, represented by a 32-bit number of seconds since the UNIX epoch.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct DateTime32 {
timestamp: u32,
}
Expand Down
197 changes: 152 additions & 45 deletions zebra-chain/src/work/difficulty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,18 @@
//! 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.
#![allow(clippy::unit_arg)]

use crate::{block, parameters::Network};
use std::{
cmp::{Ordering, PartialEq, PartialOrd},
fmt,
iter::Sum,
ops::Add,
ops::Div,
ops::Mul,
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"))]
Expand Down Expand Up @@ -60,19 +59,6 @@ mod tests;
#[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
pub struct CompactDifficulty(pub(crate) u32);

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()
}
}

/// An invalid CompactDifficulty value, for testing.
pub const INVALID_COMPACT_DIFFICULTY: CompactDifficulty = CompactDifficulty(u32::MAX);

Expand Down Expand Up @@ -101,28 +87,6 @@ pub const INVALID_COMPACT_DIFFICULTY: CompactDifficulty = CompactDifficulty(u32:
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub struct ExpandedDifficulty(U256);

impl fmt::Debug for ExpandedDifficulty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut buf = [0; 32];
// Use the same byte order as block::Hash
self.0.to_big_endian(&mut buf);
f.debug_tuple("ExpandedDifficulty")
.field(&hex::encode(buf))
.finish()
}
}

#[cfg(feature = "getblocktemplate-rpcs")]
impl fmt::Display for ExpandedDifficulty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut buf = [0; 32];
// Use the same byte order as block::Hash
self.0.to_big_endian(&mut buf);

f.write_str(&hex::encode(buf))
}
}

/// A 128-bit unsigned "Work" value.
///
/// Used to calculate the total work for each chain of blocks.
Expand Down Expand Up @@ -269,10 +233,81 @@ impl CompactDifficulty {
Work::try_from(expanded).ok()
}

#[cfg(feature = "getblocktemplate-rpcs")]
/// Returns the raw inner value.
pub fn to_value(&self) -> u32 {
self.0
/// 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)
}
}

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)
}
}

Expand Down Expand Up @@ -401,6 +436,78 @@ impl ExpandedDifficulty {
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] {
let mut reversed_bytes = [0; 32];
self.0.to_big_endian(&mut reversed_bytes);

reversed_bytes
}

/// 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 {
Expand Down
Loading

0 comments on commit 2d96189

Please sign in to comment.