ConnectNode() rejected the connection on !addrConnect.IsValid() (and
!IsReachable(addrConnect)) BEFORE the pszDest branch. But -connect (and
-addnode host:port / "addnode <host> onetry") reaches ConnectNode with an
empty placeholder addrConnect and the real target in pszDest, resolved
later by ConnectSocketByName(). An empty CAddress is invalid, so every
-connect attempt returned NULL before a socket was ever opened — the peer
logs "trying connection <host>" then "ConnectNode FAILED" and never dials.
(Introduced upstream with BIP155/addrv2; -connect went unused because
normal operation connects via addrman with real, valid addresses.)
Guard both early-return checks with `if (!pszDest)` so they apply only when
dialing addrConnect directly. Connect-by-name now falls through to
ConnectSocketByName() as intended. Direct-address connections (pszDest==NULL,
the addrman path) are unchanged.
Validated: two nodes on one host, B started with `-connect=<A>` exclusively
(no -addnode) now connects to A over TLS, syncs A's chain, and stays
isolated (0 other peers) — previously B connected to nothing. Clean build,
verifychain 4 0 = true.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
From the Phase-6 structural scoping: land the verified behavioral bugs and
the safe quick-wins/dedups now; the large refactors (monolith splits, ~180
header globals) and consensus-adjacent items stay deferred. Built clean;
self-mined; verifychain=true.
BUGS (verified by reading the code):
- net.cpp CNode::Ban: a braceless `if (subNet.Match(...))` left
`pnode->fDisconnect = true;` OUTSIDE the guard, so banning any one subnet
marked EVERY connected peer for disconnect (dropped the whole peer set).
Wrapped the two statements in braces. (LIVE, high severity.)
- rpcdump.cpp importwallet: the `!fGood -> throw "Error adding some keys"`
check was trapped inside the `if (fRescan)` block, so importwallet with
rescan=false silently reported success when key import failed. Hoisted the
check before the rescan branch and cleaned the garbled braces/indentation.
- wallet.cpp CommitTransaction: ignored AddToWallet()'s return, so a failed
disk-persist of a just-signed spend was swallowed while the tx broadcast.
Now logs a hard error on failure.
- hush_nSPV_fullnode.h: the UTXOS branch declared `uint8_t filter` while the
twin TXIDS branch uses `uint32_t filter`; dragon_rwnum switches on
sizeof(filter), so the utxos path parsed only 1 of 4 wire filter bytes.
Widened to uint32_t.
- asyncrpcoperation_sweep.cpp: LogPrintf("%s ... %s", one-arg) read a missing
vararg; added the __func__ argument.
- rpcdump.cpp importprivkey: inner `auto secret_key` shadowed the outer
uint8_t and changed the type into DecodeCustomSecret; dropped the shadow.
- rpcdump.cpp getrescaninfo: char[8] + sprintf("%.4f") overflows when the
ratio >= 10.0 (transient reorg); widened to char[16] + snprintf.
QUICK WINS: removed the duplicate DRAGON_MAXSCRIPTSIZE #define; pinned the
dead HUSH3-branch NOTARISATION_SCAN_LIMIT_BLOCKS to 1440; fixed init typos
(fRequestShutdown, RPC warmup).
DEDUP: extracted the 19-line try/catch error-mapping block — copy-pasted
identically into all six async operations — into
AsyncRPCOperation::set_error_from_current_exception(), so the mapping is
edited in one place. Behavior-identical (verified all six blocks were byte-
identical first).
Deferred (endorsed by the scoping, better as their own PRs): addrman Select_
dedup, the pow.cpp powLimit helper (consensus file), the miner CreateNewBlock
lock-asymmetry, the wallet monolith splits, and the ~180-global / consensus-
retarget / Komodo-heritage work.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fifth phase of the code-hygiene remediation, done per-file (18 files) via an
18-agent Workflow with strict guardrails. No consensus or security VALUES
changed (verified: pow/hush_utils/hush_bitcoind/net.h/crypter/stratum have
zero non-comment numeric changes); built clean, self-mined, verifychain=true.
Totals: 57 stale comments corrected, 46 user-facing branding fixes, 6
behavior-preserving named constants, 4 stratum warnings, 77 items deliberately
left (consensus/security values, copyright headers).
- Stale comments -> DragonX: corrected HUSH3/HUSH/Komodo/Equihash/Arrakis
leftovers that misdescribed the active chain (pow AWT/lwma notes, txdb
"Equihash solution" -> RandomX, wallet CLTV/overwinter/Sapling@1 notes,
util datadir provenance, crypter's stale mapSproutSpendingKeys invariant).
Replaced unprofessional/editorializing comments (profane TODOs, "developers
are elite") with neutral technical notes, preserving the real design info.
- User-facing branding: dumpwallet header "created by Hush" -> "DragonX";
RPC help text hushd/hush-cli/hushprivkey/hushaddress/Agama -> dragonx*;
rebranded provably-dead "HUSH3" symbol-fallback literals to DRAGONX.
- Named constants (same values, non-consensus/non-security): addrman
peer-selection factors (kChanceFactorGrowth/kChanceScale/deprioritize),
sietch MIN_ZOUTS, an init notarization-DB cache size.
- Left the security macros (ECC/TFM_TIMING_RESISTANT=420, comment-clarified
only), the consensus subsidy/commission literals + 128/129 TRANSITION
(comment only), and copyright headers untouched.
- Added a prominent WARNING that the stratum server is Equihash-era and NOT
updated for DragonX's RandomX PoW (flagged, not rewritten).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fourth phase of the code-hygiene remediation, addressing the ~1,082 stray
fprintf(stderr)/printf debug calls so consensus and hot paths stop spewing
to stderr/stdout. Done per-file (18 files) with conservative rules; the tree
builds clean, self-mines, and `verifychain` re-validates the whole chain
(pow/txdb/coins/miner paths) with -debug=1 enabling every converted line —
zero tinyformat/format-arg exceptions.
Net across 18 files: 174 commented-out debug lines deleted, 173 unconditional
live prints converted to LogPrint("<cat>",...)/LogPrintf (net/mining/pow/nspv/
zrpc categories, format strings + args preserved exactly), 40 pure-noise or
sensitive prints deleted, and 194 calls DELIBERATELY LEFT (already behind
fDebug/fZdebug guards, or genuine startup/fatal-error output that must reach
the console before logging init).
Notable:
- Deleted sensitive success-path dumps (nSPV SIG_TXHASH + full tx input/
output/change amounts; kvupdate privkey/pubkey hex) that were writing key
and amount material straight to stderr/stdout.
- Removed the raw 32-byte target hex dumps in the zawy adaptive-PoW helpers
and the legacy one-shot `if(height==340000)` HUSH artifact in pow.cpp.
- Converted per-tx relay + ban/banlist (net), per-setgenerate MININGTHREADS
(rpc/mining), signrawtransaction TXPOW, and per-message nSPV traces.
- Left format/arg-mismatched lines untouched (flagged) to avoid introducing
tinyformat runtime throws.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Third phase of the code-hygiene remediation: remove provably-dead code.
Each in-file deletion was adversarially verified (a per-finding investigator
plus a skeptic that greps the tree to refute deletability); the sanity grep
confirms zero dangling references, and the tree builds and self-mines clean.
Removed wholesale:
- src/cc/dapps/ (9 files, ~6,939 lines): a git-tracked but never-built Komodo
DEX / z-migration tool (hushdex.c, zmigrate.c, cJSON.c, ...). Nothing in
Makefile.am/configure.ac references it.
In-file dead code:
- pow.cpp: the `#ifdef original_algo` oldRT_CST_RST function (the macro is
never defined in source or build flags) and two `if ( 0 )` debug blocks.
- walletdb.cpp: the "orphaned staking transaction" cleanup path (deadTxns) —
DragonX is RandomX PoW with no staking, so the guard is always false and the
block never runs; also drop the now-unused static/extern decls.
- cc/eval.h: the ProcessCC / Eval::ImportCoin / ImportPayout / DisputePayout
declarations that have no definition anywhere in the tree.
- rpc/crosschain.cpp: the crosschainproof stub RPC (returned {} unconditionally)
and its registrations in rpc/server.cpp, rpc/server.h, rpc/client.cpp.
- coins.cpp: the commented-out `//TODO: delete` Sprout PushAnchor template.
- wallet.cpp: the permanently-zero KMD `interest2` term in CreateTransaction.
- rpc/net.cpp: hush_longestchain's always-zero `n` var (num > (n>>1) => num>0)
and its `if ( 0 )` debug branch.
- hush_nSPV.h / hush_nSPV_fullnode.h: three `if ( 0 && ... )` dead debug branches.
- net.cpp, crypter.h, saplingconsolidation.cpp (dup set_error_code),
shieldcoinbase.cpp (`donation < 0` on a uint8_t), cclib.cpp (unused
FAUCET2SIZE): single-line dead-code fixes.
Deliberately NOT touched (verification refuted the audit's "dead on DragonX"
premise): the ~2,250-line HUSH3 checkpoint block, the miner notary/timelock
paths, and hush_gateway.h — all reachable at runtime via -ac_name / -ac_*
args (the inherited Komodo assetchain model), and hush_gateway's
hush_opretvalidate is called from ConnectBlock (consensus). Dropping those
requires a deliberate decision to remove HAC/HUSH3 mode, tracked separately.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A DRAGONX node had no working peer discovery. Both mechanisms were broken, and a
third bug hid the fact.
1. DNS seeds were Hush's, and all three are dead. chainparams_commandline() sets an
assetchain's port, magic, blocktime, upgrade heights and checkpoints but never
touches vSeeds or vFixedSeeds, so DRAGONX silently inherited CMainParams':
seed1.hush.is, seed2.hush.is and dns.leto.net. None of the three has an A record
any more -- verified against 1.1.1.1 and 8.8.8.8, with google.com and
node1..node5.dragonx.is resolving fine from the same host as a control. Replaced
with the five DragonX node hostnames, which do resolve and do listen.
2. Every fixed seed carried port 0. contrib/seeds/generate-seeds.py documents its
input as <ip>:<port>, but contrib/seeds/nodes_main.txt held bare IPs, so
parse_spec() took the port as empty and emitted 0x00,0x00 for all five entries.
The fixed-seed fallback -- which exists precisely for when DNS seeding yields
nothing -- was therefore handing out unconnectable addresses. Added the port to
nodes_main.txt and regenerated; entries now end 0x55,0x08 (21768).
3. ThreadDNSAddressSeed never incremented `found`, so "%d addresses found from DNS
seeds" printed 0 unconditionally, whether seeding worked or not. That is almost
certainly why nobody noticed the seeds had gone dead: the one diagnostic that
would have shown it was hardcoded to say zero.
Verified on a fresh datadir (empty addrman, separate ports, real node untouched):
DNS seeding now reports "5 addresses found from DNS seeds" where it previously
reported 0, and the fixed-seed path adds 5 entries carrying the correct port.
Note on scope: the five hostnames are single-A-record hosts, so each contributes one
address rather than the spread a real seeder returns. A dedicated DNS seeder, or
simply a round-robin A record over the seed set, would be the proper fix and needs
only a DNS change rather than a release. This restores a working discovery path;
it does not make it a good one.
Also corrected the generated header's #endif comment, which said
HUSH_CHAINPARAMSSEEDS_H while the guard is DRAGONX_CHAINPARAMSSEEDS_H.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Update compiler references from gcc-8 to gcc-15 across build system
(build-mac.sh, darwin.mk, Makefile_custom)
- Use system Rust (rustup) instead of bundled Rust 1.32.0 for librustzcash
to fix rlib linker incompatibility on macOS Sequoia
- Replace deprecated std::random_shuffle with std::shuffle (net.cpp,
transaction_builder.cpp, wallet.cpp)
- Fix -std=gnu17 -> -std=gnu++17 for C++ targets (libzcash, libhush)
- Fix nodiscard warning in glibcxx_sanity.cpp
- Replace deprecated OSMemoryBarrier with std::atomic_thread_fence in LevelDB
- Add -Wno-error=deprecated-declarations to CXXFLAGS for third-party headers
- Fix REMAINING_ARGS unbound variable in build.sh
- Add --disable-tests handling to build-mac.sh
- Update README with correct macOS build dependencies and instructions
Replace an assert() in Unserialize() with the actual behavior we want,
i.e. making sure that vRandom is empty. Before the assert() was added,
the code called Clear() which ensured vRandom was empty. Clear() was
changed to the assert() in BTC commit b138973a8b4bbe061ad97011f278a21e08ea79e6
to prevent recursive locks but risks crashing the node. Instead, we
just empty out vRandom.
The addition of EXCLUSIVE_LOCKS_REQUIRED is not needed to fix
this but seems prudent since Serialize() has it and the original code
from BTC has EXCLUSIVE_LOCKS_REQUIRED on all the methods of this class.
As a side note, crashing a full node with an assert() and possibly
corrupting the wallet.dat, block files and other data is REALLY
FUCKING DUMB. Instead, code should be written to prevent the
possibility of crashing or throw an exception with a useful error.
From BTC Core https://github.com/bitcoin/bitcoin/pull/9037/ with modifications to support our asmap.
This has a small part of code commented out that depends feeler connection code.