|
18 | 18 | #include <gtest/gtest.h> |
19 | 19 | #include <impl/dgb/coin/connection_coinbase.hpp> |
20 | 20 | #include <impl/dgb/coin/last_txout_nonce.hpp> |
| 21 | +#include <c2pool/merged/merged_mining.hpp> // core SSOT: build_auxpow_commitment |
21 | 22 |
|
22 | 23 | #include <map> |
23 | 24 | #include <set> |
@@ -207,6 +208,75 @@ TEST(ConnCoinbasePplns, ValueAnchorAscendingPayoutOrder) { |
207 | 208 | } |
208 | 209 |
|
209 | 210 |
|
| 211 | +// ============================================================================ |
| 212 | +// DGB+DOGE phase DB -- embed-at-mint: the optional aux_mm_commitment field on |
| 213 | +// ConnCoinbasePplnsInputs appends the core c2pool::merged::build_auxpow_commitment blob to the |
| 214 | +// coinbase scriptSig at mint (the -DAUX_DOGE=ON DGB-as-DOGE-parent path). |
| 215 | +// Two invariants, both proven non-circularly off the same fixed inputs: |
| 216 | +// (E1) DEFAULT (nullopt) is BYTE-IDENTICAL to the standalone-parent coinbase |
| 217 | +// -- the no-op is structural, so the standalone build cannot regress. |
| 218 | +// (E2) When set, the assembled scriptSig is the baseline scriptSig with the |
| 219 | +// 44-byte MM tag appended verbatim (magic..root..size..nonce), and the |
| 220 | +// gentx grows by EXACTLY 44 bytes -- nothing else in the coinbase moves. |
| 221 | +// ============================================================================ |
| 222 | + |
| 223 | +// (E1) nullopt leaves the gentx byte-identical to the no-aux build. |
| 224 | +TEST(ConnCoinbaseEmbedAtMint, NulloptIsByteIdentical) { |
| 225 | + std::map<Script, uint288> w{{P1, uint288(3)}, {P2, uint288(1)}}; |
| 226 | + uint256 ref(std::vector<unsigned char>(32, 0xab)); |
| 227 | + // baseline: aux_mm_commitment defaults to nullopt inside wired_from_pplns. |
| 228 | + auto baseline = wired_from_pplns(w, uint288(4), 10000, true, {}, std::nullopt, ref, NONCE); |
| 229 | + |
| 230 | + dgb::coin::ConnCoinbasePplnsInputs in; |
| 231 | + in.coinbase_script = CB; |
| 232 | + in.segwit_commitment_script = std::nullopt; |
| 233 | + in.weights = w; in.total_weight = uint288(4); in.subsidy = 10000; |
| 234 | + in.use_v36_pplns = true; in.donation_script = DON; |
| 235 | + in.ref_hash = ref; in.last_txout_nonce = NONCE; |
| 236 | + in.aux_mm_commitment = std::nullopt; // explicit default |
| 237 | + auto with_field = dgb::coin::build_connection_coinbase_from_pplns(in); |
| 238 | + |
| 239 | + EXPECT_EQ(tohex(baseline.gentx.bytes), tohex(with_field.gentx.bytes)); |
| 240 | + EXPECT_EQ(baseline.gentx.txid, with_field.gentx.txid); |
| 241 | +} |
| 242 | + |
| 243 | +// (E2) a populated commitment appends the 44-byte MM tag to the scriptSig and |
| 244 | +// grows the gentx by exactly 44 bytes; the tag bytes match the core SSOT. |
| 245 | +TEST(ConnCoinbaseEmbedAtMint, AppendsMmTagToScriptSig) { |
| 246 | + std::map<Script, uint288> w{{P1, uint288(3)}, {P2, uint288(1)}}; |
| 247 | + uint256 ref(std::vector<unsigned char>(32, 0xab)); |
| 248 | + auto baseline = wired_from_pplns(w, uint288(4), 10000, true, {}, std::nullopt, ref, NONCE); |
| 249 | + |
| 250 | + // aux merkle root = 0x11..0x11 (internal LE); build the canonical 44-byte tag. |
| 251 | + uint256 aux_root(std::vector<unsigned char>(32, 0x11)); |
| 252 | + auto tag = c2pool::merged::build_auxpow_commitment(aux_root, /*size=*/1, /*nonce=*/0); |
| 253 | + ASSERT_EQ(tag.size(), size_t{44}); // magic4+root32+size4+nonce4 |
| 254 | + |
| 255 | + dgb::coin::ConnCoinbasePplnsInputs in; |
| 256 | + in.coinbase_script = CB; |
| 257 | + in.segwit_commitment_script = std::nullopt; |
| 258 | + in.weights = w; in.total_weight = uint288(4); in.subsidy = 10000; |
| 259 | + in.use_v36_pplns = true; in.donation_script = DON; |
| 260 | + in.ref_hash = ref; in.last_txout_nonce = NONCE; |
| 261 | + in.aux_mm_commitment = tag; |
| 262 | + auto embedded = dgb::coin::build_connection_coinbase_from_pplns(in); |
| 263 | + |
| 264 | + // gentx grows by EXACTLY the 44-byte tag -- nothing else shifts. |
| 265 | + EXPECT_EQ(embedded.gentx.bytes.size(), baseline.gentx.bytes.size() + tag.size()); |
| 266 | + |
| 267 | + // the embedded scriptSig is the baseline scriptSig (CB) followed by the tag. |
| 268 | + std::vector<unsigned char> expect_script = CB; |
| 269 | + expect_script.insert(expect_script.end(), tag.begin(), tag.end()); |
| 270 | + // the scriptSig sits right after the 42-byte coinbase txin prologue |
| 271 | + // (version4 + vin_count1 + prevout36 + script_len1); locate it by content. |
| 272 | + const std::string g = tohex(embedded.gentx.bytes); |
| 273 | + EXPECT_NE(g.find(tohex(expect_script)), std::string::npos); |
| 274 | + // and the bare tag is present where the baseline had none. |
| 275 | + EXPECT_NE(g.find(tohex(tag)), std::string::npos); |
| 276 | + EXPECT_EQ(tohex(baseline.gentx.bytes).find(tohex(tag)), std::string::npos); |
| 277 | +} |
| 278 | + |
| 279 | + |
210 | 280 | // ============================================================================ |
211 | 281 | // last_txout_nonce SSOT (coin/last_txout_nonce.hpp) -- oracle-faithful uniform |
212 | 282 | // 64-bit draw. Replaced three drifted std::time()-XOR formulas in |
|
0 commit comments