diff --git a/test/test_dash_header_chain.cpp b/test/test_dash_header_chain.cpp index a5ba3057d..2cedca090 100644 --- a/test/test_dash_header_chain.cpp +++ b/test/test_dash_header_chain.cpp @@ -176,3 +176,49 @@ TEST(DashDGWv3Kat, CheckPowAcceptsBelowTargetRejectsAbove) { high_hash.SetHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); EXPECT_FALSE(check_pow(high_hash, 0x1e0ffff0, pow_limit)); } + +// ── Real-node KAT: DASH testnet3 DGW-v3 retarget at height 1497944 ────────── +// Live counterpart to the hand-derived synthetic vectors above. The 24 real +// ancestors 1497920..1497943 (genuine bits + timestamps captured from a synced +// testnet3 dashd; verified to contain no min-difficulty / pow-limit resets, so +// the pure DarkGravityWave path applies) must reproduce the bits the node +// itself assigned to block 1497944, namely 0x1e00f256. A divergence here is a +// real consensus drift vs live Dash, not a synthetic-arithmetic quibble. +TEST(DashDGWv3Kat, RealTestnet3Window1497944ReproducesNextBits) { + struct Row { uint32_t height; uint32_t bits; uint32_t time; }; + static const Row rows[] = { + {1497920u, 0x1e01279eu, 1781733608u}, {1497921u, 0x1e010524u, 1781733780u}, + {1497922u, 0x1e00fa0eu, 1781734122u}, {1497923u, 0x1e010475u, 1781734381u}, + {1497924u, 0x1e0101a5u, 1781734502u}, {1497925u, 0x1e01061bu, 1781734507u}, + {1497926u, 0x1e00fcd3u, 1781734513u}, {1497927u, 0x1e00f77bu, 1781734560u}, + {1497928u, 0x1e00e365u, 1781735022u}, {1497929u, 0x1e010157u, 1781735130u}, + {1497930u, 0x1e00fa44u, 1781735136u}, {1497931u, 0x1e00eb8au, 1781735361u}, + {1497932u, 0x1e00eda8u, 1781735637u}, {1497933u, 0x1e00fb31u, 1781735760u}, + {1497934u, 0x1e00f824u, 1781736070u}, {1497935u, 0x1e00fa74u, 1781736216u}, + {1497936u, 0x1e00faccu, 1781736245u}, {1497937u, 0x1e00f8deu, 1781736267u}, + {1497938u, 0x1e00f49bu, 1781736600u}, {1497939u, 0x1e01013au, 1781736614u}, + {1497940u, 0x1e00fa45u, 1781736710u}, {1497941u, 0x1e00fb8au, 1781736758u}, + {1497942u, 0x1e00f3b6u, 1781737051u}, {1497943u, 0x1e00f4c3u, 1781737080u}, + }; + auto ancestor = [&](uint32_t h) -> std::optional { + for (const auto& r : rows) { + if (r.height == h) { + IndexEntry e; + e.height = r.height; + e.header.m_bits = r.bits; + e.header.m_timestamp = r.time; + return e; + } + } + return std::nullopt; + }; + + // testnet3 params: target_spacing 150 and pow_limit identical to mainnet, so + // the DGW arithmetic is the same; allow_min_difficulty is not consulted by + // the pure dark_gravity_wave() (it gates the validation layer, not the avg). + auto params = make_dash_chain_params_testnet(); + uint32_t bits = dark_gravity_wave(ancestor, /*tip_height=*/1497943u, params); + EXPECT_EQ(bits, 0x1e00f256u) + << "DGW-v3 over the real 1497920..1497943 window must reproduce the " + "node-assigned bits of block 1497944"; +} diff --git a/test/test_dash_x11_kat.cpp b/test/test_dash_x11_kat.cpp index 1ef56fa57..1b56dc438 100644 --- a/test/test_dash_x11_kat.cpp +++ b/test/test_dash_x11_kat.cpp @@ -59,3 +59,33 @@ TEST(DashX11Kat, Deterministic) { EXPECT_EQ(dash::crypto::hash_x11(header, 80).GetHex(), dash::crypto::hash_x11(header, 80).GetHex()); } + +// ── Real-node KAT: DASH testnet3 block #1497944 ───────────────────────────── +// Captured from a fully-synced testnet3 dashd (getblockheader RPC; blocks== +// headers, initialblockdownload=false). Hashing the real 80-byte header with +// X11 must reproduce the block hash the node reports. Unlike the static mainnet +// genesis above, this pins the pipeline against live-mined consensus data. +TEST(DashX11Kat, Testnet3Block1497944ReproducesBlockHash) { + constexpr uint32_t version = 536870912u; + constexpr uint32_t time = 1781737170u; + constexpr uint32_t bits = 0x1e00f256u; + constexpr uint32_t nonce = 721236u; + const char* prev_hex = "000000dbbc08ee519459b38b02bb7754b455dd00cd74069a1352f08f0dd986db"; + const char* merkle_hex = "0464a4ac5f058a742f6aa42b2b3c7489abde7609b529612bcfa5da34b10bdb1b"; + const char* expected = "000000b6a4e5ea1a0854ef83f0028dde5b96cdaacc604decd8b064d0cea38234"; + + uint256 prev_block; prev_block.SetHex(prev_hex); + uint256 merkle_root; merkle_root.SetHex(merkle_hex); + + unsigned char header[80]; + size_t off = 0; + std::memcpy(header + off, &version, 4); off += 4; + std::memcpy(header + off, prev_block.data(), 32); off += 32; + std::memcpy(header + off, merkle_root.data(), 32); off += 32; + std::memcpy(header + off, &time, 4); off += 4; + std::memcpy(header + off, &bits, 4); off += 4; + std::memcpy(header + off, &nonce, 4); off += 4; + + uint256 pow = dash::crypto::hash_x11(header, sizeof(header)); + EXPECT_EQ(pow.GetHex(), expected); +}