From a54d168fc5ab796bf5ce189eeb30ca02785ec8e3 Mon Sep 17 00:00:00 2001 From: frstrtr Date: Thu, 25 Jun 2026 14:14:25 +0000 Subject: [PATCH] dgb: DGB+DOGE phase-DC dual-target SELECTION scaffold (fenced KAT) Pure, header-only DC decision contract the eventual DC run-loop wiring (AUX_DOGE node seam + submit) must satisfy, landed BEFORE the seam is touched (seam parked on #82 + ltc-doge written concurrence). coin/aux_dual_target_select.hpp: - aux_mint_decision(aux_enabled, has_doge_job): embed the fabe6d6d MM commitment IFF aux MM enabled AND a DOGE job is present; else no-op (mirrors #486 embed-at-mint nullopt byte-identity). - select_submit(pow, dgb_target, has_doge_job, doge_target): independent per-path thresholds against one scrypt pow_hash (mirrors dc_proof DualTargetIndependentThresholds); DOGE-aux only fires when minted. - selection_is_consistent(): load-bearing DC<->DB guard, fire_doge_aux ==> embed_commitment, coupling submit back to #475/#486. test/aux_dual_target_select_test.cpp: 5/5 KATs, non-circular goldens (fabe6d6d tag, embed truth table, independent threshold table, no-job suppression, the impossible DOGE-win-without-mint state). Registered in test/CMakeLists.txt + both build.yml --target allowlists (#143 trap). Fenced dgb/, not rewired, consumes nothing in src/impl/doge, no node seam touch, zero consensus surface. --- .github/workflows/build.yml | 4 +- src/impl/dgb/coin/aux_dual_target_select.hpp | 80 +++++++++++++++ src/impl/dgb/test/CMakeLists.txt | 16 +++ .../dgb/test/aux_dual_target_select_test.cpp | 99 +++++++++++++++++++ 4 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 src/impl/dgb/coin/aux_dual_target_select.hpp create mode 100644 src/impl/dgb/test/aux_dual_target_select_test.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ec5299d34..a372361f9 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_mm_commitment_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 dgb_aux_dual_target_select_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_mm_commitment_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 dgb_aux_dual_target_select_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_dual_target_select.hpp b/src/impl/dgb/coin/aux_dual_target_select.hpp new file mode 100644 index 000000000..f05d64442 --- /dev/null +++ b/src/impl/dgb/coin/aux_dual_target_select.hpp @@ -0,0 +1,80 @@ +#pragma once +// --------------------------------------------------------------------------- +// DGB+DOGE merged-mining (phase DC) — dual-target SELECTION scaffold. +// +// Pure, header-only, fenced. NOT wired into any production path (no run-loop, +// no node seam, no share-tracker touch) — it pins the load-bearing DC decision +// contract that the eventual DC wiring (node.hpp:57 AUX_DOGE bind + submit) must +// satisfy, BEFORE that seam is touched (seam is parked on #82 + ltc-doge +// concurrence). Zero consensus surface; the DGB-parent consensus path is +// unchanged whether or not these helpers are ever consumed. +// +// Two independent decisions: +// +// MINT-TIME (mirrors #486 embed-at-mint): the DGB parent coinbase embeds the +// fabe6d6d merged-mining commitment (built by #475) IFF aux MM is enabled +// AND a DOGE work job is present. Otherwise no embed -> byte-identical +// no-op coinbase (the #486 nullopt invariant). +// +// SUBMIT-TIME: the DGB-parent target and the DOGE-aux target are INDEPENDENT +// thresholds against the SAME scrypt pow_hash (pow <= target == hit; +// mirrors aux_doge_dc_proof_test DualTargetIndependentThresholds). The +// DOGE-aux path is only a candidate when a DOGE job was minted in. +// +// LOAD-BEARING LINKAGE (DC<->DB): a DOGE-aux win can only be assembled when the +// fabe6d6d commitment was minted — so fire_doge_aux ==> embed_commitment. This +// guard is what couples submit-time selection back to the #475/#486 mint. +// --------------------------------------------------------------------------- + +#include + +namespace dgb +{ +namespace coin +{ + +// fabe6d6d merged-mining commitment tag — the magic prefix #475 prepends to the +// 44-byte MM commitment (fa be 6d 6d || root32BE || size4LE || nonce4LE). Pinned +// here as the non-circular mint anchor; the DC wiring builds the real record. +inline constexpr unsigned char MM_COMMITMENT_TAG[4] = {0xfa, 0xbe, 0x6d, 0x6d}; + +// MINT-TIME embed decision (#486). embed_commitment is true IFF aux MM is +// enabled and a DOGE work job is present; false -> nullopt / no-op coinbase. +struct AuxMintDecision +{ + bool embed_commitment; +}; + +inline AuxMintDecision aux_mint_decision(bool aux_enabled, bool has_doge_job) +{ + return AuxMintDecision{aux_enabled && has_doge_job}; +} + +// SUBMIT-TIME dual-target fire decision. Independent per-path thresholds against +// one scrypt pow_hash. DOGE-aux only fires when a DOGE job was minted in. +struct DualTargetFire +{ + bool fire_dgb_parent; + bool fire_doge_aux; +}; + +inline DualTargetFire select_submit(const uint256& pow_hash, + const uint256& dgb_target, + bool has_doge_job, + const uint256& doge_target) +{ + const bool dgb_hit = !(pow_hash > dgb_target); + const bool doge_hit = has_doge_job && !(pow_hash > doge_target); + return DualTargetFire{dgb_hit, doge_hit}; +} + +// LOAD-BEARING DC<->DB linkage: a DOGE-aux win is only assemblable when the +// fabe6d6d commitment was minted. fire_doge_aux ==> embed_commitment. +inline bool selection_is_consistent(const AuxMintDecision& mint, + const DualTargetFire& fire) +{ + return !fire.fire_doge_aux || mint.embed_commitment; +} + +} // namespace coin +} // namespace dgb diff --git a/src/impl/dgb/test/CMakeLists.txt b/src/impl/dgb/test/CMakeLists.txt index b1beb2df7..c7e987a09 100644 --- a/src/impl/dgb/test/CMakeLists.txt +++ b/src/impl/dgb/test/CMakeLists.txt @@ -619,6 +619,22 @@ if (BUILD_TESTING AND GTest_FOUND) dgb_coin pool sharechain) gtest_add_tests(dgb_aux_doge_bind_parsers_test "" AUTO) + # --- DGB+DOGE (phase DC) -- dual-target SELECTION scaffold KAT ------------ + # Pins the pure DC decision contract (coin/aux_dual_target_select.hpp): the + # mint-time fabe6d6d embed rule (#486 nullopt no-op), the independent dual- + # target submit thresholds (mirrors dc_proof), and the load-bearing + # fire_doge_aux ==> embed_commitment linkage back to the #475/#486 mint. + # Pure helpers, consumes nothing in src/impl/doge and touches no node + # seam. MUST appear in BOTH this registration AND the + # build.yml --target allowlist (#143 NOT_BUILT trap). + add_executable(dgb_aux_dual_target_select_test aux_dual_target_select_test.cpp) + target_link_libraries(dgb_aux_dual_target_select_test PRIVATE + GTest::gtest_main GTest::gtest + core dgb + c2pool_payout c2pool_merged_mining c2pool_hashrate c2pool_storage + dgb_coin pool sharechain) + gtest_add_tests(dgb_aux_dual_target_select_test "" AUTO) + # dgb_share_target_genesis_test: FENCED KAT pinning ShareTracker::compute_ # share_target genesis/unknown-prev clamp to [MAX_TARGET/30, MAX_TARGET] vs # the DGB oracle data.py generate_transaction. Links the same proven set as diff --git a/src/impl/dgb/test/aux_dual_target_select_test.cpp b/src/impl/dgb/test/aux_dual_target_select_test.cpp new file mode 100644 index 000000000..23ef54608 --- /dev/null +++ b/src/impl/dgb/test/aux_dual_target_select_test.cpp @@ -0,0 +1,99 @@ +// --------------------------------------------------------------------------- +// DGB+DOGE (phase DC) — dual-target SELECTION scaffold KAT. +// +// Fenced / test-only. Pins the pure DC decision contract (coin/aux_dual_target_ +// select.hpp) the eventual DC wiring must satisfy, BEFORE the AUX_DOGE node seam +// is touched. Non-circular: every golden is restated by value (the fabe6d6d tag, +// the embed-when-aux+job rule, the independent threshold table, the no-op +// invariant) — it mirrors #475 (fabe6d6d builder) / #486 (embed-at-mint nullopt +// no-op) without including their (not-yet-landed) headers, so it cannot drift +// against them and stands alone on master. +// +// Pure helpers, links only core (uint256). Consumes nothing in src/impl/doge. +// MUST appear in BOTH test/CMakeLists.txt AND the build.yml --target allowlist +// or it becomes a NOT_BUILT sentinel that reds master (#143 trap). +// --------------------------------------------------------------------------- + +#include + +#include +#include + +using dgb::coin::aux_mint_decision; +using dgb::coin::select_submit; +using dgb::coin::selection_is_consistent; +using dgb::coin::MM_COMMITMENT_TAG; + +// 1) fabe6d6d mint anchor (#475). Non-circular literal golden — the tag the +// real MM-commitment builder prepends. Guards against a silent tag reshape. +TEST(DGB_AuxDualTargetSelect, MmCommitmentTagIsFabe6d6d) { + EXPECT_EQ(MM_COMMITMENT_TAG[0], 0xfa); + EXPECT_EQ(MM_COMMITMENT_TAG[1], 0xbe); + EXPECT_EQ(MM_COMMITMENT_TAG[2], 0x6d); + EXPECT_EQ(MM_COMMITMENT_TAG[3], 0x6d); +} + +// 2) MINT-TIME embed truth table (#486). Embed IFF aux enabled AND DOGE job. +// The three non-embed corners are the byte-identical no-op (#486 nullopt). +TEST(DGB_AuxDualTargetSelect, MintEmbedsOnlyWhenAuxEnabledAndDogeJob) { + EXPECT_TRUE (aux_mint_decision(/*aux*/true, /*job*/true ).embed_commitment); + EXPECT_FALSE(aux_mint_decision(/*aux*/true, /*job*/false).embed_commitment); + EXPECT_FALSE(aux_mint_decision(/*aux*/false, /*job*/true ).embed_commitment); + EXPECT_FALSE(aux_mint_decision(/*aux*/false, /*job*/false).embed_commitment); +} + +// 3) SUBMIT-TIME independent thresholds — same pow_hash, two independent targets +// (mirrors dc_proof DualTargetIndependentThresholds). DGB-parent is the +// harder (smaller) target; DOGE-aux is easier (larger). +TEST(DGB_AuxDualTargetSelect, SubmitFiresIndependentThresholds) { + const uint256 DGB_TARGET = uint256S("0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + const uint256 DOGE_TARGET = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + + const uint256 below_both = uint256S("0000000000000000000000000000000000000000000000000000000000000001"); + const uint256 doge_only = uint256S("000000000affffffffffffffffffffffffffffffffffffffffffffffffffffff"); + const uint256 above_both = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + + // below both -> both paths fire + auto a = select_submit(below_both, DGB_TARGET, /*job*/true, DOGE_TARGET); + EXPECT_TRUE(a.fire_dgb_parent); + EXPECT_TRUE(a.fire_doge_aux); + + // between -> DOGE-aux fires, DGB-parent does NOT (the common case) + auto b = select_submit(doge_only, DGB_TARGET, /*job*/true, DOGE_TARGET); + EXPECT_FALSE(b.fire_dgb_parent); + EXPECT_TRUE (b.fire_doge_aux); + + // above both -> neither fires + auto c = select_submit(above_both, DGB_TARGET, /*job*/true, DOGE_TARGET); + EXPECT_FALSE(c.fire_dgb_parent); + EXPECT_FALSE(c.fire_doge_aux); +} + +// 4) No DOGE job suppresses the DOGE-aux path even on a target hit, and leaves +// the DGB-parent path untouched (standalone-parent default build behaviour). +TEST(DGB_AuxDualTargetSelect, NoDogeJobSuppressesAuxPathOnly) { + const uint256 DGB_TARGET = uint256S("0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + const uint256 DOGE_TARGET = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + const uint256 below_both = uint256S("0000000000000000000000000000000000000000000000000000000000000001"); + + auto f = select_submit(below_both, DGB_TARGET, /*job*/false, DOGE_TARGET); + EXPECT_TRUE (f.fire_dgb_parent); // parent path independent of aux + EXPECT_FALSE(f.fire_doge_aux); // no job minted -> no aux win +} + +// 5) LOAD-BEARING DC<->DB linkage: fire_doge_aux ==> embed_commitment. A DOGE +// win without a minted commitment is the impossible state the guard rejects. +TEST(DGB_AuxDualTargetSelect, DogeWinRequiresMintedCommitment) { + // reachable: aux on + job -> minted -> a DOGE fire is consistent + EXPECT_TRUE(selection_is_consistent( + aux_mint_decision(true, true), + dgb::coin::DualTargetFire{true, true})); + // reachable: no DOGE fire is always consistent regardless of mint + EXPECT_TRUE(selection_is_consistent( + aux_mint_decision(false, false), + dgb::coin::DualTargetFire{true, false})); + // impossible: DOGE fire without a minted commitment -> guard rejects + EXPECT_FALSE(selection_is_consistent( + aux_mint_decision(false, true), + dgb::coin::DualTargetFire{false, true})); +}