Skip to content

Commit e5c12cb

Browse files
committed
dgb: stand up embedded coin-daemon P2P producer in run-loop (Phase B)
Construct dgb::coin::p2p::NodeP2P<dgb::Config> against the coin_iface ingest seam landed in #250 and dial the local digibyted. On --run with --coin-daemon HOST:PORT (+ --coin-magic / --coin-genesis), the producer speaks the DigiByte Core wire protocol (Scrypt-only consumer), completes the version/verack handshake, drives an initial getheaders from the genesis locator, and fires coin_iface.new_headers / new_tx on each live relay. The wire_*_ingest connectors route those onto HeaderChain::validate_and_append and Mempool::add_tx, so a live feed now flows end-to-end the moment the handshake completes. Coin-daemon wire MAGIC is kept distinct from the sharechain PREFIX isolation primitive; both endpoint and magic are supplied by main() so the binary targets mainnet or a dev regtest daemon without hard-coding. No behavior change when --coin-daemon is absent (coin_p2p stays null).
1 parent 7d8d341 commit e5c12cb

1 file changed

Lines changed: 91 additions & 2 deletions

File tree

src/c2pool/main_dgb.cpp

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
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.
132133
int 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

Comments
 (0)