-
Notifications
You must be signed in to change notification settings - Fork 0
01 event bus
Companion to
00-overview. This is the authoritative, source-verified reference for everychaseenumerator: payload, issuer sites, handler sites, and known discrepancies with the inlinechase.hppdocumentation.Every fact below is grep-derived. Methodology and queries are in §4 so any future change can be re-verified mechanically.
event_subscriber_ : full_node // include/bitcoin/node/full_node.hpp:198
= network::desubscriber<object_key, chase, event_value> // define.hpp:87
A desubscriber is the libbitcoin-network primitive that combines pub/sub
with explicit unsubscription via a key. All subscribers share one bus.
There are two subscribe APIs, both eventually owning state on the
full_node strand:
| API | Used by | Strand discipline |
|---|---|---|
subscribe_events(notifier) → object_key (sync) |
chasers | Caller must already be on full_node strand |
subscribe_events(notifier, completer) (async) |
protocols | Posts to full_node strand internally; completer fires there |
Chaser subscription path (include/bitcoin/node/chasers/chaser.hpp:101,
src/chasers/chaser.cpp:92-94):
chaser::subscribe_events
→ full_node::subscribe_events(handler) // src/full_node.cpp:219-225
→ event_subscriber_.subscribe(handler, key)
The BIND macro that produces notifier re-posts the handler back to the
chaser's own strand, so handlers always execute stranded with respect to
their owning chaser. Each chaser subscribes exactly once, in its start(),
via SUBSCRIBE_EVENTS(handle_event, _1, _2, _3) — see
include/bitcoin/node/chasers/chaser.hpp:167-168 for the macro.
Protocol subscription path (src/protocols/protocol.cpp:72-89):
protocol::subscribe_events
→ session::subscribe_events(handler, complete) // src/sessions/session.cpp:86-90
→ full_node::subscribe_events(handler, complete) // src/full_node.cpp:227-242
→ posts to strand → do_subscribe_events
→ event_subscriber_.subscribe(handler, key)
→ complete(ec, key)
The async variant exists because a protocol is constructed on its channel strand, not the node strand, so it must hop across.
chaser/protocol calls notify(ec, chase::X, value)
→ full_node::notify posts to strand // src/full_node.cpp:187-193
→ do_notify on strand
→ event_subscriber_.notify(ec, X, value)
→ for each subscriber: re-post to subscriber's own strand
full_node::unsubscribe_events(key) does not remove the entry; it sends a
single chase::stop to that subscriber only
(src/full_node.cpp:244-247). The subscriber's handle_event returns
false on chase::stop, and the desubscriber interprets that as
removal. So:
Invariant (Bus-1). A
falsereturn fromhandle_eventmeans "remove me". Every chaser returnsfalseonchase::stop(verified: eachchaser_*.cpphascase chase::stop: return false;).
Invariant (Bus-2). The bus is torn down only in
full_node::do_close, which broadcastschase::stopto all subscribers (src/full_node.cpp:154). After that point no furthernotifywill deliver.
Notation:
-
Payload column shows the active variant member; types are in
include/bitcoin/node/define.hpp:70-75. -
Issuer is every
notify(... chase::X ...)ornotify_one(... chase::X ...)call site that is not commented out. -
Handler is every
case chase::X:arm that is not commented out. - Discrepancies with the
chase.hppinline doc are flagged ⚠.
| Event | Payload | Issuer (file:line) | Handler (file:line) |
|---|---|---|---|
start |
height_t |
src/full_node.cpp:115 (do_run) |
chaser_check.cpp:130, chaser_validate.cpp:77, chaser_confirm.cpp:75
|
space |
count_t |
src/full_node.cpp:279 (fault when query_.is_full()) |
chaser_storage.cpp:84 (chaser_snapshot.cpp does not handle space currently) |
snap |
height_t |
none ⚠ — chase.hpp says issued by confirm, but no live notify(chase::snap, ...) in source |
chaser_snapshot.cpp:126 |
bump |
height_t |
chaser_organize.ipp:311 (after first non-stale candidate push) |
chaser_check.cpp:131, chaser_validate.cpp:78, chaser_confirm.cpp:76
|
suspend |
— ({}) |
src/full_node.cpp:270 (suspend); also chaser_organize.ipp:442 (after do_disorganize) ⚠ |
protocol_observer.cpp:77 (only) |
resume |
— ({}) |
src/full_node.cpp:261 |
chaser_check.cpp:129, chaser_validate.cpp:76, chaser_confirm.cpp:74
|
starved |
object_t |
src/protocols/protocol_block_in_31800.cpp:423 |
chaser_check.cpp:120 |
split |
object_t |
src/chasers/chaser_check.cpp:238 (via notify_one) ⚠ |
src/protocols/protocol_block_in_31800.cpp:108 |
stall |
peer_t |
src/chasers/chaser_check.cpp:243 ⚠ |
src/protocols/protocol_block_in_31800.cpp:115 |
purge |
peer_t |
src/chasers/chaser_check.cpp:351 |
src/protocols/protocol_block_in_31800.cpp:123 |
report |
count_t |
external — issued by executor in libbitcoin-server, not in this repo |
src/protocols/protocol_block_in_31800.cpp:139 |
Discrepancy notes:
- ⚠
split,stall:chase.hpp:60-66listssession_outboundas the issuer, but the actual emits are inchaser_check. The functional intent matches (slow/stalled channel detection drives work redistribution), but the issuer is mislabeled in the inline doc. - ⚠
suspendis also issued bychaser_organizeafter a disorganization (chaser_organize.ipp:442), not only byfull_node. The comment in chase.hpp omits this. - ⚠
snaphas no live issuer anywhere in this repo. The handler inchaser_snapshot.cpp:126is wired but unreachable from the current source. Treat as a planned/dormant event.
| Event | Payload | Issuer (file:line) | Handler (file:line) |
|---|---|---|---|
blocks |
height_t |
chaser_organize.ipp:318 when Block = system::chain::block (via chase_object() helper) |
None active. ⚠ chaser_snapshot.cpp:89 has a commented-out arm. Spec-wise: handler dormant. |
headers |
height_t |
chaser_organize.ipp:318 when Block = system::chain::header
|
chaser_check.cpp:151 |
download |
count_t |
chaser_check.cpp:409, chaser_check.cpp:455
|
protocol_block_in_31800.cpp:130 |
regressed |
height_t |
chaser_organize.ipp:265 |
chaser_check.cpp:142, chaser_validate.cpp:90, chaser_confirm.cpp:88
|
disorganized |
height_t |
chaser_organize.ipp:439 |
chaser_check.cpp:143, chaser_validate.cpp:91, chaser_confirm.cpp:89
|
Notes:
-
chase_object()is the template helper atchaser_organize.hpp:127-130that selectschase::blocksvschase::headersbased onBlockparameter. So one source line (ipp:318) is the issuer of both events — choose-by-template. -
chase::blockshas no live handler today (snapshot's handler is commented out atchaser_snapshot.cpp:89). This is consistent with the current emphasis on headers-first sync.
| Event | Payload | Issuer (file:line) | Handler (file:line) |
|---|---|---|---|
checked |
height_t |
protocol_block_in_31800.cpp:348 |
chaser_check.cpp:136, chaser_validate.cpp:83 (snapshot arm commented out at chaser_snapshot.cpp:90) |
unchecked |
header_t |
protocol_block_in_31800.cpp:324 |
chaser_organize.ipp:89 (handled identically with unvalid, unconfirmable) |
| Event | Payload | Issuer (file:line) | Handler (file:line) |
|---|---|---|---|
valid |
height_t |
chaser_validate.cpp:330 |
chaser_check.cpp:157, chaser_confirm.cpp:81 (snapshot arm commented out at chaser_snapshot.cpp:99) |
unvalid |
header_t |
chaser_validate.cpp:321 |
chaser_organize.ipp:90 (treated as disorganize trigger) |
| Event | Payload | Issuer (file:line) | Handler (file:line) |
|---|---|---|---|
confirmable |
header_t |
chaser_confirm.cpp:345 |
None active (snapshot arm commented out at chaser_snapshot.cpp:108) |
unconfirmable |
header_t |
chaser_confirm.cpp:338 |
chaser_organize.ipp:91 |
| Event | Payload | Issuer (file:line) | Handler (file:line) |
|---|---|---|---|
block |
header_t |
chaser_confirm.cpp:427 ⚠ |
chaser_snapshot.cpp:117, protocol_block_out_106.cpp:75, protocol_header_out_70012.cpp:71
|
organized |
header_t |
chaser_confirm.cpp:396 |
None active (chase.hpp predicts transaction consumer; not wired) |
reorganized |
header_t |
chaser_confirm.cpp:363 |
None active (chase.hpp predicts transaction consumer; not wired) |
transaction |
transaction_t |
chaser_transaction.cpp:85 |
chaser_template.cpp:67, protocol_transaction_out_106.cpp:72
|
template_ |
height_t |
none ⚠ — chase.hpp says template issues; currently dormant |
(miners, external) |
Discrepancy:
- ⚠
chase::block:chase.hpp:138says "Issued by 'transaction' and handled by 'protocol_header/block_out'". In realitychaser_confirmissues it (chaser_confirm.cpp:427), andchaser_snapshotis also a live consumer (chaser_snapshot.cpp:117).
| Event | Payload | Issuer (file:line) | Handler |
|---|---|---|---|
stop |
— ({}) |
full_node::unsubscribe_events via notify_one (src/full_node.cpp:246); full_node::do_close via event_subscriber_.stop(...) (src/full_node.cpp:154) |
Every chaser & protocol |
This replaces and supersedes the pipeline diagram in 00-overview §5,
with one node per actual source location rather than per chase.hpp
comment.
flowchart LR
%% Issuers
FN[full_node]
ORG["chaser_organize<Block>\n(template; instantiated as\nchaser_header and chaser_block)"]
CHK[chaser_check]
VAL[chaser_validate]
CNF[chaser_confirm]
TX[chaser_transaction]
PIN["protocol_block_in_31800"]
%% Handlers (only those that introduce new edges)
SNP[chaser_snapshot]
STG[chaser_storage]
TPL[chaser_template]
OBS[protocol_observer]
POUT_B["protocol_block_out_106"]
POUT_H["protocol_header_out_70012"]
POUT_T["protocol_transaction_out_106"]
%% Edges (event labels)
FN -- "start, resume, suspend, space, stop" --> CHK
FN -- "start, resume" --> VAL
FN -- "start, resume" --> CNF
FN -- "space" --> STG
FN -- "suspend" --> OBS
ORG -- "regressed, disorganized, bump" --> CHK
ORG -- "regressed, disorganized, bump" --> VAL
ORG -- "regressed, disorganized, bump" --> CNF
ORG -- "suspend (after disorganize)" --> OBS
ORG -- "headers" --> CHK
ORG -. "blocks (no live consumer)" .-> SNP
PIN -- "checked" --> CHK
PIN -- "checked" --> VAL
PIN -- "unchecked" --> ORG
PIN -- "starved" --> CHK
CHK -- "download, split, stall, purge" --> PIN
CHK -- "purge (also re-handles disorganize indirectly via organize)" --> ORG
VAL -- "valid" --> CHK
VAL -- "valid" --> CNF
VAL -- "unvalid" --> ORG
CNF -. "confirmable (dormant)" .-> SNP
CNF -- "unconfirmable" --> ORG
CNF -- "block" --> SNP
CNF -- "block" --> POUT_B
CNF -- "block" --> POUT_H
TX -- "transaction" --> TPL
TX -- "transaction" --> POUT_T
style ORG fill:#eef
style CNF fill:#fee
style VAL fill:#fee
style CHK fill:#fee
(Solid = live; dashed = wired in source but currently dormant.)
The tables above were generated by these greps from repo root:
# Issuers (excluding notify_one)
grep -rn 'notify(.*chase::' src include | grep -v 'notify_one'
# Issuers via notify_one
grep -rn 'notify_one(.*chase::' src include
# Handlers
grep -rn 'case chase::' src include
# Subscription sites
grep -rn 'SUBSCRIBE_EVENTS\|subscribe_events' src
# Indirect issuers via the chase_object() template helper
grep -rn 'chase_object' src includeTo recheck after source changes, run the same set and diff against the tables here. Any new row must come with its source citation, and any deletion should be cross-referenced with this doc to ensure no downstream spec assumes the old behaviour.
A formal model can treat the bus as follows.
Processes. Each chaser and each event-subscribing protocol is a
process P with:
- a single inbox typed
(code, chase, event_value) - a private state space
Σ_P - a deterministic transition
δ_P : Σ_P × (code, chase, event_value) → Σ_P × Output_P - where
Output_Pis a finite set ofnotifycalls and outbound asynchronous actions (e.g. DB writes).
Bus. The bus is broadcast-with-filter: every notify(ec, X, v) is
delivered to every subscriber, and each subscriber's handle_event
inspects the chase value to decide whether to act.
Invariants worth proving.
-
Liveness of stop: after
full_node::do_close, every process eventually reaches a terminal state. (Follows from Bus-2 + the universalcase chase::stop: return false;.) -
Disorganize convergence: every
chase::regressed/disorganizedis eventually responded to by the consuming chasers' "rewind" branches (chaser_check.cpp:142-143,chaser_validate.cpp:90-91,chaser_confirm.cpp:88-89) before the next forward event is processed. -
No spurious validation:
chase::validis emitted only afterchaser_validatehas executed its validation routine on the height (chaser_validate.cpp:330is the unique emit site). -
Confirm uniqueness:
chase::confirmable,unconfirmable,organized,reorganized,blockall have a single issuer (chaser_confirm). Confirmation is centralized.
Dormant events (do not model as live).
-
chase::snap— handler exists, no issuer. -
chase::template_— handler is "miners" (external), no issuer in this repo. -
chase::report— issuer isexecutor(external, libbitcoin-server).
-
00-overview§3 (concurrency model) and §4 (high-level event table). -
02-chaser-organize— the templated state machine that emitsbump,regressed,disorganized,headers/blocks,suspend. -
04-chaser-validate— the unique issuer ofvalid/unvalid.
Users | Developers | License | Copyright © 2011-2018 libbitcoin developers