Move block::Header to primitives
Introduce an extension trait and move the `block::Header` type to `primitives`. Nothing surprising here.
This commit is contained in:
parent
65925117a0
commit
ff64fa3c46
|
@ -20,110 +20,54 @@ use crate::consensus::{encode, Decodable, Encodable};
|
||||||
use crate::internal_macros::{impl_consensus_encoding, impl_hashencode};
|
use crate::internal_macros::{impl_consensus_encoding, impl_hashencode};
|
||||||
use crate::merkle_tree::{MerkleNode as _, TxMerkleNode, WitnessMerkleNode};
|
use crate::merkle_tree::{MerkleNode as _, TxMerkleNode, WitnessMerkleNode};
|
||||||
use crate::network::Params;
|
use crate::network::Params;
|
||||||
use crate::pow::{CompactTarget, Target, Work};
|
use crate::pow::{Target, Work};
|
||||||
use crate::prelude::Vec;
|
use crate::prelude::Vec;
|
||||||
use crate::script::{self, ScriptExt as _};
|
use crate::script::{self, ScriptExt as _};
|
||||||
use crate::transaction::{Transaction, Wtxid};
|
use crate::transaction::{Transaction, Wtxid};
|
||||||
|
|
||||||
#[rustfmt::skip] // Keep public re-exports separate.
|
#[rustfmt::skip] // Keep public re-exports separate.
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use primitives::block::{Version, BlockHash, WitnessCommitment};
|
pub use primitives::block::{Version, BlockHash, Header, WitnessCommitment};
|
||||||
|
|
||||||
impl_hashencode!(BlockHash);
|
impl_hashencode!(BlockHash);
|
||||||
|
|
||||||
/// Bitcoin block header.
|
|
||||||
///
|
|
||||||
/// Contains all the block's information except the actual transactions, but
|
|
||||||
/// including a root of a [Merkle tree] committing to all transactions in the block.
|
|
||||||
///
|
|
||||||
/// [Merkle tree]: https://en.wikipedia.org/wiki/Merkle_tree
|
|
||||||
///
|
|
||||||
/// ### Bitcoin Core References
|
|
||||||
///
|
|
||||||
/// * [CBlockHeader definition](https://github.com/bitcoin/bitcoin/blob/345457b542b6a980ccfbc868af0970a6f91d1b82/src/primitives/block.h#L20)
|
|
||||||
#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
pub struct Header {
|
|
||||||
/// Block version, now repurposed for soft fork signalling.
|
|
||||||
pub version: Version,
|
|
||||||
/// Reference to the previous block in the chain.
|
|
||||||
pub prev_blockhash: BlockHash,
|
|
||||||
/// The root hash of the Merkle tree of transactions in the block.
|
|
||||||
pub merkle_root: TxMerkleNode,
|
|
||||||
/// The timestamp of the block, as claimed by the miner.
|
|
||||||
pub time: u32,
|
|
||||||
/// The target value below which the blockhash must lie.
|
|
||||||
pub bits: CompactTarget,
|
|
||||||
/// The nonce, selected to obtain a low enough blockhash.
|
|
||||||
pub nonce: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_consensus_encoding!(Header, version, prev_blockhash, merkle_root, time, bits, nonce);
|
impl_consensus_encoding!(Header, version, prev_blockhash, merkle_root, time, bits, nonce);
|
||||||
|
|
||||||
impl Header {
|
crate::internal_macros::define_extension_trait! {
|
||||||
/// The number of bytes that the block header contributes to the size of a block.
|
/// Extension functionality for the [`Header`] type.
|
||||||
// Serialized length of fields (version, prev_blockhash, merkle_root, time, bits, nonce)
|
pub trait HeaderExt impl for Header {
|
||||||
pub const SIZE: usize = 4 + 32 + 32 + 4 + 4 + 4; // 80
|
/// Computes the target (range [0, T] inclusive) that a blockhash must land in to be valid.
|
||||||
|
fn target(&self) -> Target { self.bits.into() }
|
||||||
|
|
||||||
/// Returns the block hash.
|
/// Computes the popular "difficulty" measure for mining.
|
||||||
// This is the same as `Encodable` but done manually because `Encodable` isn't in `primitives`.
|
///
|
||||||
pub fn block_hash(&self) -> BlockHash {
|
/// Difficulty represents how difficult the current target makes it to find a block, relative to
|
||||||
let mut engine = sha256d::Hash::engine();
|
/// how difficult it would be at the highest possible target (highest target == lowest difficulty).
|
||||||
engine.input(&self.version.to_consensus().to_le_bytes());
|
fn difficulty(&self, params: impl AsRef<Params>) -> u128 {
|
||||||
engine.input(self.prev_blockhash.as_byte_array());
|
self.target().difficulty(params)
|
||||||
engine.input(self.merkle_root.as_byte_array());
|
|
||||||
engine.input(&self.time.to_le_bytes());
|
|
||||||
engine.input(&self.bits.to_consensus().to_le_bytes());
|
|
||||||
engine.input(&self.nonce.to_le_bytes());
|
|
||||||
|
|
||||||
BlockHash::from_byte_array(sha256d::Hash::from_engine(engine).to_byte_array())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes the target (range [0, T] inclusive) that a blockhash must land in to be valid.
|
|
||||||
pub fn target(&self) -> Target { self.bits.into() }
|
|
||||||
|
|
||||||
/// Computes the popular "difficulty" measure for mining.
|
|
||||||
///
|
|
||||||
/// Difficulty represents how difficult the current target makes it to find a block, relative to
|
|
||||||
/// how difficult it would be at the highest possible target (highest target == lowest difficulty).
|
|
||||||
pub fn difficulty(&self, params: impl AsRef<Params>) -> u128 {
|
|
||||||
self.target().difficulty(params)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes the popular "difficulty" measure for mining and returns a float value of f64.
|
|
||||||
pub fn difficulty_float(&self, params: impl AsRef<Params>) -> f64 {
|
|
||||||
self.target().difficulty_float(params)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks that the proof-of-work for the block is valid, returning the block hash.
|
|
||||||
pub fn validate_pow(&self, required_target: Target) -> Result<BlockHash, ValidationError> {
|
|
||||||
let target = self.target();
|
|
||||||
if target != required_target {
|
|
||||||
return Err(ValidationError::BadTarget);
|
|
||||||
}
|
}
|
||||||
let block_hash = self.block_hash();
|
|
||||||
if target.is_met_by(block_hash) {
|
/// Computes the popular "difficulty" measure for mining and returns a float value of f64.
|
||||||
Ok(block_hash)
|
fn difficulty_float(&self, params: impl AsRef<Params>) -> f64 {
|
||||||
} else {
|
self.target().difficulty_float(params)
|
||||||
Err(ValidationError::BadProofOfWork)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total work of the block.
|
/// Checks that the proof-of-work for the block is valid, returning the block hash.
|
||||||
pub fn work(&self) -> Work { self.target().to_work() }
|
fn validate_pow(&self, required_target: Target) -> Result<BlockHash, ValidationError> {
|
||||||
}
|
let target = self.target();
|
||||||
|
if target != required_target {
|
||||||
|
return Err(ValidationError::BadTarget);
|
||||||
|
}
|
||||||
|
let block_hash = self.block_hash();
|
||||||
|
if target.is_met_by(block_hash) {
|
||||||
|
Ok(block_hash)
|
||||||
|
} else {
|
||||||
|
Err(ValidationError::BadProofOfWork)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Header {
|
/// Returns the total work of the block.
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn work(&self) -> Work { self.target().to_work() }
|
||||||
f.debug_struct("Header")
|
|
||||||
.field("block_hash", &self.block_hash())
|
|
||||||
.field("version", &self.version)
|
|
||||||
.field("prev_blockhash", &self.prev_blockhash)
|
|
||||||
.field("merkle_root", &self.merkle_root)
|
|
||||||
.field("time", &self.time)
|
|
||||||
.field("bits", &self.bits)
|
|
||||||
.field("nonce", &self.nonce)
|
|
||||||
.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,14 +261,6 @@ impl Block {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Header> for BlockHash {
|
|
||||||
fn from(header: Header) -> BlockHash { header.block_hash() }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Header> for BlockHash {
|
|
||||||
fn from(header: &Header) -> BlockHash { header.block_hash() }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Block> for BlockHash {
|
impl From<Block> for BlockHash {
|
||||||
fn from(block: Block) -> BlockHash { block.block_hash() }
|
fn from(block: Block) -> BlockHash { block.block_hash() }
|
||||||
}
|
}
|
||||||
|
@ -409,20 +345,6 @@ impl std::error::Error for ValidationError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
|
||||||
impl<'a> Arbitrary<'a> for Header {
|
|
||||||
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
|
||||||
Ok(Header {
|
|
||||||
version: Version::arbitrary(u)?,
|
|
||||||
prev_blockhash: BlockHash::from_byte_array(u.arbitrary()?),
|
|
||||||
merkle_root: TxMerkleNode::from_byte_array(u.arbitrary()?),
|
|
||||||
time: u.arbitrary()?,
|
|
||||||
bits: CompactTarget::from_consensus(u.arbitrary()?),
|
|
||||||
nonce: u.arbitrary()?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
impl<'a> Arbitrary<'a> for Block {
|
impl<'a> Arbitrary<'a> for Block {
|
||||||
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||||
|
@ -437,7 +359,7 @@ mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::consensus::encode::{deserialize, serialize};
|
use crate::consensus::encode::{deserialize, serialize};
|
||||||
use crate::{Network, TestnetVersion};
|
use crate::{CompactTarget, Network, TestnetVersion};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_coinbase_and_bip34() {
|
fn test_coinbase_and_bip34() {
|
||||||
|
|
|
@ -254,7 +254,7 @@ impl Target {
|
||||||
/// Panics if `self` is zero (divide by zero).
|
/// Panics if `self` is zero (divide by zero).
|
||||||
///
|
///
|
||||||
/// [max]: Target::max
|
/// [max]: Target::max
|
||||||
/// [target]: crate::block::Header::target
|
/// [target]: crate::block::HeaderExt::target
|
||||||
#[cfg_attr(all(test, mutate), mutate)]
|
#[cfg_attr(all(test, mutate), mutate)]
|
||||||
pub fn difficulty(&self, params: impl AsRef<Params>) -> u128 {
|
pub fn difficulty(&self, params: impl AsRef<Params>) -> u128 {
|
||||||
// Panic here may be eaiser to debug than during the actual division.
|
// Panic here may be eaiser to debug than during the actual division.
|
||||||
|
|
|
@ -7,9 +7,83 @@
|
||||||
//! module describes structures and functions needed to describe
|
//! module describes structures and functions needed to describe
|
||||||
//! these blocks and the blockchain.
|
//! these blocks and the blockchain.
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
use arbitrary::{Arbitrary, Unstructured};
|
use arbitrary::{Arbitrary, Unstructured};
|
||||||
use hashes::sha256d;
|
use hashes::{sha256d, HashEngine as _};
|
||||||
|
|
||||||
|
use crate::merkle_tree::TxMerkleNode;
|
||||||
|
use crate::pow::CompactTarget;
|
||||||
|
|
||||||
|
/// Bitcoin block header.
|
||||||
|
///
|
||||||
|
/// Contains all the block's information except the actual transactions, but
|
||||||
|
/// including a root of a [Merkle tree] committing to all transactions in the block.
|
||||||
|
///
|
||||||
|
/// [Merkle tree]: https://en.wikipedia.org/wiki/Merkle_tree
|
||||||
|
///
|
||||||
|
/// ### Bitcoin Core References
|
||||||
|
///
|
||||||
|
/// * [CBlockHeader definition](https://github.com/bitcoin/bitcoin/blob/345457b542b6a980ccfbc868af0970a6f91d1b82/src/primitives/block.h#L20)
|
||||||
|
#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
pub struct Header {
|
||||||
|
/// Block version, now repurposed for soft fork signalling.
|
||||||
|
pub version: Version,
|
||||||
|
/// Reference to the previous block in the chain.
|
||||||
|
pub prev_blockhash: BlockHash,
|
||||||
|
/// The root hash of the Merkle tree of transactions in the block.
|
||||||
|
pub merkle_root: TxMerkleNode,
|
||||||
|
/// The timestamp of the block, as claimed by the miner.
|
||||||
|
pub time: u32,
|
||||||
|
/// The target value below which the blockhash must lie.
|
||||||
|
pub bits: CompactTarget,
|
||||||
|
/// The nonce, selected to obtain a low enough blockhash.
|
||||||
|
pub nonce: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Header {
|
||||||
|
/// The number of bytes that the block header contributes to the size of a block.
|
||||||
|
// Serialized length of fields (version, prev_blockhash, merkle_root, time, bits, nonce)
|
||||||
|
pub const SIZE: usize = 4 + 32 + 32 + 4 + 4 + 4; // 80
|
||||||
|
|
||||||
|
/// Returns the block hash.
|
||||||
|
// This is the same as `Encodable` but done manually because `Encodable` isn't in `primitives`.
|
||||||
|
pub fn block_hash(&self) -> BlockHash {
|
||||||
|
let mut engine = sha256d::Hash::engine();
|
||||||
|
engine.input(&self.version.to_consensus().to_le_bytes());
|
||||||
|
engine.input(self.prev_blockhash.as_byte_array());
|
||||||
|
engine.input(self.merkle_root.as_byte_array());
|
||||||
|
engine.input(&self.time.to_le_bytes());
|
||||||
|
engine.input(&self.bits.to_consensus().to_le_bytes());
|
||||||
|
engine.input(&self.nonce.to_le_bytes());
|
||||||
|
|
||||||
|
BlockHash::from_byte_array(sha256d::Hash::from_engine(engine).to_byte_array())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Header {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.debug_struct("Header")
|
||||||
|
.field("block_hash", &self.block_hash())
|
||||||
|
.field("version", &self.version)
|
||||||
|
.field("prev_blockhash", &self.prev_blockhash)
|
||||||
|
.field("merkle_root", &self.merkle_root)
|
||||||
|
.field("time", &self.time)
|
||||||
|
.field("bits", &self.bits)
|
||||||
|
.field("nonce", &self.nonce)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Header> for BlockHash {
|
||||||
|
fn from(header: Header) -> BlockHash { header.block_hash() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Header> for BlockHash {
|
||||||
|
fn from(header: &Header) -> BlockHash { header.block_hash() }
|
||||||
|
}
|
||||||
|
|
||||||
/// Bitcoin block version number.
|
/// Bitcoin block version number.
|
||||||
///
|
///
|
||||||
|
@ -93,6 +167,20 @@ impl BlockHash {
|
||||||
pub const GENESIS_PREVIOUS_BLOCK_HASH: Self = Self::from_byte_array([0; 32]);
|
pub const GENESIS_PREVIOUS_BLOCK_HASH: Self = Self::from_byte_array([0; 32]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary")]
|
||||||
|
impl<'a> Arbitrary<'a> for Header {
|
||||||
|
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||||
|
Ok(Header {
|
||||||
|
version: Version::arbitrary(u)?,
|
||||||
|
prev_blockhash: BlockHash::from_byte_array(u.arbitrary()?),
|
||||||
|
merkle_root: TxMerkleNode::from_byte_array(u.arbitrary()?),
|
||||||
|
time: u.arbitrary()?,
|
||||||
|
bits: CompactTarget::from_consensus(u.arbitrary()?),
|
||||||
|
nonce: u.arbitrary()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
impl<'a> Arbitrary<'a> for Version {
|
impl<'a> Arbitrary<'a> for Version {
|
||||||
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||||
|
|
Loading…
Reference in New Issue