use crate::error::Result;
use crate::types::{BlockHeader, TimeContext};
use blvm_spec_lock::spec_locked;
#[allow(clippy::overly_complex_bool_expr, clippy::redundant_comparisons)] #[spec_locked("5.3.1", "ValidBlockHeader")]
#[inline]
pub(crate) fn validate_block_header(
header: &BlockHeader,
time_context: Option<&TimeContext>,
) -> Result<bool> {
if header.version < 1 {
return Ok(false);
}
if header.timestamp == 0 {
return Ok(false);
}
if let Some(ctx) = time_context {
let max_ts = ctx
.network_time
.saturating_add(crate::constants::MAX_FUTURE_BLOCK_TIME);
if header.timestamp > max_ts {
return Ok(false);
}
if header.timestamp < ctx.median_time_past {
return Ok(false);
}
}
if header.bits == 0 {
return Ok(false);
}
if header.merkle_root == [0u8; 32] {
return Ok(false);
}
let result = true;
#[allow(clippy::eq_op)]
{
assert!(result || !result, "Validation result must be boolean");
}
Ok(result)
}
#[spec_locked("5.3.1", "BlockHeaderHash")]
#[inline]
pub fn block_header_hash(header: &BlockHeader) -> crate::types::Hash {
use blvm_primitives::crypto::hash256;
use blvm_primitives::serialization::serialize_block_header;
hash256(&serialize_block_header(header))
}
#[spec_locked("5.3.1", "ValidatePrevBlockHash")]
#[blvm_spec_lock::ensures(result == true || result == false)]
#[inline]
pub fn validate_prev_block_hash(child: &BlockHeader, parent: &BlockHeader) -> bool {
child.prev_block_hash == block_header_hash(parent)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::BlockHeader;
#[test]
fn validate_prev_block_hash_accepts_matching_parent() {
let parent = BlockHeader {
version: 1,
prev_block_hash: [0u8; 32],
merkle_root: [1u8; 32],
timestamp: 1,
bits: 0x1d00ffff,
nonce: 0,
};
let parent_hash = block_header_hash(&parent);
let child = BlockHeader {
prev_block_hash: parent_hash,
merkle_root: [2u8; 32],
..parent
};
assert!(validate_prev_block_hash(&child, &parent));
}
#[test]
fn validate_prev_block_hash_rejects_mismatch() {
let parent = BlockHeader {
version: 1,
prev_block_hash: [0u8; 32],
merkle_root: [1u8; 32],
timestamp: 1,
bits: 0x1d00ffff,
nonce: 0,
};
let child = BlockHeader {
prev_block_hash: [9u8; 32],
merkle_root: [2u8; 32],
..parent
};
assert!(!validate_prev_block_hash(&child, &parent));
}
}