Skip to content

Commit fe4d734

Browse files
committed
dash: add sharechain pool-peer state (S8 pool-node leaf 1)
DASH lacked the p2pool sharechain pool-node layer that btc and dgb both carry (node.hpp/peer.hpp/messages.hpp/share_tracker.hpp/share_messages.hpp), which blocks the full gate (b) bind/dial-crosses-shares path. This is leaf 1: the per-peer state struct. src/impl/dash/peer.hpp — dash::Peer, analog of btc::Peer/dgb::Peer: negotiated version/subversion/services/nonce from the version handshake, connection timestamp, and the remembered-tx protocol sets (m_remote_txs hash set + m_remembered_txs hash->coin::Transaction map). Pure header-only state, no IO. test/test_dash_peer.cpp — 5 KATs: fresh-peer defaults, version-handshake round-trip, remote-tx set dedup, remembered-tx map roundtrip+erase, monotonic connection timestamps. 5/5 green, non-hollow. Strictly fenced to src/impl/dash/ + test wiring (CMakeLists + build.yml allowlist); no bitcoin_family/src/core/other-coin touch.
1 parent 062183e commit fe4d734

4 files changed

Lines changed: 157 additions & 2 deletions

File tree

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ jobs:
8282
test_threading test_weights \
8383
test_header_chain test_mempool test_template_builder \
8484
test_doge_chain test_compact_blocks test_dash_x11_kat \
85-
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_cb_payee \
85+
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_cb_payee test_dash_peer \
8686
test_multiaddress_pplns test_pplns_stress \
8787
test_hash_link test_decay_pplns \
8888
test_pplns_consensus \
@@ -226,7 +226,7 @@ jobs:
226226
test_threading test_weights \
227227
test_header_chain test_mempool test_template_builder \
228228
test_doge_chain test_compact_blocks test_dash_x11_kat \
229-
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_cb_payee \
229+
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_cb_payee test_dash_peer \
230230
test_hash_link test_decay_pplns \
231231
test_pplns_consensus \
232232
test_v36_script_sorting test_v36_cross_impl_refhash \

src/impl/dash/peer.hpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#pragma once
2+
3+
// Dash p2pool sharechain pool-peer state.
4+
//
5+
// S8 pool-node leaf 1 of N. Mirrors btc::Peer / dgb::Peer: the per-peer state a
6+
// pool Node keeps for every connected p2pool share-network peer (NOT a dashd
7+
// coin-daemon peer — that layer is coin/p2p_connection.hpp). Tracks the
8+
// negotiated version/subversion/services from the `version` handshake, the
9+
// connection timestamp, and the remembered-transaction sets used by the
10+
// share-message protocol (remote_txs = hashes the peer advertises; remembered_txs
11+
// = full txs we have forwarded/learned, keyed by hash).
12+
//
13+
// Pure state struct, no socket/IO — header-only, rig-free, fenced to src/impl/dash/.
14+
15+
#include "coin/transaction.hpp"
16+
17+
#include <chrono>
18+
#include <map>
19+
#include <optional>
20+
#include <set>
21+
#include <string>
22+
23+
#include <core/uint256.hpp>
24+
25+
namespace dash
26+
{
27+
28+
struct Peer
29+
{
30+
// === negotiated via the `version` handshake ===
31+
std::optional<uint32_t> m_other_version;
32+
std::string m_other_subversion;
33+
uint64_t m_other_services{0};
34+
uint64_t m_nonce{0};
35+
36+
std::chrono::steady_clock::time_point m_connected_at{std::chrono::steady_clock::now()};
37+
38+
// === remembered-transaction protocol state ===
39+
std::set<uint256> m_remote_txs; // hashes the remote peer has advertised
40+
std::map<uint256, coin::Transaction> m_remembered_txs; // full txs keyed by hash
41+
};
42+
43+
}; // namespace dash

test/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,16 @@ if (BUILD_TESTING AND GTest_FOUND)
491491
target_link_libraries(test_dash_config PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
492492
gtest_add_tests(test_dash_config "" AUTO)
493493

494+
add_executable(test_dash_peer test_dash_peer.cpp)
495+
target_link_libraries(test_dash_peer PRIVATE
496+
GTest::gtest_main GTest::gtest
497+
dash_x11 core
498+
nlohmann_json::nlohmann_json
499+
${Boost_LIBRARIES}
500+
)
501+
target_link_libraries(test_dash_peer PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
502+
gtest_add_tests(test_dash_peer "" AUTO)
503+
494504
# additive: pure persisted activation-latch (header-only version_activation_latch.hpp);
495505
# mirrors the test_dash_config link set (nlohmann_json + core), no ltc/pool SCC dependency.
496506
add_executable(test_dash_version_activation_latch test_dash_version_activation_latch.cpp)

test/test_dash_peer.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/// Phase S8 — Dash sharechain pool-node leaf 1: per-peer state (src/impl/dash/peer.hpp).
2+
///
3+
/// dash::Peer is the analog of btc::Peer / dgb::Peer: the state a pool Node holds
4+
/// for each connected p2pool share-network peer. The pool-node bridge (node.hpp,
5+
/// a later leaf) keys a Peer off every connection and drives it from the share
6+
/// message handlers. This KAT pins the observable contract those handlers read:
7+
///
8+
/// (a) fresh-peer defaults — no negotiated version yet, empty subversion,
9+
/// zeroed services/nonce, empty remember-sets, connection time stamped.
10+
/// (b) version-handshake fields round-trip (what the `version` handler writes).
11+
/// (c) the remembered-tx protocol state: m_remote_txs is a dedup hash set and
12+
/// m_remembered_txs maps hash -> full coin::Transaction with erase.
13+
/// (d) connection timestamps are monotonic across successive peers.
14+
15+
#include <impl/dash/peer.hpp>
16+
#include <impl/dash/coin/transaction.hpp>
17+
18+
#include <core/uint256.hpp>
19+
20+
#include <gtest/gtest.h>
21+
22+
#include <chrono>
23+
24+
using dash::Peer;
25+
26+
namespace
27+
{
28+
uint256 H(uint8_t b)
29+
{
30+
uint256 h;
31+
h.begin()[0] = b;
32+
return h;
33+
}
34+
} // namespace
35+
36+
TEST(DashPeer, FreshDefaultsAreSane)
37+
{
38+
Peer p;
39+
EXPECT_FALSE(p.m_other_version.has_value());
40+
EXPECT_TRUE(p.m_other_subversion.empty());
41+
EXPECT_EQ(p.m_other_services, 0u);
42+
EXPECT_EQ(p.m_nonce, 0u);
43+
EXPECT_TRUE(p.m_remote_txs.empty());
44+
EXPECT_TRUE(p.m_remembered_txs.empty());
45+
EXPECT_LE(p.m_connected_at, std::chrono::steady_clock::now());
46+
}
47+
48+
TEST(DashPeer, VersionHandshakeRoundTrip)
49+
{
50+
Peer p;
51+
p.m_other_version = 70238u; // dashd-aligned proto seen on the wire
52+
p.m_other_subversion = "/c2pool-dash:0.1/";
53+
p.m_other_services = 0x9u;
54+
p.m_nonce = 0xdeadbeefull;
55+
56+
ASSERT_TRUE(p.m_other_version.has_value());
57+
EXPECT_EQ(*p.m_other_version, 70238u);
58+
EXPECT_EQ(p.m_other_subversion, "/c2pool-dash:0.1/");
59+
EXPECT_EQ(p.m_other_services, 0x9u);
60+
EXPECT_EQ(p.m_nonce, 0xdeadbeefull);
61+
}
62+
63+
TEST(DashPeer, RemoteTxSetDedups)
64+
{
65+
Peer p;
66+
p.m_remote_txs.insert(H(1));
67+
p.m_remote_txs.insert(H(2));
68+
p.m_remote_txs.insert(H(1)); // duplicate advertise
69+
EXPECT_EQ(p.m_remote_txs.size(), 2u);
70+
EXPECT_EQ(p.m_remote_txs.count(H(1)), 1u);
71+
EXPECT_EQ(p.m_remote_txs.count(H(9)), 0u);
72+
}
73+
74+
TEST(DashPeer, RememberedTxRoundTripAndErase)
75+
{
76+
Peer p;
77+
78+
dash::coin::MutableTransaction mtx;
79+
mtx.version = 2;
80+
mtx.type = 5; // DIP4 CBTX
81+
mtx.locktime = 99;
82+
dash::coin::Transaction tx(mtx);
83+
84+
const uint256 key = H(7);
85+
p.m_remembered_txs.emplace(key, tx);
86+
87+
auto it = p.m_remembered_txs.find(key);
88+
ASSERT_NE(it, p.m_remembered_txs.end());
89+
EXPECT_EQ(it->second.version, 2);
90+
EXPECT_EQ(it->second.type, 5);
91+
EXPECT_EQ(it->second.locktime, 99u);
92+
93+
EXPECT_EQ(p.m_remembered_txs.erase(key), 1u);
94+
EXPECT_TRUE(p.m_remembered_txs.empty());
95+
}
96+
97+
TEST(DashPeer, ConnectedAtMonotonicAcrossPeers)
98+
{
99+
Peer a;
100+
Peer b;
101+
EXPECT_LE(a.m_connected_at, b.m_connected_at);
102+
}

0 commit comments

Comments
 (0)