Skip to main content

Event

Enum Event 

Source
#[non_exhaustive]
pub enum Event {
Show 32 variants MempoolEnter { txid: Vec<u8>, fee: u64, vsize: u64, fee_rate_sat_per_kvb: u64, time: u64, }, MempoolLeaveConfirmed { txid: Vec<u8>, block_hash: Vec<u8>, height: u32, }, MempoolLeaveEvicted { txid: Vec<u8>, reason: EvictReason, }, MempoolLeaveReplaced { txid: Vec<u8>, replacing_txid: Vec<u8>, }, BlockConnected { hash: Vec<u8>, height: u32, }, BlockDisconnected { hash: Vec<u8>, height: u32, }, Reorg { from_height: u32, old_tip: Vec<u8>, to_height: u32, new_tip: Vec<u8>, }, Heartbeat { uptime_ns: u64, }, Status { kind: StatusKind, state: StatusState, severity: StatusSeverity, message: String, details: BTreeMap<String, String>, }, OutpointSpent { outpoint: Outpoint, spending_txid: Vec<u8>, spending_vin: u32, confirmed: bool, }, ScriptMatched { scripthash: Vec<u8>, txid: Vec<u8>, is_output: bool, index: u32, confirmed: bool, amount: Option<u64>, raw_tx: Option<Vec<u8>>, descriptors: Vec<DescriptorMatch>, }, TxidMatched { txid: Vec<u8>, confirmed: bool, height: u32, }, TxidReplaced { txid: Vec<u8>, replacing_txid: Vec<u8>, }, TxidEvicted { txid: Vec<u8>, reason: String, }, TxidUnconfirmed { txid: Vec<u8>, prev_height: u32, }, TxidDepthReached { txid: Vec<u8>, depth: u32, height: u32, }, TxidFinalized { txid: Vec<u8>, depth: u32, height: u32, }, PrefixMatched(PrefixMatch), Lagged { dropped_count: u64, resume_cursor: Option<Cursor>, }, ReplayGap { resume_height: u32, first_height: u32, }, CursorAccepted { from: Option<Cursor>, clamped: bool, earliest_replayed: u32, }, CursorRejected { reason: CursorRejectReason, current_head: Option<Cursor>, }, WatchSetReplaced { added: u32, removed: u32, unchanged: u32, }, WatchSetRejected { reason: WatchSetRejectReason, required: u64, quota: u64, }, RescanAccepted { from_height: u32, to_height: u32, clamped: bool, }, RescanRejected { reason: RescanRejectReason, tip_height: u32, }, RescanComplete { from_height: u32, to_height: u32, matches: u64, }, BlockTweaks { block_hash: Vec<u8>, height: u32, entries: Vec<TweakEntry>, filtered: bool, }, MempoolTweak { entry: TweakEntry, }, SilentPaymentMatched { scan_pubkey: Vec<u8>, txid: Vec<u8>, vout: u32, output_pubkey: Vec<u8>, amount: u64, tweak: Vec<u8>, k: u32, label: Option<u32>, confirmed: bool, height: Option<u32>, raw_tx: Option<Vec<u8>>, }, WatchAddRejected(WatchAddRejected), Unknown,
}
Expand description

A typed streaming event — the flat mirror of NodeEvent.body.

Eq is not derived: the Lagged resume cursor is a prost-generated type that is only PartialEq.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

MempoolEnter

A transaction entered the mempool.

Fields

§txid: Vec<u8>

Transaction id.

§fee: u64

Fee in satoshis.

§vsize: u64

Virtual size in vbytes.

§fee_rate_sat_per_kvb: u64

Fee rate in sat/kvB.

§time: u64

Admission time, seconds since the Unix epoch.

§

MempoolLeaveConfirmed

A mempool transaction was confirmed in a block.

Fields

§txid: Vec<u8>

Transaction id.

§block_hash: Vec<u8>

Confirming block hash.

§height: u32

Confirming block height.

§

MempoolLeaveEvicted

A mempool transaction was evicted by policy.

Fields

§txid: Vec<u8>

Transaction id.

§reason: EvictReason

Eviction reason.

§

MempoolLeaveReplaced

A mempool transaction was replaced (RBF).

Fields

§txid: Vec<u8>

Transaction id.

§replacing_txid: Vec<u8>

The replacing transaction id.

§

BlockConnected

A block was connected to the active chain.

Fields

§hash: Vec<u8>

Block hash.

§height: u32

Block height.

§

BlockDisconnected

A block was disconnected (reorg).

Fields

§hash: Vec<u8>

Block hash.

§height: u32

Block height.

§

Reorg

A reorg marker, emitted once before the disconnect/connect sequence.

Fields

§from_height: u32

Height of the abandoned tip.

§old_tip: Vec<u8>

Hash of the abandoned tip.

§to_height: u32

Height of the new active tip.

§new_tip: Vec<u8>

Hash of the new active tip.

§

Heartbeat

A periodic heartbeat.

Fields

§uptime_ns: u64

Publisher uptime in nanoseconds.

§

Status

A node-health condition the daemon detected about itself — a stalled tip, a filling disk, peer starvation. Arrives only for a subscription that set the STATUS category bit, which is deliberately not part of the 0 (“all”) default.

Standing conditions are level-triggered: exactly one StatusState::Raised on entry and one StatusState::Cleared on recovery, with hysteresis so a value hovering at the threshold does not flap. Observations with no recovered state (IBD finishing, a deep reorg landing) are StatusState::Edge.

Not replayable, and the gap is not observable. A status event carries no cursor, so a from_cursor resume never yields one; the node re-raises standing conditions after a restart instead. A client that connects after a condition was raised will not see it until the condition changes.

This is not something the reconnect layer can paper over. ResilientSubscription hides reconnects by design, and its one synthetic notice (Event::ReplayGap) is cursor-anchored — which status has no part in. So a drop during which one condition raised and another cleared leaves a client’s picture silently wrong, with nothing to key recovery off.

Treat this stream as the low-latency edge signal and getwarnings over JSON-RPC as the authority on what is wrong right now: poll it on a slow timer as well as consuming this, and a missed transition self-corrects at the next poll instead of persisting for the life of the process. Seeding once on connect is not enough, because reconnects after that are invisible to you.

Match on kind and read details for the numbers; treat StatusKind::Unknown as informational rather than an error, since new conditions are added additively. See [examples/health_watch.rs].

Fields

§kind: StatusKind

Which condition this describes.

§state: StatusState

Whether it was entered, recovered, or is a one-shot observation.

§severity: StatusSeverity

How loud it is. Ordered, so a severity floor is a comparison.

§message: String

Human-readable one-liner. Log it or page on it; do not parse it.

§details: BTreeMap<String, String>

Kind-specific structured fields, as strings.

Mostly decimal numbers (free bytes and the threshold, seconds since the last block, a reorg’s depth and fork height, …) but not uniformly — a cleared event can carry a reason token such as detector_disabled or mempool_cap_zero. Parse per key, not with one integer parse over the map.

The watched path is deliberately absent: it reaches every status subscriber and every webhook receiver, and an absolute datadir path usually names the account the node runs under.

Tolerate unknown keys and absent optional ones.

§

OutpointSpent

A watched outpoint was spent.

Fields

§outpoint: Outpoint

The spent outpoint.

§spending_txid: Vec<u8>

The spending transaction id.

§spending_vin: u32

The spending input index.

§confirmed: bool

false = seen in mempool, true = confirmed.

§

ScriptMatched

A watched script was matched on the funding or spending side.

Fields

§scripthash: Vec<u8>

The matched scripthash.

§txid: Vec<u8>

The matching transaction id.

§is_output: bool

true = funding (output), false = spending (input).

§index: u32

vout if is_output, else vin.

§confirmed: bool

false = mempool, true = confirmed.

§amount: Option<u64>

Matched value in satoshis: the funded output value (is_output = true) or the spent-prevout value (is_output = false). Some on the funding side and for confirmed spends; Some for mempool spends when the node retained the prevout value (streamprevoutmeta >= amount), else None (hash tier). None lets the consumer skip the enrichment getrawtransaction for the common single-coin case.

§raw_tx: Option<Vec<u8>>

Full consensus-serialized matching transaction, present only when this stream opted in via set_watch_options with include_raw_tx = true; None otherwise.

§descriptors: Vec<DescriptorMatch>

Descriptor attribution: the descriptor watch(es) this scripthash belongs to, if it was registered via add_descriptor. Empty for a directly-watched script. See DescriptorMatch.

§

TxidMatched

A watched txid appeared in the mempool or a connected block.

Fields

§txid: Vec<u8>

Transaction id.

§confirmed: bool

false = mempool, true = confirmed.

§height: u32

Block height when confirmed; 0 in the mempool.

§

TxidReplaced

A watched tx was replaced in the mempool (RBF).

Fields

§txid: Vec<u8>

Transaction id.

§replacing_txid: Vec<u8>

The replacing transaction id.

§

TxidEvicted

A watched tx left the mempool by policy.

Fields

§txid: Vec<u8>

Transaction id.

§reason: String

Free-text reason ("full_pool" | "expiry" | "block_conflict" | "policy").

§

TxidUnconfirmed

A watched tx’s confirming block was rolled back by a reorg.

Fields

§txid: Vec<u8>

Transaction id.

§prev_height: u32

Height it had been confirmed at, now disconnected.

§

TxidDepthReached

A depth alarm fired (single-shot).

Fields

§txid: Vec<u8>

Transaction id.

§depth: u32

Confirmations reached (>= the requested depth).

§height: u32

Active-chain height where the tx is confirmed.

§

TxidFinalized

A lifecycle watch’s auto_close_depth was reached (terminal).

Fields

§txid: Vec<u8>

Transaction id.

§depth: u32

Confirmations reached (>= auto_close_depth).

§height: u32

Active-chain height where the tx is confirmed.

§

PrefixMatched(PrefixMatch)

A transaction fell inside a watched script-prefix bucket.

§

Lagged

In-band slow-consumer lag notice. Not an error: reconnect (Subscribe) or re-anchor (Watch) with resume_cursor to recover the dropped events.

Fields

§dropped_count: u64

Number of events dropped before this notice.

§resume_cursor: Option<Cursor>

The anchor to resume from to recover the gap.

§

ReplayGap

SDK-synthesized — not a wire event. Emitted by ResilientSubscription when a durable replay was clamped by the server to the most recent MAX_REPLAY_BLOCKS (10,000) blocks, so the confirmed history in [resume_height, first_height - 1] was skipped. The live stream continues correctly from first_height; the gap is unrecoverable via this stream, so full-resync the skipped range from another source (e.g. RPC getblock). Emitted once per resume, immediately before the first replayed block.

Detection limit — absence of this event is not proof of a complete scan. It is synthesized by comparing the resume cursor against the first BlockConnected delivered. A subscription that filtered chain events out — a tweaks-only silent-payment scan, say — receives no BlockConnected, so a clamp it suffered passes unremarked here. Such a subscription is normally protected server-side instead (a tweaks-only replay against a complete index is exempt from the clamp, and a node whose index is incomplete refuses the subscribe outright rather than clamping it), but that protection lives on the node, not in this event. Do not treat this variant as a wallet’s only guard against a silent hole.

Fields

§resume_height: u32

The height the resume cursor expected next (cursor.height + 1).

§first_height: u32

The first height the server actually delivered (> resume_height).

§

CursorAccepted

A mid-stream re-anchor (WatchHandle::set_cursor) was admitted. Confirmed-history replay follows this event (in height order) before the live tail resumes. When clamped is true the requested cursor predated the server’s replay window: replay still runs, but only from earliest_replayed, so full-resync history below it from another source. This is the deterministic “accepted, replaying from X” signal.

Fields

§from: Option<Cursor>

The cursor the server anchored to.

§clamped: bool

true → the replay window truncated the lower end of the gap.

§earliest_replayed: u32

First height the server will replay.

§

CursorRejected

A mid-stream re-anchor (WatchHandle::set_cursor) was not admitted. The live stream is unchanged (still emitting from its prior position). Decide whether to retry, back off, or escalate to a full resnapshot based on reason; current_head is where the server is now.

Fields

§reason: CursorRejectReason

Why the re-anchor was declined.

§current_head: Option<Cursor>

The server’s current resume position.

§

WatchSetReplaced

An atomic watch-set replace (ResilientWatch::reload, carried as SetWatchSet) was applied. The live watch-set now equals the reloaded truth; the counts are the server’s authoritative diff by effective coverage (a scripthash covered by both the old and new set — even via a different mechanism — counts as unchanged, never gapped).

Fields

§added: u32

Items newly watched.

§removed: u32

Items released.

§unchanged: u32

Items in both the old and new set (kept without re-registration).

§

WatchSetRejected

An atomic watch-set replace was rejected; the live watch-set is UNCHANGED (the prior set is still in effect). reason says which ceiling refused it, and required/quota are in the matching unit: QuotaExceeded — required units vs the quota ceiling; CapExceeded — required entries vs the per-connection entry cap (quota); Malformed — a client bug (bad element), required/quota are 0 and retrying the same set will not help. In every case the client’s mirror still reflects the (unapplied) reloaded set, so a consumer that ignores this keeps an over-claiming mirror; react by reloading a set the server accepts.

Fields

§reason: WatchSetRejectReason

Why the replace was refused.

§required: u64

What the rejected target needs: units (QuotaExceeded) or entries (CapExceeded); 0 for Malformed.

§quota: u64

The ceiling that refused it: unit quota (QuotaExceeded) or entry cap (CapExceeded); 0 for Malformed.

§

RescanAccepted

A bounded historical rescan (ResilientWatch::rescan) was admitted. Confirmed watch-matches for the scanned range follow this event (in height order), terminated by a RescanComplete. from_height/to_height are the range the server will ACTUALLY scan: clamped is true when the requested upper bound exceeded the tip and was narrowed to it. A rescan is a side query — it does not advance the durable cursor, and its match events carry no resume cursor.

Fields

§from_height: u32

First height that will be scanned (post-clamp).

§to_height: u32

Last height that will be scanned (post-clamp).

§clamped: bool

true → the requested range was narrowed to what the node holds.

§

RescanRejected

A bounded historical rescan was not admitted; no matches follow and the live stream is unchanged. tip_height is the server’s current tip so a client can re-scope the range and retry.

Fields

§reason: RescanRejectReason

Why the rescan was declined.

§tip_height: u32

The server’s current active-chain tip height.

§

RescanComplete

Terminal marker for a bounded historical rescan: the range has been fully scanned and every match delivered. matches counts the match events this rescan emitted (0 when the range held none). After this the stream resumes its prior live position.

Fields

§from_height: u32

The scanned range (post-clamp), echoing RescanAccepted.

§to_height: u32

The scanned range upper bound (post-clamp).

§matches: u64

Number of match events emitted for this rescan.

§

BlockTweaks

One connected block’s silent-payment tweaks — the Tier 1 (client-side scan, zero-custody) firehose payload. Arrives only for a subscription that set the TWEAKS category bit. For each entry, a client computes T · b_scan with its own scan secret and derives the candidate output key(s), so the scan key never leaves the device. See [examples/sp_light_scan.rs].

Fields

§block_hash: Vec<u8>

The block these tweaks describe (internal/consensus byte order).

§height: u32

The block’s height.

§entries: Vec<TweakEntry>

One entry per silent-payment-eligible transaction in the block.

§filtered: bool

true when a subscription filter dropped entries from this block — the tweak_dust_limit floor, or tweak_unspent_only cut-through — so an empty entries may mean “filtered out”, not “none present”. A surviving entry always carries its full taproot output set; no filter trims one.

§

MempoolTweak

One accepted-but-unconfirmed transaction’s silent-payment tweak — the Tier 1.5 (mempool-time, zero-custody) firehose payload. Arrives only for a subscription that set the TWEAKS category bit and SubscribeOptions::mempool_tweaks. Scan it exactly like a BlockTweaks entry — compute T · b_scan and derive the candidate output key(s) — for mempool-latency detection. Ephemeral and best-effort: not replayable, no retraction on RBF/eviction; dedup by entry.txid (always present) against the confirmed BlockTweaks. See [examples/sp_light_scan.rs].

Fields

§entry: TweakEntry

The admitted transaction’s tweak. Always full (txid present) — tweaks_only does not apply to mempool tweaks.

§

SilentPaymentMatched

A BIP 352 silent payment paid a registered scan key — the Tier 2 (scan-key watch, convenience) match, delivered on the Watch stream to a connection that registered the target via WatchHandle::add_silent_payments. The node ran the ECDH; tweak + k let the wallet re-derive the output key — and, with its b_spend, the spending key — offline. See [examples/sp_wallet.rs].

Fields

§scan_pubkey: Vec<u8>

The registered target’s identity b_scan·G (33 bytes) this output paid — echoes which of your scan keys matched, never the secret.

§txid: Vec<u8>

The paying transaction’s txid (internal byte order — parse_txid / display_hex).

§vout: u32

The matched output’s index.

§output_pubkey: Vec<u8>

The matched taproot output key (32-byte x-only).

§amount: u64

The output value in satoshis.

§tweak: Vec<u8>

The transaction’s 33-byte public tweak T. With k, re-derive the full output key offline: P_k = B_spend + hash(b_scan·T || k)·G.

§k: u32

The BIP 352 output counter for this match — the k in the derivation.

§label: Option<u32>

The matched label integer, when the output paid a registered label (e.g. change is commonly label 0); None for an unlabeled match.

§confirmed: bool

true once seen in a connected block; false while only in the mempool (re-emitted true on confirmation).

§height: Option<u32>

The confirming block height; None while unconfirmed.

§raw_tx: Option<Vec<u8>>

The full serialized transaction, only when this connection opted in via SetWatchOptions.include_raw_tx; None otherwise.

§

WatchAddRejected(WatchAddRejected)

An incremental watch add (add_scripts, add_outpoints, …) that the server did not register: over the quota, over the per-add rate limit, over a per-connection cap, without stream:watch, or malformed. None of the items it names is watched. Items the add re-asserted (already watched) are not named and stay watched. The server sends nothing for an add that registered.

ResilientWatch re-sends a RateLimited add itself after the server’s retry hint, within its backoff budget, and hands the event on only once that budget runs out. For any other reason, or then, it drops the named items from its mirror before handing this on, so a reconnect does not re-register them; re-add them yourself if you want another try.

§

Unknown

A body this client build does not recognize (a newer server arm), or an event with no body set. Ignored by well-behaved consumers.

Trait Implementations§

Source§

impl Clone for Event

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Event

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<NodeEvent> for Event

Source§

fn from(ev: NodeEvent) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for Event

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Event

Auto Trait Implementations§

§

impl Freeze for Event

§

impl RefUnwindSafe for Event

§

impl Send for Event

§

impl Sync for Event

§

impl Unpin for Event

§

impl UnsafeUnpin for Event

§

impl UnwindSafe for Event

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more