mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-03 17:54:19 +02:00
mining: add cooldown argument to createNewBlock()
At startup, if the needs to catch up, connected mining clients will receive a flood of new templates as new blocks are connected. Fix this by adding a cooldown argument to createNewBlock(). When set to true, block template creation is briefly paused while the best header chain is ahead of the tip. This wait only happens when the best header extends the current tip, to ignore competing branches. Additionally, cooldown waits for isInitialBlockDownload() to latch to false, which happens when there is less than a day of blocks left to sync. When cooldown is false createNewBlock() returns immediately. The argument is optional, because many tests are negatively impacted by this mechanism, and single miner signets could end up stuck if no block was mined for a day. The getblocktemplate RPC also opts out, because it would add a delay to each call. Fixes #33994
This commit is contained in:
@@ -122,7 +122,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
||||
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);
|
||||
std::unique_ptr<BlockTemplate> block_template = mining->createNewBlock(options, /*cooldown=*/false);
|
||||
BOOST_REQUIRE(block_template);
|
||||
CBlock block{block_template->getBlock()};
|
||||
BOOST_REQUIRE_EQUAL(block.vtx.size(), 1U);
|
||||
@@ -166,7 +166,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
||||
const auto high_fee_tx{entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)};
|
||||
TryAddToMempool(tx_mempool, high_fee_tx);
|
||||
|
||||
block_template = mining->createNewBlock(options);
|
||||
block_template = mining->createNewBlock(options, /*cooldown=*/false);
|
||||
BOOST_REQUIRE(block_template);
|
||||
block = block_template->getBlock();
|
||||
BOOST_REQUIRE_EQUAL(block.vtx.size(), 4U);
|
||||
@@ -253,7 +253,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
||||
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
|
||||
Txid hashLowFeeTx2 = tx.GetHash();
|
||||
TryAddToMempool(tx_mempool, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
|
||||
block_template = mining->createNewBlock(options);
|
||||
block_template = mining->createNewBlock(options, /*cooldown=*/false);
|
||||
BOOST_REQUIRE(block_template);
|
||||
block = block_template->getBlock();
|
||||
|
||||
@@ -268,7 +268,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
||||
tx.vin[0].prevout.n = 1;
|
||||
tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee
|
||||
TryAddToMempool(tx_mempool, entry.Fee(10000).FromTx(tx));
|
||||
block_template = mining->createNewBlock(options);
|
||||
block_template = mining->createNewBlock(options, /*cooldown=*/false);
|
||||
BOOST_REQUIRE(block_template);
|
||||
block = block_template->getBlock();
|
||||
BOOST_REQUIRE_EQUAL(block.vtx.size(), 9U);
|
||||
@@ -342,7 +342,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
LOCK(tx_mempool.cs);
|
||||
|
||||
// Just to make sure we can still make simple blocks
|
||||
auto block_template{mining->createNewBlock(options)};
|
||||
auto block_template{mining->createNewBlock(options, /*cooldown=*/false)};
|
||||
BOOST_REQUIRE(block_template);
|
||||
CBlock block{block_template->getBlock()};
|
||||
|
||||
@@ -358,7 +358,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
}
|
||||
assert(tx_mempool.mapTx.size() == 51);
|
||||
assert(legacy_sigops == 20001);
|
||||
BOOST_CHECK_EXCEPTION(mining->createNewBlock(options), std::runtime_error, HasReason("bad-blk-sigops"));
|
||||
BOOST_CHECK_EXCEPTION(mining->createNewBlock(options, /*cooldown=*/false), std::runtime_error, HasReason("bad-blk-sigops"));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -369,7 +369,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
assert(tx_mempool.mapTx.empty());
|
||||
|
||||
// Just to make sure we can still make simple blocks
|
||||
auto block_template{mining->createNewBlock(options)};
|
||||
auto block_template{mining->createNewBlock(options, /*cooldown=*/false)};
|
||||
BOOST_REQUIRE(block_template);
|
||||
CBlock block{block_template->getBlock()};
|
||||
|
||||
@@ -384,7 +384,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
assert(tx_mempool.mapTx.size() == 51);
|
||||
assert(legacy_sigops == 20001);
|
||||
|
||||
BOOST_REQUIRE(mining->createNewBlock(options));
|
||||
BOOST_REQUIRE(mining->createNewBlock(options, /*cooldown=*/false));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -414,7 +414,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
BOOST_CHECK(tx_mempool.GetIter(hash).has_value());
|
||||
tx.vin[0].prevout.hash = hash;
|
||||
}
|
||||
BOOST_REQUIRE(mining->createNewBlock(options));
|
||||
BOOST_REQUIRE(mining->createNewBlock(options, /*cooldown=*/false));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -424,7 +424,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
// orphan in tx_mempool, template creation fails
|
||||
hash = tx.GetHash();
|
||||
TryAddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).FromTx(tx));
|
||||
BOOST_CHECK_EXCEPTION(mining->createNewBlock(options), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
|
||||
BOOST_CHECK_EXCEPTION(mining->createNewBlock(options, /*cooldown=*/false), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -445,7 +445,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE; // First txn output + fresh coinbase - new txn fee
|
||||
hash = tx.GetHash();
|
||||
TryAddToMempool(tx_mempool, entry.Fee(HIGHERFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
|
||||
BOOST_REQUIRE(mining->createNewBlock(options));
|
||||
BOOST_REQUIRE(mining->createNewBlock(options, /*cooldown=*/false));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -461,7 +461,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
// give it a fee so it'll get mined
|
||||
TryAddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
|
||||
// Should throw bad-cb-multiple
|
||||
BOOST_CHECK_EXCEPTION(mining->createNewBlock(options), std::runtime_error, HasReason("bad-cb-multiple"));
|
||||
BOOST_CHECK_EXCEPTION(mining->createNewBlock(options, /*cooldown=*/false), std::runtime_error, HasReason("bad-cb-multiple"));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -478,7 +478,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
tx.vout[0].scriptPubKey = CScript() << OP_2;
|
||||
hash = tx.GetHash();
|
||||
TryAddToMempool(tx_mempool, entry.Fee(HIGHFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
|
||||
BOOST_CHECK_EXCEPTION(mining->createNewBlock(options), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
|
||||
BOOST_CHECK_EXCEPTION(mining->createNewBlock(options, /*cooldown=*/false), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -498,7 +498,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
next->BuildSkip();
|
||||
m_node.chainman->ActiveChain().SetTip(*next);
|
||||
}
|
||||
BOOST_REQUIRE(mining->createNewBlock(options));
|
||||
BOOST_REQUIRE(mining->createNewBlock(options, /*cooldown=*/false));
|
||||
// Extend to a 210000-long block chain.
|
||||
while (m_node.chainman->ActiveChain().Tip()->nHeight < 210000) {
|
||||
CBlockIndex* prev = m_node.chainman->ActiveChain().Tip();
|
||||
@@ -510,7 +510,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
next->BuildSkip();
|
||||
m_node.chainman->ActiveChain().SetTip(*next);
|
||||
}
|
||||
BOOST_REQUIRE(mining->createNewBlock(options));
|
||||
BOOST_REQUIRE(mining->createNewBlock(options, /*cooldown=*/false));
|
||||
|
||||
// invalid p2sh txn in tx_mempool, template creation fails
|
||||
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
|
||||
@@ -526,7 +526,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
tx.vout[0].nValue -= LOWFEE;
|
||||
hash = tx.GetHash();
|
||||
TryAddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
|
||||
BOOST_CHECK_EXCEPTION(mining->createNewBlock(options), std::runtime_error, HasReason("block-script-verify-flag-failed"));
|
||||
BOOST_CHECK_EXCEPTION(mining->createNewBlock(options, /*cooldown=*/false), std::runtime_error, HasReason("block-script-verify-flag-failed"));
|
||||
|
||||
// Delete the dummy blocks again.
|
||||
while (m_node.chainman->ActiveChain().Tip()->nHeight > nHeight) {
|
||||
@@ -632,7 +632,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1;
|
||||
BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail
|
||||
|
||||
auto block_template = mining->createNewBlock(options);
|
||||
auto block_template = mining->createNewBlock(options, /*cooldown=*/false);
|
||||
BOOST_REQUIRE(block_template);
|
||||
|
||||
// None of the of the absolute height/time locked tx should have made
|
||||
@@ -649,7 +649,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
|
||||
m_node.chainman->ActiveChain().Tip()->nHeight++;
|
||||
SetMockTime(m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1);
|
||||
|
||||
block_template = mining->createNewBlock(options);
|
||||
block_template = mining->createNewBlock(options, /*cooldown=*/false);
|
||||
BOOST_REQUIRE(block_template);
|
||||
block = block_template->getBlock();
|
||||
BOOST_CHECK_EQUAL(block.vtx.size(), 5U);
|
||||
@@ -725,7 +725,7 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const
|
||||
Txid hashFreeGrandchild = tx.GetHash();
|
||||
TryAddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
|
||||
|
||||
auto block_template = mining->createNewBlock(options);
|
||||
auto block_template = mining->createNewBlock(options, /*cooldown=*/false);
|
||||
BOOST_REQUIRE(block_template);
|
||||
CBlock block{block_template->getBlock()};
|
||||
BOOST_REQUIRE_EQUAL(block.vtx.size(), 6U);
|
||||
@@ -755,7 +755,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
options.include_dummy_extranonce = true;
|
||||
|
||||
// Create and check a simple template
|
||||
std::unique_ptr<BlockTemplate> block_template = mining->createNewBlock(options);
|
||||
std::unique_ptr<BlockTemplate> block_template = mining->createNewBlock(options, /*cooldown=*/false);
|
||||
BOOST_REQUIRE(block_template);
|
||||
{
|
||||
CBlock block{block_template->getBlock()};
|
||||
@@ -806,7 +806,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
* set at the end of the previous loop.
|
||||
*/
|
||||
if (current_height % 2 == 0) {
|
||||
block_template = mining->createNewBlock(options);
|
||||
block_template = mining->createNewBlock(options, /*cooldown=*/false);
|
||||
BOOST_REQUIRE(block_template);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ BOOST_AUTO_TEST_CASE(MiningInterface)
|
||||
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);
|
||||
block_template = mining->createNewBlock(options, /*cooldown=*/false);
|
||||
BOOST_REQUIRE(block_template);
|
||||
|
||||
// The template should use the mocked system time
|
||||
|
||||
Reference in New Issue
Block a user