Skip to content

Commit c2ef6a7

Browse files
committed
test(dash): G1 difficulty/vardiff parity KAT — share-diff floor + per-share min_work oracle pin
Pins dash::SharechainConfig::max_target() byte-exactness (mainnet 0xFFFF*2**208, testnet 2**256//2**20-1) and chain::target_to_average_attempts(floor) per-share min_work (mainnet 4295032833, testnet 1048576) to oracle-independent values derived from frstrtr/p2pool-dash bitcoin/data.py, plus the min_work accumulation identity and floor bits roundtrip. Pure/socket-free; 6/6 on Linux x86_64 ctest. Consensus-neutral (read-only difficulty accounting), independently-landable.
1 parent ff20c36 commit c2ef6a7

2 files changed

Lines changed: 124 additions & 0 deletions

File tree

test/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,20 @@ if (BUILD_TESTING AND GTest_FOUND)
328328
target_link_libraries(test_dash_share_messages PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
329329
gtest_add_tests(test_dash_share_messages "" AUTO)
330330

331+
# DASH G1 difficulty / vardiff PARITY KAT: share-diff floor byte-exactness +
332+
# per-share min_work (target_to_average_attempts) oracle pin. Header-only over
333+
# core/target_utils + config_pool; pure, socket-free. Mirrors the work_target
334+
# link set.
335+
add_executable(test_dash_difficulty_parity test_dash_difficulty_parity.cpp)
336+
target_link_libraries(test_dash_difficulty_parity PRIVATE
337+
GTest::gtest_main GTest::gtest
338+
dash_x11 core
339+
nlohmann_json::nlohmann_json
340+
${Boost_LIBRARIES}
341+
)
342+
target_link_libraries(test_dash_difficulty_parity PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
343+
gtest_add_tests(test_dash_difficulty_parity "" AUTO)
344+
331345
# share_init_verify gentx hash_link byte-parity vs oracle (coinbase_payload
332346
# VarStr prefix). Header-only over the dash_x11 + core link set; mirrors the
333347
# test_dash_conformance link set.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// DASH G1 difficulty / vardiff PARITY KAT.
2+
//
3+
// Pins the DASH sharechain difficulty floor and its per-share work accounting
4+
// to oracle-EXACT arithmetic from frstrtr/p2pool-dash (networks/dash.py +
5+
// bitcoin/data.py). Two independent surfaces:
6+
//
7+
// 1. dash::SharechainConfig::max_target() — the share-diff floor (easiest allowed
8+
// share target). Byte-exact to the oracle _DIFF1_TARGET (mainnet) and the
9+
// 2**256//2**20-1 testnet floor.
10+
// 2. chain::target_to_average_attempts(target) == 2**256 // (target+1) — the
11+
// per-share MINIMUM work that ShareIndex accumulates from m_max_bits
12+
// (share_chain.hpp:228). This is the quantity that drives cumulative-work
13+
// / APS retarget parity across the chain.
14+
//
15+
// Every expected value is derived INDEPENDENTLY from the oracle integer formula
16+
// (see the derive comment on each vector), NOT read back from the SUT — a true
17+
// byte-parity pin, not a tautology. The cross-coin APS-over-chain accumulation
18+
// is already pinned LTC-instantiated in test_compute_share_target.cpp; this KAT
19+
// pins the DASH-specific config floor + the min_work-per-share derivation those
20+
// oracle numbers differ on (p2pool-dash, not p2pool-ltc).
21+
//
22+
// Pure / socket-free / node-free: no VM200/201 dashd, no live sharechain.
23+
// Runs on every Linux x86_64 ctest.
24+
25+
#include <gtest/gtest.h>
26+
27+
#include <core/target_utils.hpp>
28+
#include <core/uint256.hpp>
29+
#include <impl/dash/config_pool.hpp>
30+
31+
namespace {
32+
uint288 U288(const char* h) { uint288 t; t.SetHex(h); return t; }
33+
} // namespace
34+
35+
// ── 1. share-diff floor byte-exactness (networks/dash.py SHARE_MAX_TARGET) ──
36+
37+
// mainnet floor == 0xFFFF * 2**208 (standard bdiff difficulty-1 target).
38+
TEST(DashDifficultyParity, MainnetMaxTargetFloorExact)
39+
{
40+
dash::SharechainConfig::is_testnet = false;
41+
EXPECT_EQ(dash::SharechainConfig::max_target().GetHex(),
42+
"00000000ffff0000000000000000000000000000000000000000000000000000");
43+
}
44+
45+
// testnet floor == 2**256 // 2**20 - 1. Derive (python3):
46+
// "%064x" % (2**256 // 2**20 - 1)
47+
TEST(DashDifficultyParity, TestnetMaxTargetFloorExact)
48+
{
49+
dash::SharechainConfig::is_testnet = true;
50+
EXPECT_EQ(dash::SharechainConfig::max_target().GetHex(),
51+
"00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
52+
dash::SharechainConfig::is_testnet = false;
53+
}
54+
55+
// ── 2. per-share min_work = target_to_average_attempts(floor) ───────────────
56+
//
57+
// ShareIndex(share).min_work = target_to_average_attempts(bits_to_target(
58+
// m_max_bits)) (share_chain.hpp:228). At the difficulty floor that reduces
59+
// to target_to_average_attempts(max_target()).
60+
61+
// mainnet: attempts = 2**256 // (0xFFFF*2**208 + 1). Derive (python3):
62+
// (2**256)//(0xFFFF*(2**208)+1) == 4295032833 == 0x100010001
63+
TEST(DashDifficultyParity, MainnetPerShareMinWorkExact)
64+
{
65+
dash::SharechainConfig::is_testnet = false;
66+
uint288 attempts = chain::target_to_average_attempts(dash::SharechainConfig::max_target());
67+
EXPECT_EQ(attempts.GetHex(), U288("100010001").GetHex());
68+
EXPECT_TRUE(attempts == static_cast<uint64_t>(4295032833ULL));
69+
}
70+
71+
// testnet: attempts = 2**256 // (2**256//2**20). Derive (python3):
72+
// (2**256)//((2**256//2**20-1)+1) == 1048576 == 2**20 == 0x100000
73+
TEST(DashDifficultyParity, TestnetPerShareMinWorkExact)
74+
{
75+
dash::SharechainConfig::is_testnet = true;
76+
uint288 attempts = chain::target_to_average_attempts(dash::SharechainConfig::max_target());
77+
EXPECT_EQ(attempts.GetHex(), U288("100000").GetHex());
78+
EXPECT_TRUE(attempts == static_cast<uint64_t>(1048576ULL));
79+
dash::SharechainConfig::is_testnet = false;
80+
}
81+
82+
// ── 3. ShareIndex min_work accumulation identity (dash floor) ───────────────
83+
//
84+
// Over N equal-floor shares the accumulated min_work == per_share * N, the same
85+
// identity DeltaCache maintains (test_compute_share_target DeltaCacheAfterPruning,
86+
// LTC). Pinned here with DASH-floor numbers so a config-floor regression is
87+
// caught in the DASH lane directly.
88+
TEST(DashDifficultyParity, MainnetMinWorkAccumulationIdentity)
89+
{
90+
dash::SharechainConfig::is_testnet = false;
91+
uint288 per_share = chain::target_to_average_attempts(dash::SharechainConfig::max_target());
92+
// N=199 (default real_chain window sample). Derive (python3):
93+
// 4295032833 * 199 == 854711533767
94+
uint288 acc = per_share * static_cast<uint64_t>(199);
95+
EXPECT_TRUE(acc == static_cast<uint64_t>(854711533767ULL));
96+
}
97+
98+
// ── 4. floor bits roundtrip (m_max_bits <-> floor target) ───────────────────
99+
//
100+
// ShareIndex derives min_work from m_max_bits via bits_to_target; the floor
101+
// must survive the compact encode/decode used to carry it on the wire.
102+
TEST(DashDifficultyParity, MainnetFloorBitsRoundtrip)
103+
{
104+
dash::SharechainConfig::is_testnet = false;
105+
uint256 floor = dash::SharechainConfig::max_target();
106+
uint32_t bits = chain::target_to_bits_upper_bound(floor);
107+
uint256 decoded = chain::bits_to_target(bits);
108+
EXPECT_EQ(decoded, floor); // exact roundtrip at the standard floor
109+
EXPECT_EQ(bits >> 24, 0x1du); // 0xFFFF*2**208 -> exponent 0x1d (29 bytes)
110+
}

0 commit comments

Comments
 (0)