Skip to content

Commit

Permalink
refactor: move all_zeroes & from_byte_array to inherents & make t…
Browse files Browse the repository at this point in the history
…hem const

Made these functions const fn & move them from the `Hash` trait to `hash_type` & `hash_newtype`
macros

fix rust-bitcoin#2377
  • Loading branch information
15IITian committed Mar 30, 2024
1 parent 4163641 commit 8a8be4e
Show file tree
Hide file tree
Showing 13 changed files with 66 additions and 59 deletions.
1 change: 0 additions & 1 deletion bitcoin/examples/sign-tx-segwit-v0.rs
Expand Up @@ -4,7 +4,6 @@

use std::str::FromStr;

use bitcoin::hashes::Hash;
use bitcoin::locktime::absolute;
use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing};
use bitcoin::sighash::{EcdsaSighashType, SighashCache};
Expand Down
4 changes: 2 additions & 2 deletions bitcoin/src/bip152.rs
Expand Up @@ -471,7 +471,7 @@ mod test {
{
// test serialization
let raw: Vec<u8> = serialize(&BlockTransactionsRequest {
block_hash: Hash::all_zeros(),
block_hash: BlockHash::all_zeros(),
indexes: testcase.1,
});
let mut expected_raw: Vec<u8> = [0u8; 32].to_vec();
Expand All @@ -494,7 +494,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: Hash::all_zeros(),
block_hash: BlockHash::all_zeros(),
indexes: vec![core::u64::MAX],
});
}
Expand Down
19 changes: 10 additions & 9 deletions bitcoin/src/blockdata/constants.rs
Expand Up @@ -20,7 +20,7 @@ use crate::blockdata::witness::Witness;
use crate::internal_macros::impl_bytes_newtype;
use crate::network::Network;
use crate::pow::CompactTarget;
use crate::Amount;
use crate::{Amount, BlockHash};

/// How many seconds between blocks we expect on average.
pub const TARGET_BLOCK_SPACING: u32 = 600;
Expand Down Expand Up @@ -92,7 +92,7 @@ pub fn genesis_block(network: Network) -> Block {
Network::Bitcoin => Block {
header: block::Header {
version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(),
prev_blockhash: BlockHash::all_zeros(),
merkle_root,
time: 1231006505,
bits: CompactTarget::from_consensus(0x1d00ffff),
Expand All @@ -103,7 +103,7 @@ pub fn genesis_block(network: Network) -> Block {
Network::Testnet => Block {
header: block::Header {
version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(),
prev_blockhash: BlockHash::all_zeros(),
merkle_root,
time: 1296688602,
bits: CompactTarget::from_consensus(0x1d00ffff),
Expand All @@ -114,7 +114,7 @@ pub fn genesis_block(network: Network) -> Block {
Network::Signet => Block {
header: block::Header {
version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(),
prev_blockhash: BlockHash::all_zeros(),
merkle_root,
time: 1598918400,
bits: CompactTarget::from_consensus(0x1e0377ae),
Expand All @@ -125,7 +125,7 @@ pub fn genesis_block(network: Network) -> Block {
Network::Regtest => Block {
header: block::Header {
version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(),
prev_blockhash: BlockHash::all_zeros(),
merkle_root,
time: 1296688602,
bits: CompactTarget::from_consensus(0x207fffff),
Expand Down Expand Up @@ -188,14 +188,15 @@ mod test {

use super::*;
use crate::consensus::encode::serialize;
use crate::Txid;

#[test]
fn bitcoin_genesis_first_transaction() {
let gen = bitcoin_genesis_tx();

assert_eq!(gen.version, transaction::Version::ONE);
assert_eq!(gen.input.len(), 1);
assert_eq!(gen.input[0].previous_output.txid, Hash::all_zeros());
assert_eq!(gen.input[0].previous_output.txid, Txid::all_zeros());
assert_eq!(gen.input[0].previous_output.vout, 0xFFFFFFFF);
assert_eq!(serialize(&gen.input[0].script_sig),
hex!("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73"));
Expand All @@ -218,7 +219,7 @@ mod test {
let gen = genesis_block(Network::Bitcoin);

assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(gen.header.prev_blockhash, BlockHash::all_zeros());
assert_eq!(
gen.header.merkle_root.to_string(),
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
Expand All @@ -237,7 +238,7 @@ mod test {
fn testnet_genesis_full_block() {
let gen = genesis_block(Network::Testnet);
assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(gen.header.prev_blockhash, BlockHash::all_zeros());
assert_eq!(
gen.header.merkle_root.to_string(),
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
Expand All @@ -255,7 +256,7 @@ mod test {
fn signet_genesis_full_block() {
let gen = genesis_block(Network::Signet);
assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(gen.header.prev_blockhash, BlockHash::all_zeros());
assert_eq!(
gen.header.merkle_root.to_string(),
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
Expand Down
2 changes: 1 addition & 1 deletion bitcoin/src/blockdata/transaction.rs
Expand Up @@ -84,7 +84,7 @@ impl OutPoint {
///
/// This value is used for coinbase transactions because they don't have any previous outputs.
#[inline]
pub fn null() -> OutPoint { OutPoint { txid: Hash::all_zeros(), vout: u32::MAX } }
pub fn null() -> OutPoint { OutPoint { txid: Txid::all_zeros(), vout: u32::MAX } }

/// Checks if an `OutPoint` is "null".
///
Expand Down
1 change: 0 additions & 1 deletion bitcoin/src/internal_macros.rs
Expand Up @@ -194,7 +194,6 @@ macro_rules! impl_hashencode {

impl $crate::consensus::Decodable for $hashtype {
fn consensus_decode<R: $crate::io::BufRead + ?Sized>(r: &mut R) -> core::result::Result<Self, $crate::consensus::encode::Error> {
use $crate::hashes::Hash;
Ok(Self::from_byte_array(<<$hashtype as $crate::hashes::Hash>::Bytes>::consensus_decode(r)?))
}
}
Expand Down
2 changes: 1 addition & 1 deletion bitcoin/src/merkle_tree/mod.rs
Expand Up @@ -127,7 +127,7 @@ mod tests {

let hashes_iter = block.txdata.iter().map(|obj| obj.compute_txid().to_raw_hash());

let mut hashes_array: [sha256d::Hash; 15] = [Hash::all_zeros(); 15];
let mut hashes_array: [sha256d::Hash; 15] = [sha256d::Hash::all_zeros(); 15];
for (i, hash) in hashes_iter.clone().enumerate() {
hashes_array[i] = hash;
}
Expand Down
6 changes: 3 additions & 3 deletions bitcoin/src/p2p/message_blockdata.rs
Expand Up @@ -145,11 +145,11 @@ impl_consensus_encoding!(GetHeadersMessage, version, locator_hashes, stop_hash);

#[cfg(test)]
mod tests {
use hashes::Hash;
use hex::test_hex_unwrap as hex;

use super::{GetBlocksMessage, GetHeadersMessage};
use crate::consensus::encode::{deserialize, serialize};
use crate::BlockHash;

#[test]
fn getblocks_message_test() {
Expand All @@ -162,7 +162,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, Hash::all_zeros());
assert_eq!(real_decode.stop_hash, BlockHash::all_zeros());

assert_eq!(serialize(&real_decode), from_sat);
}
Expand All @@ -178,7 +178,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, Hash::all_zeros());
assert_eq!(real_decode.stop_hash, BlockHash::all_zeros());

assert_eq!(serialize(&real_decode), from_sat);
}
Expand Down
7 changes: 0 additions & 7 deletions hashes/src/hmac.rs
Expand Up @@ -171,13 +171,6 @@ impl<T: Hash> Hash for Hmac<T> {
fn to_byte_array(self) -> Self::Bytes { self.0.to_byte_array() }

fn as_byte_array(&self) -> &Self::Bytes { self.0.as_byte_array() }

fn from_byte_array(bytes: T::Bytes) -> Self { Hmac(T::from_byte_array(bytes)) }

fn all_zeros() -> Self {
let zeros = T::all_zeros();
Hmac(zeros)
}
}

#[cfg(feature = "serde")]
Expand Down
24 changes: 14 additions & 10 deletions hashes/src/internal_macros.rs
Expand Up @@ -89,13 +89,13 @@ macro_rules! hash_trait_impls {
impl<$($gen: $gent),*> str::FromStr for Hash<$($gen),*> {
type Err = $crate::hex::HexToArrayError;
fn from_str(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Err> {
use $crate::{Hash, hex::{FromHex}};
use $crate::{ hex::{FromHex}};

let mut bytes = <[u8; $bits / 8]>::from_hex(s)?;
if $reverse {
bytes.reverse();
}
Ok(Self::from_byte_array(bytes))
Ok(Hash::from_byte_array(bytes))
}
}

Expand Down Expand Up @@ -150,14 +150,6 @@ macro_rules! hash_trait_impls {
fn as_byte_array(&self) -> &Self::Bytes {
&self.0
}

fn from_byte_array(bytes: Self::Bytes) -> Self {
Self::internal_new(bytes)
}

fn all_zeros() -> Self {
Hash::internal_new([0x00; $bits / 8])
}
}
}
}
Expand Down Expand Up @@ -188,6 +180,18 @@ macro_rules! hash_type {
fn internal_new(arr: [u8; $bits / 8]) -> Self { Hash(arr) }

fn internal_engine() -> HashEngine { Default::default() }

/// Constructs a hash from the underlying byte array.
pub const fn from_byte_array(bytes: <Self as crate::Hash>::Bytes) -> Self {
Hash(bytes)
}

/// Returns an all zero hash.
///
/// An all zeros hash is a made up construct because there is not a known input that can create
/// it. However,it is used in various places in Bitcoin e.g., the Bitcoin genesis block's
/// previous blockhash and the coinbase transaction's outpoint txid.
pub const fn all_zeros() -> Self { Hash([0x00; $bits / 8]) }
}

#[cfg(feature = "schemars")]
Expand Down
10 changes: 0 additions & 10 deletions hashes/src/lib.rs
Expand Up @@ -221,16 +221,6 @@ pub trait Hash:

/// Returns a reference to the underlying byte array.
fn as_byte_array(&self) -> &Self::Bytes;

/// Constructs a hash from the underlying byte array.
fn from_byte_array(bytes: Self::Bytes) -> Self;

/// Returns an all zero hash.
///
/// An all zeros hash is a made up construct because there is not a known input that can create
/// it, however it is used in various places in Bitcoin e.g., the Bitcoin genesis block's
/// previous blockhash and the coinbase transaction's outpoint txid.
fn all_zeros() -> Self;
}

/// Attempted to create a hash from an invalid length slice.
Expand Down
4 changes: 2 additions & 2 deletions hashes/src/sha256.rs
Expand Up @@ -102,9 +102,9 @@ impl crate::HashEngine for HashEngine {
impl Hash {
/// Iterate the sha256 algorithm to turn a sha256 hash into a sha256d hash
pub fn hash_again(&self) -> sha256d::Hash {
crate::Hash::from_byte_array(<Self as crate::Hash>::hash(&self.0).0)
let sha256_hash = Hash::from_byte_array(<Self as crate::Hash>::hash(&self.0).0);
sha256d::Hash::from_byte_array(sha256_hash.0)
}

/// Computes hash from `bytes` in `const` context.
///
/// Warning: this function is inefficient. It should be only used in `const` context.
Expand Down
12 changes: 12 additions & 0 deletions hashes/src/sha256t.rs
Expand Up @@ -41,6 +41,18 @@ impl<T: Tag> Hash<T> {
fn internal_new(arr: [u8; 32]) -> Self { Hash(arr, Default::default()) }

fn internal_engine() -> HashEngine { T::engine() }

/// Constructs a hash from the underlying byte array.
pub const fn from_byte_array(bytes: <Self as crate::Hash>::Bytes) -> Self {
Hash(bytes, PhantomData)
}

/// Returns an all zero hash.
///
/// An all zeros hash is a made up construct because there is not a known input that can create
/// it. However,it is used in various places in Bitcoin e.g., the Bitcoin genesis block's
/// previous blockhash and the coinbase transaction's outpoint txid.
pub const fn all_zeros() -> Self { Hash([0x00; 32], PhantomData) }
}

impl<T: Tag> Copy for Hash<T> {}
Expand Down
33 changes: 21 additions & 12 deletions hashes/src/util.rs
Expand Up @@ -210,8 +210,28 @@ macro_rules! hash_newtype {
pub fn as_raw_hash(&self) -> &$hash {
&self.0
}

#[allow(unused)]
/// Constructs a hash from the underlying byte array.
pub const fn from_byte_array(bytes: <Self as $crate::Hash>::Bytes) -> Self {
$newtype(<$hash>::from_byte_array(bytes))
}


#[allow(unused)]
/// Returns an all zero hash.
///
/// An all zeros hash is a made up construct because there is not a known input that can create
/// it. However,it is used in various places in Bitcoin e.g., the Bitcoin genesis block's
/// previous blockhash and the coinbase transaction's outpoint txid.
pub const fn all_zeros() -> Self {
let zeros = <$hash>::all_zeros();
$newtype(zeros)
}
}



impl $crate::_export::_core::convert::From<$hash> for $newtype {
fn from(inner: $hash) -> $newtype {
// Due to rust 1.22 we have to use this instead of simple `Self(inner)`
Expand Down Expand Up @@ -245,11 +265,6 @@ macro_rules! hash_newtype {
Ok($newtype(<$hash as $crate::Hash>::from_slice(sl)?))
}

#[inline]
fn from_byte_array(bytes: Self::Bytes) -> Self {
$newtype(<$hash as $crate::Hash>::from_byte_array(bytes))
}

#[inline]
fn to_byte_array(self) -> Self::Bytes {
self.0.to_byte_array()
Expand All @@ -259,18 +274,12 @@ macro_rules! hash_newtype {
fn as_byte_array(&self) -> &Self::Bytes {
self.0.as_byte_array()
}

#[inline]
fn all_zeros() -> Self {
let zeros = <$hash>::all_zeros();
$newtype(zeros)
}
}

impl $crate::_export::_core::str::FromStr for $newtype {
type Err = $crate::hex::HexToArrayError;
fn from_str(s: &str) -> $crate::_export::_core::result::Result<$newtype, Self::Err> {
use $crate::{Hash, hex::FromHex};
use $crate::hex::FromHex;

let mut bytes = <[u8; <Self as $crate::Hash>::LEN]>::from_hex(s)?;
if <Self as $crate::Hash>::DISPLAY_BACKWARD {
Expand Down

0 comments on commit 8a8be4e

Please sign in to comment.