Skip to content

Commit 86020b7

Browse files
committed
dash(S8): main_dash --stratum run-path caller — StratumServer <-> DASHWorkSource standup
Closes the S8 "no run-path caller" gap: the DASHWorkSource IWorkSource seam (#706, 4a skeleton + 4b bodies) and the subscribe->notify->submit KATs (#630-634) had no production caller — a real main that constructs the work source and binds a core::StratumServer to it. This is that caller. - main_dash.cpp: --stratum [HOST:]PORT argv (SSOT parse_listen); threaded into run_node; node_coin_state -> DASHWorkSource -> StratumServer standup; won-block dispatch via the EXISTING dashd-RPC submitblock arm (rpc->submit_block_hex) — embedded P2P relay leg stays S8; UNARMED path logs loudly, never a silent drop. Destruction order: stratum_server declared before the work source it references; explicit reset() after ioc.run(). dashd-RPC fallback RETAINED (never removed). - src/c2pool/CMakeLists.txt: link dash_stratum into c2pool-dash (the 4b work_source.cpp bodies) — without it the executable failed to link (undefined DASHWorkSource ctor). Build-glue for the caller. Verified Linux x86_64: c2pool-dash links clean; --run --stratum 127.0.0.1:13333 stands up the acceptor (DASHWorkSource constructed, StratumServer bound, clean stop). subscribe->notify->submit binding is KAT-covered at the work_source seam (#630-634). No other-coin / shared- base edit; per-coin isolation held.
1 parent 6de623b commit 86020b7

2 files changed

Lines changed: 110 additions & 3 deletions

File tree

src/c2pool/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ target_link_libraries(c2pool-dash
315315
c2pool_payout c2pool_merged_mining c2pool_hashrate c2pool_storage c2pool_difficulty
316316
dash_x11 # DASH X11 PoW sph reference (BLAKE->...->ECHO), additive static lib
317317
dash_rpc # launcher slice-3: external-dashd-RPC client (submitblock fallback)
318+
dash_stratum # S8: DASHWorkSource IWorkSource bodies (stratum accept-loop caller)
318319
btclibs
319320
yaml-cpp::yaml-cpp
320321
nlohmann_json::nlohmann_json

src/c2pool/main_dash.cpp

Lines changed: 109 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@
6565
#include <impl/dash/params.hpp> // dash::make_coin_params (already via top include)
6666
#include <core/uint256.hpp> // uint160 payout pubkey hash
6767

68+
#include <core/stratum_server.hpp> // core::StratumServer — miner-facing accept-loop (run-path caller)
69+
#include <impl/dash/stratum/work_source.hpp> // dash::stratum::DASHWorkSource — concrete core::stratum::IWorkSource
70+
6871
#include <boost/asio.hpp>
6972

7073
#include <cstdint>
@@ -164,11 +167,16 @@ void print_banner(const char* argv0)
164167
<< " " << argv0 << " --run [--coin-rpc H:P] [--coin-rpc-auth PATH]\n"
165168
<< " [--testnet] [--submit-block HEX | --submit-block-file PATH]\n"
166169
<< " [--listen [HOST:]PORT] [--addnode HOST:PORT]... [--connect HOST:PORT]...\n"
170+
<< " [--stratum [HOST:]PORT]\n"
167171
<< " " << argv0 << " --mine-block [--coin-rpc H:P] [--coin-rpc-auth PATH]\n"
168172
<< " [--testnet] [--payout-pubkey-hash HEX] [--max-nonce N]\n\n"
169173
<< "Status: consensus layer live (X11 PoW, subsidy, oracle CoinParams).\n"
170174
<< " --run stands up the run-loop and ARMS the external-dashd\n"
171175
<< " submitblock fallback (creds from dash.conf, never on argv).\n"
176+
<< " --stratum [HOST:]PORT binds the miner-facing Stratum accept-\n"
177+
<< " loop (DASHWorkSource seam; e.g. --stratum 3333 or\n"
178+
<< " --stratum 127.0.0.1:3333); omit to disable. Won X11 blocks\n"
179+
<< " dispatch via the retained dashd-RPC submitblock arm.\n"
172180
<< " --submit-block[-file] drives ONE real submitblock then exits\n"
173181
<< " (the won-block-reaches-network leg); embedded P2P relay = S8.\n"
174182
<< "Consensus: X11 PoW + block identity; 2.5 min spacing; 5 DASH post-V20\n"
@@ -311,7 +319,8 @@ int run_selftest()
311319
// the gate.
312320
int run_node(bool testnet, const std::string& rpc_endpoint,
313321
const std::string& rpc_conf_path, const std::string& submit_hex,
314-
const PeeringConfig& peer)
322+
const PeeringConfig& peer,
323+
const std::string& stratum_host, uint16_t stratum_port)
315324
{
316325
namespace io = boost::asio;
317326

@@ -327,9 +336,19 @@ int run_node(bool testnet, const std::string& rpc_endpoint,
327336
conf.port = testnet ? 19998 : 9998; // dashd default RPC ports
328337

329338
io::io_context ioc;
339+
340+
// Miner-facing Stratum acceptor handle, declared BEFORE the signal_set so
341+
// the shutdown callback can stop it (cancel acceptor + close sessions)
342+
// ahead of ioc.stop(). Populated below once the DASHWorkSource is built.
343+
std::unique_ptr<core::StratumServer> stratum_server;
344+
330345
io::signal_set signals(ioc, SIGINT, SIGTERM);
331-
signals.async_wait([&ioc](const boost::system::error_code&, int) {
346+
signals.async_wait([&ioc, &stratum_server](const boost::system::error_code&, int) {
332347
std::cout << "[run] shutdown signal -- stopping run-loop\n";
348+
// Stop stratum BEFORE ioc.stop() so the acceptor cancels and live miner
349+
// sessions close cleanly (their pending async ops unwind on the loop).
350+
if (stratum_server)
351+
stratum_server->stop();
333352
ioc.stop();
334353
});
335354

@@ -406,9 +425,84 @@ int run_node(bool testnet, const std::string& rpc_endpoint,
406425
// reception — version handshake + the #646 min-proto gate — is live now
407426
// via node.cpp (#656/#657).
408427

428+
// ── S8 miner-facing Stratum accept-loop standup (run-path caller) ─────
429+
// This is the production caller the DASHWorkSource 4a/4b skeleton (#706)
430+
// and the subscribe->notify->submit KATs (#630-634) were built for: a real
431+
// main constructs the work source and binds a core::StratumServer to it.
432+
//
433+
// node_coin_state MUST outlive work_source and stratum_server (DASHWorkSource
434+
// holds a non-owning const ref to it). It is declared here, in run_node's
435+
// scope, BEFORE work_source; the explicit stratum_server.reset() after
436+
// ioc.run() tears the acceptor down while node_coin_state is still alive.
437+
// Default (unpopulated) bundle: populated()==false, so get_work() takes the
438+
// retained dashd-fallback arm -- correct + documented for the 4a standup.
439+
dash::coin::NodeCoinState node_coin_state;
440+
441+
// REQUIRED always-reachable dashd-RPC fallback arm -- the safety +
442+
// [GBT-XCHECK] cross-check path, NEVER removed (operator standing rule). For
443+
// this skeleton standup it returns the documented set-gap default; wiring it
444+
// from NodeRPC getblocktemplate -> DashWorkData is a deferred sub-slice.
445+
std::function<dash::coin::DashWorkData()> dashd_fallback =
446+
[]() -> dash::coin::DashWorkData { return dash::coin::DashWorkData{}; };
447+
448+
// Won-block dispatch: mirrors the DGB stratum_submit_fn. On a won X11 block,
449+
// HexStr the bytes, log a [DASH-STRATUM-BLOCK] line, and dispatch via the
450+
// EXISTING external-dashd submitblock-RPC arm (rpc->submit_block_hex). If the
451+
// RPC arm is UNARMED (no dash.conf creds), no sink is reached (the embedded
452+
// P2P relay arm is S8) -- log loudly and return false; never a silent drop.
453+
dash::stratum::DASHWorkSource::SubmitBlockFn stratum_submit_fn =
454+
[&rpc](const std::vector<unsigned char>& block_bytes,
455+
uint32_t height) -> bool {
456+
const std::string block_hex = HexStr(block_bytes);
457+
std::cout << "[DASH-STRATUM-BLOCK] won block height=" << height
458+
<< " bytes=" << block_bytes.size()
459+
<< " -- dispatching via submitblock-RPC arm\n";
460+
if (!rpc) {
461+
std::cout << "[DASH-STRATUM-BLOCK] submit arm UNARMED -- reached NO "
462+
"sink (no dashd RPC creds; embedded P2P relay is S8) -- "
463+
"won block NOT broadcast\n";
464+
return false;
465+
}
466+
const bool ok = rpc->submit_block_hex(block_hex, /*ignore_failure=*/false);
467+
if (!ok)
468+
std::cout << "[DASH-STRATUM-BLOCK] dashd submitblock REJECTED the "
469+
"won block\n";
470+
return ok;
471+
};
472+
473+
// DASHWorkSource holds a non-owning ref to node_coin_state (declared above,
474+
// same scope). The StratumServer co-owns the work source via shared_ptr.
475+
auto work_source = std::make_shared<dash::stratum::DASHWorkSource>(
476+
node_coin_state, std::move(dashd_fallback), std::move(stratum_submit_fn),
477+
core::stratum::StratumConfig{});
478+
479+
if (stratum_port != 0) {
480+
stratum_server = std::make_unique<core::StratumServer>(
481+
ioc, stratum_host, stratum_port, work_source);
482+
if (stratum_server->start()) {
483+
std::cout << "[run] stratum listening on " << stratum_host << ":"
484+
<< stratum_port
485+
<< " (work source: DASHWorkSource 4a/4b skeleton -- X11;"
486+
<< " get_work routes to the dashd-RPC fallback until the"
487+
<< " node-held coin-state is seeded)\n";
488+
} else {
489+
std::cout << "[run] stratum FAILED to bind " << stratum_host << ":"
490+
<< stratum_port << " -- stratum disabled\n";
491+
stratum_server.reset();
492+
}
493+
} else {
494+
std::cout << "[run] stratum disabled (no --stratum flag)\n";
495+
}
496+
409497
std::cout << "[run] run-loop up (Ctrl-C to stop); won blocks relay via the\n"
410498
"[run] dashd-RPC submitblock fallback + the embedded sharechain P2P leg.\n";
411499
ioc.run();
500+
501+
// Tear the acceptor + sessions down while the work source and node_coin_state
502+
// it references are still alive -- explicit reset keeps destruction order safe
503+
// (stratum_server was declared before them, so it would otherwise outlive them).
504+
stratum_server.reset();
505+
412506
std::cout << "[run] run-loop stopped cleanly\n";
413507
return 0;
414508
}
@@ -552,6 +646,8 @@ int main(int argc, char** argv)
552646
std::string listen_raw; // --listen [HOST:]PORT (sharechain bind)
553647
std::vector<std::string> addnode_raw; // --addnode HOST:PORT (persistent outbound)
554648
std::vector<std::string> connect_raw; // --connect HOST:PORT (connect-only)
649+
std::string stratum_host = "0.0.0.0"; // --stratum [HOST:]PORT bind interface (default all)
650+
uint16_t stratum_port = 0; // 0 disables the Stratum accept-loop; --stratum sets it
555651
for (int i = 1; i < argc; ++i) {
556652
if (std::strcmp(argv[i], "--version") == 0) {
557653
std::cout << "c2pool-dash " << C2POOL_VERSION << "\n";
@@ -581,6 +677,15 @@ int main(int argc, char** argv)
581677
addnode_raw.emplace_back(argv[++i]);
582678
else if (std::strcmp(argv[i], "--connect") == 0 && i + 1 < argc)
583679
connect_raw.emplace_back(argv[++i]);
680+
else if (std::strcmp(argv[i], "--stratum") == 0 && i + 1 < argc) {
681+
// --stratum [HOST:]PORT -- bind a Stratum TCP listener for miners.
682+
// Bare PORT keeps the default 0.0.0.0 bind host (parse_listen SSOT).
683+
if (!parse_listen(argv[++i], stratum_host, stratum_port)) {
684+
std::cout << "[run] --stratum malformed (want [HOST:]PORT): "
685+
<< argv[i] << "\n";
686+
return 2;
687+
}
688+
}
584689
// --selftest is the default; accepted explicitly for symmetry.
585690
}
586691

@@ -627,7 +732,8 @@ int main(int argc, char** argv)
627732
}
628733
peer.listen_set = true;
629734
}
630-
return run_node(testnet, rpc_endpoint, rpc_conf_path, submit_hex, peer);
735+
return run_node(testnet, rpc_endpoint, rpc_conf_path, submit_hex, peer,
736+
stratum_host, stratum_port);
631737
}
632738
return run_selftest();
633739
}

0 commit comments

Comments
 (0)