AI-generated analysisPublished automatically and not human-verified. Validated context appears in community notes below.
← Watch feed
Informational 20 Bitcoin

validation: pre-reserve leaves to prevent reallocs with odd vtx count

Public commit record

What the developer wrote

Authored by Lőrinc

93/100 · Strong
validation: pre-reserve leaves to prevent reallocs with odd vtx count

`ComputeMerkleRoot` duplicates the last hash when the input size is odd. If the caller provides a `std::vector` whose capacity equals its size, that extra `push_back` forces a reallocation, doubling its capacity (allocating 3x the necessary memory).

This affects roughly half of the created blocks (those with odd transaction counts), causing unnecessary memory fragmentation during every block validation.

Fix this by pre-reserving the vector capacity to account for the odd-count duplication. The expression `(size + 1) & ~1ULL` adds 1 to the size and clears the last bit, effectively rounding up to the next even number. This syntax produces optimal assembly across x86/ARM and 32/64-bit platforms for gcc/clang, see https://godbolt.org/z/xzscoq7nv.

Also switch from `resize` to `reserve` + `push_back` to eliminate the default construction of `uint256` objects that are immediately overwritten.

> ./build/bin/bench_bitcoin -filter='MerkleRoot.*' -min-time=1000

| ns/leaf | leaf/s | err% | total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
| 43.73 | 22,867,350.51 | 0.0% | 1.10 | `MerkleRoot`
| 44.17 | 22,640,349.14 | 0.0% | 1.10 | `MerkleRootWithMutation`

Massif memory measurements after show 0.8 MB peak memory usage

KB
801.4^ #
| #
| #
| #
| #
| #
| #
| # :::::@:::::@:
| #:::@@@::@:::::::::::::::@::@:@:::@@:::::::::@::::::@:::::@::::@:::::@:
| #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
| #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
| #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
| #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
| #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
| #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
| #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
| #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
| #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
| #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
| #:::@ @: @:::::::::::::::@::@:@:::@ :::: ::::@::::::@:::::@::::@:::::@:
0 +----------------------------------------------------------------------->s
0 227.5

and the stacks don't show reallocs anymore:
96.37% (790,809B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->35.10% (288,064B) 0x2234AF: allocate (new_allocator.h:151)
| ->35.10% (288,064B) 0x2234AF: allocate (allocator.h:203)
| ->35.10% (288,064B) 0x2234AF: allocate (alloc_traits.h:614)
| ->35.10% (288,064B) 0x2234AF: _M_allocate (stl_vector.h:387)
| ->35.10% (288,064B) 0x2234AF: reserve (vector.tcc:79)
| ->35.10% (288,064B) 0x2234AF: ToMerkleLeaves<std::vector<uint256>, MerkleRoot(ankerl::nanobench::Bench&)::<lambda()>::<lambda(bool, const auto:46&)> > (merkle.h:19)
| ->35.10% (288,064B) 0x2234AF: operator() (merkle_root.cpp:25)
| ->35.10% (288,064B) 0x2234AF: ankerl::nanobench::Bench& ankerl::nanobench::Bench::run<MerkleRoot(ankerl::nanobench::Bench&)::{lambda()

Co-authored-by: optout21 <13562139+optout21@users.noreply.github.com>
Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Links an issue, advisory, or supporting reference
The short version

What changed, and why it matters

This commit is a performance and memory-efficiency improvement, not a security fix. It changes how Bitcoin Core builds the list of transaction hashes before computing a Merkle root. Previously, when a block contained an odd number of transactions, the internal duplicate-hash step could force an extra memory reallocation, wasting memory and causing fragmentation. The patch pre-allocates exactly the needed capacity and avoids default-constructing unused objects. There is no vulnerability or exploit here.

Recommended action

No security action required. Treat as a normal performance optimization during review and merge.

Security signals we found

01

No security-relevant behavior change

02

Memory allocation optimization only

03

No input validation, parsing, or cryptographic changes

04

No bug class such as overflow, use-after-free, or out-of-bounds access is introduced or fixed

Risk score

Why this scored 20/100

Our methodology →
Potential impact 2/30
Exploitability 0/25
Stealth signal 0/15
Affected reach 5/15
Confidence 9/10
Evidence quality 4/5
Human-validated context

Community notes

Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.

No validated notes yet.

The AI analysis stands alone for now. Submit a note if you can add evidence or important context.