Skip to content

Commit 7bfc465

Browse files
achow101vijaydasmp
authored andcommitted
Merge bitcoin#28170: p2p: adaptive connections services flags
27f260a net: remove now unused global 'g_initial_block_download_completed' (furszy) aff7d92 test: add coverage for peerman adaptive connections service flags (furszy) 6ed5360 net: peer manager, dynamically adjust desirable services flag (furszy) 9f36e59 net: move state dependent peer services flags (furszy) f9ac96b net: decouple state independent service flags from desirable ones (furszy) 97df4e3 net: store best block tip time inside PeerManager (furszy) Pull request description: Derived from bitcoin#28120 discussion. By relocating the peer desirable services flags into the peer manager, we allow the connections acceptance process to handle post-IBD potential stalling scenarios. The peer manager will be able to dynamically adjust the services flags based on the node's proximity to the tip (back and forth). Allowing the node to recover from the following post-IBD scenario: Suppose the node has successfully synced the chain, but later experienced dropped connections and remained inactive for a duration longer than the limited peers threshold (the timeframe within which limited peers can provide blocks). In such cases, upon reconnecting to the network, the node might only establish connections with limited peers, filling up all available outbound slots. Resulting in an inability to synchronize the chain (because limited peers will not provide blocks older than the `NODE_NETWORK_LIMITED_MIN_BLOCKS` threshold). ACKs for top commit: achow101: ACK 27f260a vasild: ACK 27f260a naumenkogs: ACK 27f260a mzumsande: Light Code Review ACK 27f260a andrewtoth: ACK 27f260a Tree-SHA512: 07befb9bcd0b60a4e7c45e4429c02e7b6c66244f0910f4b2ad97c9b98258b6f46c914660a717b5ed4ef4814d0dbfae6e18e6559fe9bec7d0fbc2034109200953
1 parent 56b4256 commit 7bfc465

File tree

10 files changed

+155
-64
lines changed

10 files changed

+155
-64
lines changed

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ BITCOIN_TESTS =\
154154
test/net_tests.cpp \
155155
test/netbase_tests.cpp \
156156
test/orphanage_tests.cpp \
157+
test/peerman_tests.cpp \
157158
test/pmt_tests.cpp \
158159
test/policyestimator_tests.cpp \
159160
test/pool_tests.cpp \

src/init.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2511,13 +2511,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
25112511
// ********************************************************* Step 12: start node
25122512

25132513
//// debug print
2514+
int64_t best_block_time{};
25142515
{
25152516
LOCK(cs_main);
25162517
LogPrintf("block tree size = %u\n", chainman.BlockIndex().size());
25172518
chain_active_height = chainman.ActiveChain().Height();
2519+
best_block_time = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockTime() : Params().GenesisBlock().GetBlockTime();
25182520
if (tip_info) {
25192521
tip_info->block_height = chain_active_height;
2520-
tip_info->block_time = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockTime() : Params().GenesisBlock().GetBlockTime();
2522+
tip_info->block_time = best_block_time
25212523
tip_info->block_hash = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockHash() : Params().GenesisBlock().GetHash();
25222524
tip_info->verification_progress = GuessVerificationProgress(Params().TxData(), chainman.ActiveChain().Tip());
25232525
}
@@ -2527,7 +2529,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
25272529
}
25282530
}
25292531
LogPrintf("nBestHeight = %d\n", chain_active_height);
2530-
if (node.peerman) node.peerman->SetBestHeight(chain_active_height);
2532+
if (node.peerman) node.peerman->SetBestBlock(chain_active_height, std::chrono::seconds{best_block_time});
25312533

25322534
// Map ports with UPnP or NAT-PMP.
25332535
StartMapPort(args.GetBoolArg("-upnp", DEFAULT_UPNP), args.GetBoolArg("-natpmp", DEFAULT_NATPMP));

src/net.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
217217
while (!s.eof()) {
218218
CService endpoint;
219219
s >> endpoint;
220-
CAddress addr{endpoint, GetDesirableServiceFlags(NODE_NONE)};
220+
CAddress addr{endpoint, SeedsServiceFlags()};
221221
addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - one_week, -one_week);
222222
LogPrint(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToStringAddrPort());
223223
vSeedsOut.push_back(addr);
@@ -2747,7 +2747,7 @@ void CConnman::ThreadDNSAddressSeed()
27472747
AddAddrFetch(seed);
27482748
} else {
27492749
std::vector<CAddress> vAdd;
2750-
ServiceFlags requiredServiceBits = GetDesirableServiceFlags(NODE_NONE);
2750+
constexpr ServiceFlags requiredServiceBits{SeedsServiceFlags()};
27512751
std::string host = strprintf("x%x.%s", requiredServiceBits, seed);
27522752
CNetAddr resolveSource;
27532753
if (!resolveSource.SetInternal(host)) {
@@ -3145,7 +3145,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, CDe
31453145
const CAddress addr = m_anchors.back();
31463146
m_anchors.pop_back();
31473147
if (!addr.IsValid() || IsLocal(addr) || !g_reachable_nets.Contains(addr) ||
3148-
!HasAllDesirableServiceFlags(addr.nServices) ||
3148+
!m_msgproc->HasAllDesirableServiceFlags(addr.nServices) ||
31493149
outbound_ipv46_peer_netgroups.count(m_netgroupman.GetGroup(addr))) continue;
31503150
addrConnect = addr;
31513151
LogPrint(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToStringAddrPort());
@@ -3220,7 +3220,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, CDe
32203220
// for non-feelers, require all the services we'll want,
32213221
// for feelers, only require they be a full node (only because most
32223222
// SPV clients don't have a good address DB available)
3223-
if (!fFeeler && !HasAllDesirableServiceFlags(addr.nServices)) {
3223+
if (!fFeeler && !m_msgproc->HasAllDesirableServiceFlags(addr.nServices)) {
32243224
continue;
32253225
} else if (fFeeler && !MayHaveUsefulAddressDB(addr.nServices)) {
32263226
continue;

src/net.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,12 @@ class NetEventsInterface
11521152
/** Handle removal of a peer (clear state) */
11531153
virtual void FinalizeNode(const CNode& node) = 0;
11541154

1155+
/**
1156+
* Callback to determine whether the given set of service flags are sufficient
1157+
* for a peer to be "relevant".
1158+
*/
1159+
virtual bool HasAllDesirableServiceFlags(ServiceFlags services) const = 0;
1160+
11551161
/**
11561162
* Process protocol messages received from a given node
11571163
*

src/net_processing.cpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
161161
static const int MAX_UNCONNECTING_HEADERS = 10;
162162
/** Minimum blocks required to signal NODE_NETWORK_LIMITED */
163163
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
164+
/** Window, in blocks, for connecting to NODE_NETWORK_LIMITED peers */
165+
static const unsigned int NODE_NETWORK_LIMITED_ALLOW_CONN_BLOCKS = 144;
164166
/** Average delay between local address broadcasts */
165167
static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL{24h};
166168
/** Average delay between peer address broadcasts */
@@ -615,6 +617,7 @@ class PeerManagerImpl final : public PeerManager
615617
/** Implement NetEventsInterface */
616618
void InitializeNode(CNode& node, ServiceFlags our_services) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
617619
void FinalizeNode(const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
620+
bool HasAllDesirableServiceFlags(ServiceFlags services) const override;
618621
bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override
619622
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, g_msgproc_mutex);
620623
bool SendMessages(CNode* pto) override
@@ -634,7 +637,11 @@ class PeerManagerImpl final : public PeerManager
634637
void RelayTransaction(const uint256& txid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
635638
void RelayRecoveredSig(const llmq::CRecoveredSig& sig, bool proactive_relay) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
636639
void RelayDSQ(const CCoinJoinQueue& queue) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
637-
void SetBestHeight(int height) override { m_best_height = height; };
640+
void SetBestBlock(int height, std::chrono::seconds time) override
641+
{
642+
m_best_height = height;
643+
m_best_block_time = time;
644+
};
638645
void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message = "") override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
639646
void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
640647
const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) override
@@ -664,6 +671,7 @@ class PeerManagerImpl final : public PeerManager
664671
void PeerAskPeersForTransaction(const uint256& txid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
665672
size_t PeerGetRequestedObjectCount(NodeId nodeid) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, ::cs_main);
666673
void PeerPostProcessMessage(MessageProcessingResult&& ret) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
674+
ServiceFlags GetDesirableServiceFlags(ServiceFlags services) const override;
667675

668676
private:
669677
void _RelayTransaction(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_peer_mutex);
@@ -830,6 +838,8 @@ class PeerManagerImpl final : public PeerManager
830838

831839
/** The height of the best chain */
832840
std::atomic<int> m_best_height{-1};
841+
/** The time of the best chain tip block */
842+
std::atomic<std::chrono::seconds> m_best_block_time{0s};
833843

834844
/** Next time to check for stale tip */
835845
std::chrono::seconds m_stale_tip_check_time GUARDED_BY(cs_main){0s};
@@ -1367,6 +1377,11 @@ bool PeerManagerImpl::TipMayBeStale()
13671377
return m_last_tip_update.load() < GetTime<std::chrono::seconds>() - std::chrono::seconds{consensusParams.nPowTargetSpacing * 3} && mapBlocksInFlight.empty();
13681378
}
13691379

1380+
int64_t PeerManagerImpl::ApproximateBestBlockDepth() const
1381+
{
1382+
return (GetTime<std::chrono::seconds>() - m_best_block_time.load()).count() / m_chainparams.GetConsensus().nPowTargetSpacing;
1383+
}
1384+
13701385
bool PeerManagerImpl::CanDirectFetch()
13711386
{
13721387
return m_chainman.ActiveChain().Tip()->GetBlockTime() > GetAdjustedTime() - m_chainparams.GetConsensus().nPowTargetSpacing * 20;
@@ -1812,6 +1827,23 @@ void PeerManagerImpl::FinalizeNode(const CNode& node) {
18121827
LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
18131828
}
18141829

1830+
bool PeerManagerImpl::HasAllDesirableServiceFlags(ServiceFlags services) const
1831+
{
1832+
// Shortcut for (services & GetDesirableServiceFlags(services)) == GetDesirableServiceFlags(services)
1833+
return !(GetDesirableServiceFlags(services) & (~services));
1834+
}
1835+
1836+
ServiceFlags PeerManagerImpl::GetDesirableServiceFlags(ServiceFlags services) const
1837+
{
1838+
if (services & NODE_NETWORK_LIMITED) {
1839+
// Limited peers are desirable when we are close to the tip.
1840+
if (ApproximateBestBlockDepth() < NODE_NETWORK_LIMITED_ALLOW_CONN_BLOCKS) {
1841+
return ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS);
1842+
}
1843+
}
1844+
return ServiceFlags(NODE_NETWORK | NODE_WITNESS);
1845+
}
1846+
18151847
PeerRef PeerManagerImpl::GetPeerRef(NodeId id) const
18161848
{
18171849
READ_LOCK(m_peer_mutex);
@@ -2218,9 +2250,7 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha
22182250
* in m_chainman.ActiveChain() to our peers.
22192251
*/
22202252
void PeerManagerImpl::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload){
2221-
m_best_height = pindexNew->nHeight;
2222-
2223-
SetServiceFlagsIBDCache(!fInitialDownload);
2253+
SetBestBlock(pindexNew->nHeight, std::chrono::seconds{pindexNew->GetBlockTime()});
22242254

22252255
// Don't relay inventory during initial block download.
22262256
if (fInitialDownload) return;

src/net_processing.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ class PeerManager : public CValidationInterface, public NetEventsInterface, publ
158158
/** Relay recovered sigs to all interested peers */
159159
virtual void RelayRecoveredSig(const llmq::CRecoveredSig& sig, bool proactive_relay) = 0;
160160

161-
/** Set the best height */
162-
virtual void SetBestHeight(int height) = 0;
161+
/** Set the height of the best block and its time (seconds since epoch). */
162+
virtual void SetBestBlock(int height, std::chrono::seconds time) = 0;
163163

164164
/**
165165
* Increment peer's misbehavior score. If the new value surpasses DISCOURAGEMENT_THRESHOLD (specified on startup or by default), mark node to be discouraged, meaning the peer might be disconnected & added to the discouragement filter.
@@ -192,6 +192,28 @@ class PeerManager : public CValidationInterface, public NetEventsInterface, publ
192192
virtual void StopHandlers() = 0;
193193
virtual void InterruptHandlers() = 0;
194194
virtual void ScheduleHandlers(CScheduler& scheduler) = 0;
195+
/**
196+
* Gets the set of service flags which are "desirable" for a given peer.
197+
*
198+
* These are the flags which are required for a peer to support for them
199+
* to be "interesting" to us, ie for us to wish to use one of our few
200+
* outbound connection slots for or for us to wish to prioritize keeping
201+
* their connection around.
202+
*
203+
* Relevant service flags may be peer- and state-specific in that the
204+
* version of the peer may determine which flags are required (eg in the
205+
* case of NODE_NETWORK_LIMITED where we seek out NODE_NETWORK peers
206+
* unless they set NODE_NETWORK_LIMITED and we are out of IBD, in which
207+
* case NODE_NETWORK_LIMITED suffices).
208+
*
209+
* Thus, generally, avoid calling with 'services' == NODE_NONE, unless
210+
* state-specific flags must absolutely be avoided. When called with
211+
* 'services' == NODE_NONE, the returned desirable service flags are
212+
* guaranteed to not change dependent on state - ie they are suitable for
213+
* use when describing peers which we know to be desirable, but for which
214+
* we do not have a confirmed set of service flags.
215+
*/
216+
virtual ServiceFlags GetDesirableServiceFlags(ServiceFlags services) const = 0;
195217
};
196218

197219
#endif // BITCOIN_NET_PROCESSING_H

src/protocol.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010
#include <atomic>
1111

12-
static std::atomic<bool> g_initial_block_download_completed(false);
13-
1412
#define MAKE_MSG(var_name, p2p_name_str) \
1513
const char* var_name=p2p_name_str; \
1614
static_assert(std::size(p2p_name_str) <= CMessageHeader::COMMAND_SIZE + 1, "p2p_name_str cannot be greater than COMMAND_SIZE"); // Includes +1 for null termination character.
@@ -248,18 +246,6 @@ bool CMessageHeader::IsCommandValid() const
248246
return true;
249247
}
250248

251-
252-
ServiceFlags GetDesirableServiceFlags(ServiceFlags services) {
253-
if ((services & NODE_NETWORK_LIMITED) && g_initial_block_download_completed) {
254-
return ServiceFlags(NODE_NETWORK_LIMITED);
255-
}
256-
return ServiceFlags(NODE_NETWORK);
257-
}
258-
259-
void SetServiceFlagsIBDCache(bool state) {
260-
g_initial_block_download_completed = state;
261-
}
262-
263249
CInv::CInv()
264250
{
265251
type = 0;

src/protocol.h

Lines changed: 6 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -347,43 +347,12 @@ enum ServiceFlags : uint64_t {
347347
std::vector<std::string> serviceFlagsToStr(uint64_t flags);
348348

349349
/**
350-
* Gets the set of service flags which are "desirable" for a given peer.
351-
*
352-
* These are the flags which are required for a peer to support for them
353-
* to be "interesting" to us, ie for us to wish to use one of our few
354-
* outbound connection slots for or for us to wish to prioritize keeping
355-
* their connection around.
356-
*
357-
* Relevant service flags may be peer- and state-specific in that the
358-
* version of the peer may determine which flags are required (eg in the
359-
* case of NODE_NETWORK_LIMITED where we seek out NODE_NETWORK peers
360-
* unless they set NODE_NETWORK_LIMITED and we are out of IBD, in which
361-
* case NODE_NETWORK_LIMITED suffices).
362-
*
363-
* Thus, generally, avoid calling with peerServices == NODE_NONE, unless
364-
* state-specific flags must absolutely be avoided. When called with
365-
* peerServices == NODE_NONE, the returned desirable service flags are
366-
* guaranteed to not change dependent on state - ie they are suitable for
367-
* use when describing peers which we know to be desirable, but for which
368-
* we do not have a confirmed set of service flags.
369-
*
370-
* If the NODE_NONE return value is changed, contrib/seeds/makeseeds.py
371-
* should be updated appropriately to filter for the same nodes.
372-
*/
373-
ServiceFlags GetDesirableServiceFlags(ServiceFlags services);
374-
375-
/** Set the current IBD status in order to figure out the desirable service flags */
376-
void SetServiceFlagsIBDCache(bool status);
377-
378-
/**
379-
* A shortcut for (services & GetDesirableServiceFlags(services))
380-
* == GetDesirableServiceFlags(services), ie determines whether the given
381-
* set of service flags are sufficient for a peer to be "relevant".
382-
*/
383-
static inline bool HasAllDesirableServiceFlags(ServiceFlags services)
384-
{
385-
return !(GetDesirableServiceFlags(services) & (~services));
386-
}
350+
* State independent service flags.
351+
* If the return value is changed, contrib/seeds/makeseeds.py
352+
* should be updated appropriately to filter for nodes with
353+
* desired service flags (compatible with our new flags).
354+
*/
355+
constexpr ServiceFlags SeedsServiceFlags() { return ServiceFlags(NODE_NETWORK | NODE_WITNESS); }
387356

388357
/**
389358
* Checks if a peer with the given service flags may be capable of having a

src/test/fuzz/integer.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,6 @@ FUZZ_TARGET(integer, .init = initialize_integer)
211211

212212
{
213213
const ServiceFlags service_flags = (ServiceFlags)u64;
214-
(void)HasAllDesirableServiceFlags(service_flags);
215214
(void)MayHaveUsefulAddressDB(service_flags);
216215
}
217216

src/test/peerman_tests.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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

Comments
 (0)