Skip to content

dgb(#82): bind 5 won-block reconstruct seams to live tracker (decision (a), deadlock-safe) - #267

Merged
frstrtr merged 1 commit into
dgb/won-block-reconstruct-closurefrom
dgb/run-loop-consume-seams
Jun 20, 2026
Merged

dgb(#82): bind 5 won-block reconstruct seams to live tracker (decision (a), deadlock-safe)#267
frstrtr merged 1 commit into
dgb/won-block-reconstruct-closurefrom
dgb/run-loop-consume-seams

Conversation

@frstrtr

@frstrtr frstrtr commented Jun 20, 2026

Copy link
Copy Markdown
Owner

#82 run-loop consume — bind the 5 reconstruct seams to the LIVE tracker (decision (a))

Stacked on #265 (base branch dgb/won-block-reconstruct-closure). Fenced to main_dgb.cpp + node.hpp only — no shared/bitcoin_family/cross-coin touch.

What

Replaces the interim return nullopt reconstruct stub in run_node() with the faithful make_reconstruct_closure (#265), bound to the live ShareTracker via 5 seams:

  • share_fieldschain.get_share(h) → {min_header, merkle_link, tx refs}
  • gentx_bytesgenerate_share_transaction(...) SSOT regen
  • nth_parentchain.get_nth_parent_via_skip
  • new_tx_hashes → share m_new_transaction_hashes
  • known_txs → new non-locking NodeImpl::known_txs() const-ref accessor

Decision (a) — deadlock-safe (integrator + decisions, 2026-06-20)

The earlier-approved shared_lock snapshot would self-deadlock: m_on_block_found fires on the COMPUTE thread, which already holds m_tracker_mutex exclusively (run_think node.cpp:1433 unique_lock → think → attempt_verify → share_tracker.hpp:537). A shared_lock from the lock-owning thread on the non-recursive std::shared_mutex is UB. Fix (a): dropped snapshot_known_txs(), read state directly under the held exclusive lock via the non-locking accessor.

HARD CONDITION verified: none of the 5 seam reads re-takes m_tracker_mutex. grep confirms the mutex lives only in NodeImpl; ShareTracker + ShareChain + generate_share_transaction contain zero mutex/lock usage. (a) does not reintroduce the recursive deadlock a frame deeper.

Share-version guard

m_tx_info (tx refs) is on-wire only for share version < 34 (Share=17 / NewShare=33 — the p2pool-dgb-scrypt oracle baseline). The generic ShareVariants::invoke must compile for all 5 variants, so the two m_tx_info seams are if constexpr (requires {...}) guarded and fail closed for any unexpected-for-DGB v34+ segwit/merged won share.

Evidence

Gate status

The #82 dual-path broadcaster gate stays OPEN. The submitblock-RPC arm is still unarmed (coin_node rpc=nullptr; #163 seam guard = deferred-not-dropped, loud). Neither arm is verified until the live won-block-reaches-network test. HOLD merge (lands after #265).

…n a, deadlock-safe)

Replace the interim nullopt reconstruct stub in main_dgb.cpp --run path
with the faithful make_reconstruct_closure (#265), bound to the LIVE
ShareTracker via 5 seams: share_fields / gentx_bytes / nth_parent /
new_tx_hashes / known_txs. Adds a NON-LOCKING const-ref known_txs()
accessor to dgb::NodeImpl (node.hpp).

THREADING -- decision (a) (integrator + decisions, 2026-06-20): the prior
approval assumed m_on_block_found fires lock-free on the IO thread and the
seams would take a shared_lock snapshot. That premise was FALSIFIED: the
callback fires on the COMPUTE thread, which ALREADY holds m_tracker_mutex
EXCLUSIVELY (run_think node.cpp:1433 unique_lock -> think -> attempt_verify
-> share_tracker.hpp:537). A shared_lock from the lock-owning thread on the
non-recursive std::shared_mutex is UB/self-deadlock. Fix (a): drop the
by-value snapshot_known_txs(), read chain + known-tx state DIRECTLY under
the exclusive lock the compute thread already owns (non-locking accessor).

HARD CONDITION verified (integrator): none of the 5 seam reads re-takes
m_tracker_mutex -- grep confirms the mutex lives ONLY in NodeImpl
(node.cpp/node.hpp); ShareTracker + ShareChain (chain.get_share,
get_nth_parent_via_skip) and generate_share_transaction contain ZERO
mutex/lock_guard/unique_lock/shared_lock. So (a) does NOT reintroduce the
recursive self-deadlock one frame deeper.

SHARE-VERSION GUARD: m_tx_info (new_transaction_hashes +
transaction_hash_refs) is on-wire ONLY for share version < 34 (Share=17 /
NewShare=33 -- the p2pool-dgb-scrypt oracle baseline). The generic
ShareVariants::invoke must compile for all 5 variants, incl. v34+
segwit/merged which carry no tx refs in the DGB share format, so the two
m_tx_info seams are if-constexpr requires-guarded and fail closed (throw ->
caught -> nullopt, never a malformed broadcast) for any unexpected-for-DGB
v34+ won share.

Fenced to main_dgb.cpp + node.hpp. build_dgb green; #265 KAT 6/6 green;
binary --help/selftest OK. The #82 dual-path broadcaster gate stays OPEN:
the submitblock-RPC arm is still unarmed (coin_node rpc=nullptr, #163 seam
guard = deferred-not-dropped, loud) and neither arm is verified until the
live won-block-reaches-network test. HOLD merge (stacked on #265).
@frstrtr
frstrtr merged commit 9046dae into dgb/won-block-reconstruct-closure Jun 20, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant