3636#include < impl/dgb/coin/header_ingest.hpp>
3737#include < impl/dgb/coin/mempool_ingest.hpp>
3838#include < impl/dgb/stratum/work_source.hpp>
39+ #include < impl/dgb/coin/p2p_node.hpp>
3940
4041#include < core/filesystem.hpp>
4142#include < core/stratum_server.hpp>
@@ -130,7 +131,10 @@ int run_selftest(const core::CoinParams& params)
130131// work (stop the stratum acceptor, close sessions) before ioc.stop() drains
131132// the rest — mirrors main_btc.cpp's teardown contract.
132133int run_node (const core::CoinParams& params, bool testnet,
133- const std::string& stratum_addr, uint16_t stratum_port)
134+ const std::string& stratum_addr, uint16_t stratum_port,
135+ const std::string& coin_daemon,
136+ const std::vector<std::byte>& coin_magic,
137+ const uint256& coin_genesis)
134138{
135139 io::io_context ioc;
136140
@@ -297,6 +301,78 @@ int run_node(const core::CoinParams& params, bool testnet,
297301 std::cout << " [DGB] embedded coin-daemon ingest surface up — header+tx "
298302 " feeds wired (NodeP2P producer standup next)" << std::endl;
299303
304+ // ── Embedded coin-daemon P2P PRODUCER standup (Phase B) ───────────────
305+ //
306+ // dgb::coin::p2p::NodeP2P<dgb::Config> (coin/p2p_node.hpp) is the producer that
307+ // binds against coin_iface: it dials the local digibyted, speaks the
308+ // DigiByte Core wire protocol (Scrypt-only consumer), and fires
309+ // coin_iface.new_headers on each `headers` batch / new_tx on each relayed
310+ // `tx`. The wire_*_ingest connectors above already route those onto
311+ // HeaderChain::validate_and_append and Mempool::add_tx, so a live feed now
312+ // flows end-to-end the moment the handshake completes.
313+ //
314+ // The coin-daemon wire MAGIC (coin_magic, the network pchMessageStart) is
315+ // DISTINCT from the sharechain PREFIX (PoolConfig::DEFAULT_PREFIX_HEX, the
316+ // p2pool peer-namespace isolation primitive): different layers, never
317+ // conflated. Both endpoint and magic are supplied by main() so the binary
318+ // can target mainnet (magic faf3b6da / port 12024) or a dev regtest daemon
319+ // (magic fabfb5da) without hard-coding either here.
320+ //
321+ // No behavior change when --coin-daemon is absent: coin_p2p stays null, the
322+ // consumer seam idles exactly as before this slice.
323+ std::unique_ptr<dgb::coin::p2p::NodeP2P<dgb::Config>> coin_p2p;
324+ io::steady_timer coin_getheaders_timer (ioc);
325+ if (!coin_daemon.empty ()) {
326+ if (coin_magic.empty ())
327+ std::cout << " [DGB] WARNING: --coin-daemon set without --coin-magic "
328+ " — handshake will fail (wrong network magic)" << std::endl;
329+ config.coin ()->m_p2p .prefix = coin_magic;
330+ const auto colon = coin_daemon.rfind (' :' );
331+ const std::string host = coin_daemon.substr (0 , colon);
332+ const uint16_t port =
333+ static_cast <uint16_t >(std::stoi (coin_daemon.substr (colon + 1 )));
334+ const NetService target (host, port);
335+ config.coin ()->m_p2p .address = target;
336+
337+ coin_p2p = std::make_unique<dgb::coin::p2p::NodeP2P<dgb::Config>>(
338+ &ioc, &coin_iface, &config, " DGB-CoinP2P" );
339+ coin_p2p->enable_mempool_request (); // also exercise the tx ingest seam
340+ coin_p2p->connect (target);
341+ std::cout << " [DGB] embedded coin-daemon P2P producer dialing "
342+ << target.to_string () << " magic=" << HexStr (coin_magic)
343+ << " (proto adv per coin/p2p_node.hpp)" << std::endl;
344+
345+ // After the version/verack handshake, drive an initial getheaders from
346+ // the genesis locator (or current tip) so the peer streams its header
347+ // chain into validate_and_append. 3s mirrors main_btc.cpp's driver.
348+ coin_getheaders_timer.expires_after (std::chrono::seconds (3 ));
349+ coin_getheaders_timer.async_wait (
350+ [&coin_p2p, coin_genesis]
351+ (const boost::system::error_code& ec) {
352+ if (ec) return ;
353+ if (!coin_p2p->is_handshake_complete ()) {
354+ std::cout << " [DGB] coin-daemon handshake not complete yet "
355+ " (peer slow?) — reconnect/getheaders retry on "
356+ " the NodeP2P 30s timer" << std::endl;
357+ return ;
358+ }
359+ // Empty chain (fresh regtest) -> locator = [genesis]; one
360+ // getheaders batch (<=2000) covers a short regtest chain. Walk-
361+ // forward continuation for long chains is a follow-up slice.
362+ std::vector<uint256> locator;
363+ if (!coin_genesis.IsNull ())
364+ locator.push_back (coin_genesis);
365+ std::cout << " [DGB] coin-daemon handshake OK — sending initial "
366+ " getheaders, locator="
367+ << (locator.empty ()
368+ ? std::string (" <empty>" )
369+ : locator.front ().GetHex ().substr (0 , 16 ))
370+ << std::endl;
371+ // 70019 == DigiByte Core PROTOCOL_VERSION (coin/p2p_node.hpp).
372+ coin_p2p->send_getheaders (70019 , locator, uint256::ZERO );
373+ });
374+ }
375+
300376 // submitblock-RPC arm of the #82 dual-path broadcaster, driven from the
301377 // miner-facing Stratum path. Reuses the SAME coin_node seam declared above
302378 // p2p_node (the sharechain arm shares it). rpc.cpp:387 submit_block_hex is
@@ -370,6 +446,9 @@ int main(int argc, char** argv)
370446 bool want_run = false ;
371447 std::string stratum_addr = " 0.0.0.0" ; // bind all interfaces by default
372448 uint16_t stratum_port = 0 ; // 0 disables stratum; --stratum sets it
449+ std::string coin_daemon; // --coin-daemon HOST:PORT (embedded P2P producer target)
450+ std::vector<std::byte> coin_magic; // --coin-magic HEX (network pchMessageStart)
451+ uint256 coin_genesis; // --coin-genesis HASH (initial getheaders locator base)
373452 for (int i = 1 ; i < argc; ++i) {
374453 if (std::strcmp (argv[i], " --version" ) == 0 ) {
375454 std::cout << " c2pool-dgb " << C2POOL_VERSION << " \n " ;
@@ -389,6 +468,15 @@ int main(int argc, char** argv)
389468 stratum_port = static_cast <uint16_t >(std::stoi (ep.substr (colon + 1 )));
390469 }
391470 }
471+ if (std::strcmp (argv[i], " --coin-daemon" ) == 0 && i + 1 < argc) {
472+ coin_daemon = argv[++i]; // embedded coin-daemon P2P endpoint
473+ }
474+ if (std::strcmp (argv[i], " --coin-magic" ) == 0 && i + 1 < argc) {
475+ coin_magic = ParseHexBytes (argv[++i]); // network magic (pchMessageStart)
476+ }
477+ if (std::strcmp (argv[i], " --coin-genesis" ) == 0 && i + 1 < argc) {
478+ coin_genesis = uint256S (argv[++i]); // genesis hash for initial getheaders
479+ }
392480 }
393481
394482 const core::CoinParams params = dgb::make_coin_params (/* testnet=*/ false );
@@ -399,7 +487,8 @@ int main(int argc, char** argv)
399487
400488 // --run: stand up the run-loop (io_context + sharechain peer + stratum).
401489 if (want_run)
402- return run_node (params, /* testnet=*/ false , stratum_addr, stratum_port);
490+ return run_node (params, /* testnet=*/ false , stratum_addr, stratum_port,
491+ coin_daemon, coin_magic, coin_genesis);
403492
404493 // --selftest, or a bare invocation: drive the live score path so the
405494 // binary exercises real consensus code, then exit cleanly.
0 commit comments