@@ -70,6 +70,23 @@ void put_le(std::vector<unsigned char>& v, uint64_t x, int n) {
7070 for (int i = 0 ; i < n; ++i) v.push_back (static_cast <unsigned char >((x >> (8 * i)) & 0xff ));
7171}
7272
73+ // Parse a hex string to bytes (test fixtures embed real on-chain payloads).
74+ std::vector<unsigned char > bytes_from_hex (const std::string& h) {
75+ std::vector<unsigned char > v; v.reserve (h.size () / 2 );
76+ auto nib = [](char c) -> int { return c <= ' 9' ? c - ' 0' : (c | 0x20 ) - ' a' + 10 ; };
77+ for (size_t i = 0 ; i + 1 < h.size (); i += 2 )
78+ v.push_back (static_cast <unsigned char >((nib (h[i]) << 4 ) | nib (h[i + 1 ])));
79+ return v;
80+ }
81+
82+ // Append Bitcoin CompactSize(n) == oracle pack.VarStrType length prefix.
83+ void append_compactsize (std::vector<unsigned char >& v, uint64_t n) {
84+ if (n < 0xfd ) { v.push_back (static_cast <unsigned char >(n)); }
85+ else if (n <= 0xffff ) { v.push_back (0xfd ); put_le (v, n, 2 ); }
86+ else if (n <= 0xffffffffULL ) { v.push_back (0xfe ); put_le (v, n, 4 ); }
87+ else { v.push_back (0xff ); put_le (v, n, 8 ); }
88+ }
89+
7390const std::vector<unsigned char > kPayload = {0xde , 0xad , 0xbe , 0xef };
7491
7592} // namespace
@@ -101,6 +118,56 @@ TEST(DashShareHashLink, OracleCheckHashLinkVarStrPayload) {
101118 EXPECT_NE (hex_of (g), hex_of (gr)) << " compactsize prefix must change gentx_hash" ;
102119}
103120
121+ // (1b) Non-circular oracle anchor over REAL testnet3 DIP4 special-tx payloads.
122+ // #412 proved the VarStr(coinbase_payload) assembly with a 4-byte synthetic
123+ // payload; G0/G1 (per-coin byte-parity gate before the G2 crossing) pins the
124+ // SAME assembly against ACTUAL on-chain extraPayloads captured from dashd
125+ // (testnet3), covering BOTH compactsize branches: single-byte (<0xfd) and
126+ // 0xfd+u16-LE. Expected digests are computed OUT-OF-BAND with CPython
127+ // (sha256d), so they are non-circular with the C++ check_hash_link path.
128+ // A: blk 1502030 txid 7d292a63... type-5 CbTx, 175B (compactsize 0xaf)
129+ // B: blk 1501948 txid b4d1a2a5... type-6 qcTx, 419B (compactsize 0xfd a3 01)
130+ TEST (DashShareHashLink, RealTestnet3SpecialTxVarStrParity) {
131+ auto hl = iv_hash_link ();
132+ const auto ce = dash::compute_gentx_before_refhash (); // unused at length%64==0
133+
134+ struct CbTxKat { const char * name; const char * payload_hex;
135+ const char * varstr; const char * raw_append; };
136+ const CbTxKat kats[] = {
137+ {" testnet3-1502030-cbtx-type5" ,
138+ " 03004eeb1600286ca33b2ec502759646df1259df9ee5b599722122f5bb4ba6a01062782e489ff09af4994ea6306dbe1aa636373c0d9c0fabc6c61d4402754b9878f63f4c277e008b96e1d2f74c1717728f47d319e151460adc51ffd76686c10ede2e3a31d5faaeb724a65736167a7d8f17b1f880585a0c1164f6882d5e5d6c8a5ff3b75d47ee6359d0662964109e7fa17658d04843e4c6eca499a55ed01bd4efd49b10848aa04a5a36b0fcdb1d0000" ,
139+ " 6e985201f8a1d0cf46c97a1379c140c9564ee56c1649af5cbce8b7d9cc986665" ,
140+ " 69ebfd8ee54d039ffece6bb1c8cab97ec3c6b24715e4ae57c30428a9dbc4ac1a" },
141+ {" testnet3-1501948-qctx-type6" ,
142+ " 0100fcea160003000270282f59392f2433c05a9f4c948c9f31dab53cf42e112ca68b9854fdc5000000fd90010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd900100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ,
143+ " e60ea7ea8c11c17af6a7573b0399c87e4672175986cf54d407875bf33c05c84f" ,
144+ " 4fa8a56bb753593362540b9d8006c2b80a191d2d194eba2714162a9cd41bbe56" },
145+ };
146+ for (const auto & k : kats) {
147+ const auto payload = bytes_from_hex (k.payload_hex );
148+
149+ // VarStr(payload) = CompactSize(len) || payload (oracle data.py:278)
150+ std::vector<unsigned char > data;
151+ for (int i = 0 ; i < 32 ; ++i) data.push_back (static_cast <unsigned char >(i));
152+ put_le (data, 0 , 8 ); // last_txout_nonce
153+ put_le (data, 0 , 4 ); // IntType(32).pack(0)
154+ append_compactsize (data, payload.size ());
155+ data.insert (data.end (), payload.begin (), payload.end ());
156+ uint256 g = dash::check_hash_link (hl, data, ce);
157+ EXPECT_EQ (hex_of (g), k.varstr ) << k.name ;
158+
159+ // Buggy raw-append (no compactsize) -> separately-pinned, must differ.
160+ std::vector<unsigned char > raw;
161+ for (int i = 0 ; i < 32 ; ++i) raw.push_back (static_cast <unsigned char >(i));
162+ put_le (raw, 0 , 8 );
163+ put_le (raw, 0 , 4 );
164+ raw.insert (raw.end (), payload.begin (), payload.end ());
165+ uint256 gr = dash::check_hash_link (hl, raw, ce);
166+ EXPECT_EQ (hex_of (gr), k.raw_append ) << k.name ;
167+ EXPECT_NE (hex_of (g), hex_of (gr)) << k.name << " : compactsize prefix must matter" ;
168+ }
169+ }
170+
104171// (2) End-to-end through the production share_init_verify().
105172TEST (DashShareHashLink, ShareInitVerifyAppendsVarStrPayload) {
106173 const core::CoinParams params = dash::make_coin_params (/* testnet=*/ false );
0 commit comments