dash(embedded/E1): opt-in coin-network P2P client + outbound dial in run_node#743
Merged
Conversation
…run_node Wire the DASH embedded (daemonless) arm to establish a live outbound connection to the Dash coin network, gated behind a new opt-in flag so the released binary's run path is byte-identical when the flag is absent. New src/impl/dash/coin/p2p_client.hpp — dash::coin::p2p::CoinClient<Config>: the outbound-dial counterpart of the S8 socket-node skeleton. Ported 1:1 from the proven per-coin clients (dgb <- btc <- ltc), trimmed to the E1 scope (dial + version/verack handshake + ping keep-alive + reconnect), with NO ingest legs. Extracts two pure, KAT-able helpers: HandshakeTracker (version/verack state machine) and DialPlan (round-robin over repeatable targets). main_dash.cpp run_node: new repeatable --coin-p2p-connect HOST:PORT flag. ABSENT => no client instantiated, NodeCoinState stays default-unpopulated, get_work() keeps the retained dashd-RPC fallback (the mining-hotel prod posture) untouched. PRESENT => CoinClient dials on the SAME ioc as the sharechain node, handshakes (proto 70230, testnet magic cee2caff / mainnet bf0c6bbd), keep-alives, and reconnects (30s, rotating the dial plan). E2 seam: the client parses inbound tx/block/headers/inv/clsig/mnlistdiff and fires the existing dash::interfaces::Node events (new_block/new_tx/ full_block/new_headers/new_chainlock) plus a set_on_handshake_complete hook. With no subscribers in E1 these are no-ops; later slices attach CoinStateMaintainer/HeaderChain/Mempool ingest to that event surface. Verify: - 11 new KATs in test_dash_coin_p2p_client.cpp, compiled into the existing allowlisted test_dash_p2p_node target (no workflow edit); 16/16 pass. - Live smoke vs a controlled testnet dashd: outbound connect + handshake complete (peer Dash Core 22.1.3, proto 70237, height 1517161), stayed up 65s with no disconnect, reconnect retry fires at exactly 30s on a dead endpoint. No-flag run path confirmed unchanged. --selftest green; existing dash p2p tests green. Links dash_block_replay (coin/vendor/blockencodings.cpp) into c2pool-dash and test_dash_p2p_node: the full coin-network Handler the client instantiates ODR-uses CBlockHeaderAndShortTxIDs::FillShortTxIDSelector(). Dash-fenced: src/impl/dash + src/c2pool/main_dash.cpp only; no src/core edit.
frstrtr
pushed a commit
that referenced
this pull request
Jul 19, 2026
…te NodeCoinState E1 (#743) landed a coin-network P2P client that fires the raw dash::interfaces:: Node wire events; E2b (#745) landed the UTXO/fee lane. Nothing joined them into a live populate loop. E2a is that join, entirely behind --coin-p2p-connect (+ --embedded-utxo): with no flag, run_node is byte-unchanged. What got wired (src/impl/dash/coin/live_feed.hpp + main_dash.cpp): - new_headers -> HeaderChain::add_headers (X11 + DarkGravityWave validated) -- the tip authority; HeaderChain::set_on_tip_changed derives a TipAdvance (next-work bits, median-time-past, address versions) and fires Node::new_tip -> wire_tip_ingest -> CoinStateMaintainer::on_new_tip (tip readiness). - new_tx -> wire_mempool_ingest -> maintainer.on_mempool_tx. - full_block -> (X11 hash -> header-chain height) -> Node::block_connected, driving BOTH wire_block_connect_ingest (MnStateMachine::apply_block) AND the E2b UTXO lane connect_block + fee recompute from one fired event. - new_block(inv) -> request_block (getdata pull); new_chainlock -> best-CL tracker. - mn_list_update leg wired for completeness (the payout-bearing DMN set source). - set_on_handshake_complete kicks initial sync (getheaders + mempool); header self-propel requests the next batch off the updated locator. - UTXO bootstrap request-by-height seam bound to the coin-P2P full-block pull. BlockType parser (src/impl/dash/coin/block.hpp): closes the S5 header-only deferral -- BlockType now (de)serializes the standard Bitcoin block body (CompactSize tx-count + txs), mirroring the DGB sibling minus witness. This lets a live dashd `block` body deserialize into the tx set the ingest legs consume, and makes the multi-entry `headers` message round-trip (each entry = 80B header + CompactSize(0)). HeaderChain gains median_time_past() (BIP113). #739 folded in: on a real tip change the header-chain callback bumps work_generation_ + notify_all() sessions (event-driven stale-work notify). KATs: block-body tx-set round-trip + 81-byte empty-body pin (test_dash_p2p_ messages); live-feed bridge translation (test_dash_live_feed_bridge in the test_dash_node_reception_wire target). All affected dash targets green; --selftest green.
frstrtr
pushed a commit
that referenced
this pull request
Jul 19, 2026
…te NodeCoinState E1 (#743) landed a coin-network P2P client that fires the raw dash::interfaces:: Node wire events; E2b (#745) landed the UTXO/fee lane. Nothing joined them into a live populate loop. E2a is that join, entirely behind --coin-p2p-connect (+ --embedded-utxo): with no flag, run_node is byte-unchanged. What got wired (src/impl/dash/coin/live_feed.hpp + main_dash.cpp): - new_headers -> HeaderChain::add_headers (X11 + DarkGravityWave validated) -- the tip authority; HeaderChain::set_on_tip_changed derives a TipAdvance (next-work bits, median-time-past, address versions) and fires Node::new_tip -> wire_tip_ingest -> CoinStateMaintainer::on_new_tip (tip readiness). - new_tx -> wire_mempool_ingest -> maintainer.on_mempool_tx. - full_block -> (X11 hash -> header-chain height) -> Node::block_connected, driving BOTH wire_block_connect_ingest (MnStateMachine::apply_block) AND the E2b UTXO lane connect_block + fee recompute from one fired event. - new_block(inv) -> request_block (getdata pull); new_chainlock -> best-CL tracker. - mn_list_update leg wired for completeness (the payout-bearing DMN set source). - set_on_handshake_complete kicks initial sync (getheaders + mempool); header self-propel requests the next batch off the updated locator. - UTXO bootstrap request-by-height seam bound to the coin-P2P full-block pull. BlockType parser (src/impl/dash/coin/block.hpp): closes the S5 header-only deferral -- BlockType now (de)serializes the standard Bitcoin block body (CompactSize tx-count + txs), mirroring the DGB sibling minus witness. This lets a live dashd `block` body deserialize into the tx set the ingest legs consume, and makes the multi-entry `headers` message round-trip (each entry = 80B header + CompactSize(0)). HeaderChain gains median_time_past() (BIP113). work_generation_ + notify_all() sessions (event-driven stale-work notify). KATs: block-body tx-set round-trip + 81-byte empty-body pin (test_dash_p2p_ messages); live-feed bridge translation (test_dash_live_feed_bridge in the test_dash_node_reception_wire target). All affected dash targets green; --selftest green.
frstrtr
added a commit
that referenced
this pull request
Jul 19, 2026
…te NodeCoinState (#747) E1 (#743) landed a coin-network P2P client that fires the raw dash::interfaces:: Node wire events; E2b (#745) landed the UTXO/fee lane. Nothing joined them into a live populate loop. E2a is that join, entirely behind --coin-p2p-connect (+ --embedded-utxo): with no flag, run_node is byte-unchanged. What got wired (src/impl/dash/coin/live_feed.hpp + main_dash.cpp): - new_headers -> HeaderChain::add_headers (X11 + DarkGravityWave validated) -- the tip authority; HeaderChain::set_on_tip_changed derives a TipAdvance (next-work bits, median-time-past, address versions) and fires Node::new_tip -> wire_tip_ingest -> CoinStateMaintainer::on_new_tip (tip readiness). - new_tx -> wire_mempool_ingest -> maintainer.on_mempool_tx. - full_block -> (X11 hash -> header-chain height) -> Node::block_connected, driving BOTH wire_block_connect_ingest (MnStateMachine::apply_block) AND the E2b UTXO lane connect_block + fee recompute from one fired event. - new_block(inv) -> request_block (getdata pull); new_chainlock -> best-CL tracker. - mn_list_update leg wired for completeness (the payout-bearing DMN set source). - set_on_handshake_complete kicks initial sync (getheaders + mempool); header self-propel requests the next batch off the updated locator. - UTXO bootstrap request-by-height seam bound to the coin-P2P full-block pull. BlockType parser (src/impl/dash/coin/block.hpp): closes the S5 header-only deferral -- BlockType now (de)serializes the standard Bitcoin block body (CompactSize tx-count + txs), mirroring the DGB sibling minus witness. This lets a live dashd `block` body deserialize into the tx set the ingest legs consume, and makes the multi-entry `headers` message round-trip (each entry = 80B header + CompactSize(0)). HeaderChain gains median_time_past() (BIP113). work_generation_ + notify_all() sessions (event-driven stale-work notify). KATs: block-body tx-set round-trip + 81-byte empty-body pin (test_dash_p2p_ messages); live-feed bridge translation (test_dash_live_feed_bridge in the test_dash_node_reception_wire target). All affected dash targets green; --selftest green. Co-authored-by: integrator <integrator@morisguide.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
SLICE E1 — DASH embedded coin-network dial (issue #738)
First slice of the DASH embedded (daemonless) wiring campaign: make the embedded arm establish a live outbound connection to the Dash coin network so later slices can populate
NodeCoinStateand build templates without a local dashd. E1 scope = instantiate the coin P2P client + dial + maintain the connection. Ingest / state population / mempool pull / fee pricing are later slices.Opt-in flag design (hard safety constraint)
A mining hotel runs the retained dashd-RPC fallback path in production right now (
NodeCoinStatedefault-unpopulated →get_work()takes the fallback). This change is strictly opt-in:--coin-p2p-connect HOST:PORTrun_nodebehavior is byte-identical to today, fallback arm untouched.dash::coin::p2p::CoinClientdials the given endpoint(s) on the sameiocas the sharechain node, handshakes, keep-alives, and reconnects.Even with the flag,
NodeCoinStatestays unpopulated in E1 (no ingest legs yet), so the fallback still serves templates — no mining-path regression in either mode.What's wired
src/impl/dash/coin/p2p_client.hpp—CoinClient<Config>: the outbound-dial counterpart of the S8 socket-node skeleton (p2p_node.hpp). Ported 1:1 from the proven per-coin clients (dgb <- btc <- ltc), trimmed to E1: dial (viacore::Factory<core::Client>), version/verack handshake (proto 70230, the version the vendored SML/clsig codecs assume), 30s ping keep-alive, idle/handshake-timeout teardown, 30s reconnect rotating the dial plan. Two pure helpers extracted for KATs:HandshakeTracker(version/verack state machine) andDialPlan(round-robin over repeated targets).main_dash.cpprun_node— flag parse/validation + gated client standup. Coin-network wire magic (bf0c6bbdmain /cee2cafftestnet) sourced intoconfig.coin()->m_p2p.prefix, kept distinct from the sharechain PREFIX. Client declared afterconfig/coin_stateso it tears down before them at scope exit.No-flag-unchanged guarantee
Live-verified:
--run --testnetwith no--coin-p2p-connectemits zero coin-network client lines; run-loop stands up, fallback armUNARMED, sharechain listener + stratum exactly as before.Live-smoke result (E1 gate) — PASS
Against a controlled testnet dashd (
192.168.86.52:19999):dialing00:50:30 →reconnecting00:51:00).Tests
test/test_dash_coin_p2p_client.cpp): handshake state machine (legal progression, verack-before-version tolerance, stray/duplicate rejection, reset), dial-plan rotation, and byte-exactversion/verackdrive through the realHandler::parsepath (peer metadata capture, handshake completion,on_handshake_completeseam, unknown-command tolerance, error-teardown-for-redial).test_dash_p2p_nodetarget (second TU) — nobuild.yml/workflow edit. 16/16 pass (5 original skeleton + 11 new).--selftestgreen;test_dash_p2p_messages(7) andtest_dash_p2p_connection(4) green.E2 seam exposed
The client parses inbound
tx/block/headers/inv/clsig/mnlistdiffand fires the existingdash::interfaces::Nodeevents (new_block/new_tx/full_block/new_headers/new_chainlock), plus aset_on_handshake_complete(cb)hook to kick initial sync. In E1 there are no subscribers, so every event is a no-op andNodeCoinStatestays unpopulated. E2 attaches its ingest legs (CoinStateMaintainer/HeaderChain/Mempool) to exactly that event surface + the handshake hook — zero change to the client to light it up.Isolation
Dash-fenced:
src/impl/dash+src/c2pool/main_dash.cpponly; nosrc/coreedit. Links the additivedash_block_replaystatic lib (coin/vendor/blockencodings.cpp) intoc2pool-dashandtest_dash_p2p_node— the full coin-networkHandlerthe client instantiates ODR-usesCBlockHeaderAndShortTxIDs::FillShortTxIDSelector().