mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 14:53:43 +01:00
Merge bitcoin/bitcoin#31283: Add waitNext() to BlockTemplate interface
cadbd4137dminer: have waitNext return after 20 min on testnet (Sjors Provoost)d4020f502aAdd waitNext() to BlockTemplate interface (Sjors Provoost) Pull request description: This PR introduces `waitNext()`. It waits for either the tip to update or for fees at the top of the mempool to rise sufficiently. It then returns a new template, with which the caller can rinse and repeat. On testnet3 and testnet4 the difficulty drops after 20 minutes, so the second ensures that a new template is returned in that case. Alternative approach to #31003, suggested in https://github.com/bitcoin/bitcoin/issues/31109#issuecomment-2451942362 ACKs for top commit: ryanofsky: Code review ACKcadbd4137d. Main change since last review is adding back a missing `m_interrupt` check in the waitNext loop. Also made various code cleanups in both commits. ismaelsadeeq: Code review ACKcadbd4137dvasild: ACKcadbd4137dTree-SHA512: c5a40053723c1c1674449ba1e4675718229a2022c8b0a4853b12a2c9180beb87536a1f99fde969a0ef099bca9ac69ca14ea4f399d277d2db7f556465ce47de95
This commit is contained in:
@@ -99,6 +99,7 @@ add_executable(test_bitcoin
|
||||
streams_tests.cpp
|
||||
sync_tests.cpp
|
||||
system_tests.cpp
|
||||
testnet4_miner_tests.cpp
|
||||
timeoffsets_tests.cpp
|
||||
torcontrol_tests.cpp
|
||||
transaction_tests.cpp
|
||||
|
||||
@@ -180,8 +180,11 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
||||
tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse;
|
||||
Txid hashLowFeeTx = tx.GetHash();
|
||||
AddToMempool(tx_mempool, entry.Fee(feeToUse).FromTx(tx));
|
||||
block_template = mining->createNewBlock(options);
|
||||
BOOST_REQUIRE(block_template);
|
||||
|
||||
// waitNext() 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);
|
||||
|
||||
block = block_template->getBlock();
|
||||
// Verify that the free tx and the low fee tx didn't get selected
|
||||
for (size_t i=0; i<block.vtx.size(); ++i) {
|
||||
@@ -196,7 +199,9 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
||||
tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee
|
||||
hashLowFeeTx = tx.GetHash();
|
||||
AddToMempool(tx_mempool, entry.Fee(feeToUse + 2).FromTx(tx));
|
||||
block_template = mining->createNewBlock(options);
|
||||
|
||||
// waitNext() should return if fees for the new template are at least 1 sat up
|
||||
block_template = block_template->waitNext({.fee_threshold = 1});
|
||||
BOOST_REQUIRE(block_template);
|
||||
block = block_template->getBlock();
|
||||
BOOST_REQUIRE_EQUAL(block.vtx.size(), 6U);
|
||||
@@ -671,9 +676,15 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
for (const auto& bi : BLOCKINFO) {
|
||||
const int current_height{mining->getTip()->height};
|
||||
|
||||
// Simple block creation, nothing special yet:
|
||||
block_template = mining->createNewBlock(options);
|
||||
BOOST_REQUIRE(block_template);
|
||||
/**
|
||||
* Simple block creation, nothing special yet.
|
||||
* If current_height is odd, block_template will have already been
|
||||
* set at the end of the previous loop.
|
||||
*/
|
||||
if (current_height % 2 == 0) {
|
||||
block_template = mining->createNewBlock(options);
|
||||
BOOST_REQUIRE(block_template);
|
||||
}
|
||||
|
||||
CBlock block{block_template->getBlock()};
|
||||
CMutableTransaction txCoinbase(*block.vtx[0]);
|
||||
@@ -709,8 +720,13 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
auto maybe_new_tip{Assert(m_node.chainman)->ActiveChain().Tip()};
|
||||
BOOST_REQUIRE_EQUAL(maybe_new_tip->GetBlockHash(), block.GetHash());
|
||||
}
|
||||
// This just adds coverage
|
||||
mining->waitTipChanged(block.hashPrevBlock);
|
||||
if (current_height % 2 == 0) {
|
||||
block_template = block_template->waitNext();
|
||||
BOOST_REQUIRE(block_template);
|
||||
} else {
|
||||
// This just adds coverage
|
||||
mining->waitTipChanged(block.hashPrevBlock);
|
||||
}
|
||||
}
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
75
src/test/testnet4_miner_tests.cpp
Normal file
75
src/test/testnet4_miner_tests.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2025 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <common/system.h>
|
||||
#include <interfaces/mining.h>
|
||||
#include <node/miner.h>
|
||||
#include <util/time.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <test/util/setup_common.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using interfaces::BlockTemplate;
|
||||
using interfaces::Mining;
|
||||
using node::BlockAssembler;
|
||||
using node::BlockWaitOptions;
|
||||
|
||||
namespace testnet4_miner_tests {
|
||||
|
||||
struct Testnet4MinerTestingSetup : public Testnet4Setup {
|
||||
std::unique_ptr<Mining> MakeMining()
|
||||
{
|
||||
return interfaces::MakeMining(m_node);
|
||||
}
|
||||
};
|
||||
} // namespace testnet4_miner_tests
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(testnet4_miner_tests, Testnet4MinerTestingSetup)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MiningInterface)
|
||||
{
|
||||
auto mining{MakeMining()};
|
||||
BOOST_REQUIRE(mining);
|
||||
|
||||
BlockAssembler::Options options;
|
||||
std::unique_ptr<BlockTemplate> block_template;
|
||||
|
||||
// Set node time a few minutes past the testnet4 genesis block
|
||||
const int64_t genesis_time{WITH_LOCK(cs_main, return m_node.chainman->ActiveChain().Tip()->GetBlockTime())};
|
||||
SetMockTime(genesis_time + 3 * 60);
|
||||
|
||||
block_template = mining->createNewBlock(options);
|
||||
BOOST_REQUIRE(block_template);
|
||||
|
||||
// The template should use the mocked system time
|
||||
BOOST_REQUIRE_EQUAL(block_template->getBlockHeader().nTime, genesis_time + 3 * 60);
|
||||
|
||||
const BlockWaitOptions wait_options{.timeout = MillisecondsDouble{0}, .fee_threshold = 1};
|
||||
|
||||
// waitNext() should return nullptr because there is no better template
|
||||
auto should_be_nullptr = block_template->waitNext(wait_options);
|
||||
BOOST_REQUIRE(should_be_nullptr == nullptr);
|
||||
|
||||
// This remains the case when exactly 20 minutes have gone by
|
||||
{
|
||||
LOCK(cs_main);
|
||||
SetMockTime(m_node.chainman->ActiveChain().Tip()->GetBlockTime() + 20 * 60);
|
||||
}
|
||||
should_be_nullptr = block_template->waitNext(wait_options);
|
||||
BOOST_REQUIRE(should_be_nullptr == nullptr);
|
||||
|
||||
// One second later the difficulty drops and it returns a new template
|
||||
// Note that we can't test the actual difficulty change, because the
|
||||
// difficulty is already at 1.
|
||||
{
|
||||
LOCK(cs_main);
|
||||
SetMockTime(m_node.chainman->ActiveChain().Tip()->GetBlockTime() + 20 * 60 + 1);
|
||||
}
|
||||
block_template = block_template->waitNext(wait_options);
|
||||
BOOST_REQUIRE(block_template);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
@@ -130,6 +130,12 @@ struct RegTestingSetup : public TestingSetup {
|
||||
: TestingSetup{ChainType::REGTEST} {}
|
||||
};
|
||||
|
||||
/** Identical to TestingSetup, but chain set to testnet4 */
|
||||
struct Testnet4Setup : public TestingSetup {
|
||||
Testnet4Setup()
|
||||
: TestingSetup{ChainType::TESTNET4} {}
|
||||
};
|
||||
|
||||
class CBlock;
|
||||
struct CMutableTransaction;
|
||||
class CScript;
|
||||
|
||||
Reference in New Issue
Block a user