Skip to content

Commit

Permalink
On testnet create min diff template after 20 mins
Browse files Browse the repository at this point in the history
  • Loading branch information
Sjors committed Jan 7, 2025
1 parent 956b449 commit 8d54cfd
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/interfaces/mining.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
10 changes: 10 additions & 0 deletions src/node/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 70 additions & 0 deletions src/test/testnet4_miner_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// 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;

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);

// 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);

// 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(1, MillisecondsDouble{0});
BOOST_REQUIRE(should_be_nullptr == nullptr);

// One second later the difficulty drops (not tested here) and it returns a new template
{
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()
6 changes: 6 additions & 0 deletions src/test/util/setup_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 8d54cfd

Please sign in to comment.