# Class BSV::Network::BlockHeader <a id="class-BSV-Network-BlockHeader"></a>

**Inherits:** `Object`

Pure, I/O-free 80-byte block-header parser and proof-of-work validator (HLR
#335, opt-in PoW-validated header verification).

bsv-sdk 0.25.0 ships no header / PoW primitive, so this is genuinely new
ground. The class does three things and nothing else:

1.  Parse the canonical 80-byte wire header into its six fields.
2.  Compute the block hash via the SDK's
    <code>BSV::Primitives::Digest.sha256d</code> (never hand-rolled — the SDK
    owns the crypto).
3.  Validate the embedded proof of work: decode the compact `nBits` target and
    check that the block hash, read as a little-endian 256-bit integer, is at
    or below it.

No network access, no database, no state beyond the parsed fields. Suitable
for the chain tracker to call on data it has already fetched.

## Byte-order convention

`prev_hash` and `merkle_root` are held as the 32 raw wire bytes the header
carries — no reversal during parse. This matches the wallet's `wtxid`
convention (wire/internal order is canonical; reversal to display order
happens only at service / display boundaries). The display-hex form a human or
a WhatsOnChain payload would show is the byte-reverse of these.

## Fail-closed posture

This is a security primitive and a sole misbehaving service is the threat
model. Every failure mode resolves to "not a valid header" rather than an
exception that a caller's `rescue` might swallow into a truthy value:

*   `parse` rejects anything that is not exactly 80 bytes **before** it
    unpacks (raising {InvalidHeaderError} — the tracker treats any failure as
    `false`).
*   {.target_from_bits} returns `nil` for a malformed compact target (negative
    sign bit, zero mantissa, or > 256-bit overflow), and
    <code>#valid_pow?</code> maps that `nil` to `false`. A bogus `nBits` can
    never be coerced into an easy target.
*   {.from_service_fields} round-trips the assembled hash against the
    service-supplied display hash when one is given, and returns `nil` on
    mismatch.

## Constants
### `HEADER_SIZE` <a id="constant-HEADER_SIZE"></a> <a id="HEADER_SIZE-constant"></a>
Canonical serialised header length in bytes.

### `MAX_TARGET_EXCLUSIVE` <a id="constant-MAX_TARGET_EXCLUSIVE"></a> <a id="MAX_TARGET_EXCLUSIVE-constant"></a>
2^256 — one past the largest value a 256-bit target may hold. Any decoded
target at or above this has overflowed and is rejected.

## Attributes
### `bits` [R] <a id="attribute-i-bits"></a> <a id="bits-instance_method"></a>
- **@return** [Integer] compact +nBits+ proof-of-work target (LE uint32)

### `merkle_root` [R] <a id="attribute-i-merkle_root"></a> <a id="merkle_root-instance_method"></a>
- **@return** [String] 32 raw wire bytes of the merkle root (no reversal)

### `nonce` [R] <a id="attribute-i-nonce"></a> <a id="nonce-instance_method"></a>
- **@return** [Integer] proof-of-work nonce (LE uint32)

### `prev_hash` [R] <a id="attribute-i-prev_hash"></a> <a id="prev_hash-instance_method"></a>
- **@return** [String] 32 raw wire bytes of the previous block hash (no reversal)

### `raw` [R] <a id="attribute-i-raw"></a> <a id="raw-instance_method"></a>
- **@return** [String] the exact 80 raw bytes this header was parsed from

### `time` [R] <a id="attribute-i-time"></a> <a id="time-instance_method"></a>
- **@return** [Integer] block timestamp, seconds since the Unix epoch (LE uint32)

### `version` [R] <a id="attribute-i-version"></a> <a id="version-instance_method"></a>
- **@return** [Integer] block version (LE uint32)

## Public Class Methods
### `from_service_fields(version:, previousblockhash:, merkleroot:, time:, bits:, nonce:, hash: = nil)` <a id="method-c-from_service_fields"></a> <a id="from_service_fields-class_method"></a>
Assemble and parse an 80-byte header from a WhatsOnChain-shaped
+/block/{height}/header+ field set.

WhatsOnChain returns decoded **fields**, not raw bytes, so the header has to
be reconstructed before it can be hashed. Two field-level quirks of that
payload are handled here:

*   `bits` arrives as a hex **string** (e.g. +"180d589d"+), not an integer —
    decoded with +to_i(16)+ before packing.
*   `previousblockhash` and `merkleroot` are **display** hex (the
    human-facing, byte-reversed form) — reversed back to wire order during
    assembly so the reconstructed bytes match the chain.

When <code>hash:</code> (WhatsOnChain's display-hex block hash) is supplied,
the assembled header's own hash is checked against it as an integrity guard; a
mismatch returns `nil` rather than a header that claims an identity it cannot
prove.
- **@param** `version` [Integer] block version
- **@param** `previousblockhash` [String] previous block hash, display hex
- **@param** `merkleroot` [String] merkle root, display hex
- **@param** `time` [Integer] block timestamp (Unix seconds)
- **@param** `bits` [String] compact target as a hex string (WhatsOnChain form)
- **@param** `nonce` [Integer] proof-of-work nonce
- **@param** `hash` [String, nil] optional display-hex block hash for round-trip verification
- **@return** [BlockHeader, nil] the parsed header, or +nil+ if assembly or the integrity check fails

### `parse(bytes)` <a id="method-c-parse"></a> <a id="parse-class_method"></a>
Parse an 80-byte wire header.

Fails closed before unpacking: a `bytes` argument that is `nil`, not a String,
or not exactly {HEADER_SIZE} long raises {InvalidHeaderError}. The original
byte slice is retained verbatim for {#block_hash} so the hash is always taken
over the bytes as received — never a re-serialisation that could drift.
- **@param** `bytes` [String] 80 raw bytes, +version|prev_hash|merkle_root|time|bits|nonce+
- **@raise** [InvalidHeaderError] if +bytes+ is not exactly 80 bytes
- **@return** [BlockHeader]

### `target_from_bits(bits)` <a id="method-c-target_from_bits"></a> <a id="target_from_bits-class_method"></a>
Decode a compact `nBits` target into its full 256-bit integer form, following
Bitcoin Core's `SetCompact`.

The compact form is +exponent (1 byte) << 24 | mantissa (3 bytes)+. The
decoded target is the mantissa scaled by a power of 256 chosen by the
exponent.

Returns `nil` — never an exception, never a clamped value — for any malformed
compact target, so a caller can treat "no target" as "invalid proof of work":

*   *sign bit set* (+bits & 0x00800000+): Bitcoin's compact format reserves a
    sign bit. A negative target is meaningless for PoW.
*   *zero mantissa*: a zero target can never be met; treat the header as
    invalid rather than dividing into it.
*   *overflow past 256 bits*: a mantissa shifted so far left that the target
    would not fit in 256 bits cannot be a real chain target. Guarded in full
    (not just +exponent > 34+) so a high exponent paired with any non-zero
    mantissa is caught.
- **@param** `bits` [Integer] compact target (the header's +nBits+ field)
- **@return** [Integer, nil] the decoded 256-bit target, or +nil+ if malformed

## Public Instance Methods
### `block_hash()` <a id="method-i-block_hash"></a> <a id="block_hash-instance_method"></a>
The block hash: SHA256d over the exact 80 bytes this header was parsed from.
Reuses the SDK digest; the original slice is hashed rather than a
re-serialisation, so the result cannot drift from what the network signed.
- **@return** [String] 32 wire bytes (display-hex is the byte-reverse of this)

### `initialize(version:, prev_hash:, merkle_root:, time:, bits:, nonce:, raw:)` <a id="method-i-initialize"></a> <a id="initialize-instance_method"></a>
- **@param** `version` [Integer]
- **@param** `prev_hash` [String] 32 raw wire bytes
- **@param** `merkle_root` [String] 32 raw wire bytes
- **@param** `time` [Integer]
- **@param** `bits` [Integer]
- **@param** `nonce` [Integer]
- **@param** `raw` [String] the 80 raw bytes the fields were parsed from
- **@return** [BlockHeader] a new instance of BlockHeader

### `links_to?(parent)` <a id="method-i-links_to-3F"></a> <a id="links_to?-instance_method"></a>
Whether this header chains onto `parent`: its `prev_hash` must equal the
parent's block hash. Both are raw wire bytes, so the comparison is a direct
byte equality with no reversal.
- **@param** `parent` [BlockHeader] the candidate predecessor header
- **@return** [Boolean]

### `target()` <a id="method-i-target"></a> <a id="target-instance_method"></a>
The decoded proof-of-work target for this header's `nBits`.
- **@return** [Integer, nil] decoded 256-bit target, or +nil+ if +nBits+ is malformed

### `valid_pow?()` <a id="method-i-valid_pow-3F"></a> <a id="valid_pow?-instance_method"></a>
Whether the header's proof of work is valid: the block hash, read as a
<strong>little-endian</strong> 256-bit integer, must be at or below the
decoded target. Equality counts as valid (Bitcoin uses +<=+).

The block hash is wire/little-endian, so it is reversed to obtain the
big-endian integer to compare against the target. A malformed `nBits` (target
`nil`) is invalid PoW, not an error.
- **@return** [Boolean]
