Class: BSV::Transaction::ChainTracker

Inherits:
Object
  • Object
show all
Defined in:
lib/bsv/transaction/chain_tracker.rb

Overview

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

Beef#verify, MerklePath#verify, and Transaction#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 Network::Provider and dispatches via Provider#call. The provider must serve the :get_block_header and :current_height 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 valid_root_for_height? 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.

Examples:

In-memory chain tracker (test / declarative)

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...')

Cache-aware chain tracker (production / imperative)

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

Provider-backed (default impl)

tracker = BSV::Transaction::ChainTracker.default
tracker.valid_root_for_height?('abcd...', 800_000)

Testnet

tracker = BSV::Transaction::ChainTracker.default(testnet: true)
tracker.current_height

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(provider = nil) ⇒ ChainTracker

Returns a new instance of ChainTracker.

Parameters:

  • provider (BSV::Network::Provider, nil) (defaults to: nil)

    provider serving :get_block_header and :current_height. Optional when the subclass overrides both methods.



66
67
68
# File 'lib/bsv/transaction/chain_tracker.rb', line 66

def initialize(provider = nil)
  @provider = provider
end

Instance Attribute Details

#providerBSV::Network::Provider? (readonly)

Returns the underlying provider, if any.

Returns:



54
55
56
# File 'lib/bsv/transaction/chain_tracker.rb', line 54

def provider
  @provider
end

Class Method Details

.default(testnet: false) ⇒ ChainTracker

Return a default ChainTracker backed by the GorillaPool provider.

Parameters:

  • testnet (Boolean) (defaults to: false)

    when true, uses the testnet provider

Returns:



60
61
62
# File 'lib/bsv/transaction/chain_tracker.rb', line 60

def self.default(testnet: false)
  new(BSV::Network::Providers::GorillaPool.default(testnet: testnet))
end

Instance Method Details

#current_heightInteger

Return the current blockchain height.

Dispatches :current_height to the configured provider.

Returns:

  • (Integer)

    the height of the chain tip

Raises:

  • (RuntimeError)

    when no provider is configured

  • (RuntimeError)

    on network or API error



101
102
103
104
105
106
107
108
# File 'lib/bsv/transaction/chain_tracker.rb', line 101

def current_height
  raise 'ChainTracker requires a provider when used directly' if @provider.nil?

  result = @provider.call(:current_height)
  return result.data if result.http_success?

  raise result.error_message.to_s
end

#valid_root_for_height?(root, height) ⇒ Boolean

Verify that a merkle root is valid for the given block height.

Dispatches :get_block_header to the configured provider. Returns false on 404 (block not found). Normalises the merkle root field name from any of merkleroot, merkleRoot, or merkle_root.

Parameters:

  • root (String)

    merkle root as a hex string

  • height (Integer)

    block height

Returns:

  • (Boolean)

    true if the root matches the block at the given height

Raises:

  • (RuntimeError)

    when no provider is configured

  • (RuntimeError)

    on network or API error



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/bsv/transaction/chain_tracker.rb', line 81

def valid_root_for_height?(root, height)
  raise 'ChainTracker requires a provider when used directly' if @provider.nil?

  result = @provider.call(:get_block_header, height)
  return false if result.http_not_found?
  raise result.error_message.to_s unless result.http_success?

  actual = normalise_merkle_root(result.data)
  return false unless actual

  actual.casecmp(root).zero?
end