From a43ea8cc7c4ee7bc6a1263f0382781cc18c7a722 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Mon, 6 Jan 2025 18:24:17 +0100 Subject: [PATCH] On testnet create min diff template after 20 mins --- src/interfaces/mining.h | 3 ++ src/node/interfaces.cpp | 10 +++++ src/test/CMakeLists.txt | 1 + src/test/testnet4_miner_tests.cpp | 64 +++++++++++++++++++++++++++++++ src/test/util/setup_common.h | 6 +++ 5 files changed, 84 insertions(+) create mode 100644 src/test/testnet4_miner_tests.cpp diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h index f1902043681bb..4e3ce0d729636 100644 --- a/src/interfaces/mining.h +++ b/src/interfaces/mining.h @@ -60,6 +60,9 @@ class BlockTemplate /** * Waits for fees in the next block to rise, a new tip or the timeout. * + * On testnet this will additionally return a template with difficulty 1 if + * the tip is more than 20 minutes old. + * * @param[in] fee_threshold By how much total fees for the next block should rise. * Default is to not monitor fee changes and only wait for a new chaintip. * @param[in] timeout How long to wait. Default is forever. diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 74c1d7c9e5837..6bae9aed9cebc 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -947,6 +947,7 @@ class BlockTemplateImpl : public BlockTemplate auto now{NodeClock::now()}; const auto deadline = now + timeout; const MillisecondsDouble tick{1000}; + const bool allow_min_difficulty{chainman().GetParams().GetConsensus().fPowAllowMinDifficultyBlocks}; while (now <= deadline) { bool tip_changed{false}; @@ -968,6 +969,15 @@ class BlockTemplateImpl : public BlockTemplate // Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks. LOCK(::cs_main); + + // On test networks return a minimum difficulty block after 20 minutes + if (!tip_changed && allow_min_difficulty) { + const NodeClock::time_point tip_time{std::chrono::seconds{chainman().ActiveChain().Tip()->GetBlockTime()}}; + if (now > tip_time + std::chrono::seconds(20 * 60)) { + tip_changed = true; + } + } + /** * The only way to determine if fees increased compared to the previous template, * is to generate a fresh template. Cluster Mempool may allow for a more efficient diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 859b913206782..b92dad1e989f4 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -120,6 +120,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 diff --git a/src/test/testnet4_miner_tests.cpp b/src/test/testnet4_miner_tests.cpp new file mode 100644 index 0000000000000..dd0654288c57f --- /dev/null +++ b/src/test/testnet4_miner_tests.cpp @@ -0,0 +1,64 @@ +// 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 +#include +#include +#include +#include + +#include + +#include + +using interfaces::BlockTemplate; +using interfaces::Mining; +using node::BlockAssembler; + +namespace testnet4_miner_tests { + +struct Testnet4MinerTestingSetup : public Testnet4Setup { + std::unique_ptr 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 block_template; + + // Set node time a few minutes past the testnet4 genesis block + { + LOCK(cs_main); + SetMockTime(m_node.chainman->ActiveChain().Tip()->GetBlockTime() + 3 * 60); + } + + block_template = mining->createNewBlock(options); + BOOST_REQUIRE(block_template); + + // The template should use the mocked system time + BOOST_REQUIRE_EQUAL(std::chrono::seconds(block_template->getBlockHeader().nTime), GetMockTime()); + + // waitNext() should return nullptr because there is no better template + auto should_be_nullptr = block_template->waitNext(1, MillisecondsDouble{0}); + BOOST_REQUIRE(should_be_nullptr == nullptr); + + // Except when 20 minutes have gone by (on test networks) + { + LOCK(cs_main); + SetMockTime(m_node.chainman->ActiveChain().Tip()->GetBlockTime() + 20 * 60 + 1); + } + block_template = block_template->waitNext(1, MillisecondsDouble{0}); + BOOST_REQUIRE(block_template); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index b0f7bdade20cf..a39f2a7329a32 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -129,6 +129,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;