Latent header-hygiene bug: crypter.h calls OPENSSL_cleanse at lines 99-100
but never declared the dependency. Built fine because the precompiled
header on triangles_common pulled in <openssl/crypto.h> transitively, so
every translation unit that included crypter.h also got the symbol.
Surfaced by enabling -DBUILD_TESTS=ON: test_triangles is configured
without REUSE_FROM the PCH, so test/sigopcount_tests.cpp fails to find
OPENSSL_cleanse when crypter.h is reached transitively via key.h/wallet.h.
Adding the explicit include is the principled fix — headers should
declare their own dependencies rather than rely on the consumer's
precompiled-header configuration.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contabo seed nodes now have persistent Tor hidden service volumes.
New onion addresses:
- seed-1: vmepp7...qtpfad
- seed-2: nsldmf...uykqd
- seed-3: on4nok...y3eqd
- seed-4: 3uyzlt...iqad
Also added Hetzner Helsinki (nawqqo...j26taid).
Reconciles two parallel implementations of multi-backend chain DB:
local kept its MakeChainDB factory + std::filesystem + unconditional
RocksDB + abstracted utxosnapshot, since those are downstream of the
boost-cleanup, smessage-RocksDB-port, and CTxDBBase abstraction work.
Preserved from origin (Krystie's branch):
- Block 2,203,594 checkpoint and matching mapSnapshotHashes entry
for P2P snapshot verification (src/checkpoints.cpp)
- Headers-first IBD stall-recovery path: during IBD, replace the
legacy PushGetBlocks fallback with RequestHeaderSyncRefillAllPeers
+ QueueHeaderSyncBlocksParallel so a stall on a weak peer set
doesn't park at a low common ancestor (src/main.cpp SendMessages)
Discarded from origin:
- src/txdb.cpp (CActiveTxDB wrapper) — superseded by txdb-factory.cpp
- BUILD_ROCKSDB-gated paths and inline LevelDB+RocksDB code in
utxosnapshot.cpp — already factored out behind CTxDBBase
- Public ReadRawBytes/WriteRawBytes/... wrappers added to
CTxDBBase for CActiveTxDB; no remaining callers
- GetActiveChainDbDirName / UseRocksDbBackend in bootstrap.cpp;
switched to GetChainDataDir()
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aligns the recorded commit with the v0.7.1 tag actually checked out
in the working tree. Carrying forward; no code change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add libsecp256k1 v0.7.1 as src/secp256k1 submodule and introduce
crypto_ecdsa / crypto_ecdh wrappers as drop-in replacements for the
OpenSSL ECDSA_verify / ECDSA_sign / ECDH_compute_key call sites used
by key.cpp and smessage.cpp. Wrappers preserve on-chain compatibility
(lax DER parsing, 65-byte recoverable compact sigs, SEC1 priv-key
DER round-trip, raw-X ECDH output for smsg KDF).
CMake wires the submodule and new sources into the build. Mid-refactor;
landing as a checkpoint before stacking sync-pipeline work on top.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-v5.10 the secure-messaging store was backed by LevelDB at
<datadir>/smsgDB/. Phase 3a switched it to RocksDB; existing nodes
upgrading to v5.10 would otherwise lose their pubkey cache and
inbox/outbox because RocksDB can't open a LevelDB tree.
Detection: presence of CURRENT without IDENTITY in smsgDB/. RocksDB
writes IDENTITY on first open; LevelDB never does.
Migration path:
1. Atomic rename smsgDB/ → smsgDB.leveldb-backup/
2. Open backup with leveldb::DB (read-only)
3. Open smsgDB/ with rocksdb::DB (create_if_missing)
4. Iterate every key, copy in 5000-entry batches
5. Leave the backup in place — never deleted by the migration code,
so the user can roll back manually if needed
Triggered lazily inside SecMsgDB::Open so no separate flag or RPC is
needed. Already-migrated nodes (IDENTITY present) skip the path. Once
all users are on v5.10+ the helper and the leveldb headers it pulls
in can be dropped.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bignum.h calls std::reverse and std::reverse_copy unqualified, relying
on ADL plus <algorithm> being transitively pulled in by an earlier
header. The Qt build path on Windows MSYS2 doesn't satisfy that
assumption — the moc-generated TUs reach bignum.h before <algorithm>
shows up via any other include. Add the explicit include.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1. rocksdb::WriteBatch::Handler typeinfo missing on Ubuntu's librocksdb-dev.
Both SecMsgBatchScanner (smessage.cpp) and CRocksBatchScanner
(txdb-rocksdb.cpp) inherited from Handler to scan an active WriteBatch
for pending writes/deletes; that subclass-based scan fails to link
because Ubuntu's package hides the parent's typeinfo. Replaced both
scanners with a parallel std::map<std::string, std::optional<std::string>>
maintained alongside each WriteBatch — Put adds a value entry, Delete
adds a nullopt entry, ScanBatch becomes an O(log n) map lookup. Same
semantics, no Handler dependency.
2. macOS Homebrew's RocksDB 10.x removed the raw DB** overload of
DB::Open; only std::unique_ptr<DB>* remains. txdb-rocksdb.cpp called
the raw form, breaking the macOS build. Added the same SFINAE Open
wrapper used in smessage.cpp (commit 4265343) that picks whichever
overload the linked rocksdb actually has.
3. CSignal<>'s SignalState::slots member collided with Qt's `#define slots`
to empty, stripping the member name in any TU that pulls in <QtCore>
(e.g. moc-generated files that include util_signal.h transitively).
Renamed to slot_map.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two issues surfaced once configure stopped failing:
1. CTxDBBase::NewIterator() was protected, but the snapshot dump/load
code (commits 76579e3, ccfada5) calls it externally. Moved to public —
the iterator interface is intentional public API.
2. RocksDB DB::Open's raw DB** overload was removed in newer releases.
Homebrew's macOS package (10.x) only exposes the std::unique_ptr<DB>*
form; Ubuntu 22.04 (rocksdb 6.x) and MSYS2 (8/9.x) still expose DB**.
Added a SFINAE wrapper OpenSmsgDB() in smessage.cpp that picks
whichever overload the linked rocksdb actually has, so we don't need
version macros or per-distro #ifdefs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
C++20 broke two things in the prior bump:
1. std::allocator no longer exposes pointer/const_pointer/reference/
const_reference member typedefs, and the 2-arg allocate(n, hint) was
removed. Both secure_allocator and zero_after_free_allocator inherited
these from std::allocator. Define the typedefs ourselves and switch
the secure_allocator allocate() to the single-arg form.
2. Bundled src/leveldb uses `std::memory_order::memory_order_relaxed`
which was valid in C++17 but became a hard error in C++20 (memory_order
is now a scoped enum class — the values are at namespace scope or
memory_order::relaxed, not memory_order::memory_order_relaxed). LevelDB
itself only needs C++11, so pin its targets to C++17 in BuildLevelDB.cmake
instead of patching vendored code.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Walks the active chain in [start_height, end_height] and runs the existing
VerifySignature path on every non-coinbase input. Returns counts plus the
first 100 failures.
Intended use: capture a pre-migration baseline (should be all-zero
failures), then re-run after switching the underlying ECDSA primitive
(e.g. OpenSSL EC -> libsecp256k1) to catch behavioural regressions before
they hit IBD on a peer.
Defaults: start = max(1, tip-1000), end = tip.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two CI failures from the prior push:
1. MSYS2 mingw64's RocksDB headers (8.x+) use `using enum` and defaulted
operator== on user-defined types — both C++20-only. Bumped
CMAKE_CXX_STANDARD from 17 to 20 across the project. GCC 11.4 (Ubuntu),
GCC 14.x (MSYS2), and Apple Clang 16 all support what we need.
2. Ubuntu 22.04's librocksdb-dev ships neither a CMake config package nor
a rocksdb.pc file, so both find_package(RocksDB CONFIG) and
pkg_check_modules(rocksdb) fail. Added a manual find_path/find_library
fallback that creates a RocksDB::rocksdb IMPORTED target from the
raw header dir + .so, with a clear FATAL_ERROR if all three probes miss.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
LoadSnapshot previously opened LevelDB directly at <datadir>/txleveldb to
write the snapshot in. Refactored to use the CTxDBBase abstraction:
- WipeChainDataDir() removes the configured backend's chain DB dir
- MakeChainDB("c+") opens fresh via the factory
- High-level methods (WriteBlockIndex, WriteUtxo, WriteHashBestChain,
WriteVersion, WriteDbFormat) replace manual key/value construction
- TxnBegin/Commit cycles every 1000 headers / 50000 UTXOs preserve the
prior batching cadence
The IsRocksDbChainBackend() guard added in 76579e3 is dropped — snapshot
loading now works on either backend.
Two adjacent paths in init.cpp also hardcoded "txleveldb": the snapshot
auto-load guard (Step 6c) and the -reindex datadir wipe. Both updated to
GetChainDataDir() / WipeChainDataDir() so they pick the right directory
for the configured backend.
Helpers added to txdb.h / txdb-factory.cpp:
- GetChainDataDir(): on-disk path of the configured backend's chain DB
- WipeChainDataDir(): rm -rf the same path
Bootstrap archive paths (bootstrap.cpp lines 721+) intentionally still
reference txleveldb specifically — the prebuilt-index distribution
remains LevelDB-format until that pipeline is ported separately.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The secure-messaging store (smsgDB) used the LevelDB API directly. Mass-
mapped to the equivalent RocksDB types: leveldb::DB/Status/WriteBatch/
Iterator/Slice/ReadOptions/WriteOptions/WriteBatch::Handler -> rocksdb::*.
The RocksDB API surface for our usage is binary-compatible — pure namespace
substitution, no semantic changes. Consumers in rpcsmessage.cpp and
qt/messagemodel.cpp updated to match.
RocksDB now becomes a hard build dependency (was optional behind
BUILD_ROCKSDB). The chain-DB rocksdb backend is consequently always
available; -chaindb=leveldb remains the default until the Phase-4
LevelDB retirement. Removed the BUILD_ROCKSDB cmake option, the
#ifdef BUILD_ROCKSDB guards in txdb*, and the runtime error path
that triggered when the flag was off.
CI updated: librocksdb-dev (Ubuntu), mingw-w64-x86_64-rocksdb (MSYS2),
and rocksdb (Homebrew) added to all build jobs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Avoids collision with the POSIX <signal.h> system header. Pure
mechanical include-path update — no behavior change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bench-chaindb.sh times FastImportBlockFile() under each backend using a
user-supplied blk0001.dat. Wall time comes from the daemon's existing
StartupPerfLog line; peak RSS via ps sampling; datadir size via du.
Output is one CSV row per backend appended to ./bench-results.csv, plus
a stdout summary. Network is disabled during the run (-nolisten -connect=0)
so we measure only DB ingest cost.
Does not yet measure: reorg cost, network IBD speed, raw disk I/O.
LoadSnapshot path is still LevelDB-only; the harness intentionally exercises
the FastImportBlockFile rebuild instead, which works on both backends.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
DumpSnapshot reached into the LevelDB backend's internal handle via
`extern leveldb::DB *txdb`, which silently broke under -chaindb=rocksdb.
Switched to the backend-agnostic CTxDBBase::NewIterator() interface; the
function now works against either backend.
LoadSnapshot is more involved (writes directly into a fresh txleveldb/
directory) and is bundled with the eventual LevelDB retirement. Added an
IsRocksDbChainBackend() helper and an explicit guard at LoadSnapshot's
entry: refuse to load with a clear error message rather than silently
creating a leveldb tree alongside an active rocksdb chain.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Format and tidy enforce only on lines changed in PRs (diff-only via
git-clang-format and clang-tidy-diff.py) — existing files keep their
current style until edited. Mass reformat deferred; .git-blame-ignore-revs
stub is in place for whenever that happens.
Sanitizer lane builds with -fsanitize=address,undefined and runs the
unit suite. continue-on-error: true initially so we can triage findings
without blocking PRs. UB categories pervasive in the Hash9 C cascade
(alignment, signed-integer-overflow, vptr) are suppressed pending
file-by-file fixes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file has been built into the binary since the M1.3 chain-DB
backend split (referenced from src/CMakeLists.txt) but was never
committed. A fresh clone wouldn't build without it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drops the last boost::signals2 dependency from the GUI/wallet/smessage
notification path. CSignal<> is a std::function-based fan-out signal
with explicit Connection tokens (no equivalent-bind disconnect). Same
semantics for the void-returning case; non-void variant returns the
last-connected slot's result via std::optional.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Migration from boost to std-library equivalents and removal of unreachable
code paths. Touches infrastructure only — no consensus rule or wallet
serialization changes.
Dead code removed:
- IRC bootstrap (irc.cpp/h, 417 lines): orphan from pre-Tor era, no callers.
- Alert system (alert.cpp/h + sendalert RPC + Qt UI signal, ~500 lines):
retired post-V5 fork; old peers' alert messages now hit the unknown-cmd
default branch, logged + ignored.
- Legacy P2P handlers in main.cpp: "checkpoint" (already a no-op stub since
V5 fork master-key removal), "checkorder"/"reply" (2010-era Receive-by-IP
feature), plus their unused supporting structures (CRequestTracker,
PushRequest overloads, mapRequests/cs_mapRequests, mapReuseKey).
- Unreachable RPCs clearwallettransactions and scanforalltxns (~175 lines):
defined in rpcwallet.cpp but never registered in the dispatch table.
- Stale -alertnotify CLI help text (option was advertised but never wired).
boost::filesystem -> std::filesystem (C++17):
- 30 source files, 5 headers. namespace fs = boost::filesystem swapped to
namespace fs = std::filesystem; boost::filesystem::ifstream/ofstream
replaced with std::ifstream/ofstream (path-aware in C++17);
fs::system_complete -> fs::absolute; boost::filesystem::filesystem_error
-> std::filesystem::filesystem_error.
- Build system: dropped Boost::filesystem from link libs and Boost
components; PCH includes updated.
- Added explicit <filesystem> includes where types were previously
available only transitively (db.h, rpcblockchain.cpp).
boost::thread -> std::thread (12 files):
- sync.h CCriticalSection/CWaitableCriticalSection now alias
std::recursive_mutex/std::mutex. boost::unique_lock and
boost::condition_variable / boost::mutex::scoped_lock swapped to std
equivalents; sync.cpp boost::thread_specific_ptr -> thread_local
std::unique_ptr.
- init.cpp boost::thread_group rewritten as std::vector<std::thread> with
manual join loop. boost::thread::hardware_concurrency ->
std::thread::hardware_concurrency.
- main.cpp/wallet.cpp -blocknotify/-walletnotify shell-out threads now use
std::thread(...).detach() — fixes a latent bug where modern boost::thread
destructor would call std::terminate on the joinable thread.
- util.cpp NewThread now catches std::system_error.
- No interruption_point/interrupt usage anywhere — pure mechanical swap.
boost::chrono / boost::posix_time -> std::chrono (3 of 5 files):
- util.h: MilliSleep, GetTimeMillis, GetTimeMicros rewritten on std::chrono
(system_clock for epoch math, sleep_for for delays).
- snapshotnet.cpp: sleep_for swapped.
- DoS_tests.cpp: timing harness uses steady_clock.
- Skipped: rpcdump.cpp (boost::posix_time::time_input_facet has no clean
std::get_time equivalent) and qt/qtipcserver.cpp (locked to
boost::posix_time by boost::interprocess::message_queue::timed_receive).
Other housekeeping:
- Dropped unnecessary "using namespace boost;" from txdb-leveldb.cpp,
txdb-rocksdb.cpp, walletdb.cpp, db.cpp (verified no unqualified boost
names in those TUs).
- Removed unused extern declaration for clearwallettransactions.
Build fixes for non-unity builds on MinGW64/GCC 15:
- net.cpp: dropped stale #include "irc.h".
- addrman.cpp + main.cpp: explicit <cmath> include for sqrt/pow (was
arriving transitively via boost headers).
- rpcblockchain.cpp + init.cpp: defensive #undef STRICT/ADVISORY/PERMISSIVE
since windows.h macros collide with the Checkpoints:: enum values when
std headers reorder include flow.
- tor_embed_hooks.cpp: triangles_tor_check_interrupted now polls fShutdown
instead of boost::this_thread::interruption_requested (we never used
boost interruption — the hook was always effectively a no-op).
- snapshotnet.cpp: fs::remove error handle uses std::error_code.
- serialize.h: added <ios> for std::ios::badbit/failbit (was relying on
transitive include via boost).
Note: unity builds currently fail on this branch due to std::byte (C++17)
colliding with COM 'byte' typedef from shlobj.h when 'using namespace std;'
from earlier files in the unity slice leaks into util.cpp's parse of
shlobj.h. Build with -DENABLE_UNITY_BUILD=OFF (the default).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
These checkpoints correspond to abandoned fork chains and are causing
IsInitialBlockDownload() to return TRUE incorrectly. The node at
height 2,207,881 is on the main chain but the code was requiring it
to sync to checkpoint 2,209,000 which doesn't exist on mainnet.
After this change, the highest mainnet checkpoint is 2,207,000,
which the node has already passed.
The >24h block-time check in IsInitialBlockDownload() incorrectly kept
IBD=true when the chain was fully synced but simply had no new blocks
arriving (stalled network). This prevented the stake miner from ever
proceeding past its IsInitialBlockDownload() wait loop.
Now returns false once we've passed the checkpoint height estimate,
which correctly indicates IBD is complete.
Fixes: stake miner stuck even when chain is fully synced
Allow historical chain sync to bypass the mandatory coinbase-height
check. Triangles blocks from the original chain do not encode block
height in the coinbase scriptSig, so unconditional enforcement causes
AcceptBlock to reject valid historical blocks during IBD.
Activation set to 2,300,000 — past the original chain's maximum height
but before any future activation point.
Adds CRocksTxDB, the second concrete backend for CTxDBBase. Mirrors
CTxDB (LevelDB) one-for-one with rocksdb:: substitutions: same key
serialization (inherited from CTxDBBase), same active-batch semantics,
same LoadBlockIndex flow including the dbformat v3 chain-trust upgrade.
Build flag BUILD_ROCKSDB defaults OFF, so the existing LevelDB build is
untouched — RocksDB headers are only included when the flag is on, and
the entire .cpp file is wrapped in #ifdef BUILD_ROCKSDB.
Build system:
* Top-level option(BUILD_ROCKSDB ... OFF)
* find_package(RocksDB CONFIG) with pkg-config fallback
* Conditional list(APPEND CORE_SOURCES txdb-rocksdb.cpp)
* Conditional target_link_libraries(... RocksDB::rocksdb)
Data layout: RocksDB lives under <datadir>/rocksdb/, separate from
<datadir>/txleveldb/, so both backends can coexist for migration and
parity testing.
Acknowledged debt: LoadBlockIndex is duplicated between CTxDB and
CRocksTxDB. Will be extracted into CTxDBBase once the iterator and
batch abstractions are proven across both backends (M1.4 or later).
Validated: default-OFF build still compiles cleanly. The BUILD_ROCKSDB=ON
path is NOT compile-validated yet — RocksDB isn't installed on this dev
machine. The code is straight namespace substitution from the working
LevelDB backend; whoever first enables the flag should report any
header/API drift between rocksdb releases.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
M1.2 (mechanical):
Convert every CTxDB& parameter and reference across main.{h,cpp},
wallet.{h,cpp}, and smessage.cpp to CTxDBBase&. Local instantiations
like `CTxDB txdb("r");` are deliberately left as concrete LevelDB —
they'll move behind a factory in M1.4 once the parity harness exists.
CTxDB IS-A CTxDBBase, so all existing call sites continue to compile:
a CTxDB instance binds to a CTxDBBase& parameter automatically.
Forward declaration `class CTxDB;` in main.h replaced with
`class CTxDBBase;`.
Parallel work (snapshotnet + version bump to 5.9.4 + checkpoints/init
/protocol/version edits) included so origin/master matches the local
working tree in one push.
NOT YET COMPILE-TESTED: pushed at the user's explicit request before
the build verification step. If CI fails, expected breakage is in
files that include main.h transitively but not txdb-base.h — fix is
to add `#include "txdb-base.h"` (or rely on the existing txdb.h which
pulls it in).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First step of the multi-phase chaindb modernization plan. Introduces a
backend-agnostic abstraction over the chain database:
* CTxDBBase — abstract class owning all serialization and named
operations (ReadTxIndex, WriteBlockIndex, ReadAddressBalance, etc.).
Templated Read/Write/Erase/Exists dispatch to byte-level virtuals
(ReadRaw/WriteRaw/EraseRaw/ExistsRaw) so every backend produces
bit-identical key bytes — required for migration and dual-backend
parity testing later.
* CTxDBIteratorBase — abstract iterator. Backends implement Seek,
Valid, Next, KeyStr, ValueStr.
* CTxDB now inherits from CTxDBBase and only implements the byte-level
I/O, batch lifecycle, NewIterator, and LoadBlockIndex (which still
uses leveldb directly during the v3 dbformat upgrade — extracted to
base in a later phase).
* UTXO read-through cache moved to txdb-base.cpp under an anonymous
namespace — backend-agnostic so RocksDB will get it for free.
* GetAddressUtxos / GetAddressTxIds / SumUtxoValues moved to base,
using NewIterator() instead of pdb->NewIterator().
No call-site changes — every existing CTxDB user keeps working exactly
as before. Stack allocations like `CTxDB txdb("r")` still work because
CTxDB remains a concrete, cheap-to-construct class. Behavior is
bit-identical: same key serialization, same batch semantics, same
LoadBlockIndex flow.
Sets up M1.2 (factory + caller conversion to CTxDBBase&) and M1.3
(RocksDB backend) — neither requires touching consensus paths.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds patterns for stray build directories, build error logs (including
the corrupted-name redirect file), and *.qm. Existing tracked .qm files
remain tracked; this only stops freshly-compiled regenerations from
cluttering git status.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Companion to the prior cruft-doc cleanup. The fix it analyzed was
superseded by the comprehensive header-sync refill/watchdog work
already in main.cpp.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop seven planning/strategy/upgrade-notes docs that have outlived their
usefulness, plus the dangling CODEX-TOR-GUIDE.md reference in
tor_embedded.cpp.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pairs net.h heartbeat-throttle field with the IBD header-sync fix
in 2a484e4, and ships a full RPC reference doc.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Nodes syncing from zero would accept blocks normally up to ~6000 then
stall permanently with askfor_queue=0 and no new blocks. Root cause: a
broken feedback loop between the header planner and block downloader.
Blocks consume entries from mapHeaderSync (MAX 15000) while getheaders
refills only 2000 at a time; when the cache drains, hashBestHeaderSync
falls to 0 and every refill site is guarded on it being non-zero, so
the pipeline deadlocks with no recovery path.
Recovery paths added:
- ProcessBlock: when the cache is empty during IBD after accepting a
block, broadcast getheaders to all full-node peers. This restarts
the planner at the exact point it dies.
- Stall detection: send getheaders alongside the existing getblocks.
getblocks alone cannot refill the header cache.
- SendMessages: belt-and-suspenders, re-request headers every 30s
while hashBestHeaderSync == 0 in IBD, independent of stall state.
Also fix a secondary issue: GetHeaderSyncDownloadPath walks back from
the tip and breaks on the first TTL-evicted entry. The accumulated
partial tail has a parent that is neither in mapBlockIndex nor
mapHeaderSync, so requesting those blocks would produce orphans.
Discard the partial path on a gap; the recovery paths above will
re-request the missing range.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two fixes for the header cache exhaustion bug:
1. Block-accepted path: when hashBestHeaderSync==0 and we're still
behind peers during IBD, send getheaders to all peers to refill
the header cache. Previously the refill was gated on
hashBestHeaderSync!=0, creating a dead loop once the cache drained.
2. Stall detection: also send getheaders alongside getblocks when
a stall is detected. Previously only getblocks was sent, which
cannot refill mapHeaderSync or restart the header planner.
Root cause: getheaders returns 2000 headers per batch. Blocks are
consumed from the cache faster than headers are fetched. Once
mapHeaderSync empties, hashBestHeaderSync becomes 0, and the
refill path is never taken again.
See BUG_ANALYSIS_IBD_STALL.md for full details.
Follow-up to #5. Addresses three risks with the apply=true path:
- MoneyRange sanity gate: refuse to persist a recalculated supply that is
negative or above MAX_MONEY (2,222,222 TRI). A walk that produces an
out-of-range figure indicates a bug (orphan contamination, missing
prevout), not real chain state. Prevents corrupting nMoneySupply with
junk values.
- Atomic apply: wrap every per-block WriteBlockIndex in a single
TxnBegin/TxnCommit so a mid-walk failure leaves on-disk state
untouched instead of half-rewritten.
- Single chain walk: cache (valueOut - valueIn) per block during the
dry-run pass and reuse the cached deltas during apply. Previous code
walked the full chain twice, roughly doubling apply runtime on a
2.2M-block chain.
Help text now warns that the RPC holds cs_main for the full walk and
blocks new blocks, wallet ops, and other RPC for the duration.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rebuild money supply by walking the active chain from genesis and
summing block valueOut - valueIn, instead of relying only on current
UTXO totals. Optionally persist repaired nMoneySupply values across the
active chain with apply=true.
This helps repair corrupted money-supply tracking after chain/index
incidents and exposes both recalculated chain supply and UTXO supply for
comparison.
- Auto-detect and use ccache as compiler launcher when available
- Add ENABLE_UNITY_BUILD option for jumbo builds (batch size 8)
- Precompile heavy STL/Boost/OpenSSL headers for C++ targets
- Exclude hash9 crypto from unity builds (colliding static symbols)
- Fix RAND_screen() compile error on OpenSSL 3.x (removed API)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>