diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8376287db..f4bdd493d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -82,7 +82,7 @@ jobs: test_address_resolution test_compute_share_target \ test_utxo test_dgb_subsidy test_dgb_coinbase_value dgb_share_test dgb_redistribute_test dgb_block_assembly_test dgb_witness_commitment_test dgb_header_sample_build_test dgb_header_ingest_test dgb_mempool_ingest_test \ dgb_gentx_coinbase_test dgb_connection_coinbase_test dgb_pplns_payout_split_test nmc_auxpow_merkle_test nmc_template_builder_test nmc_auxpow_wire_test nmc_reconstruct_won_block_test nmc_mempool_name_test nmc_block_broadcast_test nmc_host_dualpath_test nmc_fallback_path_conformance_test dgb_gentx_share_path_test dgb_conn_pplns_producer_test dgb_other_tx_resolver_test \ - 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 dgb_template_capture_test dgb_aux_doge_db_commitment_bind_test dgb_aux_doge_dc_proof_test dgb_aux_doge_bind_parsers_test dgb_compact_blocks_bip152_parity_test \ + 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 dgb_template_capture_test dgb_aux_doge_db_commitment_bind_test dgb_aux_doge_mm_commitment_test dgb_aux_doge_dc_proof_test dgb_aux_doge_bind_parsers_test dgb_compact_blocks_bip152_parity_test \ rpc_request_test softfork_check_test genesis_check_test algo_select_test digishield_walk_test header_chain_test \ 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 dgb_share_target_genesis_test dgb_pool_msg_wire_test dgb_get_shares_walk_test dgb_download_stops_test dgb_think_p1_walk_bounds_test dgb_think_p1_desired_emit_test dgb_think_p6_desired_cutoff_test dgb_think_p4_head_keys_test dgb_think_p3_best_head_test dgb_g1_oracle_byte_parity_test dgb_think_p2_walk_bounds_test dgb_expected_time_to_block_test dgb_tail_score_endpoints_test dgb_pool_attempts_per_second_test dgb_pool_efficiency_test dgb_think_p5_best_share_punish_test dgb_auto_ratchet_tail_guard_test dgb_binomial_conf_interval_test dgb_desired_version_tally_test dgb_get_height_and_last_endpoints_test dgb_chain_walk_window_test dgb_redistribute_delegate_ghal_test dgb_share_weight_decay_test dgb_naughty_propagation_test dgb_hash_format_parity_test v37_test \ -j$(nproc) @@ -214,7 +214,7 @@ jobs: test_address_resolution test_compute_share_target \ test_utxo test_dgb_subsidy test_dgb_coinbase_value dgb_share_test dgb_redistribute_test dgb_block_assembly_test dgb_witness_commitment_test dgb_header_sample_build_test dgb_header_ingest_test dgb_mempool_ingest_test \ dgb_gentx_coinbase_test dgb_connection_coinbase_test dgb_pplns_payout_split_test nmc_auxpow_merkle_test nmc_template_builder_test nmc_auxpow_wire_test nmc_reconstruct_won_block_test nmc_mempool_name_test nmc_block_broadcast_test nmc_host_dualpath_test nmc_fallback_path_conformance_test dgb_gentx_share_path_test dgb_conn_pplns_producer_test dgb_other_tx_resolver_test \ - 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 dgb_template_capture_test dgb_aux_doge_db_commitment_bind_test dgb_aux_doge_dc_proof_test dgb_aux_doge_bind_parsers_test dgb_compact_blocks_bip152_parity_test \ + 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 dgb_template_capture_test dgb_aux_doge_db_commitment_bind_test dgb_aux_doge_mm_commitment_test dgb_aux_doge_dc_proof_test dgb_aux_doge_bind_parsers_test dgb_compact_blocks_bip152_parity_test \ rpc_request_test softfork_check_test genesis_check_test algo_select_test digishield_walk_test header_chain_test \ 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 dgb_share_target_genesis_test dgb_pool_msg_wire_test dgb_get_shares_walk_test dgb_download_stops_test dgb_think_p1_walk_bounds_test dgb_think_p1_desired_emit_test dgb_think_p6_desired_cutoff_test dgb_think_p4_head_keys_test dgb_think_p3_best_head_test dgb_g1_oracle_byte_parity_test dgb_think_p2_walk_bounds_test dgb_expected_time_to_block_test dgb_tail_score_endpoints_test dgb_pool_attempts_per_second_test dgb_pool_efficiency_test dgb_think_p5_best_share_punish_test dgb_auto_ratchet_tail_guard_test dgb_binomial_conf_interval_test dgb_desired_version_tally_test dgb_get_height_and_last_endpoints_test dgb_chain_walk_window_test dgb_redistribute_delegate_ghal_test dgb_share_weight_decay_test dgb_naughty_propagation_test dgb_hash_format_parity_test test_coin_broadcaster test_multiaddress_pplns test_pplns_stress \ v37_test \ diff --git a/src/impl/dgb/coin/aux_doge_mm_commitment.hpp b/src/impl/dgb/coin/aux_doge_mm_commitment.hpp new file mode 100644 index 000000000..c88dc083f --- /dev/null +++ b/src/impl/dgb/coin/aux_doge_mm_commitment.hpp @@ -0,0 +1,72 @@ +#pragma once +// --------------------------------------------------------------------------- +// DGB+DOGE merged-mining (phase DB) -- DGB-side AuxPoW coinbase-commitment +// entry point. THIN DELEGATION to the canonical cross-coin SSOT producer +// c2pool::merged::build_auxpow_commitment. This header carries NO duplicate +// build logic of its own. +// +// RATIONALE (integrator adjudication 2026-06-25, thread "core builder = MM +// SSOT"). The AuxPoW merged-mining commitment build is a v36-NATIVE SHARED +// structure, not a per-coin transition-compat one. The single producer lives +// in shared A-level scaffolding (src/c2pool/merged/merged_mining.cpp + +// src/core/coinbase_builder.hpp); it is chain_id-parameterized, and DGB/DOGE +// plug in as CHAINS, not as a per-coin build path. A fenced DGB builder that +// "mirrors" the core one is exactly the cross-coin divergence the v36->v37 +// standardization goal forbids. DGBs real per-coin value is therefore its +// chain_id slot + fabe6d6d GOLDENS pinned to the canonical builder (see the +// KAT aux_doge_mm_commitment_test.cpp), NOT a second copy of the machinery. +// +// This header exposes only a DGB-namespaced symbol that forwards verbatim to +// the SSOT, so DGB-as-parent call sites read naturally while the bytes are +// produced in exactly one place. +// +// CANONICAL LAYOUT (owned by the SSOT; reproduced here for readers only): +// [4] fa be 6d 6d MM magic +// [32] aux_merkle_root big-endian (byte 31 first) +// [4] merkle_size little-endian +// [4] merkle_nonce little-endian +// Total: 44 bytes. +// +// FENCED -- NOT REWIRED. No live caller invokes this yet; the mint/work-source +// path is untouched. Live wiring (DB embed-at-mint / DC dual-target) routes +// THROUGH the core builder and is gated on ltc-doge concurrence + operator tap. +// --------------------------------------------------------------------------- + +#include +#include + +#include +#include // SSOT: c2pool::merged::build_auxpow_commitment + +namespace dgb { +namespace coin { + +// MM merged-mining magic marker: 0xfa 0xbe 0x6d 0x6d ("\xfa\xbe" + "mm"). +// Pinned by the KAT and available to readers/asserts; the bytes themselves are +// emitted by the SSOT, never reconstructed here. +inline constexpr unsigned char AUX_MM_MAGIC[4] = {0xfa, 0xbe, 0x6d, 0x6d}; + +// Size in bytes of the canonical AuxPoW merged-mining commitment blob +// (magic(4) + aux_merkle_root(32) + merkle_size(4) + merkle_nonce(4)). +inline constexpr std::size_t AUX_MM_COMMITMENT_SIZE = 44; + +// Build the canonical merged-mining coinbase commitment for a DGB-as-parent +// coinbase. THIN DELEGATION -- forwards verbatim to the cross-coin SSOT +// c2pool::merged::build_auxpow_commitment; there is NO DGB-local layout logic. +// +// aux_merkle_root -- auxiliary (DOGE) blockchain merkle root. +// merkle_size -- aux merkle-tree size. +// merkle_nonce -- aux merkle nonce. +// +// Returns exactly AUX_MM_COMMITMENT_SIZE (44) bytes. +inline std::vector build_aux_mm_commitment( + const uint256& aux_merkle_root, + uint32_t merkle_size, + uint32_t merkle_nonce) +{ + return c2pool::merged::build_auxpow_commitment( + aux_merkle_root, merkle_size, merkle_nonce); +} + +} // namespace coin +} // namespace dgb diff --git a/src/impl/dgb/test/CMakeLists.txt b/src/impl/dgb/test/CMakeLists.txt index f6a23e46b..b1beb2df7 100644 --- a/src/impl/dgb/test/CMakeLists.txt +++ b/src/impl/dgb/test/CMakeLists.txt @@ -566,6 +566,22 @@ if (BUILD_TESTING AND GTest_FOUND) dgb_coin pool sharechain) gtest_add_tests(dgb_aux_doge_db_commitment_bind_test "" AUTO) + # --- DGB+DOGE (phase DB) -- DGB-side AuxPoW merged-mining coinbase --- + # commitment BUILDER KAT. FENCED / test-only: pins the canonical + # fabe6d6d || aux_root(32 BE) || size(4 LE) || nonce(4 LE) byte layout + # emitted by dgb::coin::build_aux_mm_commitment, non-circularly (goldens + # hand-built from raw inputs, not the builder). Pure dgb/+core value + # transform -- no ltc/doge linkage, flag-agnostic (builds in default AND + # -DAUX_DOGE arms). MUST appear in BOTH this registration AND the build.yml + # --target allowlist or it becomes a NOT_BUILT sentinel that reds master + # (cf. DGB #137 / #143). + add_executable(dgb_aux_doge_mm_commitment_test aux_doge_mm_commitment_test.cpp) + target_link_libraries(dgb_aux_doge_mm_commitment_test PRIVATE + GTest::gtest_main GTest::gtest + core + c2pool_payout c2pool_merged_mining c2pool_hashrate c2pool_storage) + gtest_add_tests(dgb_aux_doge_mm_commitment_test "" AUTO) + # --- DGB+DOGE (phase DC) -- DGB-as-parent AuxPoW PROOF byte-parity + dual --- # Proves the neutral producer build_auxpow_proof (c2pool/merged) is byte- # identical to the typed doge::coin::CAuxPow diff --git a/src/impl/dgb/test/aux_doge_mm_commitment_test.cpp b/src/impl/dgb/test/aux_doge_mm_commitment_test.cpp new file mode 100644 index 000000000..f6dc4b92a --- /dev/null +++ b/src/impl/dgb/test/aux_doge_mm_commitment_test.cpp @@ -0,0 +1,163 @@ +// --------------------------------------------------------------------------- +// DGB+DOGE merged-mining (phase DB) — KAT for the DGB-side AuxPoW coinbase +// merged-mining commitment builder. Fenced / test-only. +// +// Pins the EXACT byte layout emitted by dgb::coin::build_aux_mm_commitment for +// fixed (aux_merkle_root, merkle_size, merkle_nonce) inputs: +// +// fa be 6d 6d || aux_root(32, big-endian) || size(4 LE) || nonce(4 LE) +// +// NON-CIRCULAR. The expected commitment bytes are hand-constructed in each +// case from the raw inputs (magic literal + reversed root bytes + manually +// little-endian-split size/nonce), NOT by re-invoking the builder. The test is +// therefore a true layout anchor: a re-shaped builder cannot self-confirm. +// +// SSOT DELEGATION GUARD. Each case ALSO asserts the DGB entry point is +// byte-identical to the canonical cross-coin producer +// c2pool::merged::build_auxpow_commitment. Per the integrator adjudication +// (core builder = MM SSOT), DGB owns no build body of its own; this pins +// DGBs chain slot + goldens to the one canonical builder (delegation), not a +// fenced copy. Mirrors the NMC SSOT drift-guard auxpow_merkle_test.cpp. +// +// Mirrors the established DGB aux-test style (unhex/tohex helpers) of the +// sibling src/impl/dgb/test/aux_doge_db_commitment_bind_test.cpp. MUST appear +// in BOTH test/CMakeLists.txt AND the build.yml --target allowlist or it +// becomes a NOT_BUILT sentinel that reds master (cf. DGB #137 / #143). +// --------------------------------------------------------------------------- + +#include + +#include // the fenced builder under test +#include // SSOT drift-guard: build_auxpow_commitment +#include + +#include +#include +#include + +namespace { + +std::vector unhex(const std::string& h) { + std::vector v; v.reserve(h.size() / 2); + auto nyb = [](char c) -> int { return (c <= '9') ? c - '0' : (c | 0x20) - 'a' + 10; }; + for (size_t i = 0; i + 1 < h.size(); i += 2) + v.push_back(static_cast((nyb(h[i]) << 4) | nyb(h[i + 1]))); + return v; +} +std::string tohex(const std::vector& v) { + static const char* H = "0123456789abcdef"; + std::string s; s.reserve(v.size() * 2); + for (unsigned char b : v) { s.push_back(H[b >> 4]); s.push_back(H[b & 0xf]); } + return s; +} + +// Build a uint256 whose internal little-endian byte image == root_le[0..31]. +// (base_uint(vector) reads the vector little-endian, so on a little-endian host +// reinterpret_cast(pn)[i] == root_le[i].) Requires exactly 32 bytes. +uint256 root_from_le_bytes(const std::vector& root_le) { + EXPECT_EQ(root_le.size(), 32u); + return uint256(root_le); +} + +// NON-CIRCULAR expected blob: magic || reverse(root_le) || size_LE || nonce_LE. +// Hand-assembled from the raw inputs — does NOT call the builder. +std::vector expected_commitment( + const std::vector& root_le, + uint32_t size, + uint32_t nonce) +{ + std::vector e; + // magic + e.push_back(0xfa); e.push_back(0xbe); e.push_back(0x6d); e.push_back(0x6d); + // root, big-endian (reverse of the internal little-endian image) + for (int i = 31; i >= 0; --i) e.push_back(root_le[i]); + // size, little-endian + e.push_back(static_cast(size & 0xFF)); + e.push_back(static_cast((size >> 8) & 0xFF)); + e.push_back(static_cast((size >> 16) & 0xFF)); + e.push_back(static_cast((size >> 24) & 0xFF)); + // nonce, little-endian + e.push_back(static_cast(nonce & 0xFF)); + e.push_back(static_cast((nonce >> 8) & 0xFF)); + e.push_back(static_cast((nonce >> 16) & 0xFF)); + e.push_back(static_cast((nonce >> 24) & 0xFF)); + return e; +} + +} // namespace + +// 0) Structural: blob is exactly 44 bytes and starts with the fabe6d6d magic. +TEST(DGB_AuxDogeMMCommitment, SizeAndMagic) { + auto root_le = unhex(std::string(64, '0')); + auto blob = dgb::coin::build_aux_mm_commitment(root_from_le_bytes(root_le), 0, 0); + ASSERT_EQ(blob.size(), 44u); + EXPECT_EQ(blob.size(), dgb::coin::AUX_MM_COMMITMENT_SIZE); + EXPECT_EQ(tohex({blob.begin(), blob.begin() + 4}), "fabe6d6d"); + // SSOT delegation: structural blob is the core builders output verbatim. + EXPECT_EQ(tohex(blob), + tohex(c2pool::merged::build_auxpow_commitment( + root_from_le_bytes(root_le), 0, 0))); +} + +// 1) All-zero root, size=1, nonce=0 — canonical degenerate (single-aux) case. +TEST(DGB_AuxDogeMMCommitment, KAT_ZeroRoot_Size1_Nonce0) { + auto root_le = unhex(std::string(64, '0')); + const uint32_t size = 1, nonce = 0; + auto got = dgb::coin::build_aux_mm_commitment(root_from_le_bytes(root_le), size, nonce); + auto want = expected_commitment(root_le, size, nonce); + // SSOT delegation: DGB entry point forwards verbatim to the core builder. + auto ssot = c2pool::merged::build_auxpow_commitment( + root_from_le_bytes(root_le), size, nonce); + EXPECT_EQ(tohex(got), tohex(ssot)); + EXPECT_EQ(tohex(got), tohex(want)); + // Fully pinned literal: magic || 32 zero bytes || 01000000 || 00000000 + EXPECT_EQ(tohex(got), + "fabe6d6d" + "0000000000000000000000000000000000000000000000000000000000000000" + "01000000" + "00000000"); +} + +// 2) Distinct-byte root, multi-byte LE size + nonce — exercises root reversal +// and full little-endian width of both 32-bit fields. +TEST(DGB_AuxDogeMMCommitment, KAT_PatternedRoot_SizeNonceLE) { + // Internal little-endian image: byte i == i (00 01 02 ... 1f). + std::vector root_le; + for (int i = 0; i < 32; ++i) root_le.push_back(static_cast(i)); + const uint32_t size = 0x04030201u, nonce = 0xdeadbeefu; + auto got = dgb::coin::build_aux_mm_commitment(root_from_le_bytes(root_le), size, nonce); + auto want = expected_commitment(root_le, size, nonce); + // SSOT delegation: DGB entry point forwards verbatim to the core builder. + auto ssot = c2pool::merged::build_auxpow_commitment( + root_from_le_bytes(root_le), size, nonce); + EXPECT_EQ(tohex(got), tohex(ssot)); + EXPECT_EQ(tohex(got), tohex(want)); + // Fully pinned literal: root big-endian is 1f..00; size LE=01020304; nonce LE=efbeadde. + EXPECT_EQ(tohex(got), + "fabe6d6d" + "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100" + "01020304" + "efbeadde"); +} + +// 3) Real-shaped DOGE-style root, max size, mid nonce. +TEST(DGB_AuxDogeMMCommitment, KAT_RealishRoot_MaxSize) { + // Internal little-endian image of a non-symmetric 32-byte root. + auto root_le = unhex( + "112233445566778899aabbccddeeff00" + "fedcba98765432100123456789abcdef"); + const uint32_t size = 0xffffffffu, nonce = 0x00c0ffeeu; + auto got = dgb::coin::build_aux_mm_commitment(root_from_le_bytes(root_le), size, nonce); + auto want = expected_commitment(root_le, size, nonce); + // SSOT delegation: DGB entry point forwards verbatim to the core builder. + auto ssot = c2pool::merged::build_auxpow_commitment( + root_from_le_bytes(root_le), size, nonce); + EXPECT_EQ(tohex(got), tohex(ssot)); + EXPECT_EQ(tohex(got), tohex(want)); + // Fully pinned literal. + EXPECT_EQ(tohex(got), + "fabe6d6d" + "efcdab89674523011032547698badcfe00ffeeddccbbaa998877665544332211" + "ffffffff" + "eeffc000"); +}