|
| 1 | +#pragma once |
| 2 | +// --------------------------------------------------------------------------- |
| 3 | +// bch::coin::EmbeddedDaemon<Config> -- M5: the embedded-daemon ENTRYPOINT |
| 4 | +// assembly. After AblaRuntime (9f5050f2) closed the size loop, four front-ends |
| 5 | +// existed but nothing OWNED them as one running daemon instance: |
| 6 | +// HeaderChain -- SPV header store + tip (M3); height source |
| 7 | +// Mempool -- tx acceptance pool (M4); template input |
| 8 | +// EmbeddedCoinNode -- in-process getwork() work source (template builder) |
| 9 | +// coin::Node<Config> -- P2P + external-RPC front-end; the full_block source |
| 10 | +// (derives bch::interfaces::Node) AND the retained |
| 11 | +// external BCHN-RPC fallback path (init_rpc / m_rpc) |
| 12 | +// AblaRuntime -- owns AblaTracker + AblaBlockFeed; wires full_block |
| 13 | +// --> feed --> tracker --> EmbeddedCoinNode budget |
| 14 | +// |
| 15 | +// This object is that owner: one daemon = one EmbeddedDaemon. It constructs the |
| 16 | +// members in the lifetime order the wiring demands, runs the node, and closes |
| 17 | +// the ABLA loop via AblaRuntime::wire(). It is the site coin::Node<Config> |
| 18 | +// instantiates concretely (config binds here, per node.hpp's deferral note). |
| 19 | +// |
| 20 | +// EMBEDDED-PRIMARY, EXTERNAL-FALLBACK (v36-master-plan, REQUIRED for every coin) |
| 21 | +// The embedded work source (EmbeddedCoinNode::getwork) is the DEFAULT. The |
| 22 | +// external BCHN-RPC path stays alongside it -- coin::Node::init_rpc() is NOT |
| 23 | +// removed; m_node keeps its NodeRPC. The CoinNode seam (node_iface.hpp) is |
| 24 | +// built embedded-primary with the RPC as the live fallback. Removing the |
| 25 | +// external path would violate the per-coin external_fallback invariant. |
| 26 | +// |
| 27 | +// COLD START = FLOOR ANCHOR (VM300 pin is the NEXT, operator-gated step). |
| 28 | +// Absent a BCHN-pinned {height,State} captured from VM300 bchn-bch, the ABLA |
| 29 | +// runtime anchors at the activation/floor State -- folding live block sizes |
| 30 | +// forward can only RAISE the budget, never undercut the 32 MB floor. The |
| 31 | +// BCHN pin is a later reanchor() passthrough (AblaRuntime::reanchor), NOT a |
| 32 | +// reconstruction; capturing it touches VM300 read-only and is surfaced to the |
| 33 | +// operator as a [decision-needed] before any read. This assembly is complete |
| 34 | +// and correct WITHOUT the pin; the pin only sharpens the cold-start budget. |
| 35 | +// |
| 36 | +// LIFETIME (members declared in this exact order so refs bind to live objects): |
| 37 | +// m_chain before m_embedded (EmbeddedCoinNode HeaderChain&) and m_abla |
| 38 | +// (AblaBlockFeed HeaderChain&) -- both bind to a constructed chain. |
| 39 | +// m_pool before m_embedded (EmbeddedCoinNode Mempool&). |
| 40 | +// m_embedded, m_node before wire() hands their addresses to m_abla; m_abla's |
| 41 | +// AblaTracker outlives the EmbeddedCoinNode raw pointer it sinks into |
| 42 | +// (the daemon owns all of them for its whole run). |
| 43 | +// |
| 44 | +// p2pool-merged-v36 SURFACE: NONE. Pure local daemon assembly -- no PoW hash, |
| 45 | +// share format, coinbase commitment, AuxPoW, or PPLNS math is touched; getwork |
| 46 | +// emits the same coin-agnostic WorkData the sweep already pinned conformant. |
| 47 | +// PER-COIN ISOLATION: src/impl/bch/coin/ only; every type is bch-owned. |
| 48 | +// Build-INERT / source-only: header-only, no impl_bch CMake registration |
| 49 | +// (bch stays skip-green; don't race ci-steward). |
| 50 | +// --------------------------------------------------------------------------- |
| 51 | + |
| 52 | +#include <cstdint> |
| 53 | + |
| 54 | +#include "header_chain.hpp" // HeaderChain |
| 55 | +#include "mempool.hpp" // Mempool |
| 56 | +#include "template_builder.hpp" // EmbeddedCoinNode |
| 57 | +#include "node.hpp" // coin::Node<Config> (interfaces::Node source) |
| 58 | +#include "abla_runtime.hpp" // AblaRuntime (owns tracker + feed) |
| 59 | + |
| 60 | +#include <core/log.hpp> |
| 61 | + |
| 62 | +namespace bch { |
| 63 | +namespace coin { |
| 64 | + |
| 65 | +/// Owns and wires one embedded BCH daemon instance. Single-threaded |
| 66 | +/// construction from the binary entrypoint; run() then drives the node. |
| 67 | +template <typename ConfigType> |
| 68 | +class EmbeddedDaemon { |
| 69 | +public: |
| 70 | + using config_t = ConfigType; |
| 71 | + |
| 72 | + /// Cold-start ctor: floor-anchored ABLA at `anchor_height` (safe default |
| 73 | + /// when no VM300 BCHN pin is available yet). `context`/`config` outlive the |
| 74 | + /// daemon (owned by the binary entrypoint, same contract as coin::Node). |
| 75 | + EmbeddedDaemon(auto* context, config_t* config, uint32_t anchor_height) |
| 76 | + : m_config(config), |
| 77 | + m_chain(), |
| 78 | + m_pool(), |
| 79 | + m_embedded(m_chain, m_pool, config->m_testnet), |
| 80 | + m_node(context, config), |
| 81 | + m_abla(config->m_testnet, anchor_height, m_chain) {} |
| 82 | + |
| 83 | + EmbeddedDaemon(const EmbeddedDaemon&) = delete; |
| 84 | + EmbeddedDaemon& operator=(const EmbeddedDaemon&) = delete; |
| 85 | + |
| 86 | + /// Bring the daemon up: start the node front-end (external RPC fallback + |
| 87 | + /// P2P relay) and close the ABLA size loop. After this, full_block events |
| 88 | + /// flow node --> feed --> tracker --> EmbeddedCoinNode dynamic budget, and |
| 89 | + /// EmbeddedCoinNode::getwork() is the live in-process work source. |
| 90 | + void run() { |
| 91 | + m_node.run(); // init_rpc(): external BCHN-RPC fallback retained |
| 92 | + m_abla.wire(m_node, m_embedded); |
| 93 | + LOG_INFO << "[EMB-BCH] embedded daemon up: embedded-primary work source," |
| 94 | + << " external BCHN-RPC fallback retained, ABLA loop closed" |
| 95 | + << " (cold-start floor anchor; VM300 pin pending operator)."; |
| 96 | + } |
| 97 | + |
| 98 | + /// Apply a BCHN-pinned {height, State} captured from VM300 bchn-bch. This |
| 99 | + /// is the operator-gated reanchor step -- call ONLY after the read is |
| 100 | + /// approved; until then the floor anchor is correct and never-undercut. |
| 101 | + void apply_bchn_anchor(uint32_t height, abla::State state) { |
| 102 | + m_abla.reanchor(height, state); |
| 103 | + } |
| 104 | + |
| 105 | + // Accessors for the CoinNode seam cluster (embedded-primary + RPC fallback) |
| 106 | + // and for tests; the daemon retains ownership. |
| 107 | + EmbeddedCoinNode& embedded() { return m_embedded; } |
| 108 | + Node<config_t>& node() { return m_node; } |
| 109 | + AblaRuntime& abla() { return m_abla; } |
| 110 | + HeaderChain& chain() { return m_chain; } |
| 111 | + Mempool& mempool() { return m_pool; } |
| 112 | + bool is_wired() const { return m_abla.is_wired(); } |
| 113 | + |
| 114 | +private: |
| 115 | + config_t* m_config; // not owned (binary entrypoint owns it) |
| 116 | + HeaderChain m_chain; // before m_embedded + m_abla: their refs bind here |
| 117 | + Mempool m_pool; // before m_embedded |
| 118 | + EmbeddedCoinNode m_embedded; // in-process work source |
| 119 | + Node<config_t> m_node; // P2P + external-RPC fallback; full_block source |
| 120 | + AblaRuntime m_abla; // owns tracker + feed; wired in run() |
| 121 | +}; |
| 122 | + |
| 123 | +} // namespace coin |
| 124 | +} // namespace bch |
0 commit comments