Fix Memory Access Bug & Improve GetAlgo Handling for Legacy & Testnet Blocks#278
Merged
ycagel merged 2 commits intoDigiByte-Core:developfrom Jan 25, 2025
Merged
Fix Memory Access Bug & Improve GetAlgo Handling for Legacy & Testnet Blocks#278ycagel merged 2 commits intoDigiByte-Core:developfrom
ycagel merged 2 commits intoDigiByte-Core:developfrom
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
digibytedduring 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 = -1comes 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,
CBlockIndexdid 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,000to 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 = -1lastAlgoBlocks[-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_UNKNOWNis 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.addresssanitizer 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.