Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ jobs:
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 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 \
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 v37_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)

- name: Run tests
Expand Down Expand Up @@ -216,7 +216,7 @@ jobs:
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 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 \
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 test_coin_broadcaster test_multiaddress_pplns test_pplns_stress \
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 \
-j$(nproc)

Expand Down
15 changes: 15 additions & 0 deletions src/impl/dgb/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,21 @@ if (BUILD_TESTING AND GTest_FOUND)
target_link_libraries(dgb_binomial_conf_interval_test PRIVATE
GTest::gtest_main GTest::gtest)
gtest_add_tests(dgb_binomial_conf_interval_test "" AUTO)
# dgb_hash_format_parity_test: FENCED, additive KAT pinning the pure GBT
# block-hash display formatter coin/hash_format.hpp u256_be_display_hex
# (most-significant-limb-first 64-hex render of the LE u256, the encoding
# both work paths emit for "previousblockhash"). NON-CIRCULAR anchor = the
# DGB mainnet genesis hash pinned at p2pool-dgb-scrypt
# bitcoin/networks/digibyte.py:55; the test reverses that external display
# constant into LE storage bytes, feeds u256::from_le_bytes, and asserts the
# formatter reproduces it byte for byte. DIAGNOSTICS/wire-display only, no
# consensus surface. Pure header (<cstdint>/<string>) -> links only GTest.
# No call site rewired. MUST also be in the build.yml --target allowlist
# (#143 NOT_BUILT trap).
add_executable(dgb_hash_format_parity_test hash_format_parity_test.cpp)
target_link_libraries(dgb_hash_format_parity_test PRIVATE
GTest::gtest_main GTest::gtest)
gtest_add_tests(dgb_hash_format_parity_test "" AUTO)
# dgb_desired_version_tally_test: FENCED, additive KAT pinning the
# version->work / version->count accumulation core lifted into
# coin/desired_version_tally.hpp vs the p2pool-dgb-scrypt data.py:918-922
Expand Down
132 changes: 132 additions & 0 deletions src/impl/dgb/test/hash_format_parity_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// ---------------------------------------------------------------------------
// dgb_hash_format_parity_test -- FENCED, additive KAT pinning the pure GBT
// block-hash display formatter dgb::coin::u256_be_display_hex lifted into
// coin/hash_format.hpp.
//
// u256_be_display_hex renders a 256-bit value (coin/dgb_arith256.hpp u256, a
// little-endian limb array with limb[0] least-significant) as the
// GBT-conventional big-endian display hex: most-significant limb first, 64
// lowercase hex digits, no 0x prefix -- the encoding the stratum work source
// and the embedded work path both emit for "previousblockhash". A 1-nibble
// divergence in limb/byte ordering there means the two callers of
// build_work_template could emit a prevhash the parent daemon never accepts.
//
// The anchor is NON-CIRCULAR: the DigiByte mainnet genesis block hash
// 7497ea1b465eb39f1c8f507bc877078fe016d6fcb6dfad3a64c98dcc6e1e8496 is the
// external constant the DGB oracle pins at frstrtr/p2pool-dgb-scrypt
// bitcoin/networks/digibyte.py:55 (helper.check_block_header(..., 'genesis')).
// The test parses that literal display hex into 32 MSB-first bytes with an
// independent hex reader, reverses to the on-the-wire little-endian byte order,
// feeds u256::from_le_bytes (the exact storage path a real tip hash takes), and
// asserts u256_be_display_hex reproduces the original oracle string byte for
// byte. The formatter under test is the only code computing the output.
//
// DIAGNOSTICS / WIRE-DISPLAY ONLY: no consensus surface, no payout/subsidy/
// version-gate value. Pure header (<cstdint>/<string>) -> links only GTest. No
// call site rewired. MUST also be in BOTH build.yml --target allowlists
// (#143 NOT_BUILT trap).
// ---------------------------------------------------------------------------

#include <gtest/gtest.h>

#include <array>
#include <cstdint>
#include <string>

#include "../coin/hash_format.hpp"

using dgb::coin::u256;
using dgb::coin::u256_be_display_hex;

namespace {

// Independent hex reader (does NOT share the formatter's nibble/limb logic):
// parse a 64-char big-endian display hex string into 32 MSB-first bytes.
std::array<unsigned char, 32> be_hex_to_msb_bytes(const std::string& hex)
{
EXPECT_EQ(hex.size(), 64u);
auto nib = [](char c) -> int {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
return -1;
};
std::array<unsigned char, 32> out{};
for (int i = 0; i < 32; ++i)
out[i] = (unsigned char)((nib(hex[2 * i]) << 4) | nib(hex[2 * i + 1]));
return out;
}

// Build a u256 from a big-endian display hex string via the production
// from_le_bytes path: reverse MSB-first display bytes into little-endian
// storage order (the byte order a parsed tip hash actually arrives in).
u256 u256_from_display_hex(const std::string& hex)
{
auto msb = be_hex_to_msb_bytes(hex);
unsigned char le[32];
for (int i = 0; i < 32; ++i) le[i] = msb[31 - i];
return u256::from_le_bytes(le);
}

} // namespace

// Oracle anchor: the DGB mainnet genesis hash (digibyte.py:55) must round-trip
// through the LE storage path back to its canonical display hex.
TEST(DgbHashFormatParity, GenesisHashRendersOracleDisplayHex)
{
const std::string genesis =
"7497ea1b465eb39f1c8f507bc877078fe016d6fcb6dfad3a64c98dcc6e1e8496";
EXPECT_EQ(u256_be_display_hex(u256_from_display_hex(genesis)), genesis);
}

// Zero renders 64 zero nibbles -- no truncation, full left-padding.
TEST(DgbHashFormatParity, ZeroRendersSixtyFourZeros)
{
EXPECT_EQ(u256_be_display_hex(u256{}), std::string(64, '0'));
}

// A tiny value pins the left zero-padding and that limb[0] is the LOW nibble.
TEST(DgbHashFormatParity, OneRendersPaddedToSixtyFourDigits)
{
u256 v;
v.limb[0] = 1;
EXPECT_EQ(u256_be_display_hex(v), std::string(63, '0') + "1");
}

// Distinct per-limb values pin most-significant-limb-FIRST ordering (limb[3]
// is the leading 16 hex digits, limb[0] the trailing 16).
TEST(DgbHashFormatParity, LimbOrderingMostSignificantFirst)
{
u256 v;
v.limb[3] = 0x0123456789abcdefULL;
v.limb[2] = 0xfedcba9876543210ULL;
v.limb[1] = 0x00000000ffffffffULL;
v.limb[0] = 0xdeadbeefcafef00dULL;
EXPECT_EQ(u256_be_display_hex(v),
"0123456789abcdef"
"fedcba9876543210"
"00000000ffffffff"
"deadbeefcafef00d");
}

// All-ones renders 64 'f' nibbles (every limb fully populated).
TEST(DgbHashFormatParity, AllOnesRendersSixtyFourEffs)
{
u256 v;
for (int i = 0; i < 4; ++i) v.limb[i] = 0xffffffffffffffffULL;
EXPECT_EQ(u256_be_display_hex(v), std::string(64, 'f'));
}

// from_le_bytes with a fully-distinct 0x00..0x1f pattern pins the byte
// reversal: LE byte 0 (0x00) is the LOW byte -> trailing "00", LE byte 31
// (0x1f) is the HIGH byte -> leading "1f".
TEST(DgbHashFormatParity, FromLeBytesByteReversalIsBigEndianDisplay)
{
unsigned char le[32];
for (int i = 0; i < 32; ++i) le[i] = (unsigned char)i;
EXPECT_EQ(u256_be_display_hex(u256::from_le_bytes(le)),
"1f1e1d1c1b1a1918"
"1716151413121110"
"0f0e0d0c0b0a0908"
"0706050403020100");
}
Loading