Check PoWLimit for difficulty threshold
This commit is contained in:
parent
00de709dd8
commit
c3a8fd3894
|
@ -11,7 +11,7 @@
|
|||
//! the actual work represented by the block header hash.
|
||||
#![allow(clippy::unit_arg)]
|
||||
|
||||
use crate::block;
|
||||
use crate::{block, parameters::Network};
|
||||
|
||||
use std::cmp::{Ordering, PartialEq, PartialOrd};
|
||||
use std::{fmt, ops::Add, ops::AddAssign};
|
||||
|
@ -257,6 +257,21 @@ impl ExpandedDifficulty {
|
|||
/// users of this module should avoid converting hashes into difficulties.
|
||||
fn from_hash(hash: &block::Hash) -> ExpandedDifficulty {
|
||||
U256::from_little_endian(&hash.0).into()
|
||||
}
|
||||
|
||||
/// Returns the easiest target difficulty allowed on `network`.
|
||||
///
|
||||
/// See `PoWLimit` in the Zcash specification.
|
||||
pub fn target_difficulty_limit(network: Network) -> ExpandedDifficulty {
|
||||
let limit: U256 = match network {
|
||||
/* 2^243 - 1 */
|
||||
Network::Mainnet => (U256::one() << 243) - 1,
|
||||
/* 2^251 - 1 */
|
||||
Network::Testnet => (U256::one() << 251) - 1,
|
||||
};
|
||||
|
||||
limit.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<U256> for ExpandedDifficulty {
|
||||
|
@ -277,6 +292,9 @@ impl PartialEq<block::Hash> for ExpandedDifficulty {
|
|||
impl PartialOrd<block::Hash> for ExpandedDifficulty {
|
||||
/// `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.
|
||||
fn partial_cmp(&self, other: &block::Hash) -> Option<Ordering> {
|
||||
self.partial_cmp(&ExpandedDifficulty::from_hash(other))
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ where
|
|||
|
||||
// Do the difficulty checks first, to raise the threshold for
|
||||
// attacks that use any other fields.
|
||||
check::difficulty_is_valid(&block.header, &height, &hash)?;
|
||||
check::difficulty_is_valid(&block.header, network, &height, &hash)?;
|
||||
check::equihash_solution_is_valid(&block.header)?;
|
||||
|
||||
// Since errors cause an early exit, try to do the
|
||||
|
|
|
@ -7,7 +7,7 @@ use zebra_chain::{
|
|||
block::Height,
|
||||
block::{Block, Header},
|
||||
parameters::{Network, NetworkUpgrade},
|
||||
work::equihash,
|
||||
work::{difficulty::ExpandedDifficulty, equihash},
|
||||
};
|
||||
|
||||
use crate::{error::*, parameters::SLOW_START_INTERVAL};
|
||||
|
@ -38,23 +38,38 @@ pub fn coinbase_is_first(block: &Block) -> Result<(), BlockError> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns `Ok(())` if `hash` passes the difficulty filter and PoW limit,
|
||||
/// Returns `Ok(())` if `hash` passes:
|
||||
/// - the target difficulty limit for `network` (PoWLimit), and
|
||||
/// - the difficulty filter,
|
||||
/// based on the fields in `header`.
|
||||
///
|
||||
/// If the block is invalid, returns an error containing `height` and `hash`.
|
||||
pub fn difficulty_is_valid(
|
||||
header: &Header,
|
||||
network: Network,
|
||||
height: &Height,
|
||||
hash: &Hash,
|
||||
) -> Result<(), BlockError> {
|
||||
// TODO:
|
||||
// - PoW limit
|
||||
|
||||
let difficulty_threshold = header
|
||||
.difficulty_threshold
|
||||
.to_expanded()
|
||||
.ok_or(BlockError::InvalidDifficulty(*height, *hash))?;
|
||||
|
||||
// Note: the comparisons in this function are u256 integer comparisons, like
|
||||
// zcashd and bitcoin. Greater values represent *less* work.
|
||||
|
||||
// The PowLimit check is part of `Threshold()` in the spec, but it doesn't
|
||||
// actually depend on any previous blocks.
|
||||
if difficulty_threshold > ExpandedDifficulty::target_difficulty_limit(network) {
|
||||
Err(BlockError::TargetDifficultyLimit(
|
||||
*height,
|
||||
*hash,
|
||||
difficulty_threshold,
|
||||
network,
|
||||
ExpandedDifficulty::target_difficulty_limit(network),
|
||||
))?;
|
||||
}
|
||||
|
||||
// Difficulty filter
|
||||
if hash > &difficulty_threshold {
|
||||
Err(BlockError::DifficultyFilter(
|
||||
|
|
|
@ -53,7 +53,16 @@ pub enum BlockError {
|
|||
#[error("invalid difficulty threshold in block header {0:?} {1:?}")]
|
||||
InvalidDifficulty(zebra_chain::block::Height, zebra_chain::block::Hash),
|
||||
|
||||
#[error("block {0:?} failed the difficulty filter: hash {1:?} must be less than or equal to the difficulty threshold {2:?}")]
|
||||
#[error("block {0:?} failed the difficulty limit: the difficulty threshold {2:?} must be at least as difficult as the {3:?} difficulty limit {4:?}, block hash {1:?}")]
|
||||
TargetDifficultyLimit(
|
||||
zebra_chain::block::Height,
|
||||
zebra_chain::block::Hash,
|
||||
zebra_chain::work::difficulty::ExpandedDifficulty,
|
||||
zebra_chain::parameters::Network,
|
||||
zebra_chain::work::difficulty::ExpandedDifficulty,
|
||||
),
|
||||
|
||||
#[error("block {0:?} failed the difficulty filter: hash {1:?} must be at least as difficult as the difficulty threshold {2:?}")]
|
||||
DifficultyFilter(
|
||||
zebra_chain::block::Height,
|
||||
zebra_chain::block::Hash,
|
||||
|
|
Loading…
Reference in New Issue