diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e023479d..1c8172cb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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_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_multiaddress_pplns test_pplns_stress \ test_hash_link test_decay_pplns \ test_pplns_consensus \ @@ -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_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_hash_link test_decay_pplns \ test_pplns_consensus \ test_v36_script_sorting test_v36_cross_impl_refhash \ diff --git a/src/impl/dash/min_protocol_gate.hpp b/src/impl/dash/min_protocol_gate.hpp new file mode 100644 index 00000000..0ff10c30 --- /dev/null +++ b/src/impl/dash/min_protocol_gate.hpp @@ -0,0 +1,53 @@ +#pragma once + +// DASH sharechain minimum-protocol-version gate (v36 min-proto ratchet, #643). +// +// SCOPE: a parameterized, per-instance policy for the reject-if-proto36 is +// older-than-v35; the floor is a chosen constant, not an oracle-derived one). +// +// ISOLATION: fenced to src/impl/dash/. Touches NO shared bitcoin_family / core +// version-handshake types (per-coin isolation primitive boundary). + +#include + +#include "config_pool.hpp" + +namespace dash +{ + +// Per-instance minimum-protocol-version policy. Default-constructed it holds the +// oracle accept-all floor (1700) and accepts every peer at or above it. +struct MinProtocolGate +{ + // The rejection floor. A peer is admitted iff peer_protocol >= min_version. + uint32_t min_version = SharechainConfig::MINIMUM_PROTOCOL_VERSION; + + MinProtocolGate() = default; + explicit MinProtocolGate(uint32_t floor) : min_version(floor) {} + + // reject-if-proto admit the peer. + // At the default floor (1700) this is accept-all for every real DASH peer. + [[nodiscard]] bool accepts(uint32_t peer_protocol) const + { + return peer_protocol >= min_version; + } + + // Convenience inverse for handshake sites that branch on rejection. + [[nodiscard]] bool rejects(uint32_t peer_protocol) const + { + return !accepts(peer_protocol); + } +}; + +} // namespace dash diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ea8e4fa9..d72432ed 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -263,6 +263,18 @@ if (BUILD_TESTING AND GTest_FOUND) target_link_libraries(test_dash_conformance PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39): core stratum/web_server TUs gtest_add_tests(test_dash_conformance "" AUTO) + # DASH min-protocol-version ratchet gate KAT (#643, option a): pure, header-only + # policy object; no socket/ltc/pool dependency. Mirrors the test_dash_conformance link set. + add_executable(test_dash_min_protocol_gate test_dash_min_protocol_gate.cpp) + target_link_libraries(test_dash_min_protocol_gate PRIVATE + GTest::gtest_main GTest::gtest + dash_x11 core + nlohmann_json::nlohmann_json + ${Boost_LIBRARIES} + ) + target_link_libraries(test_dash_min_protocol_gate PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39): core stratum/web_server TUs + gtest_add_tests(test_dash_min_protocol_gate "" AUTO) + # DASH S8 pool-node leaf 4 — share_tracker.hpp KAT: DensePPLNSWindow decayed # weight ring buffer (compute_v36_weights), decay table, donation split, # window slides. PoW-independent consensus core; socket-free, chain-free. diff --git a/test/test_dash_min_protocol_gate.cpp b/test/test_dash_min_protocol_gate.cpp new file mode 100644 index 00000000..e29c52fb --- /dev/null +++ b/test/test_dash_min_protocol_gate.cpp @@ -0,0 +1,64 @@ +// KAT for the DASH min-protocol-version ratchet gate (#643, option a). +// +// Pins the two invariants integrator required for the SAFE-ADDITIVE leaf: +// 1. NO-OP AT DEFAULT: a default-constructed gate carries the oracle floor +// (1700) and MUST admit a peer at protocol=1700. Nobody may later read the +// landed leaf as an already-live ratchet. +// 2. PARAMETERIZED, NOT BAKED: the floor is a per-instance member, so raising +// it rejects below-floor peers -- proving the ratchet MECHANISM works while +// the default stays inert. + +#include + +#include "impl/dash/config_pool.hpp" +#include "impl/dash/min_protocol_gate.hpp" + +using dash::MinProtocolGate; +using dash::SharechainConfig; + +// (1) Default gate == oracle accept-all floor, and it is a genuine no-op there. +TEST(DashMinProtocolGate, DefaultFloorIsOracleAcceptAll) +{ + MinProtocolGate gate; + EXPECT_EQ(gate.min_version, SharechainConfig::MINIMUM_PROTOCOL_VERSION); + EXPECT_EQ(gate.min_version, 1700u); + + // A peer AT the floor MUST be accepted -- this is the no-op assertion. + EXPECT_TRUE(gate.accepts(1700u)); + EXPECT_FALSE(gate.rejects(1700u)); + + // Real DASH peers advertise >= 1700, so the default admits every one. + EXPECT_TRUE(gate.accepts(1700u)); + EXPECT_TRUE(gate.accepts(1800u)); + EXPECT_TRUE(gate.accepts(70210u)); +} + +// (2) Below the default floor is rejected -- boundary is >=, not >. +TEST(DashMinProtocolGate, BelowDefaultFloorRejected) +{ + MinProtocolGate gate; + EXPECT_FALSE(gate.accepts(1699u)); + EXPECT_TRUE(gate.rejects(1699u)); + EXPECT_FALSE(gate.accepts(0u)); + // Exact boundary: floor-1 out, floor in. + EXPECT_FALSE(gate.accepts(gate.min_version - 1)); + EXPECT_TRUE(gate.accepts(gate.min_version)); +} + +// (3) The floor is a settable per-instance member -- the ratchet mechanism. +// Raising it to a hypothetical v36 value rejects the old-floor peer, but +// this is a per-instance choice, NOT a committed constant. +TEST(DashMinProtocolGate, RatchetIsParameterizedNotBaked) +{ + // Operator knob: raise the floor at G2-migration time. + MinProtocolGate ratcheted(1800u); + EXPECT_EQ(ratcheted.min_version, 1800u); + EXPECT_FALSE(ratcheted.accepts(1700u)); // old-floor peer now rejected + EXPECT_TRUE(ratcheted.accepts(1800u)); // at-new-floor peer admitted + + // The default gate is UNAFFECTED -- proving the ratchet is per-instance and + // the leaf commits no premature v36 constant. + MinProtocolGate defaulted; + EXPECT_TRUE(defaulted.accepts(1700u)); + EXPECT_EQ(defaulted.min_version, 1700u); +}