# Class BSV::Wallet::Engine::Broadcast <a id="class-BSV-Wallet-Engine-Broadcast"></a>

**Inherits:** `Object`
**Includes:** `BSV::Wallet::Engine::OmqSupport`

Background broadcast handler -- logical model for walletd.

Owns OMQ sockets for background work (PULL) and inline request-reply (REP).
Processes pending broadcasts by calling Services and recording results in
Store. Also owns the statuses PULL socket for SSE-delivered events (#265): the
Network-layer SSE listener PUSHes decoded event hashes here, this fiber PULLs
and hands off to Store::EventApplicator for atomic application.

## Attributes
### `hydrated_tx_cache` [R] <a id="attribute-i-hydrated_tx_cache"></a> <a id="hydrated_tx_cache-instance_method"></a>
Returns the value of attribute hydrated_tx_cache.

## Public Class Methods
### `pending_resolutions(store, limit: = 10)` <a id="method-c-pending_resolutions"></a> <a id="pending_resolutions-class_method"></a>
Discovery query -- returns action IDs of attempted, non-terminal broadcasts
(eligible for the resolution loop's status poll). Pre-broadcast actions (no
Broadcasts row, or broadcast_at IS NULL) are not returned here; submission
discovery is via .pending_submissions.

### `pending_submissions(store, limit: = 10)` <a id="method-c-pending_submissions"></a> <a id="pending_submissions-class_method"></a>
Discovery query -- returns action IDs of broadcasts that have never been
attempted (broadcast_at IS NULL). Counterpart to .pending_resolutions: this
drives the submission loop. Both feed the same PULL socket; `process` routes
them by broadcast_at presence.

## Public Instance Methods
### `applicator()` <a id="method-i-applicator"></a> <a id="applicator-instance_method"></a>
Lazy default — see <code>#initialize</code>.

### `hints_pull!(task:, socket_path:)` <a id="method-i-hints_pull-21"></a> <a id="hints_pull!-instance_method"></a>
BEEF hint receiver -- pulls cross-process producer hints (CLI tools, API, UI)
into the in-process EF cache. Each hint carries the action's Atomic BEEF;
receiver parses, extracts the subject Transaction::Tx (whose inputs have
`source_transaction` wired by <code>Beef.from_binary</code>), and primes the
cache so a subsequent broadcast emits EF via +Transaction::Tx#to_ef_hex+
without the JOIN.

Optional: when `socket_path` is nil, no fiber is started and the cache fills
only via intra-process producers.

Trust boundary: <code>Marshal.load</code> runs on bytes from anyone with write
permission to the socket inode. On ipc:// that means file- system perms on the
socket path; operators sharing the path with untrusted users are responsible
for the consequences. #269.

### `initialize(store:, broadcaster:, applicator: = nil, callback_token: = nil, hydrated_tx_cache: = nil)` <a id="method-i-initialize"></a> <a id="initialize-instance_method"></a>
- **@param** `store` [BSV::Wallet::Store]
- **@param** `broadcaster` [BSV::Network::Broadcaster]
- **@param** `applicator` [Store::EventApplicator, nil] consumes statuses
events on +statuses_pull!+. Lazily defaulted to a fresh
+Store::EventApplicator.new(store: store)+ on first read so
existing call sites (pre-#265 specs, the inline path) don't
trigger autoload of Store::EventApplicator (and its Sequel
dependency chain) at construction time; #265's Daemon wiring
supplies its own instance.
- **@param** `callback_token` [String, nil] Arcade callbackToken; passed
to +Broadcaster#broadcast+ on every submit so the +X-CallbackToken+
header is set on the POST and Arcade's SSE listener (subscribed
to the same token) receives the resulting status frames. Lenient
default (nil) lets unit specs that do not run a listener exercise
submit without the header.
- **@return** [Broadcast] a new instance of Broadcast

### `process(action_id)` <a id="method-i-process"></a> <a id="process-instance_method"></a>
Process a single action -- submit if not yet broadcast, poll status if already
broadcast. Emits exactly one task.dispatched on entry, then exactly one of
task.succeeded / task.failed / task.aborted / task.skipped. The emitted `task`
label reflects which loop's work this represents: `broadcast_submission` for a
first-attempt push, `broadcast_resolution` for status polling.

### `pull!(task:)` <a id="method-i-pull-21"></a> <a id="pull!-instance_method"></a>
Background queue -- fire-and-forget processing. Binds a PULL socket; the
Scheduler pushes action IDs here.

### `reply!(task:)` <a id="method-i-reply-21"></a> <a id="reply!-instance_method"></a>
Inline request-reply -- caller sends action_id, gets tx_status back.

### `statuses_pull!(task:)` <a id="method-i-statuses_pull-21"></a> <a id="statuses_pull!-instance_method"></a>
Statuses queue -- consumes SSE-delivered events. Binds a PULL socket at
<code>inproc://statuses.pull</code>; the SSE listener fiber (Daemon-wired in
#265) PUSHes Marshal-encoded event hashes here. Each message decodes into the
shape +Store::EventApplicator#apply+ consumes -- the same internal event hash
the Rack callback hands off, since the listener's `decode_event` normalises
into that shape pre-PUSH.

Runs as a peer fiber to <code>pull!</code>/<code>reply!</code>. The two PULL
sockets live in separate Async tasks, so the reactor schedules them fairly;
one busy socket does not starve the other.

Marshal (not JSON) for the wire format -- the event hash carries binary
`wtxid` / `block_hash` / `merkle_path` that would need hex round-tripping
under JSON. Marshal is the simplest in-proc Ruby-to-Ruby encoding and keeps
the convention (binary stays binary) intact across the bus.
