use core::ops::ControlFlow;
use crate::{
number::{read_i32, read_u32},
Error, ParseResult, SResult, Visit, Visitor,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BlockHeader<'a> {
slice: &'a [u8],
version: i32,
time: u32,
bits: u32,
nonce: u32,
}
impl<'a> Visit<'a> for BlockHeader<'a> {
#[inline(always)]
fn visit<'b, V: Visitor>(slice: &'a [u8], visit: &'b mut V) -> SResult<'a, Self> {
if slice.len() < 80 {
return Err(Error::MoreBytesNeeded);
}
let version = read_i32(&slice[0..4]).expect("initial check 80");
let time = read_u32(&slice[68..72]).expect("initial check 80");
let bits = read_u32(&slice[72..76]).expect("initial check 80");
let nonce = read_u32(&slice[76..80]).expect("initial check 80");
let header = BlockHeader {
slice: &slice[..80],
version,
time,
bits,
nonce,
};
if let ControlFlow::Break(_) = visit.visit_block_header(&header) {
return Err(crate::Error::VisitBreak);
}
Ok(ParseResult::new(&slice[80..], header))
}
}
impl<'a> BlockHeader<'a> {
pub fn version(&self) -> i32 {
self.version
}
pub fn prev_blockhash(&self) -> &[u8] {
&self.slice[4..36]
}
pub fn merkle_root(&self) -> &[u8] {
&self.slice[36..68]
}
pub fn time(&self) -> u32 {
self.time
}
pub fn nonce(&self) -> u32 {
self.nonce
}
pub fn block_hash_preimage(&self) -> &[u8] {
self.slice
}
#[cfg(feature = "bitcoin_hashes")]
pub fn block_hash(&self) -> crate::bitcoin_hashes::sha256d::Hash {
use crate::bitcoin_hashes::{sha256d, Hash, HashEngine};
let mut engine = sha256d::Hash::engine();
engine.input(self.block_hash_preimage());
sha256d::Hash::from_engine(engine)
}
#[cfg(feature = "sha2")]
pub fn block_hash_sha2(
&self,
) -> crate::sha2::digest::generic_array::GenericArray<u8, crate::sha2::digest::typenum::U32>
{
use crate::sha2::{Digest, Sha256};
let first = Sha256::digest(self.block_hash_preimage());
Sha256::digest(&first[..])
}
}
impl<'a> AsRef<[u8]> for BlockHeader<'a> {
fn as_ref(&self) -> &[u8] {
self.slice
}
}
#[cfg(test)]
mod test {
use crate::{bsl::BlockHeader, test_common::GENESIS_BLOCK_HEADER, Parse};
use hex_lit::hex;
#[test]
fn parse_block() {
let block_header = BlockHeader::parse(&GENESIS_BLOCK_HEADER).unwrap();
assert_eq!(block_header.remaining(), &[][..]);
assert_eq!(
block_header.parsed(),
&BlockHeader {
slice: &GENESIS_BLOCK_HEADER,
version: 1,
time: 1231006505,
bits: 486604799,
nonce: 2083236893
}
);
assert_eq!(block_header.consumed(), 80);
assert_eq!(
block_header.parsed().prev_blockhash(),
hex!("0000000000000000000000000000000000000000000000000000000000000000")
);
assert_eq!(
block_header.parsed().merkle_root(),
hex!("3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a")
);
check_hash(
block_header.parsed(),
hex!("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"),
);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn size_of() {
assert_eq!(std::mem::size_of::<BlockHeader>(), 32);
}
#[cfg(all(not(feature = "sha2"), not(feature = "bitcoin_hashes")))]
fn check_hash(_block: &BlockHeader, _expected: [u8; 32]) {}
#[cfg(all(not(feature = "sha2"), feature = "bitcoin_hashes"))]
fn check_hash(block: &BlockHeader, expected: [u8; 32]) {
use crate::test_common::reverse;
assert_eq!(&block.block_hash()[..], &reverse(expected)[..]);
}
#[cfg(all(feature = "sha2", not(feature = "bitcoin_hashes")))]
fn check_hash(block: &BlockHeader, expected: [u8; 32]) {
use crate::test_common::reverse;
assert_eq!(&block.block_hash_sha2()[..], &reverse(expected)[..]);
}
#[cfg(all(feature = "sha2", feature = "bitcoin_hashes"))]
fn check_hash(block: &BlockHeader, expected: [u8; 32]) {
use crate::test_common::reverse;
assert_eq!(&block.block_hash()[..], &reverse(expected)[..]);
assert_eq!(&block.block_hash_sha2()[..], &reverse(expected)[..]);
}
}