Repository: bitcoin/bitcoin
File: src/consensus/merkle.cpp (C++)

Code before:
        if (hashes.size() & 1) {
            hashes.push_back(hashes.back());
        }
        SHA256D64(hashes[0].begin(), hashes[0].begin(), hashes.size() / 2);
        hashes.resize(hashes.size() / 2);
    }
    if (mutated) *mutated = mutation;
    if (hashes.size() == 0) return uint256();
    return hashes[0];
}


uint256 BlockMerkleRoot(const CBlock& block, bool* mutated)
{
    std::vector<uint256> leaves;
    leaves.resize(block.vtx.size());
    for (size_t s = 0; s < block.vtx.size(); s++) {
        leaves[s] = block.vtx[s]->GetHash().ToUint256();
    }
    return ComputeMerkleRoot(std::move(leaves), mutated);
}

uint256 BlockWitnessMerkleRoot(const CBlock& block)
{
    std::vector<uint256> leaves;
    leaves.resize(block.vtx.size());
    leaves[0].SetNull(); // The witness hash of the coinbase is 0.
    for (size_t s = 1; s < block.vtx.size(); s++) {
        leaves[s] = block.vtx[s]->GetWitnessHash().ToUint256();
    }
    return ComputeMerkleRoot(std::move(leaves));
}

/* This implements a constant-space merkle path calculator, limited to 2^32 leaves. */
static void MerkleComputation(const std::vector<uint256>& leaves, uint32_t leaf_pos, std::vector<uint256>& path)
{
    path.clear();
    Assume(leaves.size() <= UINT32_MAX);
    if (leaves.size() == 0) {
        return;
    }
    // count is the number of leaves processed so far.
    uint32_t count = 0;
    // inner is an array of eagerly computed subtree hashes, indexed by tree
    // level (0 being the leaves).
    // For example, when count is 25 (11001 in binary), inner[4] is the hash of
    // the first 16 leaves, inner[3] of the next 8 leaves, and inner[0] equal to
    // the last leaf. The other inner entries are undefined.
    uint256 inner[32];
    // Which position in inner is a hash that depends on the matching leaf.
    int matchlevel = -1;

Review comment (refactor):
The pattern `(size + 1) & ~1ULL` with identical comment appears 4 times across 3 files:
  - merkle.cpp:69
  - merkle.cpp:79
  - signet.cpp:61
  - merkle_root.cpp:27

  A small helper would reduce duplication and can be arguably more readable: "add 1 if odd":
  ```cpp
  constexpr size_t RoundUpToEven(size_t n) { return n + (n & 1); }
  ```
  
  Also: `(size + 1) & ~1ULL` works but assumes 64-bit arithmetic. `assumptions.h` explicitly supports 32-bit `size_t`.


Code after:
        if (hashes.size() & 1) {
            hashes.push_back(hashes.back());
        }
        SHA256D64(hashes[0].begin(), hashes[0].begin(), hashes.size() / 2);
        hashes.resize(hashes.size() / 2);
    }
    if (mutated) *mutated = mutation;
    if (hashes.size() == 0) return uint256();
    return hashes[0];
}


uint256 BlockMerkleRoot(const CBlock& block, bool* mutated)
{
    std::vector<uint256> leaves;
    leaves.reserve((block.vtx.size() + 1) & ~1ULL); // capacity rounded up to even
    for (size_t s = 0; s < block.vtx.size(); s++) {
        leaves.push_back(block.vtx[s]->GetHash().ToUint256());
    }
    return ComputeMerkleRoot(std::move(leaves), mutated);
}

uint256 BlockWitnessMerkleRoot(const CBlock& block)
{
    std::vector<uint256> leaves;
    leaves.reserve((block.vtx.size() + 1) & ~1ULL); // capacity rounded up to even
    leaves.emplace_back(); // The witness hash of the coinbase is 0.
    for (size_t s = 1; s < block.vtx.size(); s++) {
        leaves.push_back(block.vtx[s]->GetWitnessHash().ToUint256());
    }
    return ComputeMerkleRoot(std::move(leaves));
}

/* This implements a constant-space merkle path calculator, limited to 2^32 leaves. */
static void MerkleComputation(const std::vector<uint256>& leaves, uint32_t leaf_pos, std::vector<uint256>& path)
{
    path.clear();
    Assume(leaves.size() <= UINT32_MAX);
    if (leaves.size() == 0) {
        return;
    }
    // count is the number of leaves processed so far.
    uint32_t count = 0;
    // inner is an array of eagerly computed subtree hashes, indexed by tree
    // level (0 being the leaves).
    // For example, when count is 25 (11001 in binary), inner[4] is the hash of
    // the first 16 leaves, inner[3] of the next 8 leaves, and inner[0] equal to
    // the last leaf. The other inner entries are undefined.
    uint256 inner[32];
    // Which position in inner is a hash that depends on the matching leaf.
    int matchlevel = -1;