Skip to content

Commit 48e93de

Browse files
authored
Merge pull request #674 from frstrtr/dash/s8-coin-state-maintainer
dash(S8): CoinStateMaintainer populates NodeCoinState off tip/MN/mempool updates (stacks on #673)
2 parents 90a59de + cd1d56a commit 48e93de

4 files changed

Lines changed: 383 additions & 2 deletions

File tree

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ jobs:
102102
core_test sharechain_test share_test btc_share_test \
103103
test_threading test_weights \
104104
test_header_chain test_mempool test_template_builder \
105-
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 \
105+
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 \
106106
test_multiaddress_pplns test_pplns_stress \
107107
test_hash_link test_decay_pplns \
108108
test_pplns_consensus \
@@ -252,7 +252,7 @@ jobs:
252252
test_threading test_weights \
253253
test_header_chain test_mempool test_template_builder \
254254
test_doge_chain test_compact_blocks test_dash_x11_kat \
255-
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 \
255+
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 \
256256
test_hash_link test_decay_pplns \
257257
test_pplns_consensus \
258258
test_v36_script_sorting test_v36_cross_impl_refhash \
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// SPDX-License-Identifier: AGPL-3.0-or-later
2+
#pragma once
3+
4+
/// Phase C-TEMPLATE step 7 (S8 embedded_gbt live-wire, follow-on to #673):
5+
/// the maintainer that POPULATES the node-held NodeCoinState off the
6+
/// reception + think update path, replacing the set_tip-on-demand pattern
7+
/// where a caller poked NodeCoinState::set_tip() directly.
8+
///
9+
/// #672 landed select_dash_work() as the branch point; #673 landed
10+
/// NodeCoinState as the node-held bundle whose populated() flips the hot arm.
11+
/// But #673 left publication to whoever calls set_tip() -- fine for the KAT,
12+
/// wrong for a live node: the tip advances on the header/think path, the MN
13+
/// list advances on the mnlistdiff reception path, and mempool txs arrive on
14+
/// the relay path, all ASYNCHRONOUSLY. The bundle must only go live once the
15+
/// prerequisites the embedded template needs are actually present, else the
16+
/// selector would build a template against a stale/empty MN list.
17+
///
18+
/// CoinStateMaintainer is that ordering gate. It owns no state of its own
19+
/// beyond readiness flags + the last tip params; it drives a NodeCoinState&
20+
/// the node owns. The reception/think slices call the on_*() event methods;
21+
/// the maintainer republishes (calls set_tip) only when BOTH the MN list has
22+
/// been seeded AND a tip has arrived. Until then, and after any invalidating
23+
/// event (reorg / MN-list gap), populated() stays false and select_work()
24+
/// routes to the retained dashd getblocktemplate fallback.
25+
///
26+
/// STRICTLY single-coin: src/impl/dash/coin/ only, no bitcoin_family / src/core
27+
/// reach. The dashd RPC arm is NEVER removed -- it is the always-reachable
28+
/// safety path and the [GBT-XCHECK] cross-check whenever the bundle is not live.
29+
30+
#include <impl/dash/coin/node_coin_state.hpp> // NodeCoinState
31+
#include <impl/dash/coin/mn_state_machine.hpp> // MNState
32+
#include <impl/dash/coin/transaction.hpp> // MutableTransaction
33+
34+
#include <core/uint256.hpp>
35+
36+
#include <cstdint>
37+
#include <utility>
38+
#include <vector>
39+
40+
namespace dash {
41+
namespace coin {
42+
43+
/// Drives a node-owned NodeCoinState from the async update events the running
44+
/// node observes. Non-copyable (holds a reference to the node's holder). The
45+
/// node constructs exactly one, wired to its NodeCoinState member; the
46+
/// reception (mnlistdiff / mempool) and header/think (tip) slices call the
47+
/// on_*() methods as their respective updates land.
48+
class CoinStateMaintainer {
49+
public:
50+
explicit CoinStateMaintainer(NodeCoinState& state) : m_state(state) {}
51+
CoinStateMaintainer(const CoinStateMaintainer&) = delete;
52+
CoinStateMaintainer& operator=(const CoinStateMaintainer&) = delete;
53+
54+
/// Reception path (mnlistdiff): replace the masternode set the embedded
55+
/// coinbase pays. An EMPTY list is treated as a gap -- it cannot back a
56+
/// valid payee, so it clears MN-readiness and drops the bundle to fallback
57+
/// rather than publishing a template with no masternode payment.
58+
void on_mn_list_update(std::vector<std::pair<uint256, MNState>> mnstates) {
59+
m_have_mn = !mnstates.empty();
60+
m_state.mnstates().load(std::move(mnstates));
61+
if (!m_have_mn)
62+
demote();
63+
else
64+
republish();
65+
}
66+
67+
/// Reception path (mempool relay): fold a relayed tx into the local
68+
/// mempool. Mempool contents are OPTIONAL for viability -- an empty
69+
/// mempool yields a valid coinbase-only template -- so this never gates
70+
/// publication; it only enriches the next assembled template. Returns the
71+
/// mempool's accept verdict (false = rejected: bad utxo ref / already in).
72+
bool on_mempool_tx(const MutableTransaction& tx) {
73+
return m_state.mempool().add_tx(tx);
74+
}
75+
76+
/// Header / think path: the chain tip advanced. Stash the params the
77+
/// embedded template needs and mark tip-readiness, then republish if the
78+
/// MN list is also ready. curtime/version left 0 defer to
79+
/// build_embedded_workdata()'s own SAFE-ADDITIVE defaults.
80+
void on_new_tip(uint32_t prev_height, const uint256& prev_hash,
81+
uint32_t bits_for_next, uint32_t mtp_at_tip,
82+
uint8_t address_version, uint8_t address_p2sh_version,
83+
uint32_t curtime = 0, uint32_t version = 0) {
84+
m_prev_height = prev_height;
85+
m_prev_hash = prev_hash;
86+
m_bits_for_next = bits_for_next;
87+
m_mtp_at_tip = mtp_at_tip;
88+
m_address_version = address_version;
89+
m_address_p2sh_version = address_p2sh_version;
90+
m_curtime = curtime;
91+
m_version = version;
92+
m_have_tip = true;
93+
republish();
94+
}
95+
96+
/// Reorg / MN-list gap / mempool flush: invalidate the live bundle so the
97+
/// next get_work falls back to dashd until a fresh tip rebuilds it. The
98+
/// stashed tip params are dropped -- a reorg means the old prev_hash is no
99+
/// longer the tip, so we must NOT auto-republish it; a subsequent
100+
/// on_new_tip() re-arms tip-readiness. The MN list (which survives a mere
101+
/// reorg) is left in place.
102+
void on_invalidate() {
103+
m_have_tip = false;
104+
demote();
105+
}
106+
107+
/// True iff both prerequisites are met AND the holder is currently live.
108+
bool live() const { return m_state.populated(); }
109+
110+
private:
111+
// Publish only when both prerequisites are present; otherwise leave the
112+
// holder in whatever (un)published state it is in -- callers reach demote()
113+
// explicitly for the invalidating transitions.
114+
void republish() {
115+
if (m_have_tip && m_have_mn)
116+
m_state.set_tip(m_prev_height, m_prev_hash, m_bits_for_next,
117+
m_mtp_at_tip, m_address_version, m_address_p2sh_version,
118+
m_curtime, m_version);
119+
}
120+
121+
void demote() {
122+
if (m_state.populated())
123+
m_state.invalidate();
124+
}
125+
126+
NodeCoinState& m_state;
127+
128+
bool m_have_mn{false};
129+
bool m_have_tip{false};
130+
131+
// Last observed tip params, applied on republish().
132+
uint32_t m_prev_height{0};
133+
uint256 m_prev_hash;
134+
uint32_t m_bits_for_next{0};
135+
uint32_t m_mtp_at_tip{0};
136+
uint8_t m_address_version{0};
137+
uint8_t m_address_p2sh_version{0};
138+
uint32_t m_curtime{0};
139+
uint32_t m_version{0};
140+
};
141+
142+
} // namespace coin
143+
} // namespace dash

test/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,19 @@ if (BUILD_TESTING AND GTest_FOUND)
534534
target_link_libraries(test_dash_node_coin_state PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
535535
gtest_add_tests(test_dash_node_coin_state "" AUTO)
536536

537+
# CoinStateMaintainer: drives NodeCoinState off async tip/MN/mempool update
538+
# events (readiness gate: MN+tip required before publish). Same link set as
539+
# test_dash_node_coin_state -- header-only over the work_source selector set.
540+
add_executable(test_dash_coin_state_maintainer test_dash_coin_state_maintainer.cpp)
541+
target_link_libraries(test_dash_coin_state_maintainer PRIVATE
542+
GTest::gtest_main GTest::gtest
543+
dash_x11 core
544+
nlohmann_json::nlohmann_json
545+
${Boost_LIBRARIES}
546+
)
547+
target_link_libraries(test_dash_coin_state_maintainer PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
548+
gtest_add_tests(test_dash_coin_state_maintainer "" AUTO)
549+
537550
# DASH CSimplifiedMNListDiff (mnlistdiff wire, S8.1 leaf): vendored diff
538551
# round-trip + dashcore field-layout pin + apply_diff semantics. Header-only
539552
# over the SimplifiedMNList leaf + coin/transaction; no ltc/pool SCC dep.

0 commit comments

Comments
 (0)