Merge bitcoin/bitcoin#31197: refactor: mining interface 30955 followups
Some checks are pending
CI / test each commit (push) Waiting to run
CI / macOS 14 native, arm64, no depends, sqlite only, gui (push) Waiting to run
CI / macOS 14 native, arm64, fuzz (push) Waiting to run
CI / Win64 native, VS 2022 (push) Waiting to run
CI / Win64 native fuzz, VS 2022 (push) Waiting to run
CI / ASan + LSan + UBSan + integer, no depends, USDT (push) Waiting to run

f86678156a Check leaves size maximum in MerkleComputation (Sjors Provoost)
4d57288246 refactor: use CTransactionRef in submitSolution (Sjors Provoost)
2e81791d90 Drop TransactionMerklePath default position arg (Sjors Provoost)
39d3b538e6 Rename merkle branch to path (Sjors Provoost)

Pull request description:

  This PR implements the refactors suggested in https://github.com/bitcoin/bitcoin/pull/30955#pullrequestreview-2354931253.

ACKs for top commit:
  tdb3:
    code review re-ACK f86678156a
  itornaza:
    re ACK f86678156a
  ryanofsky:
    Code review ACK f86678156a only changes since last review are a whitespace change and adding an Assume statement to check for size_t -> uint32_t overflows

Tree-SHA512: 661b5d5d0e24b2269bf33ab1484e37c36e67b32a7796d77ca3b1856d3043378b081ad43c32a8638b46fa8c0de51c823fd9747dd9fc81f958f20d327bf330a47c
This commit is contained in:
Ryan Ofsky 2024-12-17 11:53:51 -05:00
commit a95a8ba3a3
No known key found for this signature in database
GPG key ID: 46800E30FC748A66
5 changed files with 25 additions and 24 deletions

View file

@ -4,6 +4,7 @@
#include <consensus/merkle.h> #include <consensus/merkle.h>
#include <hash.h> #include <hash.h>
#include <util/check.h>
/* WARNING! If you're reading this because you're learning about crypto /* WARNING! If you're reading this because you're learning about crypto
and/or designing a new system that will use merkle trees, keep in mind and/or designing a new system that will use merkle trees, keep in mind
@ -84,8 +85,10 @@ uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated)
} }
/* This implements a constant-space merkle root/path calculator, limited to 2^32 leaves. */ /* This implements a constant-space merkle root/path calculator, limited to 2^32 leaves. */
static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector<uint256>* pbranch) { static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot, bool* pmutated, uint32_t leaf_pos, std::vector<uint256>* path)
if (pbranch) pbranch->clear(); {
if (path) path->clear();
Assume(leaves.size() <= UINT32_MAX);
if (leaves.size() == 0) { if (leaves.size() == 0) {
if (pmutated) *pmutated = false; if (pmutated) *pmutated = false;
if (proot) *proot = uint256(); if (proot) *proot = uint256();
@ -105,18 +108,18 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
// First process all leaves into 'inner' values. // First process all leaves into 'inner' values.
while (count < leaves.size()) { while (count < leaves.size()) {
uint256 h = leaves[count]; uint256 h = leaves[count];
bool matchh = count == branchpos; bool matchh = count == leaf_pos;
count++; count++;
int level; int level;
// For each of the lower bits in count that are 0, do 1 step. Each // For each of the lower bits in count that are 0, do 1 step. Each
// corresponds to an inner value that existed before processing the // corresponds to an inner value that existed before processing the
// current leaf, and each needs a hash to combine it. // current leaf, and each needs a hash to combine it.
for (level = 0; !(count & ((uint32_t{1}) << level)); level++) { for (level = 0; !(count & ((uint32_t{1}) << level)); level++) {
if (pbranch) { if (path) {
if (matchh) { if (matchh) {
pbranch->push_back(inner[level]); path->push_back(inner[level]);
} else if (matchlevel == level) { } else if (matchlevel == level) {
pbranch->push_back(h); path->push_back(h);
matchh = true; matchh = true;
} }
} }
@ -144,8 +147,8 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
// If we reach this point, h is an inner value that is not the top. // If we reach this point, h is an inner value that is not the top.
// We combine it with itself (Bitcoin's special rule for odd levels in // We combine it with itself (Bitcoin's special rule for odd levels in
// the tree) to produce a higher level one. // the tree) to produce a higher level one.
if (pbranch && matchh) { if (path && matchh) {
pbranch->push_back(h); path->push_back(h);
} }
h = Hash(h, h); h = Hash(h, h);
// Increment count to the value it would have if two entries at this // Increment count to the value it would have if two entries at this
@ -154,11 +157,11 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
level++; level++;
// And propagate the result upwards accordingly. // And propagate the result upwards accordingly.
while (!(count & ((uint32_t{1}) << level))) { while (!(count & ((uint32_t{1}) << level))) {
if (pbranch) { if (path) {
if (matchh) { if (matchh) {
pbranch->push_back(inner[level]); path->push_back(inner[level]);
} else if (matchlevel == level) { } else if (matchlevel == level) {
pbranch->push_back(h); path->push_back(h);
matchh = true; matchh = true;
} }
} }
@ -171,18 +174,18 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
if (proot) *proot = h; if (proot) *proot = h;
} }
static std::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leaves, uint32_t position) { static std::vector<uint256> ComputeMerklePath(const std::vector<uint256>& leaves, uint32_t position) {
std::vector<uint256> ret; std::vector<uint256> ret;
MerkleComputation(leaves, nullptr, nullptr, position, &ret); MerkleComputation(leaves, nullptr, nullptr, position, &ret);
return ret; return ret;
} }
std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position) std::vector<uint256> TransactionMerklePath(const CBlock& block, uint32_t position)
{ {
std::vector<uint256> leaves; std::vector<uint256> leaves;
leaves.resize(block.vtx.size()); leaves.resize(block.vtx.size());
for (size_t s = 0; s < block.vtx.size(); s++) { for (size_t s = 0; s < block.vtx.size(); s++) {
leaves[s] = block.vtx[s]->GetHash(); leaves[s] = block.vtx[s]->GetHash();
} }
return ComputeMerkleBranch(leaves, position); return ComputeMerklePath(leaves, position);
} }

View file

@ -28,10 +28,10 @@ uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated = nullptr);
* Compute merkle path to the specified transaction * Compute merkle path to the specified transaction
* *
* @param[in] block the block * @param[in] block the block
* @param[in] position transaction for which to calculate the merkle path, defaults to coinbase * @param[in] position transaction for which to calculate the merkle path (0 is the coinbase)
* *
* @return merkle path ordered from the deepest * @return merkle path ordered from the deepest
*/ */
std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position = 0); std::vector<uint256> TransactionMerklePath(const CBlock& block, uint32_t position);
#endif // BITCOIN_CONSENSUS_MERKLE_H #endif // BITCOIN_CONSENSUS_MERKLE_H

View file

@ -55,7 +55,7 @@ public:
* *
* @returns if the block was processed, independent of block validity * @returns if the block was processed, independent of block validity
*/ */
virtual bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CMutableTransaction coinbase) = 0; virtual bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CTransactionRef coinbase) = 0;
}; };
//! Interface giving clients (RPC, Stratum v2 Template Provider in the future) //! Interface giving clients (RPC, Stratum v2 Template Provider in the future)

View file

@ -913,19 +913,17 @@ public:
std::vector<uint256> getCoinbaseMerklePath() override std::vector<uint256> getCoinbaseMerklePath() override
{ {
return BlockMerkleBranch(m_block_template->block); return TransactionMerklePath(m_block_template->block, 0);
} }
bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CMutableTransaction coinbase) override bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CTransactionRef coinbase) override
{ {
CBlock block{m_block_template->block}; CBlock block{m_block_template->block};
auto cb = MakeTransactionRef(std::move(coinbase));
if (block.vtx.size() == 0) { if (block.vtx.size() == 0) {
block.vtx.push_back(cb); block.vtx.push_back(coinbase);
} else { } else {
block.vtx[0] = cb; block.vtx[0] = coinbase;
} }
block.nVersion = version; block.nVersion = version;

View file

@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(merkle_test)
if (ntx > 16) { if (ntx > 16) {
mtx = m_rng.randrange(ntx); mtx = m_rng.randrange(ntx);
} }
std::vector<uint256> newBranch = BlockMerkleBranch(block, mtx); std::vector<uint256> newBranch = TransactionMerklePath(block, mtx);
std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx); std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx);
BOOST_CHECK(oldBranch == newBranch); BOOST_CHECK(oldBranch == newBranch);
BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx]->GetHash(), newBranch, mtx) == oldRoot); BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx]->GetHash(), newBranch, mtx) == oldRoot);