From 792327f5359357ddf5fea4a7a19f465f645698fc Mon Sep 17 00:00:00 2001 From: frstrtr Date: Fri, 19 Jun 2026 01:52:44 +0000 Subject: [PATCH 1/5] =?UTF-8?q?dgb(#82):=20run-loop=20spine=20=E2=80=94=20?= =?UTF-8?q?io=5Fcontext=20+=20graceful=20signal=5Fset=20shutdown=20(--run)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stand up the run-loop spine in main_dgb.cpp behind a new --run flag: a boost::asio::io_context plus an explicit graceful shutdown driven from signal_set(SIGINT, SIGTERM), mirroring main_btc.cpp s teardown contract. This is the lifecycle every node subsystem (sharechain peer dgb::Node, embedded digibyted P2P, Stratum acceptor) and the #82 won-block dispatch handler hangs off. Standing the spine up first keeps the next increments (node/Config construction over LevelDB, P2P listen, Stratum, and the m_on_block_found -> reconstruct_won_block -> broadcast_won_block binding landed across #163/#166/#167/#173/#174/#176/#177/#179) build-verifiable rather than landing a large unverified port in one step. --selftest / bare invocation unchanged (live ShareTracker::score() path). External digibyted RPC fallback posture preserved. Build: c2pool-dgb links EXIT=0 (-DCOIN_DGB=ON). Smoke: --selftest OK (block_period=75s SSOT); --run spine up, SIGINT -> clean shutdown exit 0. --- src/c2pool/main_dgb.cpp | 97 +++++++++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 17 deletions(-) diff --git a/src/c2pool/main_dgb.cpp b/src/c2pool/main_dgb.cpp index aa4e1b7be..9d2afa357 100644 --- a/src/c2pool/main_dgb.cpp +++ b/src/c2pool/main_dgb.cpp @@ -2,26 +2,32 @@ // // Wires the real dgb sharechain/pool TU (pool pillars + score path, ported from // LTC under impl/dgb/ across PRs #112/#113/#115/#121/#129/#131/#132/#134) into -// the c2pool-dgb executable. This is the exe-wire slice: it replaces the -// slice-#4 skeleton entry (dgb::run_skeleton/network_summary, removed when #134 -// dropped the real node.cpp in) and drives the LIVE chain-score path at -// startup, so the coin smoke gate exercises share_tracker::score() rather than -// merely linking it. node.cpp (the concrete dgb::NodeImpl) is compiled into the -// target so the real node TU links; its full run-loop (NodeBridge over the -// embedded digibyted P2P + Stratum) is a later Phase B slice — dgb::NodeImpl is -// abstract (ICommunicator::handle is supplied by the NodeBridge wrapper), so a -// bare node is not stood up here. The score path lives on dgb::ShareTracker, -// which we drive directly (header-only, no network / no LevelDB). +// the c2pool-dgb executable. Two entry paths: +// +// --selftest / bare : drive the LIVE dgb::ShareTracker::score() path so the +// coin smoke gate exercises real consensus code, then exit. +// --run : stand up the run-loop SPINE (this slice) — io_context + +// graceful SIGINT/SIGTERM shutdown. The node/stratum/P2P +// subsystems and the won-block dispatch binding +// (m_on_block_found -> reconstruct_won_block -> +// broadcast_won_block, #82 connecting tissue landed across +// PRs #163/#166/#167/#173/#174/#176/#177/#179) bind onto +// this io_context in the NEXT stacked slice. Standing the +// spine up first gives those subsystems the lifecycle they +// hang off and keeps each increment build-verifiable. // // V36 scope: Scrypt blocks validated; the other 4 DGB algos (SHA256d, Skein, // Qubit, Odocrypt) are accept-by-continuity / ignored — full 5-algo support is // V37. Conformance oracle: frstrtr/p2pool-dgb-scrypt (DGB-Scrypt standalone // parent; merged-v36 byte-compat WAIVED for DGB per operator 2026-06-17). // CoinParams are oracle-sourced via dgb::make_coin_params (no hardcoded bytes). -// Mirrors src/c2pool/main_btc.cpp's target shape. +// External digibyted RPC stays as a fallback alongside the embedded path. +// Mirrors src/c2pool/main_btc.cpp s target shape. #include +#include + #include #include #include @@ -31,6 +37,8 @@ #define C2POOL_VERSION "dev" #endif +namespace io = boost::asio; + namespace { // Live network summary sourced from the oracle-populated CoinParams @@ -49,10 +57,11 @@ void print_banner(const char* argv0, const core::CoinParams& p) { std::cout << "c2pool-dgb " << C2POOL_VERSION << " — DigiByte Scrypt-only (V36)\n\n" - << "Usage: " << argv0 << " [--version] [--help] [--selftest]\n\n" - << "Status: pool/sharechain pillars live (Phase B). The embedded-daemon\n" - << " run-loop (digibyted P2P + Stratum) lands in a later slice;\n" - << " external digibyted RPC stays as a fallback.\n" + << "Usage: " << argv0 << " [--version] [--help] [--selftest] [--run]\n\n" + << "Status: pool/sharechain pillars live (Phase B); run-loop spine up\n" + << " (--run: io_context + graceful shutdown). Node/stratum/P2P +\n" + << " won-block dispatch binding land in the next slice; external\n" + << " digibyted RPC stays as a fallback.\n" << "Network: " << network_summary(p) << "\n"; } @@ -84,12 +93,61 @@ int run_selftest(const core::CoinParams& params) return 0; } +// Run-loop SPINE. Stands up the io_context that every node subsystem +// (sharechain peer dgb::Node, embedded digibyted P2P, Stratum acceptor) and +// the #82 won-block dispatch handler will hang off, plus an explicit graceful +// shutdown driven from boost::asio::signal_set. +// +// Why signal_set and not std::signal: std::signal handlers run in the +// async-signal-only delivery context; io_context::stop is thread-safe but not +// documented signal-safe. signal_set delivers SIGINT/SIGTERM as an ordinary +// async callback on the io_context thread, so the shutdown path can do real +// work (stop the stratum acceptor, close sessions) before ioc.stop() drains +// the rest — mirrors main_btc.cpp s teardown contract. +// +// SEAM (next stacked slice): construct dgb::Config + dgb::Node(&ioc, &config), +// listen on the sharechain P2P port, stand up the Stratum work source, and +// bind make_on_block_found(reconstruct_won_block, p2p_sink) into +// m_on_block_found so a won share reaches the network (closes #82). Those +// subsystems open LevelDB + bind sockets, so they land as their own +// build-verified increment rather than inline here. +int run_node(const core::CoinParams& params) +{ + io::io_context ioc; + + bool shutdown_initiated = false; + io::signal_set signals(ioc, SIGINT, SIGTERM); + signals.async_wait( + [&ioc, &shutdown_initiated](const boost::system::error_code& ec, int signo) { + if (ec) return; + if (shutdown_initiated) return; + shutdown_initiated = true; + + std::cout << "[DGB] received signal " << signo + << " — initiating graceful shutdown" << std::endl; + // Next slice: stop stratum acceptor + close sessions here BEFORE + // ioc.stop(), so their pending async ops cancel cleanly. + ioc.stop(); + }); + + std::cout << "[DGB] run-loop spine up: " << network_summary(params) << "\n"; + std::cout << "[DGB] io_context running. Ctrl-C to stop. " + << "(node/stratum/P2P + won-block dispatch bind in the next slice)" + << std::endl; + + ioc.run(); + + std::cout << "[DGB] io_context stopped — clean exit" << std::endl; + return 0; +} + } // namespace int main(int argc, char** argv) { bool want_help = false; bool want_selftest = false; + bool want_run = false; for (int i = 1; i < argc; ++i) { if (std::strcmp(argv[i], "--version") == 0) { std::cout << "c2pool-dgb " << C2POOL_VERSION << "\n"; @@ -97,6 +155,7 @@ int main(int argc, char** argv) } if (std::strcmp(argv[i], "--help") == 0) want_help = true; if (std::strcmp(argv[i], "--selftest") == 0) want_selftest = true; + if (std::strcmp(argv[i], "--run") == 0) want_run = true; } const core::CoinParams params = dgb::make_coin_params(/*testnet=*/false); @@ -105,8 +164,12 @@ int main(int argc, char** argv) if (want_help) return 0; - // --selftest, or a bare invocation (no run-loop yet): drive the live score - // path so the binary exercises real consensus code, then exit cleanly. + // --run: stand up the run-loop spine (io_context + graceful shutdown). + if (want_run) + return run_node(params); + + // --selftest, or a bare invocation: drive the live score path so the + // binary exercises real consensus code, then exit cleanly. (void)want_selftest; return run_selftest(params); } From 648ac2f5e88c2fed3979e30ae0f0909f172d1624 Mon Sep 17 00:00:00 2001 From: frstrtr Date: Fri, 19 Jun 2026 03:02:30 +0000 Subject: [PATCH 2/5] dgb(#82): construct dgb::Node sharechain peer + bind P2P listener (--run) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Second stacked run-loop slice. main_dgb.cpp --run now constructs the real dgb::Config + dgb::Node (pool::NodeBridge) on the spine io_context, opens the sharechain LevelDB, and binds the P2P listener on PoolConfig::P2P_PORT (5024) — the sharechain peer is live, not just the io_context spine. Config is set directly from the p2pool-dgb-scrypt oracle constants (PREFIX 1c0553f2..., IDENTIFIER 4b62545b...), skipping Config::init() yaml load, the same contract main_btc.cpp uses. DEFAULT_BOOTSTRAP_HOSTS is empty until DGB p2pool nodes come online, so there are no outbound seeds to dial this slice; the node listens and waits for inbound peers. The per-coin net dir is digibyte/ (bucket-1 isolation). Constructing the node pulls BaseNode::connected (boost::log) and the NodeImpl TU, so the c2pool-dgb exe must link the real dgb pool runtime, not just the header-only score path. Wire the exe to link the dgb OBJECT lib + dgb_coin + core/pool/sharechain/storage base, mirroring the c2pool-btc link set; c2pool_merged_mining is pulled for symbol resolution of the core web_server tangle only (same as c2pool-btc) and does NOT enable -DAUX_DOGE — DGB default build stays standalone. Only the c2pool-dgb target stanza changes; per-coin isolation holds. Build EXIT=0. Smoke: --run binds 0.0.0.0:5024 (ss-confirmed), SIGINT -> graceful shutdown -> clean exit 0, LevelDB closed cleanly; --selftest still drives the live score() path; --version OK. SEAM (next slice): stand up the Stratum work source + bind make_on_block_found(reconstruct_won_block, p2p_sink) into m_on_block_found to close the #82 embedded P2P relay path (submitblock RPC fallback at rpc.cpp:387 is already real, not a stub). --- src/c2pool/CMakeLists.txt | 29 +++++++++++--- src/c2pool/main_dgb.cpp | 79 +++++++++++++++++++++++++++++++-------- 2 files changed, 86 insertions(+), 22 deletions(-) diff --git a/src/c2pool/CMakeLists.txt b/src/c2pool/CMakeLists.txt index eb0482075..bf1c6d32b 100644 --- a/src/c2pool/CMakeLists.txt +++ b/src/c2pool/CMakeLists.txt @@ -183,14 +183,31 @@ target_link_libraries(c2pool-btc # json/Boost. Per-coin isolation held. The embedded run-loop (NodeBridge over # digibyted P2P + Stratum) and its pool-runtime link land in a later Phase B # slice. -add_executable(c2pool-dgb - main_dgb.cpp - ${CMAKE_SOURCE_DIR}/src/core/uint256.cpp -) +# RUN-LOOP slice (#82): main_dgb.cpp --run now constructs dgb::Config + the +# dgb::Node sharechain peer (pool::NodeBridge) and binds its P2P +# listener, so the exe must link the real dgb pool runtime — not just the +# header-only score path. We link the `dgb` OBJECT lib (node.cpp + protocol +# handlers) and the shared core/pool/sharechain/storage base it sits on, +# mirroring the c2pool-btc link set. c2pool_merged_mining is pulled for SYMBOL +# RESOLUTION of the core web_server/stratum tangle ONLY (same reason c2pool-btc +# links it) — it does NOT enable -DAUX_DOGE; DGB default build stays standalone +# (no DOGE aux). core provides core/uint256.cpp, so the explicit source is +# dropped to avoid a duplicate-symbol link. Per-coin isolation holds: only the +# c2pool-dgb target stanza changes. +add_executable(c2pool-dgb main_dgb.cpp) target_compile_definitions(c2pool-dgb PRIVATE C2POOL_VERSION="${C2POOL_GIT_VERSION}") target_link_libraries(c2pool-dgb - btclibs # STATIC util lib: HexStr/HexDigit (strencodings) for base_uint hex - pure utility, no pool runtime - yaml-cpp::yaml-cpp # config_{coin,pool}.hpp -> core/netaddress.hpp -> + c2pool_payout + c2pool_merged_mining # symbol resolution for core web_server tangle (NOT -DAUX_DOGE) + c2pool_hashrate + core + dgb # DGB pool-layer OBJECT lib: node.cpp NodeImpl + protocol handlers + dgb_coin # DGB coin-layer: embedded P2P + mempool + transaction ctors + pool + sharechain + c2pool_storage + btclibs + yaml-cpp::yaml-cpp nlohmann_json::nlohmann_json ${Boost_LIBRARIES} ) diff --git a/src/c2pool/main_dgb.cpp b/src/c2pool/main_dgb.cpp index 9d2afa357..62da62cac 100644 --- a/src/c2pool/main_dgb.cpp +++ b/src/c2pool/main_dgb.cpp @@ -26,12 +26,17 @@ #include +#include +#include + #include #include #include +#include #include #include +#include #ifndef C2POOL_VERSION #define C2POOL_VERSION "dev" @@ -93,28 +98,54 @@ int run_selftest(const core::CoinParams& params) return 0; } -// Run-loop SPINE. Stands up the io_context that every node subsystem -// (sharechain peer dgb::Node, embedded digibyted P2P, Stratum acceptor) and -// the #82 won-block dispatch handler will hang off, plus an explicit graceful -// shutdown driven from boost::asio::signal_set. +// Run-loop SPINE + sharechain peer bring-up. Stands up the io_context that +// every node subsystem hangs off, an explicit graceful shutdown driven from +// boost::asio::signal_set, and (this slice) constructs the dgb::Config + +// dgb::Node sharechain peer and binds its P2P listener. // // Why signal_set and not std::signal: std::signal handlers run in the // async-signal-only delivery context; io_context::stop is thread-safe but not // documented signal-safe. signal_set delivers SIGINT/SIGTERM as an ordinary // async callback on the io_context thread, so the shutdown path can do real // work (stop the stratum acceptor, close sessions) before ioc.stop() drains -// the rest — mirrors main_btc.cpp s teardown contract. +// the rest — mirrors main_btc.cpp's teardown contract. // -// SEAM (next stacked slice): construct dgb::Config + dgb::Node(&ioc, &config), -// listen on the sharechain P2P port, stand up the Stratum work source, and -// bind make_on_block_found(reconstruct_won_block, p2p_sink) into -// m_on_block_found so a won share reaches the network (closes #82). Those -// subsystems open LevelDB + bind sockets, so they land as their own -// build-verified increment rather than inline here. -int run_node(const core::CoinParams& params) +// SEAM (next stacked slice): stand up the Stratum work source and bind +// make_on_block_found(reconstruct_won_block, p2p_sink) into m_on_block_found +// so a won share reaches the network (closes #82's embedded P2P relay path); +// the submitblock RPC fallback (rpc.cpp:387, already real — NOT a stub) is the +// second arm of the dual-path broadcaster gate. +int run_node(const core::CoinParams& params, bool testnet) { io::io_context ioc; + // Per-coin config root: ~/.c2pool// (sharechain LevelDB + addrs.json + // open underneath). Bucket-1 isolation primitive: DGB never shares LTC's + // net dir — keep the subdir per-coin in v36 AND v37. + const std::string net_subdir = testnet ? "digibyte_testnet" : "digibyte"; + const std::filesystem::path net_dir = + core::filesystem::config_path() / net_subdir; + std::error_code mkdir_ec; + std::filesystem::create_directories(net_dir, mkdir_ec); // best effort + + // dgb::Config = core::Config. Skip Config::init() + // (it would load pool.yaml + coin.yaml from disk); set the sharechain + // identity directly from the oracle-sourced constants instead — the same + // contract main_btc.cpp uses for its net smoke. prefix/identifier come from + // the p2pool-dgb-scrypt oracle (PREFIX 1c0553f2…, IDENTIFIER 4b62545b…). + dgb::Config config(net_subdir); + config.pool()->m_prefix = ParseHexBytes(dgb::PoolConfig::DEFAULT_PREFIX_HEX); + config.m_testnet = testnet; + // DEFAULT_BOOTSTRAP_HOSTS is empty until DGB p2pool nodes come online, so + // there are no outbound seeds to dial this slice — the node binds its + // listener and waits for inbound sharechain peers. + for (const auto& host : dgb::PoolConfig::DEFAULT_BOOTSTRAP_HOSTS) { + const std::string addr = host.find(':') == std::string::npos + ? host + ":" + std::to_string(dgb::PoolConfig::P2P_PORT) + : host; + config.pool()->m_bootstrap_addrs.emplace_back(addr); + } + bool shutdown_initiated = false; io::signal_set signals(ioc, SIGINT, SIGTERM); signals.async_wait( @@ -126,13 +157,29 @@ int run_node(const core::CoinParams& params) std::cout << "[DGB] received signal " << signo << " — initiating graceful shutdown" << std::endl; // Next slice: stop stratum acceptor + close sessions here BEFORE - // ioc.stop(), so their pending async ops cancel cleanly. + // ioc.stop(), so their pending async ops cancel cleanly. The + // sharechain peer's sockets close when p2p_node destructs at scope + // exit after ioc.run() returns. ioc.stop(); }); - std::cout << "[DGB] run-loop spine up: " << network_summary(params) << "\n"; + // Sharechain peer node: pool::NodeBridge. The + // NodeImpl ctor opens ~/.c2pool//sharechain_leveldb and seeds the addr + // store from m_bootstrap_addrs, so config must be populated BEFORE + // construction (above). + dgb::Node p2p_node(&ioc, &config); + p2p_node.set_target_outbound_peers(4); + p2p_node.core::Server::listen(dgb::PoolConfig::P2P_PORT); + std::cout << "[DGB] sharechain peer listening on port " + << dgb::PoolConfig::P2P_PORT + << " — proto adv=" << dgb::PoolConfig::ADVERTISED_PROTOCOL_VERSION + << " min=" << dgb::PoolConfig::MINIMUM_PROTOCOL_VERSION + << " prefix=" << dgb::PoolConfig::DEFAULT_PREFIX_HEX << std::endl; + p2p_node.start_outbound_connections(); // no-op until seed hosts exist + + std::cout << "[DGB] run-loop up: " << network_summary(params) << "\n"; std::cout << "[DGB] io_context running. Ctrl-C to stop. " - << "(node/stratum/P2P + won-block dispatch bind in the next slice)" + << "(Stratum work source + won-block dispatch bind in the next slice)" << std::endl; ioc.run(); @@ -166,7 +213,7 @@ int main(int argc, char** argv) // --run: stand up the run-loop spine (io_context + graceful shutdown). if (want_run) - return run_node(params); + return run_node(params, /*testnet=*/false); // --selftest, or a bare invocation: drive the live score path so the // binary exercises real consensus code, then exit cleanly. From 55dbd05f7dfb305b97b2ed7060bf34b43f4341e8 Mon Sep 17 00:00:00 2001 From: frstrtr Date: Fri, 19 Jun 2026 10:37:35 +0000 Subject: [PATCH 3/5] dgb(#82): define dgb/dgb_coin libs unconditionally so coin-matrix links c2pool-dgb The run-loop slice switched c2pool-dgb to link the dgb and dgb_coin OBJECT libs, but both were defined only inside if(COIN_DGB). The coin-matrix CI job configures without -DCOIN_DGB, so the targets were undefined and CMake emitted raw -ldgb/-ldgb_coin, failing the link (cannot find -ldgb). Mirror btc/ltc, which define their per-coin libs unconditionally; keep only the test subtree behind COIN_DGB (build.yml sets the flag and builds those targets). Verified: fresh configure with COIN_DGB=OFF builds + links c2pool-dgb and --help smokes clean (EXIT=0). --- src/impl/dgb/CMakeLists.txt | 49 +++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/impl/dgb/CMakeLists.txt b/src/impl/dgb/CMakeLists.txt index e284a09ba..507e9d9bf 100644 --- a/src/impl/dgb/CMakeLists.txt +++ b/src/impl/dgb/CMakeLists.txt @@ -1,5 +1,4 @@ -# c2pool-dgb coin module (V36). Built when -DCOIN_DGB=ON. -# Mirrors src/impl/btc/CMakeLists.txt; emits the c2pool-dgb binary. +# c2pool-dgb coin module (V36). Mirrors src/impl/btc/CMakeLists.txt. # Per-coin binary scheme: project_v36_per_coin_binary_v37_unified_process. # Impl plan: c2pool-dgb-embedded-impl-plan.md (frstrtr/the docs/v36, 8ef8d2d). # @@ -11,30 +10,32 @@ # in this module yet: parked behind the Phase 5.8 settle (ltc-doge owns the # shared DOGE-aux surface). Do not add AUX_DOGE plumbing here at M2. # -# TODO(M3): add_library(impl_dgb ...) sources as an OBJECT lib (ci-steward -# PR-CMake-object-library convention; impl_dgb = 1 of 5 per-coin OBJECT libs), -# link bitcoin_family/Scrypt shared base, wire embedded DigiByte Core daemon -# slice under daemon/. Top-level add_subdirectory(src/impl/dgb) registration -# follows the OBJECT-lib convention PR; held ~2-3 heartbeats, not raced here. +# LIB GATING (mirrors btc/ltc): the dgb_coin (coin-layer) and dgb (pool-layer) +# OBJECT libs are defined UNCONDITIONALLY — the c2pool-dgb executable links +# them, and the coin-matrix CI builds that exe WITHOUT -DCOIN_DGB, so the +# targets MUST exist regardless of the flag (gating them behind COIN_DGB makes +# the linker fall back to raw -ldgb/-ldgb_coin and fail). Only the test subtree +# stays behind COIN_DGB; build.yml sets -DCOIN_DGB=ON and builds those targets. +add_subdirectory(coin) +# add_subdirectory(daemon) + +# dgb -- DGB Scrypt pool-layer OBJECT lib. Mirrors the ltc/btc OBJECT lib: +# compiles the real NodeImpl translation unit (node.cpp + protocol handlers) +# so share_tracker.hpp / share_check.hpp are pulled into a compiled TU. Links +# the shared core / pool / sharechain base plus dgb_coin (embedded P2P+mempool) +# and c2pool_storage (LevelDB sharechain). +add_library(dgb OBJECT + config_coin.hpp config_coin.cpp config_pool.hpp config_pool.cpp + node.hpp node.cpp + peer.hpp + protocol_actual.cpp protocol_legacy.cpp + messages.hpp + share_types.hpp share.hpp +) +target_link_libraries(dgb core pool sharechain dgb_coin btclibs c2pool_storage ${SECP256K1_LIBRARIES}) + if(COIN_DGB) message(STATUS "c2pool: DGB Scrypt-only coin module enabled") - add_subdirectory(coin) add_subdirectory(stratum) # dgb_stratum: IWorkSource (#82 miner-facing path) - # add_subdirectory(daemon) add_subdirectory(test) - - # dgb -- DGB Scrypt pool-layer OBJECT lib. Mirrors the ltc OBJECT lib - # (src/impl/ltc/CMakeLists.txt): compiles the real NodeImpl translation unit - # (node.cpp + protocol handlers) so share_tracker.hpp / share_check.hpp are - # pulled into a compiled TU. Links the shared core / pool / sharechain base - # plus dgb_coin (embedded P2P+mempool) and c2pool_storage (LevelDB sharechain). - add_library(dgb OBJECT - config_coin.hpp config_coin.cpp config_pool.hpp config_pool.cpp - node.hpp node.cpp - peer.hpp - protocol_actual.cpp protocol_legacy.cpp - messages.hpp - share_types.hpp share.hpp - ) - target_link_libraries(dgb core pool sharechain dgb_coin btclibs c2pool_storage ${SECP256K1_LIBRARIES}) endif() From a205ecf5c36bb427679a6cd84aec498949f844e3 Mon Sep 17 00:00:00 2001 From: frstrtr Date: Fri, 19 Jun 2026 03:55:58 +0000 Subject: [PATCH 4/5] =?UTF-8?q?dgb(#82):=20stand=20StratumServer=20up=20in?= =?UTF-8?q?=20main=5Fdgb.cpp=20--run=20=E2=80=94=20submitblock-RPC=20arm?= =?UTF-8?q?=20wired?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stacks on the run-loop (#182 spine + node-construct) and the DGBWorkSource 4a skeleton (#186): closes the SEAM both left for "stand the Stratum work source up + bind the won-block broadcaster." --run now constructs the miner-facing path on the run-loop io_context: - c2pool::dgb::HeaderChain + dgb::coin::Mempool (MVP-unwired this slice — the 4a work source returns default work; mining_submit low-diff-rejects via the 0.0 compute_share_difficulty sentinel BEFORE the broadcaster, so no garbage block is ever emitted) - dgb::coin::CoinNode(nullptr,nullptr) + a SubmitBlockFn bridging block_bytes -> hex -> submit_block_hex (rpc.cpp:387, REAL not a stub): the submitblock-RPC arm of the #82 dual-path broadcaster. has_rpc()==false => returns false LOUDLY (the #163 seam guard: no silent drop). - dgb::stratum::DGBWorkSource + core::StratumServer, gated on a new --stratum [HOST:]PORT flag (mirrors main_btc.cpp). Acceptor lifecycle is wired into the signal_set handler: stratum stop() runs BEFORE ioc.stop() so live miner sessions close cleanly. CMake: link c2pool-dgb against dgb_stratum. Single-coin (no bitcoin_family / src/core touch); core::StratumServer consumed, not modified. No -DAUX_DOGE. Remaining for the #82 closer (NEXT slice): the embedded P2P-relay arm (m_on_block_found -> reconstruct_won_block -> broadcast_won_block) needs the reconstructor stack (#163/#166/#167/#177), HELD off master. Two-arm independent broadcast evidence captured once both arms are live. Build EXIT=0; --run --stratum 127.0.0.1:5022 smoke: StratumServer started, sharechain peer on 5024, SIGINT -> ordered graceful shutdown (stratum stop then clean exit), EXIT=0. --- src/c2pool/CMakeLists.txt | 1 + src/c2pool/main_dgb.cpp | 165 ++++++++++++++++++++++++++++++-------- 2 files changed, 132 insertions(+), 34 deletions(-) diff --git a/src/c2pool/CMakeLists.txt b/src/c2pool/CMakeLists.txt index bf1c6d32b..bc5d8b488 100644 --- a/src/c2pool/CMakeLists.txt +++ b/src/c2pool/CMakeLists.txt @@ -203,6 +203,7 @@ target_link_libraries(c2pool-dgb core dgb # DGB pool-layer OBJECT lib: node.cpp NodeImpl + protocol handlers dgb_coin # DGB coin-layer: embedded P2P + mempool + transaction ctors + dgb_stratum # DGB miner-facing IWorkSource (DGBWorkSource) — #82 stratum standup pool sharechain c2pool_storage diff --git a/src/c2pool/main_dgb.cpp b/src/c2pool/main_dgb.cpp index 62da62cac..c40e53667 100644 --- a/src/c2pool/main_dgb.cpp +++ b/src/c2pool/main_dgb.cpp @@ -6,15 +6,17 @@ // // --selftest / bare : drive the LIVE dgb::ShareTracker::score() path so the // coin smoke gate exercises real consensus code, then exit. -// --run : stand up the run-loop SPINE (this slice) — io_context + -// graceful SIGINT/SIGTERM shutdown. The node/stratum/P2P -// subsystems and the won-block dispatch binding +// --run : stand up the run-loop — io_context + graceful +// SIGINT/SIGTERM shutdown, the dgb::Node sharechain peer +// (P2P listener), and (this slice) the miner-facing +// Stratum work source. A won Scrypt block reaches the +// network via the #82 dual-path broadcaster: the +// submitblock-RPC arm (rpc.cpp:387 submit_block_hex, REAL) +// is wired here; the embedded P2P-relay arm // (m_on_block_found -> reconstruct_won_block -> -// broadcast_won_block, #82 connecting tissue landed across -// PRs #163/#166/#167/#173/#174/#176/#177/#179) bind onto -// this io_context in the NEXT stacked slice. Standing the -// spine up first gives those subsystems the lifecycle they -// hang off and keeps each increment build-verifiable. +// broadcast_won_block, PRs #163/#166/#167/#173/#174/#176/ +// #177/#179) binds in the NEXT stacked slice once that +// reconstructor stack lands on this base. // // V36 scope: Scrypt blocks validated; the other 4 DGB algos (SHA256d, Skein, // Qubit, Odocrypt) are accept-by-continuity / ignored — full 5-algo support is @@ -25,8 +27,13 @@ // Mirrors src/c2pool/main_btc.cpp s target shape. #include +#include +#include +#include +#include #include +#include #include #include @@ -35,8 +42,11 @@ #include #include #include +#include #include #include +#include +#include #ifndef C2POOL_VERSION #define C2POOL_VERSION "dev" @@ -62,11 +72,14 @@ void print_banner(const char* argv0, const core::CoinParams& p) { std::cout << "c2pool-dgb " << C2POOL_VERSION << " — DigiByte Scrypt-only (V36)\n\n" - << "Usage: " << argv0 << " [--version] [--help] [--selftest] [--run]\n\n" - << "Status: pool/sharechain pillars live (Phase B); run-loop spine up\n" - << " (--run: io_context + graceful shutdown). Node/stratum/P2P +\n" - << " won-block dispatch binding land in the next slice; external\n" - << " digibyted RPC stays as a fallback.\n" + << "Usage: " << argv0 + << " [--version] [--help] [--selftest] [--run] [--stratum [H:]P]\n\n" + << "Status: pool/sharechain pillars live (Phase B); run-loop up\n" + << " (--run: io_context + sharechain peer + Stratum standup).\n" + << " --stratum [HOST:]PORT binds a miner-facing TCP listener\n" + << " (e.g. --stratum 5022 or --stratum 127.0.0.1:5022); omit to\n" + << " disable. Embedded P2P won-block relay + external digibyted\n" + << " RPC fallback land in the next slices.\n" << "Network: " << network_summary(p) << "\n"; } @@ -98,10 +111,11 @@ int run_selftest(const core::CoinParams& params) return 0; } -// Run-loop SPINE + sharechain peer bring-up. Stands up the io_context that -// every node subsystem hangs off, an explicit graceful shutdown driven from -// boost::asio::signal_set, and (this slice) constructs the dgb::Config + -// dgb::Node sharechain peer and binds its P2P listener. +// Run-loop: sharechain peer bring-up + miner-facing Stratum standup. Stands up +// the io_context that every node subsystem hangs off, an explicit graceful +// shutdown driven from boost::asio::signal_set, the dgb::Node sharechain peer +// (P2P listener), and (this slice) the Stratum work source + acceptor so a +// won Scrypt block reaches the network. // // Why signal_set and not std::signal: std::signal handlers run in the // async-signal-only delivery context; io_context::stop is thread-safe but not @@ -109,13 +123,8 @@ int run_selftest(const core::CoinParams& params) // async callback on the io_context thread, so the shutdown path can do real // work (stop the stratum acceptor, close sessions) before ioc.stop() drains // the rest — mirrors main_btc.cpp's teardown contract. -// -// SEAM (next stacked slice): stand up the Stratum work source and bind -// make_on_block_found(reconstruct_won_block, p2p_sink) into m_on_block_found -// so a won share reaches the network (closes #82's embedded P2P relay path); -// the submitblock RPC fallback (rpc.cpp:387, already real — NOT a stub) is the -// second arm of the dual-path broadcaster gate. -int run_node(const core::CoinParams& params, bool testnet) +int run_node(const core::CoinParams& params, bool testnet, + const std::string& stratum_addr, uint16_t stratum_port) { io::io_context ioc; @@ -146,20 +155,28 @@ int run_node(const core::CoinParams& params, bool testnet) config.pool()->m_bootstrap_addrs.emplace_back(addr); } + // Stratum acceptor handle, declared BEFORE the signal_set so the shutdown + // callback can stop it (cancel acceptor + close sessions) ahead of + // ioc.stop(). Populated below once the work source is built. + std::unique_ptr stratum_server; + bool shutdown_initiated = false; io::signal_set signals(ioc, SIGINT, SIGTERM); signals.async_wait( - [&ioc, &shutdown_initiated](const boost::system::error_code& ec, int signo) { + [&ioc, &stratum_server, &shutdown_initiated] + (const boost::system::error_code& ec, int signo) { if (ec) return; if (shutdown_initiated) return; shutdown_initiated = true; std::cout << "[DGB] received signal " << signo << " — initiating graceful shutdown" << std::endl; - // Next slice: stop stratum acceptor + close sessions here BEFORE - // ioc.stop(), so their pending async ops cancel cleanly. The - // sharechain peer's sockets close when p2p_node destructs at scope - // exit after ioc.run() returns. + // Stop stratum BEFORE ioc.stop() so the acceptor cancels and live + // miner sessions close cleanly (their pending async ops unwind on + // the io_context). The sharechain peer's sockets close when + // p2p_node destructs at scope exit after ioc.run() returns. + if (stratum_server) + stratum_server->stop(); ioc.stop(); }); @@ -177,13 +194,80 @@ int run_node(const core::CoinParams& params, bool testnet) << " prefix=" << dgb::PoolConfig::DEFAULT_PREFIX_HEX << std::endl; p2p_node.start_outbound_connections(); // no-op until seed hosts exist + // ── #82 dual-path won-block CLOSER: miner-facing Stratum standup ─────── + // + // Stand the miner path up so a Scrypt block found by a connected miner + // reaches the network. The embedded coin side is MVP-unwired this slice + // (empty HeaderChain + Mempool): the DGBWorkSource 4a skeleton returns + // default work and mining_submit low-diff-rejects before the broadcaster + // (compute_share_difficulty's 0.0 sentinel), so NO garbage block is ever + // emitted — the standup proves the StratumServer<->IWorkSource wiring + // end-to-end. Real work-gen / Scrypt share-validation land in 4b/4c. + // This mirrors btc::stratum standing its skeleton wiring up first. + c2pool::dgb::HeaderChain header_chain; // §7b chain, MVP-unwired (empty) + dgb::coin::Mempool mempool; // unwired (no UTXO/template feed yet) + + // submitblock-RPC arm of the #82 dual-path broadcaster (rpc.cpp:387 + // submit_block_hex — REAL, not a stub). CoinNode(nullptr embedded, + // nullptr rpc) => has_rpc()==false => submit_block_hex returns false + // LOUDLY (the #163 seam guard: no silent drop). Point a real NodeRPC at + // external digibyted here to light this arm up. + dgb::coin::CoinNode coin_node(/*embedded=*/nullptr, /*rpc=*/nullptr); + + auto stratum_submit_fn = + [&coin_node](const std::vector& block_bytes, + uint32_t height) -> bool { + const std::string block_hex = HexStr(block_bytes); + std::cout << "[DGB-STRATUM-BLOCK] won block height=" << height + << " bytes=" << block_bytes.size() + << " — dispatching via submitblock-RPC arm" << std::endl; + // P2P-relay arm (m_on_block_found -> reconstruct_won_block -> + // broadcast_won_block) binds in the NEXT slice once the + // reconstructor stack (#163/#166/#167/#177) lands on this base. + const bool ok = + coin_node.submit_block_hex(block_hex, /*ignore_failure=*/false); + if (!ok) + std::cout << "[DGB-STRATUM-BLOCK] submitblock arm reached NO sink " + "(no embedded backend / no digibyted RPC wired yet) " + "— P2P-relay arm pending reconstructor stack" + << std::endl; + return ok; + }; + + // DGBWorkSource holds non-owning refs to chain + mempool; both outlive it + // (declared just above, same scope). The StratumServer co-owns the work + // source via shared_ptr. + auto work_source = std::make_shared( + header_chain, mempool, testnet, std::move(stratum_submit_fn)); + + if (stratum_port != 0) { + stratum_server = std::make_unique( + ioc, stratum_addr, stratum_port, work_source); + if (stratum_server->start()) { + std::cout << "[DGB] stratum listening on " << stratum_addr << ":" + << stratum_port + << " (work source: DGBWorkSource 4a skeleton — Scrypt-only;" + << " work-gen/share-validation land in 4b/4c)" << std::endl; + } else { + std::cout << "[DGB] stratum FAILED to bind " << stratum_addr << ":" + << stratum_port << " — stratum disabled" << std::endl; + stratum_server.reset(); + } + } else { + std::cout << "[DGB] stratum disabled (no --stratum flag)" << std::endl; + } + std::cout << "[DGB] run-loop up: " << network_summary(params) << "\n"; - std::cout << "[DGB] io_context running. Ctrl-C to stop. " - << "(Stratum work source + won-block dispatch bind in the next slice)" - << std::endl; + std::cout << "[DGB] io_context running. Ctrl-C to stop." << std::endl; ioc.run(); + // Tear the acceptor + sessions down while the work source and the coin + // objects it references (header_chain / mempool / coin_node) are still + // alive — explicit reset keeps destruction order safe (stratum_server was + // declared first, so it would otherwise outlive them). + stratum_server.reset(); + std::cout << "[DGB] io_context stopped — clean exit" << std::endl; return 0; } @@ -195,6 +279,8 @@ int main(int argc, char** argv) bool want_help = false; bool want_selftest = false; bool want_run = false; + std::string stratum_addr = "0.0.0.0"; // bind all interfaces by default + uint16_t stratum_port = 0; // 0 disables stratum; --stratum sets it for (int i = 1; i < argc; ++i) { if (std::strcmp(argv[i], "--version") == 0) { std::cout << "c2pool-dgb " << C2POOL_VERSION << "\n"; @@ -203,6 +289,17 @@ int main(int argc, char** argv) if (std::strcmp(argv[i], "--help") == 0) want_help = true; if (std::strcmp(argv[i], "--selftest") == 0) want_selftest = true; if (std::strcmp(argv[i], "--run") == 0) want_run = true; + if (std::strcmp(argv[i], "--stratum") == 0 && i + 1 < argc) { + // --stratum [HOST:]PORT — bind a stratum TCP listener for miners. + const std::string ep = argv[++i]; + const auto colon = ep.find(':'); + if (colon == std::string::npos) { + stratum_port = static_cast(std::stoi(ep)); + } else { + stratum_addr = ep.substr(0, colon); + stratum_port = static_cast(std::stoi(ep.substr(colon + 1))); + } + } } const core::CoinParams params = dgb::make_coin_params(/*testnet=*/false); @@ -211,9 +308,9 @@ int main(int argc, char** argv) if (want_help) return 0; - // --run: stand up the run-loop spine (io_context + graceful shutdown). + // --run: stand up the run-loop (io_context + sharechain peer + stratum). if (want_run) - return run_node(params, /*testnet=*/false); + return run_node(params, /*testnet=*/false, stratum_addr, stratum_port); // --selftest, or a bare invocation: drive the live score path so the // binary exercises real consensus code, then exit cleanly. From f8f45540dd397793d55c5ae209091b192be45023 Mon Sep 17 00:00:00 2001 From: frstrtr Date: Fri, 19 Jun 2026 10:39:29 +0000 Subject: [PATCH 5/5] dgb(#82): define dgb/dgb_coin/dgb_stratum libs unconditionally for coin-matrix The --run stratum standup links dgb, dgb_coin and dgb_stratum, but all three were defined only inside if(COIN_DGB). The coin-matrix CI configures without -DCOIN_DGB, so the targets were undefined and CMake emitted raw -ldgb/-ldgb_coin/ -ldgb_stratum, failing the link. Mirror btc/ltc: define the per-coin libs unconditionally, keep only the test subtree behind COIN_DGB (build.yml sets it). Verified: fresh configure with COIN_DGB=OFF builds + links c2pool-dgb and --help smokes clean (EXIT=0). --- src/impl/dgb/CMakeLists.txt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/impl/dgb/CMakeLists.txt b/src/impl/dgb/CMakeLists.txt index 507e9d9bf..f87fb9785 100644 --- a/src/impl/dgb/CMakeLists.txt +++ b/src/impl/dgb/CMakeLists.txt @@ -10,13 +10,15 @@ # in this module yet: parked behind the Phase 5.8 settle (ltc-doge owns the # shared DOGE-aux surface). Do not add AUX_DOGE plumbing here at M2. # -# LIB GATING (mirrors btc/ltc): the dgb_coin (coin-layer) and dgb (pool-layer) -# OBJECT libs are defined UNCONDITIONALLY — the c2pool-dgb executable links -# them, and the coin-matrix CI builds that exe WITHOUT -DCOIN_DGB, so the -# targets MUST exist regardless of the flag (gating them behind COIN_DGB makes -# the linker fall back to raw -ldgb/-ldgb_coin and fail). Only the test subtree -# stays behind COIN_DGB; build.yml sets -DCOIN_DGB=ON and builds those targets. +# LIB GATING (mirrors btc/ltc): the dgb_coin (coin-layer), dgb_stratum +# (miner-facing IWorkSource) and dgb (pool-layer) OBJECT libs are defined +# UNCONDITIONALLY — the c2pool-dgb executable links them, and the coin-matrix +# CI builds that exe WITHOUT -DCOIN_DGB, so the targets MUST exist regardless +# of the flag (gating them behind COIN_DGB makes the linker fall back to raw +# -ldgb/-ldgb_coin/-ldgb_stratum and fail). Only the test subtree stays behind +# COIN_DGB; build.yml sets -DCOIN_DGB=ON and builds those targets. add_subdirectory(coin) +add_subdirectory(stratum) # dgb_stratum: IWorkSource (#82 miner-facing path) # add_subdirectory(daemon) # dgb -- DGB Scrypt pool-layer OBJECT lib. Mirrors the ltc/btc OBJECT lib: @@ -36,6 +38,5 @@ target_link_libraries(dgb core pool sharechain dgb_coin btclibs c2pool_storage $ if(COIN_DGB) message(STATUS "c2pool: DGB Scrypt-only coin module enabled") - add_subdirectory(stratum) # dgb_stratum: IWorkSource (#82 miner-facing path) add_subdirectory(test) endif()