From 20d8dbd58652cd03133cb8cf60edc7e9c4ecbd4c Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 23 Sep 2024 13:42:42 +1000 Subject: [PATCH 1/3] Add missing line of whitespace As is customary put a line of whitespace before the `impl Blockhash` block. --- bitcoin/src/blockdata/block.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs index 6c6e73622..985d32894 100644 --- a/bitcoin/src/blockdata/block.rs +++ b/bitcoin/src/blockdata/block.rs @@ -30,6 +30,7 @@ hashes::hash_newtype! { pub struct WitnessCommitment(sha256d::Hash); } impl_hashencode!(BlockHash); + impl BlockHash { /// The "all zeros" blockhash. /// From 6b9429ac7b9587bb13d8e2250abc2102b475008c Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 23 Sep 2024 13:51:45 +1000 Subject: [PATCH 2/3] Remove BlockHash::all_zeros Recently we removed the `all_zeros` function from `OutPoint` in favour of a more meaningfully named associated const. We can do the same for `BlockHash`, the all zeros has is used for the previous blockhash of the genesis block, add a const named as such. In test code where we use the `all_zeros` function, just use the more explicit form `from_byte_array([0; 32])`. --- bitcoin/src/bip152.rs | 4 ++-- bitcoin/src/blockdata/block.rs | 7 ++----- bitcoin/src/blockdata/constants.rs | 14 +++++++------- bitcoin/src/p2p/message_blockdata.rs | 4 ++-- bitcoin/src/pow.rs | 6 +++--- 5 files changed, 16 insertions(+), 19 deletions(-) diff --git a/bitcoin/src/bip152.rs b/bitcoin/src/bip152.rs index cb6fb9ec3..105259246 100644 --- a/bitcoin/src/bip152.rs +++ b/bitcoin/src/bip152.rs @@ -497,7 +497,7 @@ mod test { { // test serialization let raw: Vec = serialize(&BlockTransactionsRequest { - block_hash: BlockHash::all_zeros(), + block_hash: BlockHash::from_byte_array([0; 32]), indexes: testcase.1, }); let mut expected_raw: Vec = [0u8; 32].to_vec(); @@ -520,7 +520,7 @@ mod test { #[should_panic] // 'attempt to add with overflow' in consensus_encode() fn test_getblocktx_panic_when_encoding_u64_max() { serialize(&BlockTransactionsRequest { - block_hash: BlockHash::all_zeros(), + block_hash: BlockHash::from_byte_array([0; 32]), indexes: vec![u64::MAX], }); } diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs index 985d32894..7a83b98dd 100644 --- a/bitcoin/src/blockdata/block.rs +++ b/bitcoin/src/blockdata/block.rs @@ -32,11 +32,8 @@ hashes::hash_newtype! { impl_hashencode!(BlockHash); impl BlockHash { - /// The "all zeros" blockhash. - /// - /// This is not the hash of a real block. It is used as the previous blockhash - /// of the genesis block and in other placeholder contexts. - pub fn all_zeros() -> Self { Self::from_byte_array([0; 32]) } + /// Dummy hash used as the previous blockhash of the genesis block. + pub const GENESIS_PREVIOUS_BLOCK_HASH: Self = Self::from_byte_array([0; 32]); } /// Bitcoin block header. diff --git a/bitcoin/src/blockdata/constants.rs b/bitcoin/src/blockdata/constants.rs index e1d49833c..e19694ce8 100644 --- a/bitcoin/src/blockdata/constants.rs +++ b/bitcoin/src/blockdata/constants.rs @@ -113,7 +113,7 @@ pub fn genesis_block(params: impl AsRef) -> Block { Network::Bitcoin => Block { header: block::Header { version: block::Version::ONE, - prev_blockhash: BlockHash::all_zeros(), + prev_blockhash: BlockHash::GENESIS_PREVIOUS_BLOCK_HASH, merkle_root, time: 1231006505, bits: CompactTarget::from_consensus(0x1d00ffff), @@ -124,7 +124,7 @@ pub fn genesis_block(params: impl AsRef) -> Block { Network::Testnet => Block { header: block::Header { version: block::Version::ONE, - prev_blockhash: BlockHash::all_zeros(), + prev_blockhash: BlockHash::GENESIS_PREVIOUS_BLOCK_HASH, merkle_root, time: 1296688602, bits: CompactTarget::from_consensus(0x1d00ffff), @@ -135,7 +135,7 @@ pub fn genesis_block(params: impl AsRef) -> Block { Network::Signet => Block { header: block::Header { version: block::Version::ONE, - prev_blockhash: BlockHash::all_zeros(), + prev_blockhash: BlockHash::GENESIS_PREVIOUS_BLOCK_HASH, merkle_root, time: 1598918400, bits: CompactTarget::from_consensus(0x1e0377ae), @@ -146,7 +146,7 @@ pub fn genesis_block(params: impl AsRef) -> Block { Network::Regtest => Block { header: block::Header { version: block::Version::ONE, - prev_blockhash: BlockHash::all_zeros(), + prev_blockhash: BlockHash::GENESIS_PREVIOUS_BLOCK_HASH, merkle_root, time: 1296688602, bits: CompactTarget::from_consensus(0x207fffff), @@ -261,7 +261,7 @@ mod test { let gen = genesis_block(¶ms::MAINNET); assert_eq!(gen.header.version, block::Version::ONE); - assert_eq!(gen.header.prev_blockhash, BlockHash::all_zeros()); + assert_eq!(gen.header.prev_blockhash, BlockHash::GENESIS_PREVIOUS_BLOCK_HASH); assert_eq!( gen.header.merkle_root.to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" @@ -280,7 +280,7 @@ mod test { fn testnet_genesis_full_block() { let gen = genesis_block(¶ms::TESTNET); assert_eq!(gen.header.version, block::Version::ONE); - assert_eq!(gen.header.prev_blockhash, BlockHash::all_zeros()); + assert_eq!(gen.header.prev_blockhash, BlockHash::GENESIS_PREVIOUS_BLOCK_HASH); assert_eq!( gen.header.merkle_root.to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" @@ -298,7 +298,7 @@ mod test { fn signet_genesis_full_block() { let gen = genesis_block(¶ms::SIGNET); assert_eq!(gen.header.version, block::Version::ONE); - assert_eq!(gen.header.prev_blockhash, BlockHash::all_zeros()); + assert_eq!(gen.header.prev_blockhash, BlockHash::GENESIS_PREVIOUS_BLOCK_HASH); assert_eq!( gen.header.merkle_root.to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" diff --git a/bitcoin/src/p2p/message_blockdata.rs b/bitcoin/src/p2p/message_blockdata.rs index 9c9d3b001..78c34f059 100644 --- a/bitcoin/src/p2p/message_blockdata.rs +++ b/bitcoin/src/p2p/message_blockdata.rs @@ -159,7 +159,7 @@ mod tests { assert_eq!(real_decode.version, 70002); assert_eq!(real_decode.locator_hashes.len(), 1); assert_eq!(serialize(&real_decode.locator_hashes[0]), genhash); - assert_eq!(real_decode.stop_hash, BlockHash::all_zeros()); + assert_eq!(real_decode.stop_hash, BlockHash::GENESIS_PREVIOUS_BLOCK_HASH); assert_eq!(serialize(&real_decode), from_sat); } @@ -175,7 +175,7 @@ mod tests { assert_eq!(real_decode.version, 70002); assert_eq!(real_decode.locator_hashes.len(), 1); assert_eq!(serialize(&real_decode.locator_hashes[0]), genhash); - assert_eq!(real_decode.stop_hash, BlockHash::all_zeros()); + assert_eq!(real_decode.stop_hash, BlockHash::GENESIS_PREVIOUS_BLOCK_HASH); assert_eq!(serialize(&real_decode), from_sat); } diff --git a/bitcoin/src/pow.rs b/bitcoin/src/pow.rs index 6d1afe18c..0e505b4bd 100644 --- a/bitcoin/src/pow.rs +++ b/bitcoin/src/pow.rs @@ -1771,7 +1771,7 @@ mod tests { // Block 2015, the only information used are `bits` and `time` let current = Header { version: Version::ONE, - prev_blockhash: BlockHash::all_zeros(), + prev_blockhash: BlockHash::from_byte_array([0; 32]), merkle_root: TxMerkleNode::from_byte_array([0; 32]), time: 1599332177, bits: epoch_start.bits, @@ -1793,7 +1793,7 @@ mod tests { // Block 2016, the only information used is `time` let epoch_start = Header { version: Version::ONE, - prev_blockhash: BlockHash::all_zeros(), + prev_blockhash: BlockHash::from_byte_array([0; 32]), merkle_root: TxMerkleNode::from_byte_array([0; 32]), time: 1599332844, bits: starting_bits, @@ -1803,7 +1803,7 @@ mod tests { // Block 4031, the only information used are `bits` and `time` let current = Header { version: Version::ONE, - prev_blockhash: BlockHash::all_zeros(), + prev_blockhash: BlockHash::from_byte_array([0; 32]), merkle_root: TxMerkleNode::from_byte_array([0; 32]), time: 1600591200, bits: starting_bits, From 2d8c613340184555c47f3d6fa89323fb8582cd30 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 23 Sep 2024 13:56:04 +1000 Subject: [PATCH 3/3] Move the block hash types to primitives Move the `BlockHash` and `WitnessCommitment` hash types over to `primitives`. --- bitcoin/src/blockdata/block.rs | 19 ++++++------------- primitives/src/block.rs | 22 ++++++++++++++++++++++ primitives/src/lib.rs | 2 ++ 3 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 primitives/src/block.rs diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs index 7a83b98dd..484b72293 100644 --- a/bitcoin/src/blockdata/block.rs +++ b/bitcoin/src/blockdata/block.rs @@ -23,18 +23,11 @@ use crate::script::{self, ScriptExt as _}; use crate::transaction::{Transaction, Wtxid}; use crate::VarInt; -hashes::hash_newtype! { - /// A bitcoin block hash. - pub struct BlockHash(sha256d::Hash); - /// A hash corresponding to the witness structure commitment in the coinbase transaction. - pub struct WitnessCommitment(sha256d::Hash); -} -impl_hashencode!(BlockHash); +#[rustfmt::skip] // Keep public re-exports separate. +#[doc(inline)] +pub use primitives::block::*; -impl BlockHash { - /// Dummy hash used as the previous blockhash of the genesis block. - pub const GENESIS_PREVIOUS_BLOCK_HASH: Self = Self::from_byte_array([0; 32]); -} +impl_hashencode!(BlockHash); /// Bitcoin block header. /// @@ -74,7 +67,7 @@ impl Header { pub fn block_hash(&self) -> BlockHash { let mut engine = sha256d::Hash::engine(); self.consensus_encode(&mut engine).expect("engines don't error"); - BlockHash(sha256d::Hash::from_engine(engine)) + 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. @@ -296,7 +289,7 @@ impl Block { let mut encoder = sha256d::Hash::engine(); witness_root.consensus_encode(&mut encoder).expect("engines don't error"); encoder.input(witness_reserved_value); - WitnessCommitment(sha256d::Hash::from_engine(encoder)) + WitnessCommitment::from_byte_array(sha256d::Hash::from_engine(encoder).to_byte_array()) } /// Computes the Merkle root of transactions hashed for witness. diff --git a/primitives/src/block.rs b/primitives/src/block.rs new file mode 100644 index 000000000..3ddf01034 --- /dev/null +++ b/primitives/src/block.rs @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Bitcoin blocks. +//! +//! A block is a bundle of transactions with a proof-of-work attached, +//! which commits to an earlier block to form the blockchain. This +//! module describes structures and functions needed to describe +//! these blocks and the blockchain. + +use hashes::sha256d; + +hashes::hash_newtype! { + /// A bitcoin block hash. + pub struct BlockHash(sha256d::Hash); + /// A hash corresponding to the witness structure commitment in the coinbase transaction. + pub struct WitnessCommitment(sha256d::Hash); +} + +impl BlockHash { + /// Dummy hash used as the previous blockhash of the genesis block. + pub const GENESIS_PREVIOUS_BLOCK_HASH: Self = Self::from_byte_array([0; 32]); +} diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 83149ba20..de1b10694 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -29,6 +29,7 @@ extern crate std; #[macro_use] extern crate serde; +pub mod block; #[cfg(feature = "alloc")] pub mod locktime; pub mod opcodes; @@ -44,6 +45,7 @@ pub use units::*; pub use self::locktime::{absolute, relative}; #[doc(inline)] pub use self::{ + block::{BlockHash, WitnessCommitment}, pow::CompactTarget, sequence::Sequence, transaction::{Txid, Wtxid},