Skip to content

Commit cadbd41

Browse files
committed
miner: have waitNext return after 20 min on testnet
On testnet we need to create a min diff template after 20 min.
1 parent d4020f5 commit cadbd41

File tree

5 files changed

+94
-0
lines changed

5 files changed

+94
-0
lines changed

src/interfaces/mining.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class BlockTemplate
6464
* for the next block should rise (default infinite).
6565
*
6666
* @returns a new BlockTemplate or nothing if the timeout occurs.
67+
*
68+
* On testnet this will additionally return a template with difficulty 1 if
69+
* the tip is more than 20 minutes old.
6770
*/
6871
virtual std::unique_ptr<BlockTemplate> waitNext(const node::BlockWaitOptions options = {}) = 0;
6972
};

src/node/interfaces.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,7 @@ class BlockTemplateImpl : public BlockTemplate
958958
auto now{NodeClock::now()};
959959
const auto deadline = now + options.timeout;
960960
const MillisecondsDouble tick{1000};
961+
const bool allow_min_difficulty{chainman().GetParams().GetConsensus().fPowAllowMinDifficultyBlocks};
961962

962963
do {
963964
bool tip_changed{false};
@@ -982,6 +983,14 @@ class BlockTemplateImpl : public BlockTemplate
982983
// Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks.
983984
LOCK(::cs_main);
984985

986+
// On test networks return a minimum difficulty block after 20 minutes
987+
if (!tip_changed && allow_min_difficulty) {
988+
const NodeClock::time_point tip_time{std::chrono::seconds{chainman().ActiveChain().Tip()->GetBlockTime()}};
989+
if (now > tip_time + 20min) {
990+
tip_changed = true;
991+
}
992+
}
993+
985994
/**
986995
* We determine if fees increased compared to the previous template by generating
987996
* a fresh template. There may be more efficient ways to determine how much

src/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ add_executable(test_bitcoin
121121
streams_tests.cpp
122122
sync_tests.cpp
123123
system_tests.cpp
124+
testnet4_miner_tests.cpp
124125
timeoffsets_tests.cpp
125126
torcontrol_tests.cpp
126127
transaction_tests.cpp

src/test/testnet4_miner_tests.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright (c) 2025 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <common/system.h>
6+
#include <interfaces/mining.h>
7+
#include <node/miner.h>
8+
#include <util/time.h>
9+
#include <validation.h>
10+
11+
#include <test/util/setup_common.h>
12+
13+
#include <boost/test/unit_test.hpp>
14+
15+
using interfaces::BlockTemplate;
16+
using interfaces::Mining;
17+
using node::BlockAssembler;
18+
using node::BlockWaitOptions;
19+
20+
namespace testnet4_miner_tests {
21+
22+
struct Testnet4MinerTestingSetup : public Testnet4Setup {
23+
std::unique_ptr<Mining> MakeMining()
24+
{
25+
return interfaces::MakeMining(m_node);
26+
}
27+
};
28+
} // namespace testnet4_miner_tests
29+
30+
BOOST_FIXTURE_TEST_SUITE(testnet4_miner_tests, Testnet4MinerTestingSetup)
31+
32+
BOOST_AUTO_TEST_CASE(MiningInterface)
33+
{
34+
auto mining{MakeMining()};
35+
BOOST_REQUIRE(mining);
36+
37+
BlockAssembler::Options options;
38+
std::unique_ptr<BlockTemplate> block_template;
39+
40+
// Set node time a few minutes past the testnet4 genesis block
41+
const int64_t genesis_time{WITH_LOCK(cs_main, return m_node.chainman->ActiveChain().Tip()->GetBlockTime())};
42+
SetMockTime(genesis_time + 3 * 60);
43+
44+
block_template = mining->createNewBlock(options);
45+
BOOST_REQUIRE(block_template);
46+
47+
// The template should use the mocked system time
48+
BOOST_REQUIRE_EQUAL(block_template->getBlockHeader().nTime, genesis_time + 3 * 60);
49+
50+
const BlockWaitOptions wait_options{.timeout = MillisecondsDouble{0}, .fee_threshold = 1};
51+
52+
// waitNext() should return nullptr because there is no better template
53+
auto should_be_nullptr = block_template->waitNext(wait_options);
54+
BOOST_REQUIRE(should_be_nullptr == nullptr);
55+
56+
// This remains the case when exactly 20 minutes have gone by
57+
{
58+
LOCK(cs_main);
59+
SetMockTime(m_node.chainman->ActiveChain().Tip()->GetBlockTime() + 20 * 60);
60+
}
61+
should_be_nullptr = block_template->waitNext(wait_options);
62+
BOOST_REQUIRE(should_be_nullptr == nullptr);
63+
64+
// One second later the difficulty drops and it returns a new template
65+
// Note that we can't test the actual difficulty change, because the
66+
// difficulty is already at 1.
67+
{
68+
LOCK(cs_main);
69+
SetMockTime(m_node.chainman->ActiveChain().Tip()->GetBlockTime() + 20 * 60 + 1);
70+
}
71+
block_template = block_template->waitNext(wait_options);
72+
BOOST_REQUIRE(block_template);
73+
}
74+
75+
BOOST_AUTO_TEST_SUITE_END()

src/test/util/setup_common.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ struct RegTestingSetup : public TestingSetup {
130130
: TestingSetup{ChainType::REGTEST} {}
131131
};
132132

133+
/** Identical to TestingSetup, but chain set to testnet4 */
134+
struct Testnet4Setup : public TestingSetup {
135+
Testnet4Setup()
136+
: TestingSetup{ChainType::TESTNET4} {}
137+
};
138+
133139
class CBlock;
134140
struct CMutableTransaction;
135141
class CScript;

0 commit comments

Comments
 (0)