|
| 1 | +// Copyright (c) 2024-present The Bitcoin Core developers |
| 2 | +// Distributed under the MIT software license, see the accompanying |
| 3 | +// file COPYING or https://www.opensource.org/licenses/mit-license.php. |
| 4 | + |
| 5 | +#include <chainparams.h> |
| 6 | +#include <node/miner.h> |
| 7 | +#include <net_processing.h> |
| 8 | +#include <pow.h> |
| 9 | +#include <test/util/setup_common.h> |
| 10 | +#include <validation.h> |
| 11 | + |
| 12 | +#include <boost/test/unit_test.hpp> |
| 13 | + |
| 14 | +BOOST_FIXTURE_TEST_SUITE(peerman_tests, RegTestingSetup) |
| 15 | + |
| 16 | +/** Window, in blocks, for connecting to NODE_NETWORK_LIMITED peers */ |
| 17 | +static constexpr int64_t NODE_NETWORK_LIMITED_ALLOW_CONN_BLOCKS = 144; |
| 18 | + |
| 19 | +static void mineBlock(const node::NodeContext& node, std::chrono::seconds block_time) |
| 20 | +{ |
| 21 | + auto curr_time = GetTime<std::chrono::seconds>(); |
| 22 | + SetMockTime(block_time); // update time so the block is created with it |
| 23 | + CBlock block = node::BlockAssembler{node.chainman->ActiveChainstate(), nullptr}.CreateNewBlock(CScript() << OP_TRUE)->block; |
| 24 | + while (!CheckProofOfWork(block.GetHash(), block.nBits, node.chainman->GetConsensus())) ++block.nNonce; |
| 25 | + block.fChecked = true; // little speedup |
| 26 | + SetMockTime(curr_time); // process block at current time |
| 27 | + Assert(node.chainman->ProcessNewBlock(std::make_shared<const CBlock>(block), /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)); |
| 28 | + SyncWithValidationInterfaceQueue(); // drain events queue |
| 29 | +} |
| 30 | + |
| 31 | +// Verifying when network-limited peer connections are desirable based on the node's proximity to the tip |
| 32 | +BOOST_AUTO_TEST_CASE(connections_desirable_service_flags) |
| 33 | +{ |
| 34 | + std::unique_ptr<PeerManager> peerman = PeerManager::make(*m_node.connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, {}); |
| 35 | + auto consensus = m_node.chainman->GetParams().GetConsensus(); |
| 36 | + |
| 37 | + // Check we start connecting to full nodes |
| 38 | + ServiceFlags peer_flags{NODE_WITNESS | NODE_NETWORK_LIMITED}; |
| 39 | + BOOST_CHECK(peerman->GetDesirableServiceFlags(peer_flags) == ServiceFlags(NODE_NETWORK | NODE_WITNESS)); |
| 40 | + |
| 41 | + // Make peerman aware of the initial best block and verify we accept limited peers when we start close to the tip time. |
| 42 | + auto tip = WITH_LOCK(::cs_main, return m_node.chainman->ActiveChain().Tip()); |
| 43 | + uint64_t tip_block_time = tip->GetBlockTime(); |
| 44 | + int tip_block_height = tip->nHeight; |
| 45 | + peerman->SetBestBlock(tip_block_height, std::chrono::seconds{tip_block_time}); |
| 46 | + |
| 47 | + SetMockTime(tip_block_time + 1); // Set node time to tip time |
| 48 | + BOOST_CHECK(peerman->GetDesirableServiceFlags(peer_flags) == ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS)); |
| 49 | + |
| 50 | + // Check we don't disallow limited peers connections when we are behind but still recoverable (below the connection safety window) |
| 51 | + SetMockTime(GetTime<std::chrono::seconds>() + std::chrono::seconds{consensus.nPowTargetSpacing * (NODE_NETWORK_LIMITED_ALLOW_CONN_BLOCKS - 1)}); |
| 52 | + BOOST_CHECK(peerman->GetDesirableServiceFlags(peer_flags) == ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS)); |
| 53 | + |
| 54 | + // Check we disallow limited peers connections when we are further than the limited peers safety window |
| 55 | + SetMockTime(GetTime<std::chrono::seconds>() + std::chrono::seconds{consensus.nPowTargetSpacing * 2}); |
| 56 | + BOOST_CHECK(peerman->GetDesirableServiceFlags(peer_flags) == ServiceFlags(NODE_NETWORK | NODE_WITNESS)); |
| 57 | + |
| 58 | + // By now, we tested that the connections desirable services flags change based on the node's time proximity to the tip. |
| 59 | + // Now, perform the same tests for when the node receives a block. |
| 60 | + RegisterValidationInterface(peerman.get()); |
| 61 | + |
| 62 | + // First, verify a block in the past doesn't enable limited peers connections |
| 63 | + // At this point, our time is (NODE_NETWORK_LIMITED_ALLOW_CONN_BLOCKS + 1) * 10 minutes ahead the tip's time. |
| 64 | + mineBlock(m_node, /*block_time=*/std::chrono::seconds{tip_block_time + 1}); |
| 65 | + BOOST_CHECK(peerman->GetDesirableServiceFlags(peer_flags) == ServiceFlags(NODE_NETWORK | NODE_WITNESS)); |
| 66 | + |
| 67 | + // Verify a block close to the tip enables limited peers connections |
| 68 | + mineBlock(m_node, /*block_time=*/GetTime<std::chrono::seconds>()); |
| 69 | + BOOST_CHECK(peerman->GetDesirableServiceFlags(peer_flags) == ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS)); |
| 70 | + |
| 71 | + // Lastly, verify the stale tip checks can disallow limited peers connections after not receiving blocks for a prolonged period. |
| 72 | + SetMockTime(GetTime<std::chrono::seconds>() + std::chrono::seconds{consensus.nPowTargetSpacing * NODE_NETWORK_LIMITED_ALLOW_CONN_BLOCKS + 1}); |
| 73 | + BOOST_CHECK(peerman->GetDesirableServiceFlags(peer_flags) == ServiceFlags(NODE_NETWORK | NODE_WITNESS)); |
| 74 | +} |
| 75 | + |
| 76 | +BOOST_AUTO_TEST_SUITE_END() |
0 commit comments