hygiene: fix seven latent defects from the v1.2.0 code audit

Phase 1 of the code-hygiene remediation. Each is a genuine defect, not
style. The two consensus functions are touched only by provably
behavior-preserving dead-code removal and a comment.

- miner: initialize the anti-spin loop counter (was `int i;` -- the loop
  condition read an indeterminate value, UB) and break once the block
  time advances past the median, which is what the comment intended.
- consensus/upgrades: drop a stray printf() on the NetworkUpgradeState
  path; the following assert already documents the invariant.
- txdb: CBlockTreeDB::Snapshot2's outer catch treated ANY exception as
  normal end-of-iteration and built a snapshot from partial data. Fail
  instead, matching the inner catch the author marked consensus-relevant
  ("we need to exit here if so for consensus code!"). iter->Valid()
  already handles genuine end-of-iteration.
- wallet/rpcwallet + init: -sietch-min-zouts used a "--" key that the arg
  parser (which normalizes --foo to -foo) can never match, so the Sietch
  decoy floor was silently stuck at the default. Use the single-dash key
  so the knob works, and document it in -help.
- hush_bitcoind + hush_utils: remove four unreachable duplicate `else if`
  branches from hush_commission()/hush_block_subsidy() (a second
  `height < 23860000` and a second `height < 27220000` in each). Proven
  identical across 49,591 heights. NB: the dead values hint at an intended
  clean halving schedule that was never wired up; the DEPLOYED schedule
  (two double-steps) is preserved exactly. Changing it is a future
  consensus decision, not this cleanup.
- hush_bitcoind: replace the "likely a bug" halving TODO with an accurate
  note -- INTERVAL is only consumed by a debug fprintf, so the > vs >=
  boundary at HALVING1 has no consensus effect.
- git rm two committed macOS build artifacts (cc/customcc.dylib and
  libcc.dylib) and add the missing .dylib .gitignore rules.

Built clean on Linux; an isolated node self-mined genesis->5113 exercising
the miner and consensus-subsidy paths, and getsnapshot returned normally.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-27 11:35:38 -05:00
parent 02b4d03fc6
commit 798eccc624
10 changed files with 27 additions and 18 deletions

2
.gitignore vendored
View File

@@ -160,8 +160,10 @@ doc/man/Makefile.in
Makefile.in Makefile.in
src/libcc.so src/libcc.so
src/libcc.dll src/libcc.dll
src/libcc.dylib
src/cc/customcc.so src/cc/customcc.so
src/cc/customcc.dll src/cc/customcc.dll
src/cc/customcc.dylib
src/HUSH3_7776 src/HUSH3_7776
REGTEST_7776 REGTEST_7776
src/cc/librogue.so src/cc/librogue.so

Binary file not shown.

View File

@@ -63,10 +63,6 @@ UpgradeState NetworkUpgradeState(
const Consensus::Params& params, const Consensus::Params& params,
Consensus::UpgradeIndex idx) Consensus::UpgradeIndex idx)
{ {
if (nHeight < 0)
{
printf("height: %d", nHeight);
}
assert(nHeight >= 0); assert(nHeight >= 0);
assert(idx >= Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES); assert(idx >= Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES);
auto nActivationHeight = params.vUpgrades[idx].nActivationHeight; auto nActivationHeight = params.vUpgrades[idx].nActivationHeight;

View File

@@ -975,8 +975,9 @@ uint64_t hush_commission(int height)
INTERVAL = GetArg("-ac_halving1",840000), TRANSITION = 129; INTERVAL = GetArg("-ac_halving1",840000), TRANSITION = 129;
uint64_t commission = 0; uint64_t commission = 0;
//TODO: Likely a bug hiding here or at the next halving :) // NB: INTERVAL is consumed only by the debug fprintf at the end of this function;
//if( height >= HALVING1) { // the commission schedule below uses hardcoded height thresholds, not INTERVAL. So
// the > vs >= boundary at HALVING1 has no consensus effect. Left as > for stability.
if( height > HALVING1) { if( height > HALVING1) {
// Block time going from 150s to 75s (half) means the interval between halvings // Block time going from 150s to 75s (half) means the interval between halvings
// must be twice as often, i.e. 840000*2=1680000 // must be twice as often, i.e. 840000*2=1680000
@@ -1019,14 +1020,14 @@ uint64_t hush_commission(int height)
commission = 61035; commission = 61035;
} else if (height < 23860000) { } else if (height < 23860000) {
commission = 30517; commission = 30517;
} else if (height < 23860000) { // removed unreachable duplicate `height < 23860000` (=> 15258); the schedule
commission = 15258; // intentionally drops straight to 7629 next — this is the deployed behavior.
} else if (height < 25540000) { } else if (height < 25540000) {
commission = 7629; commission = 7629;
} else if (height < 27220000) { } else if (height < 27220000) {
commission = 3814; commission = 3814;
} else if (height < 27220000) { // removed unreachable duplicate `height < 27220000` (=> 1907); the schedule
commission = 1907; // intentionally drops straight to 953 next — this is the deployed behavior.
} else if (height < 28900000) { } else if (height < 28900000) {
commission = 953; commission = 953;
} else if (height < 30580000) { } else if (height < 30580000) {

View File

@@ -1564,14 +1564,14 @@ uint64_t hush_block_subsidy(int height)
subsidy = 549316; subsidy = 549316;
} else if (height < 23860000) { } else if (height < 23860000) {
subsidy = 274658; subsidy = 274658;
} else if (height < 23860000) { // removed unreachable duplicate `height < 23860000` (=> 137329); kept in sync
subsidy = 137329; // with hush_commission() — the schedule drops straight to 68664 next.
} else if (height < 25540000) { } else if (height < 25540000) {
subsidy = 68664; subsidy = 68664;
} else if (height < 27220000) { } else if (height < 27220000) {
subsidy = 34332; subsidy = 34332;
} else if (height < 27220000) { // removed unreachable duplicate `height < 27220000` (=> 17166); kept in sync
subsidy = 17166; // with hush_commission() — the schedule drops straight to 8583 next.
} else if (height < 28900000) { } else if (height < 28900000) {
subsidy = 8583; subsidy = 8583;
} else if (height < 30580000) { } else if (height < 30580000) {

View File

@@ -494,6 +494,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-autoshieldinterval", strprintf(_("Block interval between automatic coinbase-shielding rounds (default: %i, min 5)"), 25)); strUsage += HelpMessageOpt("-autoshieldinterval", strprintf(_("Block interval between automatic coinbase-shielding rounds (default: %i, min 5)"), 25));
strUsage += HelpMessageOpt("-autoshieldaddress=<zaddr>", _("Destination Sapling z-address for auto-shielded coinbase (default: reuse or create a wallet z-address). Must be spendable by this wallet.")); strUsage += HelpMessageOpt("-autoshieldaddress=<zaddr>", _("Destination Sapling z-address for auto-shielded coinbase (default: reuse or create a wallet z-address). Must be spendable by this wallet."));
strUsage += HelpMessageOpt("-autoshieldfee", strprintf(_("Fee in puposhis for automatic coinbase-shielding transactions (default: %i)"), 10000)); strUsage += HelpMessageOpt("-autoshieldfee", strprintf(_("Fee in puposhis for automatic coinbase-shielding transactions (default: %i)"), 10000));
strUsage += HelpMessageOpt("-sietch-min-zouts=<n>", strprintf(_("Minimum number of shielded (Sapling) outputs Sietch adds to each z_sendmany transaction as decoys, strengthening amount/linkability privacy. Higher values add privacy at the cost of larger transactions (default: %u, clamped to the range 3-50)"), 7));
strUsage += HelpMessageOpt("-autoshieldminutxos", strprintf(_("Only auto-shield once at least this many matured coinbase UTXOs exist (default: %i)"), 1)); strUsage += HelpMessageOpt("-autoshieldminutxos", strprintf(_("Only auto-shield once at least this many matured coinbase UTXOs exist (default: %i)"), 1));
strUsage += HelpMessageOpt("-deletetx", _("Enable Old Transaction Deletion")); strUsage += HelpMessageOpt("-deletetx", _("Enable Old Transaction Deletion"));

Binary file not shown.

View File

@@ -249,11 +249,13 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
{ {
// too fast or stuck, this addresses the too fast issue, while moving // too fast or stuck, this addresses the too fast issue, while moving
// forward as quickly as possible // forward as quickly as possible
for (int i; i < 100; i++) for (int i = 0; i < 100; i++)
{ {
proposedTime = GetTime(); proposedTime = GetTime();
if (proposedTime == nMedianTimePast) if (proposedTime == nMedianTimePast)
MilliSleep(10); MilliSleep(10);
else
break; // time advanced past the median; stop waiting
} }
} }
pblock->nTime = GetTime(); pblock->nTime = GetTime();

View File

@@ -517,8 +517,14 @@ bool CBlockTreeDB::Snapshot2(std::map <std::string, CAmount> &addressAmounts, Un
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
fprintf(stderr, "DONE reading index entries\n"); // A genuine deserialization/LevelDB error here is NOT normal completion:
break; // the for-loop's iter->Valid() already handles end-of-iteration, and
// non-address key types are skipped by the chType check above. Swallowing
// the exception and building a snapshot from partial data is wrong. Fail
// like the inner catch, which the author marked consensus-relevant
// ("we need to exit here if so for consensus code!").
fprintf(stderr, "%s: LevelDB index iteration exception! - %s\n", __func__, e.what());
return false;
} }
} }
//fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses); //fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses);

View File

@@ -5404,7 +5404,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
// A value of 7 will provide much stronger linkability privacy versus pre-Sietch operations // A value of 7 will provide much stronger linkability privacy versus pre-Sietch operations
unsigned int DEFAULT_MIN_ZOUTS=7; unsigned int DEFAULT_MIN_ZOUTS=7;
unsigned int MAX_ZOUTS=50; unsigned int MAX_ZOUTS=50;
unsigned int MIN_ZOUTS=GetArg("--sietch-min-zouts", DEFAULT_MIN_ZOUTS); unsigned int MIN_ZOUTS=GetArg("-sietch-min-zouts", DEFAULT_MIN_ZOUTS);
if((MIN_ZOUTS<3) || (MIN_ZOUTS>MAX_ZOUTS)) { if((MIN_ZOUTS<3) || (MIN_ZOUTS>MAX_ZOUTS)) {
fprintf(stderr,"%s: Sietch min zouts must be >= 3 and <= %d, setting to default value of %d\n", __FUNCTION__, MAX_ZOUTS, DEFAULT_MIN_ZOUTS ); fprintf(stderr,"%s: Sietch min zouts must be >= 3 and <= %d, setting to default value of %d\n", __FUNCTION__, MAX_ZOUTS, DEFAULT_MIN_ZOUTS );