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

**Inherits:** `Object`

Duck type for block header lookups used by the SDK's verify methods.

{Beef#verify}, {MerklePath#verify}, and {Tx#verify} define what a valid
structure **is** — they walk trees, check proofs, and compare roots. But they
have no data source of their own. The chain tracker is the data source: an
object the consumer provides that can answer "is this merkle root valid for
this block height?"

This class is a working default implementation that wraps a
{BSV::Network::Provider} and dispatches via {Provider#call}. The provider must
serve the <code>:get_block_header</code> and <code>:current_height</code>
commands (e.g. a provider configured with {Protocols::JungleBus}).

Subclasses may override either or both methods to supply their own data source
(in-memory hash, database cache, etc.) without touching the provider at all.
The `provider` argument is optional precisely to preserve this pattern — a
subclass that overrides both methods never reaches the provider-dispatch path.

Any object responding to <code>valid_root_for_height?</code> and
`current_height` satisfies this interface. Inheriting from this class is
optional — it exists to document the contract and provide a ready-to-use
provider-backed implementation.

**@example In-memory chain tracker (test / declarative)**
```ruby
class HashTracker < BSV::Transaction::ChainTracker
  def initialize(headers)  @headers = headers end
  def valid_root_for_height?(root, h) @headers[h] == root end
  def current_height() @headers.keys.max end
end
tracker = HashTracker.new(800_000 => 'abcd...')
```

**@example Cache-aware chain tracker (production / imperative)**
```ruby
class WalletChainTracker < BSV::Transaction::ChainTracker
  def valid_root_for_height?(root, height)
    header = @db.find_header(height) || fetch_and_store(height)
    header.merkle_root == root
  end
end
```

**@example Provider-backed (default impl)**
```ruby
tracker = BSV::Transaction::ChainTracker.default
tracker.valid_root_for_height?('abcd...', 800_000)
```

**@example Testnet**
```ruby
tracker = BSV::Transaction::ChainTracker.default(testnet: true)
tracker.current_height
```

## Attributes
### `provider` [R] <a id="attribute-i-provider"></a> <a id="provider-instance_method"></a>
- **@return** [BSV::Network::Provider, nil] the underlying provider, if any

## Public Class Methods
### `default(testnet: = false)` <a id="method-c-default"></a> <a id="default-class_method"></a>
Return a default ChainTracker backed by the GorillaPool provider.
- **@param** `testnet` [Boolean] when true, uses the testnet provider
- **@return** [Transaction::ChainTracker]

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

Dispatches <code>:current_height</code> to the configured provider.
- **@raise** [RuntimeError] when no provider is configured
- **@raise** [RuntimeError] on network or API error
- **@return** [Integer] the height of the chain tip

### `initialize(provider = nil)` <a id="method-i-initialize"></a> <a id="initialize-instance_method"></a>
- **@param** `provider` [BSV::Network::Provider, nil] provider serving +:get_block_header+
and +:current_height+. Optional when the subclass overrides both methods.
- **@return** [ChainTracker] a new instance of ChainTracker

### `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.

Dispatches <code>:get_block_header</code> to the configured provider. Returns
`false` on 404 (block not found). Relies on the wire-protocol classes that
expose <code>:get_block_header</code> (<code>Protocols::JungleBus</code>,
<code>Protocols::Chaintracks</code>, <code>Protocols::WoCREST</code>) to emit
the canonical `merkle_root` key — see issue #791 for the Pattern A
normalisation that absorbed the previous field-name shim.
- **@param** `root` [String] merkle root as a hex string
- **@param** `height` [Integer] block height
- **@raise** [RuntimeError] when no provider is configured
- **@raise** [RuntimeError] on network or API error
- **@return** [Boolean] true if the root matches the block at the given height
