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

**Inherits:** `BSV::Transaction::ChainTracker`

Write-through chain tracker backed by the `blocks` table and the Services
routing layer. Satisfies the SDK's {Transaction::ChainTracker} duck type so it
can be passed to +Transaction::Tx#verify+.

Fast path: look up the block by height in the local `blocks` table. Miss path:
fetch the header from the network via Services, persist it, then answer.

Fails closed: any error returns `false` — verification fails rather than
passing on incomplete data.

## Public Instance Methods
### `current_height()` <a id="method-i-current_height"></a> <a id="current_height-instance_method"></a>
Return the current blockchain height.
- **@return** [Integer]

### `initialize(store:, services:)` <a id="method-i-initialize"></a> <a id="initialize-instance_method"></a>
- **@param** `store` [BSV::Wallet::Store] store providing block header persistence
- **@param** `services` [BSV::Network::Services] routing layer for network calls
- **@return** [ChainTracker] a new instance of ChainTracker

### `known_roots_for_heights(heights)` <a id="method-i-known_roots_for_heights"></a> <a id="known_roots_for_heights-instance_method"></a>
Height-deduplicated merkle-root lookup for anchor liveness (HLR #516 Sub 6).

Returns +{ height => root_bytes | nil }+ — one entry per input height.
Wire-order 32-byte binary bytes, matching the persisted convention (never hex,
never BUMP-bytes). `nil` for a height the tracker cannot resolve (fetch
failure, network error): distinct from "mismatch" — the anchor-liveness caller
must not invalidate on unresolvable heights, only on genuine root mismatches.

Empty input short-circuits: no fetches, empty Hash returned.

**Batching scope.** This base implementation only guarantees height
de-duplication before dispatch — on a store miss it still performs one
`get_block_header` network call per height. Callers wanting a single-sync
batch (one header-syncer round trip for the whole set) should use
+SpvHeaderChainTracker#known_roots_for_heights+, which does exactly that.
(Copilot round-3 on #533.)

This is a fast-path helper for <code>Engine::AnchorLivenessCache</code>, not a
duck-type contract with the SDK.

**Freshness for anchor-liveness.** Passes +refresh: true+ down to
`resolve_root_for_height` so the cached <code>blocks.merkle_root</code> (set
at proof-import time and never auto-refreshed on the trusted-service model)
doesn't hide a re-org from the caller. <code>valid_root_for_height?</code>
(the SDK verify hot path) still hits the cache-first fast path unchanged.
#535.
- **@param** `heights` [Array<Integer>]
- **@return** [Hash{Integer => String, nil}]

### `valid_root_for_height?(root, height)` <a id="method-i-valid_root_for_height-3F"></a> <a id="valid_root_for_height?-instance_method"></a>
Verify that a merkle root is valid for the given block height.
- **@param** `root` [String] merkle root as a hex string (from SDK's MerklePath#verify)
- **@param** `height` [Integer] block height
- **@return** [Boolean]
