Merge bitcoin/bitcoin#33566: miner: fix empty mempool case for waitNext()

8f7673257a miner: fix empty mempool case for waitNext() (Sjors Provoost)

Pull request description:

  Block template fees are calculated by looping over `new_tmpl->vTxFees` and return (early) once the `fee_threshold` is exceeded.

  This left an edge case when the mempool is empty, which this commit fixes and adds a test for.

  Also update `test/functional/interface_ipc.py` to reflect the new behavior,

  Fixes https://github.com/Sjors/sv2-tp/issues/9

ACKs for top commit:
  optout21:
    ACK 8f7673257a
  cedwies:
    tACK 8f76732
  sipa:
    utACK 8f7673257a
  zaidmstrr:
    Concept ACK [8f76732](8f7673257a)

Tree-SHA512: ef200fe95e96f810e425283bc37f945c4bf5efa16f4b74820b8a07968f30c5146bca213a372124be84b48beead5dfd35f2b5d10d188d0a465f847ebab61de10a
This commit is contained in:
merge-script
2025-10-23 05:49:29 -04:00
3 changed files with 27 additions and 13 deletions

View File

@@ -29,6 +29,7 @@
#include <algorithm>
#include <utility>
#include <numeric>
namespace node {
@@ -522,18 +523,13 @@ std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainma
// Calculate the original template total fees if we haven't already
if (current_fees == -1) {
current_fees = 0;
for (CAmount fee : block_template->vTxFees) {
current_fees += fee;
}
current_fees = std::accumulate(block_template->vTxFees.begin(), block_template->vTxFees.end(), CAmount{0});
}
CAmount new_fees = 0;
for (CAmount fee : new_tmpl->vTxFees) {
new_fees += fee;
Assume(options.fee_threshold != MAX_MONEY);
if (new_fees >= current_fees + options.fee_threshold) return new_tmpl;
}
// Check if fees increased enough to return the new template
const CAmount new_fees = std::accumulate(new_tmpl->vTxFees.begin(), new_tmpl->vTxFees.end(), CAmount{0});
Assume(options.fee_threshold != MAX_MONEY);
if (new_fees >= current_fees + options.fee_threshold) return new_tmpl;
}
now = NodeClock::now();

View File

@@ -113,6 +113,22 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
options.coinbase_output_script = scriptPubKey;
LOCK(tx_mempool.cs);
BOOST_CHECK(tx_mempool.size() == 0);
// Block template should only have a coinbase when there's nothing in the mempool
std::unique_ptr<BlockTemplate> block_template = mining->createNewBlock(options);
BOOST_REQUIRE(block_template);
CBlock block{block_template->getBlock()};
BOOST_REQUIRE_EQUAL(block.vtx.size(), 1U);
// waitNext() on an empty mempool should return nullptr because there is no better template
auto should_be_nullptr = block_template->waitNext({.timeout = MillisecondsDouble{0}, .fee_threshold = 1});
BOOST_REQUIRE(should_be_nullptr == nullptr);
// Unless fee_threshold is 0
block_template = block_template->waitNext({.timeout = MillisecondsDouble{0}, .fee_threshold = 0});
BOOST_REQUIRE(block_template);
// Test the ancestor feerate transaction selection.
TestMemPoolEntryHelper entry;
@@ -144,9 +160,9 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
const auto high_fee_tx{entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)};
AddToMempool(tx_mempool, high_fee_tx);
std::unique_ptr<BlockTemplate> block_template = mining->createNewBlock(options);
block_template = mining->createNewBlock(options);
BOOST_REQUIRE(block_template);
CBlock block{block_template->getBlock()};
block = block_template->getBlock();
BOOST_REQUIRE_EQUAL(block.vtx.size(), 4U);
BOOST_CHECK(block.vtx[1]->GetHash() == hashParentTx);
BOOST_CHECK(block.vtx[2]->GetHash() == hashHighFeeTx);
@@ -184,7 +200,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
AddToMempool(tx_mempool, entry.Fee(feeToUse).FromTx(tx));
// waitNext() should return nullptr because there is no better template
auto should_be_nullptr = block_template->waitNext({.timeout = MillisecondsDouble{0}, .fee_threshold = 1});
should_be_nullptr = block_template->waitNext({.timeout = MillisecondsDouble{0}, .fee_threshold = 1});
BOOST_REQUIRE(should_be_nullptr == nullptr);
block = block_template->getBlock();