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_dash_work_source test_dash_node_coin_state \
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_dash_coin_state_maintainer \
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_work_source test_dash_node_coin_state \
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_dash_coin_state_maintainer \
test_hash_link test_decay_pplns \
test_pplns_consensus \
test_v36_script_sorting test_v36_cross_impl_refhash \
Expand Down
143 changes: 143 additions & 0 deletions src/impl/dash/coin/coin_state_maintainer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
#pragma once

/// Phase C-TEMPLATE step 7 (S8 embedded_gbt live-wire, follow-on to #673):
/// the maintainer that POPULATES the node-held NodeCoinState off the
/// reception + think update path, replacing the set_tip-on-demand pattern
/// where a caller poked NodeCoinState::set_tip() directly.
///
/// #672 landed select_dash_work() as the branch point; #673 landed
/// NodeCoinState as the node-held bundle whose populated() flips the hot arm.
/// But #673 left publication to whoever calls set_tip() -- fine for the KAT,
/// wrong for a live node: the tip advances on the header/think path, the MN
/// list advances on the mnlistdiff reception path, and mempool txs arrive on
/// the relay path, all ASYNCHRONOUSLY. The bundle must only go live once the
/// prerequisites the embedded template needs are actually present, else the
/// selector would build a template against a stale/empty MN list.
///
/// CoinStateMaintainer is that ordering gate. It owns no state of its own
/// beyond readiness flags + the last tip params; it drives a NodeCoinState&
/// the node owns. The reception/think slices call the on_*() event methods;
/// the maintainer republishes (calls set_tip) only when BOTH the MN list has
/// been seeded AND a tip has arrived. Until then, and after any invalidating
/// event (reorg / MN-list gap), populated() stays false and select_work()
/// routes to the retained dashd getblocktemplate fallback.
///
/// STRICTLY single-coin: src/impl/dash/coin/ only, no bitcoin_family / src/core
/// reach. The dashd RPC arm is NEVER removed -- it is the always-reachable
/// safety path and the [GBT-XCHECK] cross-check whenever the bundle is not live.

#include <impl/dash/coin/node_coin_state.hpp> // NodeCoinState
#include <impl/dash/coin/mn_state_machine.hpp> // MNState
#include <impl/dash/coin/transaction.hpp> // MutableTransaction

#include <core/uint256.hpp>

#include <cstdint>
#include <utility>
#include <vector>

namespace dash {
namespace coin {

/// Drives a node-owned NodeCoinState from the async update events the running
/// node observes. Non-copyable (holds a reference to the node's holder). The
/// node constructs exactly one, wired to its NodeCoinState member; the
/// reception (mnlistdiff / mempool) and header/think (tip) slices call the
/// on_*() methods as their respective updates land.
class CoinStateMaintainer {
public:
explicit CoinStateMaintainer(NodeCoinState& state) : m_state(state) {}
CoinStateMaintainer(const CoinStateMaintainer&) = delete;
CoinStateMaintainer& operator=(const CoinStateMaintainer&) = delete;

/// Reception path (mnlistdiff): replace the masternode set the embedded
/// coinbase pays. An EMPTY list is treated as a gap -- it cannot back a
/// valid payee, so it clears MN-readiness and drops the bundle to fallback
/// rather than publishing a template with no masternode payment.
void on_mn_list_update(std::vector<std::pair<uint256, MNState>> mnstates) {
m_have_mn = !mnstates.empty();
m_state.mnstates().load(std::move(mnstates));
if (!m_have_mn)
demote();
else
republish();
}

/// Reception path (mempool relay): fold a relayed tx into the local
/// mempool. Mempool contents are OPTIONAL for viability -- an empty
/// mempool yields a valid coinbase-only template -- so this never gates
/// publication; it only enriches the next assembled template. Returns the
/// mempool's accept verdict (false = rejected: bad utxo ref / already in).
bool on_mempool_tx(const MutableTransaction& tx) {
return m_state.mempool().add_tx(tx);
}

/// Header / think path: the chain tip advanced. Stash the params the
/// embedded template needs and mark tip-readiness, then republish if the
/// MN list is also ready. curtime/version left 0 defer to
/// build_embedded_workdata()'s own SAFE-ADDITIVE defaults.
void on_new_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_have_tip = true;
republish();
}

/// Reorg / MN-list gap / mempool flush: invalidate the live bundle so the
/// next get_work falls back to dashd until a fresh tip rebuilds it. The
/// stashed tip params are dropped -- a reorg means the old prev_hash is no
/// longer the tip, so we must NOT auto-republish it; a subsequent
/// on_new_tip() re-arms tip-readiness. The MN list (which survives a mere
/// reorg) is left in place.
void on_invalidate() {
m_have_tip = false;
demote();
}

/// True iff both prerequisites are met AND the holder is currently live.
bool live() const { return m_state.populated(); }

private:
// Publish only when both prerequisites are present; otherwise leave the
// holder in whatever (un)published state it is in -- callers reach demote()
// explicitly for the invalidating transitions.
void republish() {
if (m_have_tip && m_have_mn)
m_state.set_tip(m_prev_height, m_prev_hash, m_bits_for_next,
m_mtp_at_tip, m_address_version, m_address_p2sh_version,
m_curtime, m_version);
}

void demote() {
if (m_state.populated())
m_state.invalidate();
}

NodeCoinState& m_state;

bool m_have_mn{false};
bool m_have_tip{false};

// Last observed tip params, applied on republish().
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};
};

} // namespace coin
} // namespace dash
13 changes: 13 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,19 @@ if (BUILD_TESTING AND GTest_FOUND)
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)

# CoinStateMaintainer: drives NodeCoinState off async tip/MN/mempool update
# events (readiness gate: MN+tip required before publish). Same link set as
# test_dash_node_coin_state -- header-only over the work_source selector set.
add_executable(test_dash_coin_state_maintainer test_dash_coin_state_maintainer.cpp)
target_link_libraries(test_dash_coin_state_maintainer PRIVATE
GTest::gtest_main GTest::gtest
dash_x11 core
nlohmann_json::nlohmann_json
${Boost_LIBRARIES}
)
target_link_libraries(test_dash_coin_state_maintainer PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
gtest_add_tests(test_dash_coin_state_maintainer "" 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