Class: BSV::Overlay::LookupResolver

Inherits:
Object
  • Object
show all
Defined in:
lib/bsv/overlay/lookup_resolver.rb

Overview

Resolves LookupQuestions by discovering competent overlay hosts via SLAP trackers and querying them in parallel.

Host discovery

For any service other than ls_slap, the resolver first queries the configured SLAP trackers to discover which hosts advertise competence for that service. Discovery results are cached with a configurable TTL (default: 5 minutes) to avoid redundant network round-trips.

Host overrides and additional hosts

host_overrides replaces SLAP discovery entirely for a named service. additional_hosts supplements discovered (or overridden) hosts. Both maps require service names that begin with ls_.

Parallel querying

All competent hosts are queried concurrently using Ruby threads. Responses are collected, outputs are merged, and duplicates are removed by “#{txid}.#{output_index}” key.

Reputation tracking

Hosts are ranked before querying via HostReputationTracker#rank_hosts, and success/failure outcomes (with latency) are recorded after each query.

Thread-safe via an internal Mutex on the hosts cache.

Constant Summary collapse

QUERY_GRACE_SECONDS =

Grace window (seconds) after the first valid response arrives during which other in-flight host queries may still contribute their outputs.

0.08
SLAP_TRACKER_TIMEOUT =

Timeout applied when querying SLAP trackers for host discovery.

5

Instance Method Summary collapse

Constructor Details

#initialize(network_preset: :mainnet, facilitator: nil, slap_trackers: nil, host_overrides: {}, additional_hosts: {}, reputation_tracker: nil, cache_ttl: 300) ⇒ LookupResolver

Returns a new instance of LookupResolver.

Parameters:

  • network_preset (Symbol) (defaults to: :mainnet)

    :mainnet, :testnet, or :local

  • facilitator (LookupFacilitator, nil) (defaults to: nil)

    injectable facilitator

  • slap_trackers (Array<String>, nil) (defaults to: nil)

    override default tracker list

  • host_overrides (Hash{String=>Array<String>}) (defaults to: {})
  • additional_hosts (Hash{String=>Array<String>}) (defaults to: {})
  • reputation_tracker (HostReputationTracker, nil) (defaults to: nil)

    injectable tracker

  • cache_ttl (Integer) (defaults to: 300)

    seconds before cached hosts expire



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/bsv/overlay/lookup_resolver.rb', line 52

def initialize(
  network_preset:     :mainnet,
  facilitator:        nil,
  slap_trackers:      nil,
  host_overrides:     {},
  additional_hosts:   {},
  reputation_tracker: nil,
  cache_ttl:          300
)
  @network_preset = network_preset

  @facilitator = facilitator || default_facilitator

  @slap_trackers = slap_trackers || default_slap_trackers
  validate_slap_trackers!

  validate_service_keys!('host_overrides',   host_overrides)
  validate_service_keys!('additional_hosts', additional_hosts)

  @host_overrides   = host_overrides
  @additional_hosts = additional_hosts

  @reputation_tracker = reputation_tracker || HostReputationTracker.new

  @cache_ttl   = cache_ttl
  @hosts_cache = {}
  @cache_mutex = Mutex.new
end

Instance Method Details

#find_competent_hosts(service) ⇒ Array<String>

Discover competent hosts for service via SLAP trackers.

Results are cached for cache_ttl seconds. Concurrent callers for the same service will each trigger their own SLAP query (no in-flight coalescing in this implementation).

Parameters:

  • service (String)

    lookup service name (e.g. ‘ls_foo’)

Returns:

  • (Array<String>)

    array of host URLs



116
117
118
119
120
121
122
123
124
125
# File 'lib/bsv/overlay/lookup_resolver.rb', line 116

def find_competent_hosts(service)
  cached = @cache_mutex.synchronize { @hosts_cache[service] }
  return cached[:hosts].dup if cached && (Time.now.to_f - cached[:fetched_at]) < @cache_ttl

  hosts = fetch_hosts_from_slap(service)
  @cache_mutex.synchronize do
    @hosts_cache[service] = { hosts: hosts, fetched_at: Time.now.to_f }
  end
  hosts
end

#query(question, timeout: nil) ⇒ LookupAnswer

Resolve a LookupQuestion by discovering competent hosts and querying them.

Parameters:

  • question (LookupQuestion)

    the question to resolve

  • timeout (Integer, nil) (defaults to: nil)

    per-host query timeout in seconds

Returns:

Raises:



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/bsv/overlay/lookup_resolver.rb', line 87

def query(question, timeout: nil)
  competent_hosts = resolve_hosts(question)
  apply_additional_hosts!(competent_hosts, question.service)

  if competent_hosts.empty?
    raise NoCompetentHostsError,
          "No competent #{@network_preset} hosts found by the SLAP trackers " \
          "for lookup service: #{question.service}"
  end

  ranked = @reputation_tracker.rank_hosts(competent_hosts)
  answers = query_hosts_in_parallel(ranked, question, timeout)

  if answers.empty?
    raise NoCompetentHostsError,
          "All competent hosts for #{question.service} failed to return a valid answer"
  end

  merge_answers(answers)
end