Skip to content

Commit e2a563c

Browse files
authored
Merge pull request #298 from frstrtr/dgb/aux-parent-coinbase-parity-baseline
dgb: aux-parent coinbase serialization parity baseline KAT (D0)
2 parents 8a79990 + 2356967 commit e2a563c

3 files changed

Lines changed: 208 additions & 2 deletions

File tree

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ jobs:
8282
test_address_resolution test_compute_share_target \
8383
test_utxo test_dgb_subsidy test_dgb_coinbase_value dgb_share_test dgb_block_assembly_test dgb_header_sample_build_test dgb_header_ingest_test dgb_mempool_ingest_test \
8484
dgb_gentx_coinbase_test nmc_auxpow_merkle_test nmc_template_builder_test nmc_auxpow_wire_test nmc_reconstruct_won_block_test dgb_gentx_share_path_test dgb_other_tx_resolver_test \
85-
dgb_other_tx_assembler_test dgb_reconstruct_won_block_test dgb_reconstruct_closure_test dgb_gentx_unpack_test dgb_work_source_test dgb_template_builder_test dgb_embedded_coin_node_test dgb_embedded_tx_select_test dgb_template_other_txs_test dgb_coinbase_value_parity_test dgb_submit_classify_test \
85+
dgb_other_tx_assembler_test dgb_reconstruct_won_block_test dgb_reconstruct_closure_test dgb_gentx_unpack_test dgb_work_source_test dgb_template_builder_test dgb_embedded_coin_node_test dgb_embedded_tx_select_test dgb_template_other_txs_test dgb_coinbase_value_parity_test dgb_submit_classify_test dgb_aux_parent_coinbase_parity_test \
8686
rpc_request_test softfork_check_test genesis_check_test algo_select_test digishield_walk_test header_chain_test \
8787
dgb_coin_node_seam_test dgb_block_broadcast_test dgb_won_block_dispatch_test dgb_forced_won_share_dualpath_test dgb_scrypt_pow_test dgb_nonce_grinder_test dgb_regrind_block_test dgb_won_block_finalize_test v37_test \
8888
-j$(nproc)
@@ -214,7 +214,7 @@ jobs:
214214
test_address_resolution test_compute_share_target \
215215
test_utxo test_dgb_subsidy test_dgb_coinbase_value dgb_share_test dgb_block_assembly_test dgb_header_sample_build_test dgb_header_ingest_test dgb_mempool_ingest_test \
216216
dgb_gentx_coinbase_test nmc_auxpow_merkle_test nmc_template_builder_test nmc_auxpow_wire_test nmc_reconstruct_won_block_test dgb_gentx_share_path_test dgb_other_tx_resolver_test \
217-
dgb_other_tx_assembler_test dgb_reconstruct_won_block_test dgb_reconstruct_closure_test dgb_gentx_unpack_test dgb_work_source_test dgb_template_builder_test dgb_embedded_coin_node_test dgb_embedded_tx_select_test dgb_template_other_txs_test dgb_coinbase_value_parity_test dgb_submit_classify_test \
217+
dgb_other_tx_assembler_test dgb_reconstruct_won_block_test dgb_reconstruct_closure_test dgb_gentx_unpack_test dgb_work_source_test dgb_template_builder_test dgb_embedded_coin_node_test dgb_embedded_tx_select_test dgb_template_other_txs_test dgb_coinbase_value_parity_test dgb_submit_classify_test dgb_aux_parent_coinbase_parity_test \
218218
rpc_request_test softfork_check_test genesis_check_test algo_select_test digishield_walk_test header_chain_test \
219219
dgb_coin_node_seam_test dgb_block_broadcast_test dgb_won_block_dispatch_test dgb_forced_won_share_dualpath_test dgb_scrypt_pow_test dgb_nonce_grinder_test dgb_regrind_block_test dgb_won_block_finalize_test test_coin_broadcaster test_multiaddress_pplns test_pplns_stress \
220220
v37_test \

src/impl/dgb/test/CMakeLists.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,4 +434,22 @@ if (BUILD_TESTING AND GTest_FOUND)
434434
GTest::gtest_main GTest::gtest)
435435
gtest_add_tests(dgb_submit_classify_test "" AUTO)
436436

437+
# --- DGB+DOGE (D0) aux-pow parent-coinbase serialization PARITY BASELINE ----
438+
# Pins the pre-templating wire image of the shared aux module struct
439+
# doge::coin::CMerkleTx (src/impl/doge/coin/auxpow.hpp) anchored to master
440+
# f732061bc, so the v36-standardize Scrypt value-type extraction can prove
441+
# its parent-coinbase type swap is byte-neutral. Links the ltc OBJECT lib
442+
# (member type ltc::coin::MutableTransaction) + dgb (neutral stand-in type
443+
# for the cross-type byte-identity assert) — the -DAUX_DOGE consumption path
444+
# legitimately couples to ltc. Test-only; consumes the shared module, does
445+
# not modify it. MUST appear in BOTH this registration AND the build.yml
446+
# --target allowlist.
447+
add_executable(dgb_aux_parent_coinbase_parity_test aux_parent_coinbase_parity_test.cpp)
448+
target_link_libraries(dgb_aux_parent_coinbase_parity_test PRIVATE
449+
GTest::gtest_main GTest::gtest
450+
core dgb ltc_coin
451+
c2pool_payout c2pool_merged_mining c2pool_hashrate c2pool_storage
452+
dgb_coin pool sharechain)
453+
gtest_add_tests(dgb_aux_parent_coinbase_parity_test "" AUTO)
454+
437455
endif()
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
// ---------------------------------------------------------------------------
2+
// DGB+DOGE merged-mining (D0) — aux-pow parent-coinbase serialization PARITY
3+
// BASELINE KAT. Fenced / test-only — consumes the shared aux module, modifies
4+
// nothing.
5+
//
6+
// PURPOSE. The v36-standardize Scrypt value-type extraction will lift the
7+
// parent-coinbase member out of ltc::coin into a neutral Scrypt-family base so
8+
// that a non-LTC parent (DGB-as-parent under -DAUX_DOGE=ON) can occupy it
9+
// without the dgb -> ltc_coin build edge. Today that member is hard-typed:
10+
//
11+
// src/impl/doge/coin/auxpow.hpp:77 ltc::coin::MutableTransaction m_tx;
12+
// src/impl/doge/coin/auxpow.hpp:84 ::Serialize(s, TX_NO_WITNESS(m_tx));
13+
//
14+
// This KAT freezes the CURRENT, PRE-TEMPLATING wire image of the whole
15+
// doge::coin::CMerkleTx (the struct that carries m_tx) so the extraction PR can
16+
// prove its type swap is byte-neutral: re-run after templating must reproduce
17+
// the golden BYTE-FOR-BYTE. A single moved byte fails here.
18+
//
19+
// ANCHOR. Golden captured against the shared aux module at master HEAD
20+
// git rev-parse origin/master == f732061bc
21+
// recorded below as AUX_MODULE_MASTER_SHA. A later rebase that silently
22+
// re-shapes the serializer cannot move the golden without tripping this test;
23+
// if the anchor SHA and the live module diverge in field order, that is a HARD
24+
// STOP back to integrator, not a golden update.
25+
//
26+
// CROSS-TYPE INVARIANT. The extraction's whole safety claim is that the parent
27+
// coinbase serializes identically whichever Scrypt-family type holds it. We
28+
// assert that directly: the same canonical coinbase fields, serialized once
29+
// through ltc::coin::MutableTransaction (the real member type) and once through
30+
// dgb::coin::MutableTransaction (a stand-in for the future neutral / DGB-parent
31+
// type), produce identical witness-stripped bytes. Both extend
32+
// bitcoin_family::coin::base_transaction, so a divergence would mean the shared
33+
// base is NOT actually shared — exactly the thing extraction must not break.
34+
//
35+
// Per-coin isolation note: this test legitimately links the ltc OBJECT lib
36+
// because it exercises the -DAUX_DOGE dual-parent consumption path, whose
37+
// shared module (ltc-doge's domain) already includes ltc/coin/transaction.hpp
38+
// by design. We CONSUME the module; we do not modify it. MUST appear in BOTH
39+
// test/CMakeLists.txt AND the build.yml --target allowlist or it becomes a
40+
// NOT_BUILT sentinel that reds master (cf. DGB #137).
41+
// ---------------------------------------------------------------------------
42+
43+
#include <gtest/gtest.h>
44+
45+
#include <impl/doge/coin/auxpow.hpp> // the REAL shared module (SSOT)
46+
#include <impl/ltc/coin/transaction.hpp> // ltc::coin::MutableTransaction (member type)
47+
#include <impl/dgb/coin/transaction.hpp> // dgb::coin::MutableTransaction + dgb::coin::TX_NO_WITNESS (neutral stand-in)
48+
49+
#include <core/pack.hpp>
50+
#include <core/uint256.hpp>
51+
#include <core/opscript.hpp>
52+
53+
#include <cstdint>
54+
#include <string>
55+
#include <vector>
56+
57+
namespace {
58+
59+
// Anchor — see file header. Update ONLY together with a re-verified golden.
60+
constexpr const char* AUX_MODULE_MASTER_SHA = "f732061bc";
61+
62+
std::vector<unsigned char> unhex(const std::string& h) {
63+
std::vector<unsigned char> v; v.reserve(h.size() / 2);
64+
auto nyb = [](char c) -> int { return (c <= '9') ? c - '0' : (c | 0x20) - 'a' + 10; };
65+
for (size_t i = 0; i + 1 < h.size(); i += 2)
66+
v.push_back(static_cast<unsigned char>((nyb(h[i]) << 4) | nyb(h[i + 1])));
67+
return v;
68+
}
69+
std::string tohex(const std::vector<unsigned char>& v) {
70+
static const char* H = "0123456789abcdef";
71+
std::string s; s.reserve(v.size() * 2);
72+
for (unsigned char b : v) { s.push_back(H[b >> 4]); s.push_back(H[b & 0xf]); }
73+
return s;
74+
}
75+
template <typename T>
76+
std::string pack_hex(const T& value) {
77+
auto packed = pack(value);
78+
auto sp = packed.get_span();
79+
std::vector<unsigned char> v(
80+
reinterpret_cast<const unsigned char*>(sp.data()),
81+
reinterpret_cast<const unsigned char*>(sp.data()) + sp.size());
82+
return tohex(v);
83+
}
84+
85+
OPScript script_of(const std::vector<unsigned char>& bytes) {
86+
return OPScript(bytes.data(), bytes.data() + bytes.size());
87+
}
88+
89+
// --- canonical, deterministic parent coinbase fields -----------------------
90+
// A minimal but representative coinbase: null prevout, a fixed coinbase
91+
// scriptSig, one P2PKH-shaped payout, version 1, locktime 0. Shared verbatim
92+
// between the ltc- and dgb-typed builders below so the only variable is the
93+
// transaction TYPE, not the data.
94+
const std::vector<unsigned char> CB_SCRIPT = unhex("03a1b2c3041122334455667788");
95+
const std::vector<unsigned char> PK_SCRIPT =
96+
unhex(std::string("76a914") + std::string(40, '3') + "88ac");
97+
constexpr int32_t TX_VERSION = 1;
98+
constexpr uint32_t TX_LOCKTIME = 0;
99+
constexpr uint32_t CB_SEQUENCE = 0xffffffffu;
100+
constexpr int64_t CB_VALUE = 5000000000ll; // 50.00000000
101+
102+
template <typename MTx>
103+
MTx build_parent_coinbase() {
104+
MTx tx;
105+
tx.version = TX_VERSION;
106+
tx.locktime = TX_LOCKTIME;
107+
108+
typename decltype(tx.vin)::value_type in;
109+
in.prevout.hash = uint256(); // null
110+
in.prevout.index = 0xffffffffu; // coinbase marker
111+
in.scriptSig = script_of(CB_SCRIPT);
112+
in.sequence = CB_SEQUENCE;
113+
tx.vin.push_back(in);
114+
115+
typename decltype(tx.vout)::value_type out;
116+
out.value = CB_VALUE;
117+
out.scriptPubKey = script_of(PK_SCRIPT);
118+
tx.vout.push_back(out);
119+
120+
return tx;
121+
}
122+
123+
// Fixed surrounding CMerkleTx fields.
124+
const uint256 BLOCK_HASH =
125+
uint256S("00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff");
126+
const uint256 MERKLE_BRANCH_0 =
127+
uint256S("ffeeddccbbaa99887766554433221100ffeeddccbbaa99887766554433221100");
128+
constexpr uint32_t MERKLE_INDEX = 1;
129+
130+
doge::coin::CMerkleTx build_merkle_tx() {
131+
doge::coin::CMerkleTx mt;
132+
mt.m_tx = build_parent_coinbase<ltc::coin::MutableTransaction>();
133+
mt.m_block_hash = BLOCK_HASH;
134+
mt.m_merkle_link.m_branch = {MERKLE_BRANCH_0};
135+
mt.m_merkle_link.m_index = MERKLE_INDEX;
136+
return mt;
137+
}
138+
139+
// ---------------------------------------------------------------------------
140+
// GOLDENS — captured against master f732061bc (see header). DO NOT hand-edit;
141+
// regenerate only with a documented module change and integrator sign-off.
142+
// ---------------------------------------------------------------------------
143+
// Witness-stripped parent coinbase (the m_tx member payload, == tx_id_type).
144+
const std::string PARENT_COINBASE_NOSEG =
145+
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0d03a1b2c3041122334455667788ffffffff0100f2052a010000001976a914333333333333333333333333333333333333333388ac00000000";
146+
// Full doge::coin::CMerkleTx wire image:
147+
// TX_NO_WITNESS(m_tx) ++ m_block_hash(32, LE) ++ merkle_link(branch ++ index)
148+
const std::string MERKLE_TX_WIRE =
149+
"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0d03a1b2c3041122334455667788ffffffff0100f2052a010000001976a914333333333333333333333333333333333333333388ac00000000ffeeddccbbaa99887766554433221100ffeeddccbbaa998877665544332211000100112233445566778899aabbccddeeff00112233445566778899aabbccddeeff01000000"; // index = 1 (uint32 LE)
150+
151+
} // namespace
152+
153+
// 1) The member payload: witness-stripped parent coinbase, ltc-typed (real type).
154+
TEST(DGB_AuxParentCoinbaseParity, LtcTypedMemberPayloadGolden) {
155+
auto tx = build_parent_coinbase<ltc::coin::MutableTransaction>();
156+
EXPECT_EQ(pack_hex(ltc::coin::TX_NO_WITNESS(tx)), PARENT_COINBASE_NOSEG);
157+
}
158+
159+
// 2) CROSS-TYPE INVARIANT: the dgb-typed (neutral stand-in) coinbase serializes
160+
// BYTE-IDENTICALLY to the ltc-typed one. This is exactly what the extraction
161+
// must preserve when m_tx's type is lifted to the Scrypt-family base.
162+
TEST(DGB_AuxParentCoinbaseParity, LtcVsDgbTypeByteIdentical) {
163+
auto ltc_tx = build_parent_coinbase<ltc::coin::MutableTransaction>();
164+
auto dgb_tx = build_parent_coinbase<dgb::coin::MutableTransaction>();
165+
const auto ltc_bytes = pack_hex(ltc::coin::TX_NO_WITNESS(ltc_tx));
166+
const auto dgb_bytes = pack_hex(dgb::coin::TX_NO_WITNESS(dgb_tx));
167+
EXPECT_EQ(ltc_bytes, dgb_bytes);
168+
EXPECT_EQ(ltc_bytes, PARENT_COINBASE_NOSEG);
169+
}
170+
171+
// 3) Full shared-module CMerkleTx wire image, anchored to AUX_MODULE_MASTER_SHA.
172+
// Pins the pre-templating layout the extraction must reproduce verbatim.
173+
TEST(DGB_AuxParentCoinbaseParity, MerkleTxWireGoldenAnchored) {
174+
ASSERT_STREQ(AUX_MODULE_MASTER_SHA, "f732061bc"); // golden provenance guard
175+
auto mt = build_merkle_tx();
176+
EXPECT_EQ(pack_hex(mt), MERKLE_TX_WIRE);
177+
}
178+
179+
// 4) Round-trip: Unserialize(serialize(mt)) re-serializes to the same bytes.
180+
// A field-order/width bug that happened to be self-consistent on write but
181+
// not on read would diverge here.
182+
TEST(DGB_AuxParentCoinbaseParity, MerkleTxRoundTripStable) {
183+
auto mt = build_merkle_tx();
184+
auto packed = pack(mt);
185+
doge::coin::CMerkleTx rt;
186+
packed >> rt;
187+
EXPECT_EQ(pack_hex(rt), MERKLE_TX_WIRE);
188+
}

0 commit comments

Comments
 (0)