Problem
ComputeMerkleRoot has a subtle two-output contract: an optional mutation flag and a return value that callers expect to always equal the Merkle root of the full input (regardless of mutations).
That contract is currently undocumented and only exercised indirectly by merkle_test (random duplications, old-vs-new comparison), so a refactor could silently break it - as the discussion under #22046/#28430 illustrates.
Fix
Document the contract on the function declaration and inside the inner loop, and add a direct regression test for the duplicate-subtree construction described in the code comments for CVE-2012-2459: https://github.com/bitcoin/bitcoin/blob/8faf7b6cdc0c93ddf542d20d9ad0afb3579d47eb/src/consensus/merkle.cpp#L20-L29
Coverage check
Both merkle_test and the new merkle_test_mutated_return_value would fail under a refactor that stops the outer reduction once mutation is detected, e.g.:
<details><summary>Hypothetical regression</summary>
diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp
--- a/src/consensus/merkle.cpp
+++ b/src/consensus/merkle.cpp
@@ -53,6 +53,7 @@
if (hashes[pos] == hashes[pos + 1]) mutation = true;
}
}
+ if (mutation) break;
if (hashes.size() & 1) {
hashes.push_back(hashes.back());
}
</details>
Fixes #28457