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 @@ -88,7 +88,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_cb_payee test_dash_poolnode_messages \
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_poolnode_messages test_dash_peer \
test_multiaddress_pplns test_pplns_stress \
test_hash_link test_decay_pplns \
test_pplns_consensus \
Expand Down Expand Up @@ -238,7 +238,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_cb_payee test_dash_poolnode_messages \
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_poolnode_messages test_dash_peer \
test_hash_link test_decay_pplns \
test_pplns_consensus \
test_v36_script_sorting test_v36_cross_impl_refhash \
Expand Down
43 changes: 43 additions & 0 deletions src/impl/dash/peer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once

// Dash p2pool sharechain pool-peer state.
//
// S8 pool-node leaf 1 of N. Mirrors btc::Peer / dgb::Peer: the per-peer state a
// pool Node keeps for every connected p2pool share-network peer (NOT a dashd
// coin-daemon peer — that layer is coin/p2p_connection.hpp). Tracks the
// negotiated version/subversion/services from the `version` handshake, the
// connection timestamp, and the remembered-transaction sets used by the
// share-message protocol (remote_txs = hashes the peer advertises; remembered_txs
// = full txs we have forwarded/learned, keyed by hash).
//
// Pure state struct, no socket/IO — header-only, rig-free, fenced to src/impl/dash/.

#include "coin/transaction.hpp"

#include <chrono>
#include <map>
#include <optional>
#include <set>
#include <string>

#include <core/uint256.hpp>

namespace dash
{

struct Peer
{
// === negotiated via the `version` handshake ===
std::optional<uint32_t> m_other_version;
std::string m_other_subversion;
uint64_t m_other_services{0};
uint64_t m_nonce{0};

std::chrono::steady_clock::time_point m_connected_at{std::chrono::steady_clock::now()};

// === remembered-transaction protocol state ===
std::set<uint256> m_remote_txs; // hashes the remote peer has advertised
std::map<uint256, coin::Transaction> m_remembered_txs; // full txs keyed by hash
};

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

add_executable(test_dash_peer test_dash_peer.cpp)
target_link_libraries(test_dash_peer PRIVATE
GTest::gtest_main GTest::gtest
dash_x11 core
nlohmann_json::nlohmann_json
${Boost_LIBRARIES}
)
target_link_libraries(test_dash_peer PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
gtest_add_tests(test_dash_peer "" AUTO)

# additive: pure persisted activation-latch (header-only version_activation_latch.hpp);
# mirrors the test_dash_config link set (nlohmann_json + core), no ltc/pool SCC dependency.
add_executable(test_dash_version_activation_latch test_dash_version_activation_latch.cpp)
Expand Down
102 changes: 102 additions & 0 deletions test/test_dash_peer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/// Phase S8 — Dash sharechain pool-node leaf 1: per-peer state (src/impl/dash/peer.hpp).
///
/// dash::Peer is the analog of btc::Peer / dgb::Peer: the state a pool Node holds
/// for each connected p2pool share-network peer. The pool-node bridge (node.hpp,
/// a later leaf) keys a Peer off every connection and drives it from the share
/// message handlers. This KAT pins the observable contract those handlers read:
///
/// (a) fresh-peer defaults — no negotiated version yet, empty subversion,
/// zeroed services/nonce, empty remember-sets, connection time stamped.
/// (b) version-handshake fields round-trip (what the `version` handler writes).
/// (c) the remembered-tx protocol state: m_remote_txs is a dedup hash set and
/// m_remembered_txs maps hash -> full coin::Transaction with erase.
/// (d) connection timestamps are monotonic across successive peers.

#include <impl/dash/peer.hpp>
#include <impl/dash/coin/transaction.hpp>

#include <core/uint256.hpp>

#include <gtest/gtest.h>

#include <chrono>

using dash::Peer;

namespace
{
uint256 H(uint8_t b)
{
uint256 h;
h.begin()[0] = b;
return h;
}
} // namespace

TEST(DashPeer, FreshDefaultsAreSane)
{
Peer p;
EXPECT_FALSE(p.m_other_version.has_value());
EXPECT_TRUE(p.m_other_subversion.empty());
EXPECT_EQ(p.m_other_services, 0u);
EXPECT_EQ(p.m_nonce, 0u);
EXPECT_TRUE(p.m_remote_txs.empty());
EXPECT_TRUE(p.m_remembered_txs.empty());
EXPECT_LE(p.m_connected_at, std::chrono::steady_clock::now());
}

TEST(DashPeer, VersionHandshakeRoundTrip)
{
Peer p;
p.m_other_version = 70238u; // dashd-aligned proto seen on the wire
p.m_other_subversion = "/c2pool-dash:0.1/";
p.m_other_services = 0x9u;
p.m_nonce = 0xdeadbeefull;

ASSERT_TRUE(p.m_other_version.has_value());
EXPECT_EQ(*p.m_other_version, 70238u);
EXPECT_EQ(p.m_other_subversion, "/c2pool-dash:0.1/");
EXPECT_EQ(p.m_other_services, 0x9u);
EXPECT_EQ(p.m_nonce, 0xdeadbeefull);
}

TEST(DashPeer, RemoteTxSetDedups)
{
Peer p;
p.m_remote_txs.insert(H(1));
p.m_remote_txs.insert(H(2));
p.m_remote_txs.insert(H(1)); // duplicate advertise
EXPECT_EQ(p.m_remote_txs.size(), 2u);
EXPECT_EQ(p.m_remote_txs.count(H(1)), 1u);
EXPECT_EQ(p.m_remote_txs.count(H(9)), 0u);
}

TEST(DashPeer, RememberedTxRoundTripAndErase)
{
Peer p;

dash::coin::MutableTransaction mtx;
mtx.version = 2;
mtx.type = 5; // DIP4 CBTX
mtx.locktime = 99;
dash::coin::Transaction tx(mtx);

const uint256 key = H(7);
p.m_remembered_txs.emplace(key, tx);

auto it = p.m_remembered_txs.find(key);
ASSERT_NE(it, p.m_remembered_txs.end());
EXPECT_EQ(it->second.version, 2);
EXPECT_EQ(it->second.type, 5);
EXPECT_EQ(it->second.locktime, 99u);

EXPECT_EQ(p.m_remembered_txs.erase(key), 1u);
EXPECT_TRUE(p.m_remembered_txs.empty());
}

TEST(DashPeer, ConnectedAtMonotonicAcrossPeers)
{
Peer a;
Peer b;
EXPECT_LE(a.m_connected_at, b.m_connected_at);
}
Loading