From 13d51a504c61cf2a7a724e7c11b41aa783e99d9c Mon Sep 17 00:00:00 2001 From: xanimo Date: Tue, 4 Aug 2026 20:06:34 +0000 Subject: [PATCH] pow, validation: report the condition that actually failed check_pow() rejects on four conditions but its diagnostic could only ever report two of them honestly. The second column, labelled "target == 0", passed "(const uint8_t*)target == 0" to printf: a NULL test on the pointer init_arith_uint256() had just returned, which is never NULL. It printed 0 unconditionally and never called arith_uint256_is_zero(). The fourth condition, target above the chain's pow_limit, was not printed at all. A rejection caused by either of those two therefore produced output in which every printed field read 0, giving no indication of the cause. This is reachable from the existing test suite: the synthetic cases in test_auxpow_deserialize_e2e() hand the auxpow body to deserialize_dogecoin_auxpow_block() without a preceding 80-byte header parse, so block->header->bits is still zero, set_compact(0) yields a zero target, and check_pow() correctly refuses while appearing to report nothing wrong. Evaluate each condition into a named local, report all four, and include nbits so a zero target is attributable to its source. check_auxpow() separately appended strerror(errno) to four failure messages. Nothing on those paths sets errno; the value is stale or zero, so a consensus rejection routinely printed "Success". Drop it. No functional change: the same inputs are accepted and rejected as before. --- src/pow.c | 19 ++++++++++++++++--- src/validation.c | 10 +++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/pow.c b/src/pow.c index cc63517e5..928e39db8 100644 --- a/src/pow.c +++ b/src/pow.c @@ -45,9 +45,22 @@ dogecoin_bool check_pow(uint256_t* hash, unsigned int nbits, const dogecoin_chai arith_uint256* target = init_arith_uint256(); target = set_compact(target, nbits, &f_negative, &f_overflow); const uint8_t* target_bytes = (const uint8_t*)target->pn; - if (f_negative || arith_uint256_is_zero(target) || f_overflow || uint256_cmp(target_bytes, params->pow_limit)) { - printf("%d:%s: f_negative: %d target == 0: %d f_overflow: %d\n", - __LINE__, __func__, f_negative, (const uint8_t*)target == 0, f_overflow); + /* Report which rejection condition actually fired. The previous printf passed + "(const uint8_t*)target == 0", a NULL test on the pointer just returned by + init_arith_uint256(), so the "target == 0" column read 0 unconditionally and + never reported arith_uint256_is_zero(). The above-pow-limit term was not + printed at all, so a rejection could show every printed field as 0. */ + if (f_negative || arith_uint256_is_zero(target) || f_overflow + || uint256_cmp(target_bytes, params->pow_limit)) { + /* Evaluate the individual terms only here, on the failure path. Hoisting + them above the condition would report all four but destroy the + short-circuit, so uint256_cmp would run against a target that + set_compact had already flagged as overflowed. Defined behaviour, but + there is no reason to compare a target we have already rejected. */ + dogecoin_bool target_is_zero = arith_uint256_is_zero(target); + dogecoin_bool above_pow_limit = uint256_cmp(target_bytes, params->pow_limit); + printf("%d:%s: nbits: 0x%08x f_negative: %d target_is_zero: %d f_overflow: %d above_pow_limit: %d\n", + __LINE__, __func__, nbits, f_negative, target_is_zero, f_overflow, above_pow_limit); dogecoin_free(target); return false; } diff --git a/src/validation.c b/src/validation.c index 56f30b860..0578484e7 100644 --- a/src/validation.c +++ b/src/validation.c @@ -71,9 +71,9 @@ dogecoin_bool check_auxpow(dogecoin_auxpow_block* block, dogecoin_chainparams* p where the height is known. */ if (!is_legacy(block->header->version) && params->strict_id && get_chainid(block->header->version) != params->auxpow_id) { printf("%s:%d:%s : block does not have our chain ID" - " (got %d, expected %d, full nVersion %d) : %s\n", + " (got %d, expected %d, full nVersion %d)\n", __FILE__, __LINE__, __func__, get_chainid(block->header->version), - params->auxpow_id, block->header->version, strerror(errno)); + params->auxpow_id, block->header->version); return false; } @@ -87,7 +87,7 @@ dogecoin_bool check_auxpow(dogecoin_auxpow_block* block, dogecoin_chainparams* p cstr_free(s, true); if (!check_pow(&hash, block->header->bits, params, chainwork)) { - printf("%s:%d:%s : non-AUX proof of work failed : %s\n", __FILE__, __LINE__, __func__, strerror(errno)); + printf("%s:%d:%s : non-AUX proof of work failed\n", __FILE__, __LINE__, __func__); return false; } @@ -101,7 +101,7 @@ dogecoin_bool check_auxpow(dogecoin_auxpow_block* block, dogecoin_chainparams* p dogecoin_block_header_scrypt_hash(s2, &parent_hash); cstr_free(s2, true); if (!check_pow(&parent_hash, block->header->bits, params, chainwork)) { - printf("%s:%d:%s : AUX proof of work failed: %s\n", __FILE__, __LINE__, __func__, strerror(errno)); + printf("%s:%d:%s : AUX proof of work failed\n", __FILE__, __LINE__, __func__); return false; } @@ -109,7 +109,7 @@ dogecoin_bool check_auxpow(dogecoin_auxpow_block* block, dogecoin_chainparams* p dogecoin_block_header_hash(block->header, block_header_hash); uint32_t chainid = get_chainid(block->header->version); if (!block->header->auxpow->check(block, &block_header_hash, chainid, params)) { - printf("%s:%d:%s : AUX POW is not valid : %s\n", __FILE__, __LINE__, __func__, strerror(errno)); + printf("%s:%d:%s : AUX POW is not valid\n", __FILE__, __LINE__, __func__); return false; }