Fix Memory Access Bug & Improve GetAlgo Handling for Legacy & Testnet Blocks #278
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fix Memory Access Bug & Improve GetAlgo Handling for Legacy & Testnet Blocks
Summary of the Problem
For years many users have encountered a memory-access error after first launching DigiByte-QT or
digibyted
during the indexing phase that begins loading/parsing DigiByte block headers. This bug appears most often with older (pre-multi-algo) blocks and certain blocks after the Odo PoW fork.Symptom & LLDB Trace
During initial block loading and when indexing reaches around 40% the wallet’s memory usage can spike dramatically, sometimes causing crashes or out-of-memory conditions. In LLDB, a this memory error back trace looks like:
This indicates a memory violation (
EXC_BAD_ACCESS
), typically meaning an invalid pointer or out-of-bounds array usage.Diagnosis
Older Blocks Returning ALGO_UNKNOWN (-1)
In DigiByte v8.22.0, the function that determines a block’s proof-of-work algorithm looked like:
Many older (2014–2015) blocks, or blocks using a version that does not set one of the above algo bits, end up returning
ALGO_UNKNOWN = -1
.DigiByte has had 4 different block versioning periods or eras throughout its 11-year history, so we have a variety of block versions that need to be properly accounted for when indexing the chain. Modern multi-algo code is much different than older versions and therefore historical chain data was getting misinterpreted by newer code. Below is where the code returning a
ALGO_UNKNOWN = -1
comes from and other bitwise block versioning.digibyte/src/primitives/block.h
Lines 16 to 44 in c5d9a01
Out-of-Bounds Writes to
lastAlgoBlocks[]
In older code,
CBlockIndex
did something like:lastAlgoBlocks[GetAlgo()] = this;
If
GetAlgo()
returned-1
(unknown), we wrote tolastAlgoBlocks[-1]
, corrupting memory outside the array. This could go unnoticed until subsequent calls (e.g.GetBlockHeader()
) triggered a crash.Incorrect Mainnet-Only Logic on Testnet
Historically, mainnet scrypt was used up to block height 145k. Older code forced all blocks
< 145,000
to be interpreted as scrypt—even on testnet. But on testnet, multi-algo and version bits activated earlier/later, so forcibly labeling testnet blocks as scrypt introduced further mismatch and potential memory corruption.Root Cause in Brief
ALGO_UNKNOWN = -1
lastAlgoBlocks[-1]
Changes Implemented
Safer Handling of Unknown Block Versions
CBlockIndex::GetAlgo()
and/or the constructor logic, any unrecognized version bits now yield a safe fallback (ALGO_UNKNOWN
) without updatinglastAlgoBlocks[]
.ALGO_UNKNOWN
is encountered but avoid any array assignment that could go out of bounds.Accurate Version Parsing Below 145k (Mainnet vs Testnet)
Robust Logging & Safety Checks
CBlockIndex::CBlockIndex(const CBlockHeader&)
, log a message if the block’s version maps toALGO_UNKNOWN
.Why This Fixes the Memory Bug
By properly handling unrecognized or out-of-range block versions, we:
lastAlgoBlocks[-1] = this;
whenGetAlgo()
isALGO_UNKNOWN
.Test Results
p2p_dos_header_tree.py
, which checks correct header acceptance/rejection for older heights.address
sanitizer compiler flag. Multiple syncs & wallet restarts on Windows, macOS, and a Raspberry Pi 5 confirm stable memory usage (around 6.5–6.7 GB) without spikes or crashes.Thank you for reviewing these changes! If you have any questions, please feel free to ask in this PR discussion.