mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-04-08 22:57:56 +02:00
3dd815f048validation: pre-reserve leaves to prevent reallocs with odd vtx count (Lőrinc)7fd47e0e56bench: make `MerkleRoot` benchmark more representative (Lőrinc)f0a2183108test: adjust `ComputeMerkleRoot` tests (Lőrinc) Pull request description: #### Summary `ComputeMerkleRoot` [duplicates the last hash](39b6c139bd/src/consensus/merkle.cpp (L54-L56)) 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 (causing peak memory usage of 3x the necessary size). This affects roughly half of the created blocks (those with odd transaction counts), causing unnecessary memory fragmentation during every block validation. #### Fix * Pre-reserves vector capacity to account for the odd-count duplication using `(size + 1) & ~1ULL`. * This syntax produces [optimal assembly](https://github.com/bitcoin/bitcoin/pull/32497#discussion_r2553107836) across x86/ARM and 32/64-bit platforms for GCC & Clang. * Eliminates default construction of `uint256` objects that are immediately overwritten by switching from `resize` to `reserve` + `push_back`. #### Memory Impact [Memory profiling](https://github.com/bitcoin/bitcoin/pull/32497#issuecomment-3563724551) shows **50% reduction in peak allocation** (576KB → 288KB) and elimination of reallocation overhead. #### Validation The benchmark was updated to use an odd leaf count to demonstrate the real-world scenario where the reallocation occurs. A full `-reindex-chainstate` up to block **896 408** ran without triggering the asserts. <details> <summary>Validation asserts</summary> Temporary asserts (not included in this PR) confirm that `push_back` never reallocates and that the coinbase witness hash remains null: ```cpp if (hashes.size() & 1) { assert(hashes.size() < hashes.capacity()); // TODO remove hashes.push_back(hashes.back()); } leaves.reserve((block.vtx.size() + 1) & ~1ULL); // capacity rounded up to even leaves.emplace_back(); assert(leaves.back().IsNull()); // TODO remove ``` </details> #### Benchmark Performance While the main purpose is to improve predictability, the reduced memory operations also improve hashing throughput slightly. ACKs for top commit: achow101: ACK3dd815f048optout21: reACK3dd815f048hodlinator: re-ACK3dd815f048vasild: ACK3dd815f048w0xlt: ACK3dd815f048with minor nits. danielabrozzoni: Code review ACK3dd815f048Tree-SHA512: e7b578f9deadc0de7d61c062c7f65c5e1d347548ead4a4bb74b056396ad7df3f1c564327edc219670e6e2b2cb51f4e1ccfd4f58dd414aeadf2008d427065c11f