diff --git a/src/impl/dgb/coin/CMakeLists.txt b/src/impl/dgb/coin/CMakeLists.txt new file mode 100644 index 000000000..8e7dc89d1 --- /dev/null +++ b/src/impl/dgb/coin/CMakeLists.txt @@ -0,0 +1,22 @@ +# dgb_coin -- DGB coin-layer library (Path A minimal-stub surface). +# Mirrors src/impl/btc/coin/CMakeLists.txt, listing only the files that exist +# at this milestone. NOT yet referenced by any add_subdirectory(): top-level +# registration of src/impl/dgb follows the ci-steward OBJECT-lib convention +# (see ../CMakeLists.txt); staged here so that wiring is a one-line flip. + +set(dgb_coin_impl + rpc_data.hpp + rpc.hpp + node.hpp + coin_node.hpp coin_node.cpp +) + +set(dgb_coin_interface + node_interface.hpp + header_chain.hpp + template_builder.hpp +) + +add_library(dgb_coin ${dgb_coin_interface} ${dgb_coin_impl}) + +target_link_libraries(dgb_coin core nlohmann_json::nlohmann_json) diff --git a/src/impl/dgb/coin/coin_node.cpp b/src/impl/dgb/coin/coin_node.cpp new file mode 100644 index 000000000..b8446485b --- /dev/null +++ b/src/impl/dgb/coin/coin_node.cpp @@ -0,0 +1,51 @@ +#include "coin_node.hpp" + +#include +#include + +namespace dgb +{ + +namespace coin +{ + +core::coin::WorkView CoinNode::get_work_view() +{ + // No work source configured at all -> empty view (1:1 with the btc/ltc + // reference). + if (!m_embedded && !m_rpc) + return {}; + + // Embedded preferred, external RPC fallback. getwork() throws + // std::runtime_error when no template can be produced -- propagated to the + // caller (web_server), matching the ICoinNode contract. On DGB Path A both + // sources are stubs, so this path always throws until M3 lands a real one. + rpc::WorkData wd = m_embedded ? m_embedded->getwork() : m_rpc->getwork(); + + // Retain the FULL WorkData coin-side. Variable::set takes its argument BY + // VALUE, so this copies wd; sequenced BEFORE the std::move()s below so the + // copy completes first -- never move out of wd beforehand. + work.set(wd); + + core::coin::WorkView v; + v.m_data = std::move(wd.m_data); + v.m_hashes = std::move(wd.m_hashes); + v.m_latency = wd.m_latency; + return v; +} + +bool CoinNode::submit_block_hex(const std::string& block_hex, bool ignore_failure) +{ + // Guard sits ahead of the submit: in embedded-preferred mode m_rpc can be + // null. Returning false is the correct "no RPC sink" result. + if (!m_rpc) + return false; + + // DGB's NodeRPC::submit_block_hex is already the agnostic 2-arg/no-mweb + // form (MWEB is LTC-specific and absent here), so we forward directly. + return m_rpc->submit_block_hex(block_hex, ignore_failure); +} + +} // namespace coin + +} // namespace dgb diff --git a/src/impl/dgb/coin/coin_node.hpp b/src/impl/dgb/coin/coin_node.hpp new file mode 100644 index 000000000..59a22d06e --- /dev/null +++ b/src/impl/dgb/coin/coin_node.hpp @@ -0,0 +1,70 @@ +#pragma once + +// --------------------------------------------------------------------------- +// dgb::coin::CoinNode -- concrete core::coin::ICoinNode for DGB (family-1 P2 +// WorkView seam, Path A minimal-stub). 1:1 mirror of btc::coin::CoinNode +// (src/impl/btc/coin/coin_node.{hpp,cpp}), which is itself member-mapped from +// the ltc::coin::CoinNode reference -- the control flow / sequencing are the +// load-bearing part and are preserved verbatim: +// m_embedded : CoinNodeInterface* -- embedded in-process source +// m_rpc : NodeRPC* -- external coin-RPC client (STUB) +// work : Variable -- full per-coin WorkData kept +// coin-side; only the agnostic +// WorkView slice crosses the seam +// +// DGB Path A status: both work sources behind this adapter are stubs -- +// NodeRPC throws on getwork() (rpc.hpp) and no EmbeddedCoinNode exists until +// the M3 daemon slice -- so a wired DGB node reports "no template" loudly +// through the ICoinNode contract rather than fabricating work. The adapter +// itself is COMPLETE: when either source becomes real, no seam-side change +// is needed. +// +// Build-INERT: defines the type; NOT yet wired into web_server or a +// main_dgb.cpp (no such binary split exists yet). Registration follows the +// ci-steward OBJECT-lib convention; see src/impl/dgb/CMakeLists.txt. +// --------------------------------------------------------------------------- + +#include + +#include +#include +#include + +#include "rpc.hpp" +#include "rpc_data.hpp" +#include "template_builder.hpp" + +namespace dgb +{ + +namespace coin +{ + +class CoinNode : public core::coin::ICoinNode +{ + // Embedded in-process template source (EmbeddedCoinNode, M3). May be null + // when the node runs RPC-only. is_embedded() reports its presence. + CoinNodeInterface* m_embedded = nullptr; + + // External coin-RPC client. May be null in embedded-preferred mode; it is + // the sole sink for submit_block_hex(). has_rpc() reports its presence. + NodeRPC* m_rpc = nullptr; + + // Full per-coin WorkData retained coin-side via work.set(wd); only the + // agnostic WorkView slice crosses the seam into core/web_server. + Variable work; + +public: + CoinNode(CoinNodeInterface* embedded, NodeRPC* rpc) + : m_embedded(embedded), m_rpc(rpc) {} + + core::coin::WorkView get_work_view() override; + bool submit_block_hex(const std::string& block_hex, bool ignore_failure) override; + + bool is_embedded() const override { return m_embedded != nullptr; } + bool has_rpc() const override { return m_rpc != nullptr; } +}; + +} // namespace coin + +} // namespace dgb diff --git a/src/impl/dgb/coin/node.hpp b/src/impl/dgb/coin/node.hpp new file mode 100644 index 000000000..7d7a05737 --- /dev/null +++ b/src/impl/dgb/coin/node.hpp @@ -0,0 +1,55 @@ +#pragma once + +// --------------------------------------------------------------------------- +// dgb::coin::Node -- per-coin node owner (Path A minimal-stub). TRIMMED mirror +// of src/impl/btc/coin/node.hpp: owns the NodeRPC client and inherits the +// dgb::interfaces::Node shared-state surface (work variable + new_block +// event) that NodeRPC and the seam-side CoinNode bind against. +// +// Deliberately ABSENT until M3 (each needs a port dgb does not have yet): +// - NodeP2P / p2p_connection (coin P2P block relay; btc's p2p_node.hpp) +// - init_rpc() transport connect (NodeRPC is a stub with no transport) +// - submit_block_p2p / send_getheaders / handshake surface +// The ctor keeps btc's (context, config) shape via auto params (no boost +// include needed in the stub) so M3 restores the body without re-typing +// construction sites. +// --------------------------------------------------------------------------- + +#include + +#include "node_interface.hpp" +#include "rpc.hpp" + +namespace dgb +{ + +namespace coin +{ + +template +class Node : public dgb::interfaces::Node +{ + using config_t = ConfigType; + + config_t* m_config = nullptr; + + std::unique_ptr m_rpc; + +public: + Node(auto* /*context*/, auto* config) : m_config(config) + { + } + + void run() + { + // Stub NodeRPC: constructed so has-rpc presence wiring can be + // exercised, but no transport connect until M3. + m_rpc = std::make_unique(this); + } + + NodeRPC* rpc() { return m_rpc.get(); } +}; + +} // namespace coin + +} // namespace dgb diff --git a/src/impl/dgb/coin/node_interface.hpp b/src/impl/dgb/coin/node_interface.hpp new file mode 100644 index 000000000..7c6e6803f --- /dev/null +++ b/src/impl/dgb/coin/node_interface.hpp @@ -0,0 +1,39 @@ +#pragma once + +// --------------------------------------------------------------------------- +// dgb::interfaces::Node -- coin-node shared-state surface (Path A +// minimal-stub). Mirrors src/impl/btc/coin/node_interface.hpp TRIMMED to the +// members the family-1 ICoinNode seam actually binds today: +// +// work : Variable -- get_work result (NodeRPC fills, +// CoinNode retains coin-side per the WorkView seam contract) +// new_block : Event -- block-hash announce (header-chain +// feed; uint256 only, no per-coin type needed) +// +// Deliberately ABSENT until the M3 type ports land (each pulls a type dgb +// does not have yet): Event new_tx, Event> new_headers, Event full_block, TXIDCache +// txidcache, known_txs map. Restoring them is additive; nothing in the seam +// depends on their absence. +// --------------------------------------------------------------------------- + +#include +#include + +#include "rpc_data.hpp" + +namespace dgb +{ + +namespace interfaces +{ + +struct Node +{ + Variable work; // get_work result + Event new_block; // block_hash +}; + +} // namespace interfaces + +} // namespace dgb diff --git a/src/impl/dgb/coin/rpc.hpp b/src/impl/dgb/coin/rpc.hpp new file mode 100644 index 000000000..40a01f444 --- /dev/null +++ b/src/impl/dgb/coin/rpc.hpp @@ -0,0 +1,65 @@ +#pragma once + +// --------------------------------------------------------------------------- +// dgb::coin::NodeRPC -- external coin-RPC client STUB (Path A minimal-stub, +// "rpc stubs" scope item). +// +// btc/ltc NodeRPC is a boost::beast + jsonrpccxx HTTP JSON-RPC client whose +// header drags in block.hpp / transaction.hpp -- types dgb does not port +// until M3. This stub keeps the call surface coin_node.cpp and coin/node.hpp +// consume, with no transport behind it: +// +// getwork() -> throws std::runtime_error. This is the ICoinNode +// contract for "no template available" -- web_server +// already handles the throw, so a wired-but-stub DGB +// node degrades loudly, not silently. +// submit_block_hex() -> false ("no RPC sink"; the same result the null- +// m_rpc guard in CoinNode::submit_block_hex yields). +// check() -> false (never connected). +// +// connect()/reconnect()/the RPC method set (getblocktemplate etc.) arrive +// with the real transport in M3 as a body-only swap mirroring +// src/impl/btc/coin/rpc.{hpp,cpp}; DGB's getblocktemplate call passes +// rules=["scrypt"] per the Scrypt GBT filter point (template_builder.hpp, +// impl plan section 3) so only Scrypt-eligible templates are returned. +// --------------------------------------------------------------------------- + +#include +#include + +#include "node_interface.hpp" +#include "rpc_data.hpp" + +namespace dgb +{ + +namespace coin +{ + +class NodeRPC +{ + // Shared-state surface the real client fills (work variable); the stub + // holds the pointer so the M3 swap does not change construction sites. + dgb::interfaces::Node* m_coin = nullptr; + +public: + explicit NodeRPC(dgb::interfaces::Node* coin = nullptr) : m_coin(coin) {} + + // Never connected: no transport in the stub. + bool check() const { return false; } + + rpc::WorkData getwork() + { + throw std::runtime_error( + "dgb: NodeRPC is a Path A stub -- no external RPC transport until M3"); + } + + bool submit_block_hex(const std::string& /*block_hex*/, bool /*ignore_failure*/) + { + return false; + } +}; + +} // namespace coin + +} // namespace dgb diff --git a/src/impl/dgb/coin/rpc_data.hpp b/src/impl/dgb/coin/rpc_data.hpp new file mode 100644 index 000000000..1589db1d2 --- /dev/null +++ b/src/impl/dgb/coin/rpc_data.hpp @@ -0,0 +1,63 @@ +#pragma once + +// --------------------------------------------------------------------------- +// dgb::coin::rpc::WorkData -- per-coin work payload for the family-1 P2 +// WorkView seam (Path A minimal-stub). +// +// Mirrors src/impl/btc/coin/rpc_data.hpp with ONE deliberate trim: btc's +// WorkData carries std::vector m_txs, but DGB has no +// coin/transaction.{hpp,cpp} port yet -- that lands with the M3 embedded +// daemon slice. The ICoinNode seam contract makes the trim safe: web_server +// consumes ONLY the agnostic slice (m_data/m_hashes/m_latency); the full +// per-coin WorkData (incl. txs) never crosses the seam +// (src/core/coin/node_iface.hpp). When the DGB transaction port lands, m_txs +// is restored here and the coin-side work.set(wd) retention in +// CoinNode::get_work_view() carries it without any seam change. +// +// V36 master compat: field semantics match p2pool-merged-v36 getwork result +// (data / txhashes / latency); impl plan section 3 (frstrtr/the, 8ef8d2d). +// --------------------------------------------------------------------------- + +#include +#include +#include + +#include + +#include + +namespace dgb +{ + +namespace coin +{ + +namespace rpc +{ + +struct WorkData +{ + nlohmann::json m_data; + std::vector m_hashes; // transaction hashes + time_t m_latency = 0; + + // TODO(M3): std::vector m_txs once coin/transaction.{hpp,cpp} + // is ported (DGB txs are bitcoin-family; expected near-verbatim from btc's + // port). Kept out of the stub so the rpc chain compiles without the + // Transaction/Block types dgb does not have yet. + + WorkData() {} + WorkData(nlohmann::json data, std::vector txhashes, time_t latency) + : m_data(std::move(data)), m_hashes(std::move(txhashes)), m_latency(latency) + { + } + + bool operator==(const WorkData& rhs) const { return m_data == rhs.m_data; } + bool operator!=(const WorkData& rhs) const { return !(*this == rhs); } +}; + +} // namespace rpc + +} // namespace coin + +} // namespace dgb diff --git a/src/impl/dgb/coin/template_builder.hpp b/src/impl/dgb/coin/template_builder.hpp index da15d2569..4df325420 100644 --- a/src/impl/dgb/coin/template_builder.hpp +++ b/src/impl/dgb/coin/template_builder.hpp @@ -2,12 +2,59 @@ // DGB block-template builder. Mirrors src/impl/btc/coin/template_builder.hpp. // Must emit p2pool-merged-v36-compatible templates (V36 master compat). // -// >>> SCRYPT GBT FILTER POINT (M1 §3) <<< +// >>> SCRYPT GBT FILTER POINT (M1 section 3) <<< // DGB multi-algo: getblocktemplate is requested with rules=["scrypt"] so the // embedded daemon only returns Scrypt-eligible templates. The builder assembles // and submits Scrypt blocks only in V36. (config_coin.hpp CoinParams::GBT_ALGO.) // // Share/PoW format is identical to LTC Scrypt; share assembly reuses the shared -// Scrypt-family path (do NOT fork LTC share logic — per-coin isolation). -// TODO(M3): TemplateBuilder emitting p2pool-merged-v36-parity Scrypt templates. -namespace c2pool::dgb { /* TODO(M3): TemplateBuilder, Scrypt GBT */ } +// Scrypt-family path (do NOT fork LTC share logic -- per-coin isolation). +// TODO(M3): TemplateBuilder + EmbeddedCoinNode emitting p2pool-merged-v36-parity +// Scrypt templates (mirror of btc's HeaderChain+Mempool-backed EmbeddedCoinNode). +// +// Namespace note: seam-facing DGB types live in dgb::coin / dgb::interfaces, +// matching config_coin.hpp (namespace dgb) and the btc::coin / ltc::coin +// pattern the family-1 seam binds against. + +#include + +#include + +#include "rpc_data.hpp" + +namespace dgb +{ + +namespace coin +{ + +// --- CoinNodeInterface ------------------------------------------------------ +// Abstract interface for obtaining work and submitting blocks; lets the +// concrete CoinNode swap between RPC (legacy), embedded, or hybrid sources +// without changing downstream code. TRIMMED mirror of btc's CoinNodeInterface +// (src/impl/btc/coin/template_builder.hpp:93): submit_block(BlockType&) is +// deferred to M3 with the coin/block.hpp port -- BlockType does not exist for +// dgb yet, and the family-1 seam submits via NodeRPC::submit_block_hex, so +// nothing binds the trimmed slot today. +class CoinNodeInterface { +public: + virtual ~CoinNodeInterface() = default; + + /// Return a block template as WorkData. + /// Throws std::runtime_error if no template can be produced. + virtual rpc::WorkData getwork() = 0; + + /// Return chain info (analogous to getblockchaininfo RPC). + virtual nlohmann::json getblockchaininfo() = 0; + + /// True when the embedded chain is up to date with the network + /// AND has enough UTXO depth for coinbase maturity validation. + virtual bool is_synced() const { return false; } + + // TODO(M3): virtual void submit_block(BlockType& block) = 0; -- restored + // verbatim from btc once coin/block.hpp is ported. +}; + +} // namespace coin + +} // namespace dgb