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

**Inherits:** `Object`

Porcelain routing layer above SDK providers/protocols.

Same +call(command, *args, **kwargs)+ interface as Provider — drop-in
replacement. Adds capability-based routing, fallback on retryable errors,
per-provider rate limiting, response normalization, and opportunistic sibling
data caching.

**@example**
```ruby
services = BSV::Network::Services.new(providers: [gorilla_pool, woc])
services.call(:broadcast, tx)
services.call(:get_tx, txid)
services.call(:get_utxos, address)
```

## Constants
### `MAX_MEMO_ENTRIES` <a id="constant-MAX_MEMO_ENTRIES"></a> <a id="MAX_MEMO_ENTRIES-constant"></a>
Not documented.

### `MEMO_TTL` <a id="constant-MEMO_TTL"></a> <a id="MEMO_TTL-constant"></a>
--- Sibling Memo ---

### `NORMALIZED_COMMANDS` <a id="constant-NORMALIZED_COMMANDS"></a> <a id="NORMALIZED_COMMANDS-constant"></a>
--- Normalization ---

### `RETRYABLE_ATTEMPTS` <a id="constant-RETRYABLE_ATTEMPTS"></a> <a id="RETRYABLE_ATTEMPTS-constant"></a>
Backoff attempts for a single provider after the TokenBucket has released a
request slot. Distinguishes "wallet-side spacing" (TokenBucket) from
"provider-side rate-limit / transient 5xx" (retry-with-backoff). Returns the
final `ProtocolResponse` after exhausting attempts.

### `RETRYABLE_BACKOFF_BASE_S` <a id="constant-RETRYABLE_BACKOFF_BASE_S"></a> <a id="RETRYABLE_BACKOFF_BASE_S-constant"></a>
Not documented.

## Attributes
### `providers` [R] <a id="attribute-i-providers"></a> <a id="providers-instance_method"></a>
Returns the registered providers (frozen at construction time).
- **@return** [Array<BSV::Network::Provider>]

## Public Instance Methods
### `backoff_sleep(seconds)` <a id="method-i-backoff_sleep"></a> <a id="backoff_sleep-instance_method"></a>
Indirection so specs can stub backoff to zero without monkey-patching
+Kernel#sleep+ globally.

### `call(command, *args, **kwargs)` <a id="method-i-call"></a> <a id="call-instance_method"></a>
Dispatch a command with provider routing and fallback.
- **@param** `command` [Symbol] SDK command name
- **@param** `args` [Array] positional arguments forwarded to the provider
- **@param** `kwargs` [Hash] keyword arguments forwarded to the provider
- **@return** [BSV::Network::ProtocolResponse]

### `call_with_backoff(provider, sym, args, kwargs)` <a id="method-i-call_with_backoff"></a> <a id="call_with_backoff-instance_method"></a>
Not documented.

### `call_with_candidates(command, candidates, *args, **kwargs)` <a id="method-i-call_with_candidates"></a> <a id="call_with_candidates-instance_method"></a>
Dispatch a command against an explicitly-ordered candidate list.

Same retry / backoff / fallback / normalisation as <code>#call</code>, but the
caller supplies the provider ordering instead of relying on
<code>#candidates_for</code>. Used by <code>BSV::Network::Broadcaster</code>
to overlay wtxid-keyed affinity onto the dispatch path without duplicating the
per-provider backoff loop here.

When a block is given, it is yielded the `Provider` that produced the
successful response so callers (e.g. Broadcaster) can persist affinity. The
block is not invoked on failure.

Broadcast affinity persistence is <code>BSV::Network::Broadcaster</code>'s
contract, not this layer's. Services intentionally does not record affinity
itself — any direct caller of +#call(:broadcast, ...)+ outside Broadcaster
will silently skip the affinity hook. Route broadcast and
<code>:get_tx_status</code> through Broadcaster for any flow where affinity
matters.
- **@param** `command` [Symbol] SDK command name
- **@param** `candidates` [Array<BSV::Network::Provider>] ordered providers
- **@return** [BSV::Network::ProtocolResponse]
- **@yield** [provider] succeeding provider (success only)

### `commands()` <a id="method-i-commands"></a> <a id="commands-instance_method"></a>
Union of all commands available across all registered providers.
- **@return** [Set<Symbol>]

### `fetch!(entity)` <a id="method-i-fetch-21"></a> <a id="fetch!-instance_method"></a>
Fetch state from the network into an entity.

Calls <code>entity.fetch_command</code> and <code>entity.fetch_args</code>,
dispatches through the routing layer, and writes the response back on success.
- **@param** `entity` [#fetch_command, #fetch_args, #write!]
- **@return** [BSV::Network::ProtocolResponse]

### `initialize(providers:)` <a id="method-i-initialize"></a> <a id="initialize-instance_method"></a>
- **@param** `providers` [Array<BSV::Network::Provider>] providers in priority order
- **@raise** [ArgumentError]
- **@return** [Services] a new instance of Services

### `push!(entity)` <a id="method-i-push-21"></a> <a id="push!-instance_method"></a>
Push an entity to the network.

Calls <code>entity.push_command</code> and <code>entity.push_payload</code>,
dispatches through the routing layer, and writes the response back on success.
- **@param** `entity` [#push_command, #push_payload, #write!]
- **@return** [BSV::Network::ProtocolResponse]
