Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ jobs:
core_test sharechain_test share_test btc_share_test \
test_threading test_weights \
test_header_chain test_mempool test_template_builder \
test_doge_chain test_compact_blocks test_dash_x11_kat test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm test_dash_coinbase_parity test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_stratum_binding test_dash_job_notify_roundtrip test_dash_cb_payee test_dash_stratum_notify_roundtrip test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node test_dash_share_messages test_dash_stratum_extranonce_split test_dash_stratum_submit_reassembly test_dash_difficulty_parity test_dash_auto_ratchet test_dash_min_protocol_gate \
test_doge_chain test_compact_blocks test_dash_x11_kat test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm test_dash_coinbase_parity test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_stratum_binding test_dash_job_notify_roundtrip test_dash_cb_payee test_dash_stratum_notify_roundtrip test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node test_dash_share_messages test_dash_stratum_extranonce_split test_dash_stratum_submit_reassembly test_dash_difficulty_parity test_dash_auto_ratchet test_dash_min_protocol_gate test_dash_work_source test_dash_node_coin_state \
test_multiaddress_pplns test_pplns_stress \
test_hash_link test_decay_pplns \
test_pplns_consensus \
Expand Down Expand Up @@ -252,7 +252,7 @@ jobs:
test_threading test_weights \
test_header_chain test_mempool test_template_builder \
test_doge_chain test_compact_blocks test_dash_x11_kat \
test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm test_dash_coinbase_parity test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_stratum_binding test_dash_job_notify_roundtrip test_dash_cb_payee test_dash_stratum_notify_roundtrip test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node test_dash_share_messages test_dash_stratum_extranonce_split test_dash_stratum_submit_reassembly test_dash_difficulty_parity test_dash_auto_ratchet test_dash_min_protocol_gate \
test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm test_dash_coinbase_parity test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_stratum_binding test_dash_job_notify_roundtrip test_dash_cb_payee test_dash_stratum_notify_roundtrip test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node test_dash_share_messages test_dash_stratum_extranonce_split test_dash_stratum_submit_reassembly test_dash_difficulty_parity test_dash_auto_ratchet test_dash_min_protocol_gate test_dash_work_source test_dash_node_coin_state \
test_hash_link test_decay_pplns \
test_pplns_consensus \
test_v36_script_sorting test_v36_cross_impl_refhash \
Expand Down
21 changes: 20 additions & 1 deletion src/c2pool/main_dash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include <core/netaddress.hpp> // NetService (dashd RPC endpoint)

#include <impl/dash/coin/rpc.hpp> // dash::coin::NodeRPC — external-dashd submitblock arm (slice 3)
#include <impl/dash/coin/work_source.hpp> // dash::coin::select_dash_work -- embedded-gbt live-wire + dashd fallback (S8 capstone)
#include <impl/dash/coin/rpc_conf.hpp> // dash.conf creds resolution (rpcpassword off argv)
#include <impl/dash/coin/node_interface.hpp>
#include <impl/dash/node.hpp> // dash::Node — sharechain pool-node (NodeBridge<NodeImpl,Legacy,Actual>)
Expand Down Expand Up @@ -457,7 +458,25 @@ int run_mine_block(bool testnet, const std::string& rpc_endpoint,

// 1) Pull the template.
std::cout << "[mine] fetching block template (getblocktemplate)...\n";
dash::coin::DashWorkData work = rpc.getwork();
// Work source (S8 embedded_gbt live-wire capstone): PREFER the locally
// assembled embedded template via build_embedded_workdata, fall back to
// dashd getblocktemplate. The dashd arm is RETAINED as fallback + the
// [GBT-XCHECK] cross-check -- never removed.
//
// NOTE: NodeImpl does not yet hold the embedded coin-state (masternode
// list + mempool + header tip) that build_embedded_workdata consumes, so
// emb.has_state stays false here and the selector routes to the dashd
// fallback today. Populating that in-process state is the flagged next
// sub-slice; once it lands, set emb.has_state=true and the embedded arm
// goes live with zero change to this call site.
dash::coin::EmbeddedWorkInputs emb; // has_state=false until node-held coin-state lands
dash::coin::WorkSelection sel =
dash::coin::select_dash_work(emb, [&]{ return rpc.getwork(); });
dash::coin::DashWorkData work = std::move(sel.work);
std::cout << "[mine] work source: "
<< (sel.source == dash::coin::WorkSource::Embedded
? "EMBEDDED (build_embedded_workdata)"
: "dashd getblocktemplate (fallback)") << "\n";
std::cout << "[mine] template: height=" << work.m_height
<< " bits=0x" << std::hex << work.m_bits << std::dec
<< " prev=" << work.m_previous_block.GetHex().substr(0, 16) << "..."
Expand Down
120 changes: 120 additions & 0 deletions src/impl/dash/coin/node_coin_state.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
#pragma once

/// Phase C-TEMPLATE step 6 (S8 embedded_gbt live-wire, follow-on to #672):
/// the node-held embedded coin-state bundle that flips select_dash_work()'s
/// hot arm live.
///
/// #672 landed select_dash_work() (work_source.hpp) as the stable branch
/// point, but every caller still presents has_state=false, so 100% of the
/// running node's get_work path routes to the retained dashd
/// getblocktemplate fallback. This holder is the in-process coin-state the
/// DASH node maintains as mnlistdiff / mempool / header-tip updates arrive --
/// masternode list + mempool + header-tip params. make_embedded_work_inputs()
/// presents it as a viable() EmbeddedWorkInputs so select_dash_work() takes
/// the oracle-parity embedded path (build_embedded_workdata, pinned by
/// test_dash_embedded_gbt vs frstrtr/p2pool-dash getwork()).
///
/// STRICTLY single-coin: src/impl/dash/ only, no bitcoin_family / src/core
/// reach. The external-daemon (dashd RPC) arm is NEVER removed -- populated()
/// == false always routes there, and it remains the [GBT-XCHECK] cross-check.

#include <impl/dash/coin/work_source.hpp> // EmbeddedWorkInputs, select_dash_work, WorkSelection
#include <impl/dash/coin/mn_state_machine.hpp> // MnStateMachine
#include <impl/dash/coin/mempool.hpp> // Mempool
#include <impl/dash/coin/rpc_data.hpp> // DashWorkData

#include <core/uint256.hpp>

#include <cstdint>
#include <functional>

namespace dash {
namespace coin {

/// In-process coin-state the running node maintains for LOCAL template
/// assembly. Non-copyable: it owns a Mempool (itself non-copyable) and is
/// node-owned, never duplicated. The maintainer mutates mnstates()/mempool()
/// in place and calls set_tip() once the tip advances; get_work reads it
/// through select_work().
class NodeCoinState {
public:
NodeCoinState() = default;
NodeCoinState(const NodeCoinState&) = delete;
NodeCoinState& operator=(const NodeCoinState&) = delete;

// Mutable accessors for the maintainer (the reception / think slices seed
// these from mnlistdiff + relayed mempool txs).
MnStateMachine& mnstates() { return m_mnstates; }
Mempool& mempool() { return m_mempool; }

/// Record the header-tip parameters and mark the bundle live. Call after
/// the tip advances AND the MN list + mempool are seeded; until then the
/// selector must route to the dashd fallback. curtime/version left 0 use
/// build_embedded_workdata()'s own SAFE-ADDITIVE defaults.
void set_tip(uint32_t prev_height, const uint256& prev_hash,
uint32_t bits_for_next, uint32_t mtp_at_tip,
uint8_t address_version, uint8_t address_p2sh_version,
uint32_t curtime = 0, uint32_t version = 0) {
m_prev_height = prev_height;
m_prev_hash = prev_hash;
m_bits_for_next = bits_for_next;
m_mtp_at_tip = mtp_at_tip;
m_address_version = address_version;
m_address_p2sh_version = address_p2sh_version;
m_curtime = curtime;
m_version = version;
m_populated = true;
}

/// Invalidate the bundle (reorg / mempool flush / MN list gap) so the next
/// get_work falls back to dashd until the state is rebuilt.
void invalidate() { m_populated = false; }

bool populated() const { return m_populated; }

/// Assemble the selector input. has_state is populated(); the two required
/// pointers are always non-null (members), so viable() reduces to
/// populated() -- exactly the semantics work_source.hpp documents.
EmbeddedWorkInputs make_embedded_work_inputs() const {
EmbeddedWorkInputs e;
e.has_state = m_populated;
e.prev_height = m_prev_height;
e.prev_hash = m_prev_hash;
e.mnstates = &m_mnstates;
e.mempool = &m_mempool;
e.bits_for_next = m_bits_for_next;
e.mtp_at_tip = m_mtp_at_tip;
e.address_version = m_address_version;
e.address_p2sh_version = m_address_p2sh_version;
e.curtime = m_curtime;
e.version = m_version;
return e;
}

/// Live get_work entry point: prefer the locally-assembled embedded
/// template when this bundle is populated, else the supplied dashd
/// getblocktemplate fallback. Thin wrapper over select_dash_work() so the
/// node call site is one line. dashd_fallback is REQUIRED -- it is the
/// always-reachable safety path and the cross-check arm.
WorkSelection select_work(
const std::function<DashWorkData()>& dashd_fallback) const {
return select_dash_work(make_embedded_work_inputs(), dashd_fallback);
}

private:
MnStateMachine m_mnstates;
Mempool m_mempool;
uint32_t m_prev_height{0};
uint256 m_prev_hash;
uint32_t m_bits_for_next{0};
uint32_t m_mtp_at_tip{0};
uint8_t m_address_version{0};
uint8_t m_address_p2sh_version{0};
uint32_t m_curtime{0};
uint32_t m_version{0};
bool m_populated{false};
};

} // namespace coin
} // namespace dash
102 changes: 102 additions & 0 deletions src/impl/dash/coin/work_source.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
#pragma once

/// Phase C-TEMPLATE step 5 (capstone): embedded-vs-dashd work-source selector.
///
/// build_embedded_workdata() (embedded_gbt.hpp) is source-complete and pinned
/// by test_dash_embedded_gbt (oracle: frstrtr/p2pool-dash getwork(),
/// older-than-v35 semantics). What was missing is a LIVE consumer: the running
/// node's get_work path must PREFER the locally-assembled embedded template and
/// fall back to dashd getblocktemplate only when the embedded coin-state bundle
/// is unavailable.
///
/// select_dash_work() is that branch point. When the EmbeddedWorkInputs bundle
/// is viable (masternode list + mempool + header-tip params all present) it
/// assembles the template LOCALLY via build_embedded_workdata() — the
/// oracle-parity path. Otherwise it invokes the supplied dashd fallback.
///
/// The external-daemon (dashd RPC) arm is NEVER removed: it is BOTH the fallback
/// AND the [GBT-XCHECK] cross-check. viable()==false must always route there.

#include <impl/dash/coin/embedded_gbt.hpp> // build_embedded_workdata
#include <impl/dash/coin/mn_state_machine.hpp> // MnStateMachine
#include <impl/dash/coin/mempool.hpp> // Mempool
#include <impl/dash/coin/rpc_data.hpp> // DashWorkData

#include <core/uint256.hpp>

#include <ctime>
#include <cstdint>
#include <functional>
#include <utility>

namespace dash {
namespace coin {

/// The inputs build_embedded_workdata() consumes, plus a validity flag. For the
/// embedded path to be taken, has_state must be true AND both pointers non-null
/// (viable()). Until NodeImpl carries embedded coin-state in-process, callers
/// leave has_state=false and the selector routes to the dashd fallback.
struct EmbeddedWorkInputs {
bool has_state{false};
uint32_t prev_height{0};
uint256 prev_hash;
const MnStateMachine* mnstates{nullptr};
const Mempool* mempool{nullptr};
uint32_t bits_for_next{0};
uint32_t mtp_at_tip{0};
uint8_t address_version{0};
uint8_t address_p2sh_version{0};
// Optional seams. 0 => use build_embedded_workdata's own SAFE-ADDITIVE
// defaults (std::time(nullptr) / 0x20000000 BIP9 baseline).
uint32_t curtime{0};
uint32_t version{0};

bool viable() const {
return has_state && mnstates != nullptr && mempool != nullptr;
}
};

enum class WorkSource { Embedded, DashdFallback };

struct WorkSelection {
DashWorkData work;
WorkSource source{WorkSource::DashdFallback};
};

/// Injectable core — the routing decision, testable without a live daemon or a
/// populated MN/mempool harness. Production binds embedded_builder to the real
/// build_embedded_workdata() closure (see the 2-arg overload below).
inline WorkSelection select_dash_work(
const EmbeddedWorkInputs& emb,
const std::function<DashWorkData()>& embedded_builder,
const std::function<DashWorkData()>& dashd_fallback)
{
if (emb.viable())
return WorkSelection{embedded_builder(), WorkSource::Embedded};
return WorkSelection{dashd_fallback(), WorkSource::DashdFallback};
}

/// Production entry point: builds the embedded template from `emb` when viable,
/// else calls `dashd_fallback` (the retained external-daemon getblocktemplate
/// arm). dashd_fallback is REQUIRED — it is the always-reachable safety path.
inline WorkSelection select_dash_work(
const EmbeddedWorkInputs& emb,
const std::function<DashWorkData()>& dashd_fallback)
{
return select_dash_work(
emb,
[&emb]() {
return build_embedded_workdata(
emb.prev_height, emb.prev_hash, *emb.mnstates, *emb.mempool,
emb.bits_for_next, emb.mtp_at_tip,
emb.address_version, emb.address_p2sh_version,
emb.curtime ? emb.curtime
: static_cast<uint32_t>(std::time(nullptr)),
emb.version ? emb.version : 0x20000000u);
},
dashd_fallback);
}

} // namespace coin
} // namespace dash
30 changes: 30 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,36 @@ if (BUILD_TESTING AND GTest_FOUND)
target_link_libraries(test_dash_embedded_gbt PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
gtest_add_tests(test_dash_embedded_gbt "" AUTO)

# DASH embedded-vs-dashd work-source selector (S8 embedded_gbt live-wire
# capstone): select_dash_work() prefers the locally-assembled embedded
# template (build_embedded_workdata) and falls back to dashd
# getblocktemplate when the coin-state bundle is not viable. Routing +
# retained-fallback KAT; harness-free (embedded builder injected as a stub,
# oracle-parity already pinned by test_dash_embedded_gbt). Same link set as
# the embedded_gbt capstone (work_source.hpp includes embedded_gbt.hpp).
add_executable(test_dash_work_source test_dash_work_source.cpp)
target_link_libraries(test_dash_work_source PRIVATE
GTest::gtest_main GTest::gtest
dash_x11 core
nlohmann_json::nlohmann_json
${Boost_LIBRARIES}
)
target_link_libraries(test_dash_work_source PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
gtest_add_tests(test_dash_work_source "" AUTO)

# NodeCoinState: node-held embedded coin-state holder over the
# work_source selector link set (mn_state_machine + mempool header-only);
# no ltc/pool SCC dependency. Mirrors the test_dash_work_source link set.
add_executable(test_dash_node_coin_state test_dash_node_coin_state.cpp)
target_link_libraries(test_dash_node_coin_state PRIVATE
GTest::gtest_main GTest::gtest
dash_x11 core
nlohmann_json::nlohmann_json
${Boost_LIBRARIES}
)
target_link_libraries(test_dash_node_coin_state PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
gtest_add_tests(test_dash_node_coin_state "" AUTO)

# DASH CSimplifiedMNListDiff (mnlistdiff wire, S8.1 leaf): vendored diff
# round-trip + dashcore field-layout pin + apply_diff semantics. Header-only
# over the SimplifiedMNList leaf + coin/transaction; no ltc/pool SCC dep.
Expand Down
Loading
Loading