diff --git a/src/impl/bitcoin_family/coin/base_p2p_messages.hpp b/src/impl/bitcoin_family/coin/base_p2p_messages.hpp index 5848e2bd8..c28f660df 100644 --- a/src/impl/bitcoin_family/coin/base_p2p_messages.hpp +++ b/src/impl/bitcoin_family/coin/base_p2p_messages.hpp @@ -19,6 +19,19 @@ #include #include +// READWRITE collision guard. +// The C2POOL_SERIALIZE_METHODS bodies below rely on core/pack.hpp's READWRITE +// contract (formatter.action(stream, ...)). btclibs/serialize.h, pulled +// transitively into some translation units, re-#defines READWRITE to the legacy +// (s, ser_action) contract and can win by include order, breaking every body here +// ("use of undeclared identifier 's' / 'ser_action'" on macOS arm64 / Linux). +// Re-assert the core contract so this header is include-order-independent; mirrors +// btc/coin/p2p_messages.hpp, whose include chain keeps the core macro active. +#ifdef READWRITE +# undef READWRITE +#endif +#define READWRITE(...) formatter.action(stream, __VA_ARGS__) + namespace bitcoin_family { namespace coin diff --git a/src/impl/ltc/coin/CMakeLists.txt b/src/impl/ltc/coin/CMakeLists.txt index 27a92440a..b0a4f99fd 100644 --- a/src/impl/ltc/coin/CMakeLists.txt +++ b/src/impl/ltc/coin/CMakeLists.txt @@ -6,6 +6,7 @@ set(ltc_coin_impl p2p_node.cpp p2p_node.hpp p2p_messages.hpp node.hpp + coin_node.hpp coin_node.cpp ) set(ltc_coin_interface diff --git a/src/impl/ltc/coin/coin_node.cpp b/src/impl/ltc/coin/coin_node.cpp new file mode 100644 index 000000000..da551fa7a --- /dev/null +++ b/src/impl/ltc/coin/coin_node.cpp @@ -0,0 +1,60 @@ +#include "coin_node.hpp" + +#include +#include + +namespace ltc +{ + +namespace coin +{ + +core::coin::WorkView CoinNode::get_work_view() +{ + // No work source configured at all -> empty view. + 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. Folds the old + // web_server.cpp:2167-2168 embedded-vs-rpc decision coin-side. + rpc::WorkData wd = m_embedded ? m_embedded->getwork() : m_rpc->getwork(); + + // Retain the FULL WorkData (incl. m_txs) 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. + // (Pre-seam this was web_server.cpp:2171-2172 m_coin_node->work.set(wd), + // which only ran in rpc mode; keeping it unconditional here is strictly + // safe -- the agnostic slice still leaves, the payload still stays.) + 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-only mode m_rpc can be null. + // Returning false is the correct "no RPC sink" result (mirrors the old + // web_server.cpp:2728 `if (m_coin_rpc)` guard). + if (!m_rpc) + return false; + + // MWEB arity bridge: ltc NodeRPC::submit_block_hex is the 3-arg + // (block_hex, mweb, ignore_failure) form. The ICoinNode contract is the + // 2-arg coin-agnostic form, so we supply mweb="" here. The sole pre-seam + // caller (web_server.cpp:2730) already passed "" for mweb, so this is + // behaviour-preserving. FLAG (per integrator, for review): when MWEB + // submit grows a non-empty extension-block path, mweb must NOT be hard-"" + // -- it would need a coin-side source (e.g. the retained WorkData) rather + // than a new arg on the shared seam, since mweb is LTC-specific. + return m_rpc->submit_block_hex(block_hex, "", ignore_failure); +} + +} // namespace coin + +} // namespace ltc diff --git a/src/impl/ltc/coin/coin_node.hpp b/src/impl/ltc/coin/coin_node.hpp new file mode 100644 index 000000000..96dff30a0 --- /dev/null +++ b/src/impl/ltc/coin/coin_node.hpp @@ -0,0 +1,73 @@ +#pragma once + +// --------------------------------------------------------------------------- +// ltc::coin::CoinNode -- concrete core::coin::ICoinNode for LTC (family-1 P2 +// WorkView seam). This is the REFERENCE impl the btc::coin::CoinNode mirrors +// (piece-5(c)); the control flow / sequencing here are the load-bearing part. +// +// m_embedded : CoinNodeInterface* -- EmbeddedCoinNode in-process source +// m_rpc : NodeRPC* -- external coin-RPC client +// work : Variable -- full per-coin WorkData kept coin-side +// +// web_server (shared core) historically held raw pointers to CONCRETE ltc types +// (ltc::coin::NodeRPC, ltc::interfaces::Node) and called getwork()/submit on +// them directly -- that names ltc:: symbols in web_server.cpp.o and breaks the +// BTC link. This type collapses the embedded-vs-rpc decision plus the full +// WorkData retention coin-side, and exposes only the coin-agnostic +// core::coin::ICoinNode contract across the seam (WorkView, 2-arg submit). +// +// MWEB arity: ltc::coin::NodeRPC::submit_block_hex is the 3-arg +// (block_hex, mweb, ignore_failure) LTC form. The ICoinNode override is the +// coin-agnostic 2-arg form; it forwards to the 3-arg rpc with mweb="" coin-side. +// The sole pre-seam caller (web_server.cpp:2730) already passed mweb="", so +// dropping the mweb slot across the seam is behaviour-preserving for MWEB +// submit. (See coin_node.cpp for the forward + the standing flag.) +// --------------------------------------------------------------------------- + +#include + +#include +#include +#include + +#include "rpc.hpp" +#include "rpc_data.hpp" +#include "template_builder.hpp" + +namespace ltc +{ + +namespace coin +{ + +class CoinNode : public core::coin::ICoinNode +{ + // Embedded in-process template source (EmbeddedCoinNode, via the + // CoinNodeInterface base). 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-only mode; it is the + // sole sink for submit_block_hex(). has_rpc() reports its presence. + NodeRPC* m_rpc = nullptr; + + // Full per-coin WorkData (incl. vector m_txs) retained + // coin-side via work.set(wd); only the agnostic WorkView slice crosses the + // seam into core/web_server. Replaces the old ltc::interfaces::Node::work + // slot that web_server used to reach through m_coin_node. + 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 ltc