|
57 | 57 | #include <impl/dash/coin/p2p_client.hpp> // dash::coin::p2p::CoinClient — OPT-IN coin-network dial (E1, --coin-p2p-connect) |
58 | 58 | #include <impl/dash/coin/node_coin_state.hpp> // dash::coin::NodeCoinState (embedded work bundle) |
59 | 59 | #include <impl/dash/coin/utxo_lane.hpp> // dash::coin::UtxoLane — embedded UTXO/fee lane (E2b, #738) |
| 60 | +#include <impl/dash/coin/header_chain.hpp> // dash::coin::HeaderChain — SPV header/tip authority (E2a) |
| 61 | +#include <impl/dash/coin/coin_state_maintainer.hpp> // dash::coin::CoinStateMaintainer — populate ordering gate (E2a) |
| 62 | +#include <impl/dash/coin/live_feed.hpp> // E2a live-feed bridge (raw wire events -> derived ingest events) |
| 63 | +#include <impl/dash/coin/mempool_ingest.hpp> // wire_mempool_ingest (leg 1) |
| 64 | +#include <impl/dash/coin/tip_ingest.hpp> // wire_tip_ingest (leg 2) |
| 65 | +#include <impl/dash/coin/block_connect_ingest.hpp> // wire_block_connect_ingest (leg 3) |
| 66 | +#include <impl/dash/coin/mn_list_ingest.hpp> // wire_mn_list_ingest (leg 4) |
60 | 67 | #include <impl/dash/node.hpp> // dash::Node — sharechain pool-node (NodeBridge<NodeImpl,Legacy,Actual>) |
61 | 68 | #include <impl/dash/config.hpp> // dash::Config (PoolConfig/CoinConfig) |
62 | 69 | #include <impl/dash/config_pool.hpp> // dash::SharechainConfig — P2P_PORT / PREFIX / min-proto SSOT |
@@ -892,6 +899,156 @@ int run_node(bool testnet, const std::string& rpc_endpoint, |
892 | 899 | think_timer->expires_after(std::chrono::seconds(15)); |
893 | 900 | think_timer->async_wait(*think_tick); |
894 | 901 |
|
| 902 | + // ── E2a: wire the LIVE coin-P2P feed into the maintainer -> populate ── |
| 903 | + // GUARANTEE: this whole block is gated on `coin_p2p` (i.e. --coin-p2p-connect |
| 904 | + // was supplied). With NO flag, coin_p2p is null, none of the header chain / |
| 905 | + // maintainer / ingest legs below are constructed, and run_node is byte- |
| 906 | + // identical to the released dashd-fallback prod path. The subscriptions are |
| 907 | + // REGISTERED here (before ioc.run()); no wire event can fire until the loop |
| 908 | + // below pumps the socket I/O, so wiring after the E1 connect() is race-free. |
| 909 | + // |
| 910 | + // These locals are declared LAST in run_node's scope so they are destroyed |
| 911 | + // FIRST at return (after ioc.run() has stopped and no further events fire): |
| 912 | + // subscription handles -> maintainer -> header_chain, all torn down before |
| 913 | + // node_coin_state / coin_state (declared earlier) they reference. |
| 914 | + std::unique_ptr<dash::coin::HeaderChain> header_chain; |
| 915 | + std::unique_ptr<dash::coin::CoinStateMaintainer> maintainer; |
| 916 | + std::vector<std::shared_ptr<EventDisposable>> coin_feed_subs; |
| 917 | + if (coin_p2p) { |
| 918 | + const auto dash_params = testnet |
| 919 | + ? dash::coin::make_dash_chain_params_testnet() |
| 920 | + : dash::coin::make_dash_chain_params_mainnet(); |
| 921 | + const auto hdr_db = (core::filesystem::config_path() |
| 922 | + / net_subdir / "dash_headers").string(); |
| 923 | + header_chain = std::make_unique<dash::coin::HeaderChain>(dash_params, hdr_db); |
| 924 | + header_chain->init(); |
| 925 | + |
| 926 | + maintainer = std::make_unique<dash::coin::CoinStateMaintainer>(node_coin_state); |
| 927 | + |
| 928 | + // Coin address versions for the embedded coinbase-payee encoding (the |
| 929 | + // TipAdvance carries them so build_embedded_workdata can encode the MN |
| 930 | + // payee); sourced from the oracle CoinParams, testnet/mainnet-aware. |
| 931 | + const core::CoinParams coin_params = dash::make_coin_params(testnet); |
| 932 | + const uint8_t addr_ver = coin_params.address_version; |
| 933 | + const uint8_t p2sh_ver = coin_params.address_p2sh_version; |
| 934 | + |
| 935 | + // Leg 1 (mempool relay): new_tx -> maintainer.on_mempool_tx. Optional |
| 936 | + // for viability; enriches the assembled template. |
| 937 | + coin_feed_subs.push_back( |
| 938 | + c2pool::dash::wire_mempool_ingest(coin_state, *maintainer)); |
| 939 | + // Leg 2 (tip advance): Node::new_tip -> maintainer.on_new_tip. The |
| 940 | + // new_tip event is FIRED by the tip-changed callback below (off the |
| 941 | + // header chain), NOT the raw wire. |
| 942 | + coin_feed_subs.push_back( |
| 943 | + c2pool::dash::wire_tip_ingest(coin_state, *maintainer)); |
| 944 | + // Leg 3 (block connect): Node::block_connected -> maintainer |
| 945 | + // .on_block_connected (MnStateMachine::apply_block, folds DIP3 special |
| 946 | + // txs into the DMN set). block_connected is fired by the live-feed |
| 947 | + // bridge (full_block -> height lookup). The E2b UTXO lane is ALSO |
| 948 | + // subscribed to the same event (its connect_block + fee recompute). |
| 949 | + coin_feed_subs.push_back( |
| 950 | + c2pool::dash::wire_block_connect_ingest(coin_state, *maintainer)); |
| 951 | + // Leg 4 (mnlistdiff RESYNC): Node::mn_list_update -> maintainer |
| 952 | + // .on_mn_list_update. Wired for completeness; a payee-complete DMN-set |
| 953 | + // source over P2P is the known follow-on (see PR — Dash's Simplified MN |
| 954 | + // List omits scriptPayout, so the authoritative payout-bearing set is |
| 955 | + // built by leg 3's apply_block over connected block bodies). |
| 956 | + coin_feed_subs.push_back( |
| 957 | + c2pool::dash::wire_mn_list_ingest(coin_state, *maintainer)); |
| 958 | + |
| 959 | + // Bridge: new_headers -> HeaderChain::add_headers (X11 PoW + DGW |
| 960 | + // validated). The tip authority for the embedded template. |
| 961 | + coin_feed_subs.push_back( |
| 962 | + dash::coin::wire_header_ingest(coin_state, *header_chain)); |
| 963 | + // Bridge: full_block -> (X11 hash -> header-chain height) -> |
| 964 | + // Node::block_connected, driving leg 3 + the E2b UTXO lane. |
| 965 | + coin_feed_subs.push_back( |
| 966 | + dash::coin::wire_full_block_ingest(coin_state, *header_chain)); |
| 967 | + |
| 968 | + // new_block(inv hash) -> pull the full block from the peer (getdata). |
| 969 | + // Closes the loop so live tip blocks arrive as full_block -> connect. |
| 970 | + coin_feed_subs.push_back( |
| 971 | + coin_state.new_block.subscribe( |
| 972 | + [cp = coin_p2p.get()](const uint256& hash) { |
| 973 | + cp->request_block(hash); |
| 974 | + })); |
| 975 | + |
| 976 | + // new_chainlock -> record into the best-chainlock tracker (finalization |
| 977 | + // signal the block-find submit path can consult). |
| 978 | + coin_feed_subs.push_back( |
| 979 | + coin_state.new_chainlock.subscribe( |
| 980 | + [&coin_state](const std::pair<uint256, int32_t>& cl) { |
| 981 | + coin_state.chainlocked_blocks[cl.first] = cl.second; |
| 982 | + })); |
| 983 | + |
| 984 | + // Header self-propel: after each accepted headers batch, request the |
| 985 | + // next batch off the updated locator so the chain catches up to tip. |
| 986 | + // Registered AFTER wire_header_ingest so add_headers runs first and the |
| 987 | + // locator reflects the new tip. |
| 988 | + coin_feed_subs.push_back( |
| 989 | + coin_state.new_headers.subscribe( |
| 990 | + [cp = coin_p2p.get(), hc = header_chain.get()] |
| 991 | + (const std::vector<dash::coin::BlockHeaderType>& batch) { |
| 992 | + if (batch.empty()) return; |
| 993 | + cp->send_getheaders(70230, hc->get_locator(), uint256::ZERO); |
| 994 | + })); |
| 995 | + |
| 996 | + // Tip-changed callback: (a) fire Node::new_tip (leg 2 arms tip-readiness |
| 997 | + // -> the maintainer republishes once the MN list is ALSO seeded -> |
| 998 | + // populated() flips), and (b) #739 idle-notify: bump work-generation + |
| 999 | + // notify sessions on a real tip change so idle miners are not wedged on |
| 1000 | + // stale work between job-push timer firings (event-driven notify). |
| 1001 | + header_chain->set_on_tip_changed( |
| 1002 | + [&coin_state, &stratum_server, hc = header_chain.get(), |
| 1003 | + addr_ver, p2sh_ver, ws = work_source.get()] |
| 1004 | + (const uint256&, uint32_t, const uint256& new_tip, uint32_t new_height) { |
| 1005 | + auto ta = dash::coin::tip_advance_from_chain( |
| 1006 | + *hc, addr_ver, p2sh_ver); |
| 1007 | + if (ta) { |
| 1008 | + coin_state.new_tip.happened(*ta); |
| 1009 | + LOG_INFO << "[EMB-DASH] tip advanced h=" << new_height |
| 1010 | + << " " << new_tip.GetHex().substr(0, 16) |
| 1011 | + << " bits=0x" << std::hex << ta->bits_for_next << std::dec |
| 1012 | + << " -> new_tip fired (maintainer arm)"; |
| 1013 | + } |
| 1014 | + // #739: event-driven stale-work notify. |
| 1015 | + if (ws) ws->bump_work_generation(); |
| 1016 | + if (stratum_server) stratum_server->notify_all(); |
| 1017 | + }); |
| 1018 | + |
| 1019 | + // E2b UTXO bootstrap window-refill seam: request historical block |
| 1020 | + // bodies BY HEIGHT (header-chain hash lookup) so the UTXO view + the |
| 1021 | + // MnStateMachine (apply_block) fill forward from the live feed. |
| 1022 | + if (embedded_utxo && utxo_lane.live()) { |
| 1023 | + utxo_lane.set_request_block_fn( |
| 1024 | + [cp = coin_p2p.get(), hc = header_chain.get()](uint32_t h) { |
| 1025 | + auto e = hc->get_header_by_height(h); |
| 1026 | + if (e) cp->request_block(e->hash); |
| 1027 | + }); |
| 1028 | + } |
| 1029 | + |
| 1030 | + // Peer's reported chain height -> header-chain sync-progress gauge. |
| 1031 | + coin_p2p->set_on_peer_height( |
| 1032 | + [hc = header_chain.get()](uint32_t h) { hc->set_peer_tip_height(h); }); |
| 1033 | + |
| 1034 | + // Kick the initial sync once the version/verack handshake completes: |
| 1035 | + // getheaders off our current locator + a mempool prime. |
| 1036 | + coin_p2p->set_on_handshake_complete( |
| 1037 | + [cp = coin_p2p.get(), hc = header_chain.get()]() { |
| 1038 | + LOG_INFO << "[EMB-DASH] handshake complete -> initial sync:" |
| 1039 | + " getheaders + mempool"; |
| 1040 | + cp->send_getheaders(70230, hc->get_locator(), uint256::ZERO); |
| 1041 | + cp->send_mempool(); |
| 1042 | + }); |
| 1043 | + |
| 1044 | + std::cout << "[run] E2a live-feed wired: header-chain(" << hdr_db |
| 1045 | + << ") + CoinStateMaintainer + 6 ingest subscriptions;" |
| 1046 | + " populate flips get_work to the EMBEDDED arm once the tip" |
| 1047 | + " (headers) AND the DMN set (block-connect apply_block) are" |
| 1048 | + " present" << (embedded_utxo ? " + UTXO maturity>=106" : "") |
| 1049 | + << "\n"; |
| 1050 | + } |
| 1051 | + |
895 | 1052 | std::cout << "[run] run-loop up (Ctrl-C to stop); won blocks relay via the\n" |
896 | 1053 | "[run] dashd-RPC submitblock fallback + the embedded sharechain P2P leg.\n"; |
897 | 1054 | ioc.run(); |
|
0 commit comments