diff --git a/ci/dash/lint-tidy.sh b/ci/dash/lint-tidy.sh index 23875d727e68..e82444291d5e 100755 --- a/ci/dash/lint-tidy.sh +++ b/ci/dash/lint-tidy.sh @@ -123,7 +123,6 @@ iwyu_tool.py \ "src/util/check.cpp" \ "src/util/error.cpp" \ "src/util/exception.cpp" \ - "src/util/getuniquepath.cpp" \ "src/util/hasher.cpp" \ "src/util/message.cpp" \ "src/util/moneystr.cpp" \ diff --git a/src/Makefile.am b/src/Makefile.am index 097e04f334a7..0724e19a22da 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -454,7 +454,6 @@ BITCOIN_CORE_H = \ util/fees.h \ util/fs.h \ util/fs_helpers.h \ - util/getuniquepath.h \ util/golombrice.h \ util/hash_type.h \ util/hasher.h \ @@ -1076,7 +1075,6 @@ libbitcoin_util_a_SOURCES = \ util/fees.cpp \ util/fs.cpp \ util/fs_helpers.cpp \ - util/getuniquepath.cpp \ util/hasher.cpp \ util/message.cpp \ util/moneystr.cpp \ @@ -1388,7 +1386,6 @@ libdashkernel_la_SOURCES = \ util/exception.cpp \ util/fs.cpp \ util/fs_helpers.cpp \ - util/getuniquepath.cpp \ util/hasher.cpp \ util/message.cpp \ util/moneystr.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 7a180f80daa4..a145cbdec341 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -173,6 +173,7 @@ BITCOIN_TESTS =\ test/net_tests.cpp \ test/netbase_tests.cpp \ test/orphanage_tests.cpp \ + test/peerman_tests.cpp \ test/pmt_tests.cpp \ test/policyestimator_tests.cpp \ test/pool_tests.cpp \ @@ -263,7 +264,8 @@ FUZZ_WALLET_SRC = \ if USE_SQLITE FUZZ_WALLET_SRC += \ - wallet/test/fuzz/notifications.cpp + wallet/test/fuzz/notifications.cpp \ + wallet/test/fuzz/scriptpubkeyman.cpp endif # USE_SQLITE BITCOIN_TEST_SUITE += \ diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include index e909ab9359c1..b41475894e82 100644 --- a/src/Makefile.test_fuzz.include +++ b/src/Makefile.test_fuzz.include @@ -12,6 +12,7 @@ TEST_FUZZ_H = \ test/fuzz/FuzzedDataProvider.h \ test/fuzz/util.h \ test/util/mining.h \ + test/fuzz/util/descriptor.h \ test/fuzz/util/mempool.h \ test/fuzz/util/net.h @@ -21,6 +22,7 @@ libtest_fuzz_a_SOURCES = \ test/fuzz/fuzz.cpp \ test/util/mining.cpp \ test/fuzz/util.cpp \ + test/fuzz/util/descriptor.cpp \ test/fuzz/util/mempool.cpp \ test/fuzz/util/net.cpp \ $(TEST_FUZZ_H) diff --git a/src/init.cpp b/src/init.cpp index 38bda8f4212a..a29b3c24a8f0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -675,7 +675,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-forcednsseed", strprintf("Always query for peer addresses via DNS lookup (default: %u)", DEFAULT_FORCEDNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-listen", strprintf("Accept connections from outside (default: %u if no -proxy, -connect or -maxconnections=0)", DEFAULT_LISTEN), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-listenonion", strprintf("Automatically create Tor onion service if Tor is available and the onion bind could be bound (see -bind). If set to 1 explicitly, fail to start if the onion bind cannot be bound (default: %d)", DEFAULT_LISTEN_ONION), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-maxconnections=", strprintf("Maintain at most connections to peers (temporary service connections excluded) (default: %u). This limit does not apply to connections manually added via -addnode or the addnode RPC, which have a separate limit of %u.", DEFAULT_MAX_PEER_CONNECTIONS, MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + argsman.AddArg("-maxconnections=", strprintf("Maintain at most automatic connections to peers (temporary service connections excluded) (default: %u). This limit does not apply to connections manually added via -addnode or the addnode RPC, which have a separate limit of %u.", DEFAULT_MAX_PEER_CONNECTIONS, MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-maxreceivebuffer=", strprintf("Maximum per-connection receive buffer, *1000 bytes (default: %u)", DEFAULT_MAXRECEIVEBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-maxsendbuffer=", strprintf("Maximum per-connection memory usage for the send buffer, *1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-maxtimeadjustment", strprintf("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by outbound peers forward or backward by this amount (default: %u seconds).", DEFAULT_MAX_TIME_ADJUSTMENT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -1438,13 +1438,14 @@ static bool LockDataDirectory(bool probeOnly) { // Make sure only a single Dash Core process is using the data directory. const fs::path& datadir = gArgs.GetDataDirNet(); - if (!DirIsWritable(datadir)) { + switch (util::LockDirectory(datadir, ".lock", probeOnly)) { + case util::LockResult::ErrorWrite: return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), fs::PathToString(datadir))); - } - if (!LockDirectory(datadir, ".lock", probeOnly)) { + case util::LockResult::ErrorLock: return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), fs::PathToString(datadir), PACKAGE_NAME)); - } - return true; + case util::LockResult::Success: return true; + } // no default case, so the compiler can warn about missing cases + assert(false); } bool AppInitSanityChecks(const kernel::Context& kernel) @@ -2598,13 +2599,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 12: start node //// debug print + int64_t best_block_time{}; { LOCK(cs_main); LogPrintf("block tree size = %u\n", chainman.BlockIndex().size()); chain_active_height = chainman.ActiveChain().Height(); + best_block_time = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockTime() : chainman.GetParams().GenesisBlock().GetBlockTime(); if (tip_info) { tip_info->block_height = chain_active_height; - tip_info->block_time = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockTime() : chainman.GetParams().GenesisBlock().GetBlockTime(); + tip_info->block_time = best_block_time; tip_info->block_hash = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockHash() : chainman.GetParams().GenesisBlock().GetHash(); tip_info->verification_progress = GuessVerificationProgress(chainman.GetParams().TxData(), chainman.ActiveChain().Tip()); } @@ -2614,19 +2617,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } } LogPrintf("nBestHeight = %d\n", chain_active_height); - if (node.peerman) node.peerman->SetBestHeight(chain_active_height); + if (node.peerman) node.peerman->SetBestBlock(chain_active_height, std::chrono::seconds{best_block_time}); // Map ports with UPnP or NAT-PMP. StartMapPort(args.GetBoolArg("-upnp", DEFAULT_UPNP), args.GetBoolArg("-natpmp", DEFAULT_NATPMP)); CConnman::Options connOptions; connOptions.nLocalServices = nLocalServices; - connOptions.nMaxConnections = nMaxConnections; - connOptions.m_max_outbound_full_relay = std::min(MAX_OUTBOUND_FULL_RELAY_CONNECTIONS, connOptions.nMaxConnections); - connOptions.m_max_outbound_block_relay = std::min(MAX_BLOCK_RELAY_ONLY_CONNECTIONS, connOptions.nMaxConnections-connOptions.m_max_outbound_full_relay); - connOptions.m_max_outbound_onion = std::min(MAX_DESIRED_ONION_CONNECTIONS, connOptions.nMaxConnections / 2); - connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS; - connOptions.nMaxFeeler = MAX_FEELER_CONNECTIONS; + connOptions.m_max_automatic_connections = nMaxConnections; + connOptions.m_max_outbound_onion = std::min(MAX_DESIRED_ONION_CONNECTIONS, nMaxConnections / 2); connOptions.uiInterface = &uiInterface; connOptions.m_banman = node.banman.get(); connOptions.m_msgproc = node.peerman.get(); diff --git a/src/net.cpp b/src/net.cpp index 131d8083899c..012f8de5d207 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -219,7 +219,7 @@ static std::vector ConvertSeeds(const std::vector &vSeedsIn) while (!s.eof()) { CService endpoint; s >> endpoint; - CAddress addr{endpoint, GetDesirableServiceFlags(NODE_NONE)}; + CAddress addr{endpoint, SeedsServiceFlags()}; addr.nTime = rng.rand_uniform_delay(Now() - one_week, -one_week); LogPrint(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToStringAddrPort()); vSeedsOut.push_back(addr); @@ -1900,7 +1900,6 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr&& sock, { int nInbound = 0; int nVerifiedInboundMasternodes = 0; - int nMaxInbound = nMaxConnections - m_max_outbound; const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end(); @@ -1956,18 +1955,18 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr&& sock, // Only accept connections from discouraged peers if our inbound slots aren't (almost) full. bool discouraged = m_banman && m_banman->IsDiscouraged(addr); - if (!NetPermissions::HasFlag(permission_flags, NetPermissionFlags::NoBan) && nInbound + 1 >= nMaxInbound && discouraged) + if (!NetPermissions::HasFlag(permission_flags, NetPermissionFlags::NoBan) && nInbound + 1 >= m_max_inbound && discouraged) { LogPrint(BCLog::NET_NETCONN, "connection from %s dropped (discouraged)\n", addr.ToStringAddrPort()); return; } - // Evict connections until we are below nMaxInbound. In case eviction protection resulted in nodes to not be evicted + // Evict connections until we are below m_max_inbound. In case eviction protection resulted in nodes to not be evicted // before, they might get evicted in batches now (after the protection timeout). // We don't evict verified MN connections and also don't take them into account when checking limits. We can do // this because such connections are limited by the total number of MNs times MAX_VERIFIED_INBOUND_PER_PROTX // (enforced in TryMarkVerified), so this is not usable for attacks. - while (nInbound - nVerifiedInboundMasternodes >= nMaxInbound) + while (nInbound - nVerifiedInboundMasternodes >= m_max_inbound) { if (!AttemptToEvictConnection()) { // No connection to evict, disconnect the new connection @@ -2780,7 +2779,7 @@ void CConnman::ThreadDNSAddressSeed() AddAddrFetch(seed); } else { std::vector vAdd; - ServiceFlags requiredServiceBits = GetDesirableServiceFlags(NODE_NONE); + constexpr ServiceFlags requiredServiceBits{SeedsServiceFlags()}; std::string host = strprintf("x%x.%s", requiredServiceBits, seed); CNetAddr resolveSource; if (!resolveSource.SetInternal(host)) { @@ -3178,7 +3177,7 @@ void CConnman::ThreadOpenConnections(const std::vector connect, CDe const CAddress addr = m_anchors.back(); m_anchors.pop_back(); if (!addr.IsValid() || IsLocal(addr) || !g_reachable_nets.Contains(addr) || - !HasAllDesirableServiceFlags(addr.nServices) || + !m_msgproc->HasAllDesirableServiceFlags(addr.nServices) || outbound_ipv46_peer_netgroups.count(m_netgroupman.GetGroup(addr))) continue; addrConnect = addr; LogPrint(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToStringAddrPort()); @@ -3253,7 +3252,7 @@ void CConnman::ThreadOpenConnections(const std::vector connect, CDe // for non-feelers, require all the services we'll want, // for feelers, only require they be a full node (only because most // SPV clients don't have a good address DB available) - if (!fFeeler && !HasAllDesirableServiceFlags(addr.nServices)) { + if (!fFeeler && !m_msgproc->HasAllDesirableServiceFlags(addr.nServices)) { continue; } else if (fFeeler && !MayHaveUsefulAddressDB(addr.nServices)) { continue; @@ -3303,7 +3302,7 @@ void CConnman::ThreadOpenConnections(const std::vector connect, CDe // different netgroups in ipv4/ipv6 networks + all peers in Tor/I2P/CJDNS networks. // Don't record addrman failure attempts when node is offline. This can be identified since all local // network connections (if any) belong in the same netgroup, and the size of `outbound_ipv46_peer_netgroups` would only be 1. - const bool count_failures{((int)outbound_ipv46_peer_netgroups.size() + outbound_privacy_network_peers) >= std::min(nMaxConnections - 1, 2)}; + const bool count_failures{((int)outbound_ipv46_peer_netgroups.size() + outbound_privacy_network_peers) >= std::min(m_max_automatic_connections - 1, 2)}; // Use BIP324 transport when both us and them have NODE_V2_P2P set. const bool use_v2transport(addrConnect.nServices & GetLocalServices() & NODE_P2P_V2); OpenNetworkConnection(addrConnect, count_failures, std::move(grant), /*strDest=*/nullptr, conn_type, use_v2transport); @@ -4063,11 +4062,11 @@ bool CConnman::Start(CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_met if (semOutbound == nullptr) { // initialize semaphore - semOutbound = std::make_unique(std::min(m_max_outbound, nMaxConnections)); + semOutbound = std::make_unique(std::min(m_max_automatic_outbound, m_max_automatic_connections)); } if (semAddnode == nullptr) { // initialize semaphore - semAddnode = std::make_unique(nMaxAddnode); + semAddnode = std::make_unique(m_max_addnode); } // @@ -4177,13 +4176,13 @@ void CConnman::Interrupt() InterruptSocks5(true); if (semOutbound) { - for (int i=0; ipost(); } } if (semAddnode) { - for (int i=0; ipost(); } } @@ -4571,7 +4570,7 @@ std::map CConnman::getNetLocalAddresses() const size_t CConnman::GetMaxOutboundNodeCount() { - return m_max_outbound; + return m_max_automatic_outbound; } size_t CConnman::GetMaxOutboundOnionNodeCount() diff --git a/src/net.h b/src/net.h index bef696cc76d5..bb3146e7edd9 100644 --- a/src/net.h +++ b/src/net.h @@ -1177,6 +1177,12 @@ class NetEventsInterface /** Handle removal of a peer (clear state) */ virtual void FinalizeNode(const CNode& node) = 0; + /** + * Callback to determine whether the given set of service flags are sufficient + * for a peer to be "relevant". + */ + virtual bool HasAllDesirableServiceFlags(ServiceFlags services) const = 0; + /** * Process protocol messages received from a given node * @@ -1220,12 +1226,8 @@ friend class CNode; struct Options { ServiceFlags nLocalServices = NODE_NONE; - int nMaxConnections = 0; - int m_max_outbound_full_relay = 0; - int m_max_outbound_block_relay = 0; + int m_max_automatic_connections = 0; int m_max_outbound_onion = 0; - int nMaxAddnode = 0; - int nMaxFeeler = 0; CClientUIInterface* uiInterface = nullptr; NetEventsInterface* m_msgproc = nullptr; BanMan* m_banman = nullptr; @@ -1263,14 +1265,13 @@ friend class CNode; AssertLockNotHeld(m_total_bytes_sent_mutex); nLocalServices = connOptions.nLocalServices; - nMaxConnections = connOptions.nMaxConnections; - m_max_outbound_full_relay = std::min(connOptions.m_max_outbound_full_relay, connOptions.nMaxConnections); - m_max_outbound_block_relay = connOptions.m_max_outbound_block_relay; + m_max_automatic_connections = connOptions.m_max_automatic_connections; + m_max_outbound_full_relay = std::min(MAX_OUTBOUND_FULL_RELAY_CONNECTIONS, m_max_automatic_connections); + m_max_outbound_block_relay = std::min(MAX_BLOCK_RELAY_ONLY_CONNECTIONS, m_max_automatic_connections - m_max_outbound_full_relay); m_max_outbound_onion = connOptions.m_max_outbound_onion; + m_max_automatic_outbound = m_max_outbound_full_relay + m_max_outbound_block_relay + m_max_feeler; + m_max_inbound = std::max(0, m_max_automatic_connections - m_max_automatic_outbound); m_use_addrman_outgoing = connOptions.m_use_addrman_outgoing; - nMaxAddnode = connOptions.nMaxAddnode; - nMaxFeeler = connOptions.nMaxFeeler; - m_max_outbound = m_max_outbound_full_relay + m_max_outbound_block_relay + nMaxFeeler; m_client_interface = connOptions.uiInterface; m_banman = connOptions.m_banman; m_msgproc = connOptions.m_msgproc; @@ -1893,7 +1894,18 @@ friend class CNode; std::unique_ptr semOutbound; std::unique_ptr semAddnode; - int nMaxConnections; + + /** + * Maximum number of automatic connections permitted, excluding manual + * connections but including inbounds. May be changed by the user and is + * potentially limited by the operating system (number of file descriptors). + */ + int m_max_automatic_connections; + + /* + * Maximum number of peers by connection type. Might vary from defaults + * based on -maxconnections init value. + */ // How many full-relay (tx, block, addr) outbound peers we want int m_max_outbound_full_relay; @@ -1902,12 +1914,14 @@ friend class CNode; // We do not relay tx or addr messages with these peers int m_max_outbound_block_relay; - // How many onion outbound peers we want; don't care if full or block only; does not increase m_max_outbound + // How many onion outbound peers we want; don't care if full or block only; does not increase m_max_automatic_outbound int m_max_outbound_onion; - int nMaxAddnode; - int nMaxFeeler; - int m_max_outbound; + int m_max_addnode{MAX_ADDNODE_CONNECTIONS}; + int m_max_feeler{MAX_FEELER_CONNECTIONS}; + int m_max_automatic_outbound; + int m_max_inbound; + bool m_use_addrman_outgoing; CClientUIInterface* m_client_interface; NetEventsInterface* m_msgproc; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index ef6825d814ea..d4004d3112bc 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -177,6 +177,8 @@ static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8; static const int MAX_NUM_UNCONNECTING_HEADERS_MSGS = 10; /** Minimum blocks required to signal NODE_NETWORK_LIMITED */ static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288; +/** Window, in blocks, for connecting to NODE_NETWORK_LIMITED peers */ +static const unsigned int NODE_NETWORK_LIMITED_ALLOW_CONN_BLOCKS = 144; /** Average delay between local address broadcasts */ static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL{24h}; /** Average delay between peer address broadcasts */ @@ -611,6 +613,7 @@ class PeerManagerImpl final : public PeerManager void InitializeNode(CNode& node, ServiceFlags our_services) override EXCLUSIVE_LOCKS_REQUIRED(!m_object_request_mutex, !m_peer_mutex); void FinalizeNode(const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_object_request_mutex, !m_peer_mutex); + bool HasAllDesirableServiceFlags(ServiceFlags services) const override; bool ProcessMessages(CNode* pfrom, std::atomic& interrupt) override EXCLUSIVE_LOCKS_REQUIRED(!m_object_request_mutex, !m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, g_msgproc_mutex); @@ -632,13 +635,18 @@ class PeerManagerImpl final : public PeerManager void RelayTransaction(const uint256& txid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void RelayRecoveredSig(const llmq::CRecoveredSig& sig, bool proactive_relay) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void RelayDSQ(const CCoinJoinQueue& queue) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); - void SetBestHeight(int height) override { m_best_height = height; }; + void SetBestBlock(int height, std::chrono::seconds time) override + { + m_best_height = height; + m_best_block_time = time; + }; void UnitTestMisbehaving(NodeId peer_id, int howmuch) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex) { Misbehaving(*Assert(GetPeerRef(peer_id)), howmuch, ""); }; void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, const std::chrono::microseconds time_received, const std::atomic& interruptMsgProc) override EXCLUSIVE_LOCKS_REQUIRED(!m_object_request_mutex, !m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, g_msgproc_mutex); void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) override; + ServiceFlags GetDesirableServiceFlags(ServiceFlags services) const override; size_t GetRequestedObjectCount(NodeId nodeid) const override EXCLUSIVE_LOCKS_REQUIRED(!m_object_request_mutex); /** Implements external handlers logic */ @@ -863,6 +871,8 @@ class PeerManagerImpl final : public PeerManager /** The height of the best chain */ std::atomic m_best_height{-1}; + /** The time of the best chain tip block */ + std::atomic m_best_block_time{0s}; /** Next time to check for stale tip */ std::chrono::seconds m_stale_tip_check_time GUARDED_BY(cs_main){0s}; @@ -902,6 +912,12 @@ class PeerManagerImpl final : public PeerManager void UpdateBlockAvailability(NodeId nodeid, const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool CanDirectFetch() EXCLUSIVE_LOCKS_REQUIRED(cs_main); + /** + * Estimates the distance, in blocks, between the best-known block and the network chain tip. + * Utilizes the best-block time and the chainparams blocks spacing to approximate it. + */ + int64_t ApproximateBestBlockDepth() const; + /** * To prevent fingerprinting attacks, only send blocks/headers outside of the * active chain if they are no more than a month older (both in time, and in @@ -1450,6 +1466,11 @@ bool PeerManagerImpl::TipMayBeStale() return m_last_tip_update.load() < GetTime() - std::chrono::seconds{consensusParams.nPowTargetSpacing * 3} && mapBlocksInFlight.empty(); } +int64_t PeerManagerImpl::ApproximateBestBlockDepth() const +{ + return (GetTime() - m_best_block_time.load()).count() / m_chainparams.GetConsensus().nPowTargetSpacing; +} + bool PeerManagerImpl::CanDirectFetch() { return m_chainman.ActiveChain().Tip()->Time() > NodeClock::now() - m_chainparams.GetConsensus().PowTargetSpacing() * 20; @@ -1886,6 +1907,23 @@ void PeerManagerImpl::FinalizeNode(const CNode& node) { LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid); } +bool PeerManagerImpl::HasAllDesirableServiceFlags(ServiceFlags services) const +{ + // Shortcut for (services & GetDesirableServiceFlags(services)) == GetDesirableServiceFlags(services) + return !(GetDesirableServiceFlags(services) & (~services)); +} + +ServiceFlags PeerManagerImpl::GetDesirableServiceFlags(ServiceFlags services) const +{ + if (services & NODE_NETWORK_LIMITED) { + // Limited peers are desirable when we are close to the tip. + if (ApproximateBestBlockDepth() < NODE_NETWORK_LIMITED_ALLOW_CONN_BLOCKS) { + return ServiceFlags(NODE_NETWORK_LIMITED); + } + } + return ServiceFlags(NODE_NETWORK); +} + PeerRef PeerManagerImpl::GetPeerRef(NodeId id) const { READ_LOCK(m_peer_mutex); @@ -2300,10 +2338,9 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha * Update our best height and announce any block hashes which weren't previously * in m_chainman.ActiveChain() to our peers. */ -void PeerManagerImpl::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload){ - m_best_height = pindexNew->nHeight; - - SetServiceFlagsIBDCache(!fInitialDownload); +void PeerManagerImpl::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) +{ + SetBestBlock(pindexNew->nHeight, std::chrono::seconds{pindexNew->GetBlockTime()}); // Don't relay inventory during initial block download. if (fInitialDownload) return; diff --git a/src/net_processing.h b/src/net_processing.h index 20b30fbddf33..d83a30d0f493 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -230,8 +230,8 @@ class PeerManager : public CValidationInterface, public NetEventsInterface, publ /** Relay recovered sigs to all interested peers */ virtual void RelayRecoveredSig(const llmq::CRecoveredSig& sig, bool proactive_relay) = 0; - /** Set the best height */ - virtual void SetBestHeight(int height) = 0; + /** Set the height of the best block and its time (seconds since epoch). */ + virtual void SetBestBlock(int height, std::chrono::seconds time) = 0; /* Public for unit testing. */ virtual void UnitTestMisbehaving(NodeId peer_id, int howmuch) = 0; @@ -252,6 +252,29 @@ class PeerManager : public CValidationInterface, public NetEventsInterface, publ /** This function is used for testing the stale tip eviction logic, see denialofservice_tests.cpp */ virtual void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) = 0; + /** + * Gets the set of service flags which are "desirable" for a given peer. + * + * These are the flags which are required for a peer to support for them + * to be "interesting" to us, ie for us to wish to use one of our few + * outbound connection slots for or for us to wish to prioritize keeping + * their connection around. + * + * Relevant service flags may be peer- and state-specific in that the + * version of the peer may determine which flags are required (eg in the + * case of NODE_NETWORK_LIMITED where we seek out NODE_NETWORK peers + * unless they set NODE_NETWORK_LIMITED and we are out of IBD, in which + * case NODE_NETWORK_LIMITED suffices). + * + * Thus, generally, avoid calling with 'services' == NODE_NONE, unless + * state-specific flags must absolutely be avoided. When called with + * 'services' == NODE_NONE, the returned desirable service flags are + * guaranteed to not change dependent on state - ie they are suitable for + * use when describing peers which we know to be desirable, but for which + * we do not have a confirmed set of service flags. + */ + virtual ServiceFlags GetDesirableServiceFlags(ServiceFlags services) const = 0; + virtual size_t GetRequestedObjectCount(NodeId nodeid) const = 0; virtual void AddExtraHandler(std::unique_ptr&& handler) = 0; diff --git a/src/protocol.cpp b/src/protocol.cpp index 5b225e3627d6..f27f00bf835b 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -9,8 +9,6 @@ #include -static std::atomic g_initial_block_download_completed(false); - #define MAKE_MSG(var_name, p2p_name_str) \ const char* var_name=p2p_name_str; \ 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. @@ -247,18 +245,6 @@ bool CMessageHeader::IsCommandValid() const return true; } - -ServiceFlags GetDesirableServiceFlags(ServiceFlags services) { - if ((services & NODE_NETWORK_LIMITED) && g_initial_block_download_completed) { - return ServiceFlags(NODE_NETWORK_LIMITED); - } - return ServiceFlags(NODE_NETWORK); -} - -void SetServiceFlagsIBDCache(bool state) { - g_initial_block_download_completed = state; -} - CInv::CInv() { type = 0; diff --git a/src/protocol.h b/src/protocol.h index 754abb35b1a5..c9c8337d9965 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -347,43 +347,12 @@ enum ServiceFlags : uint64_t { std::vector serviceFlagsToStr(uint64_t flags); /** - * Gets the set of service flags which are "desirable" for a given peer. - * - * These are the flags which are required for a peer to support for them - * to be "interesting" to us, ie for us to wish to use one of our few - * outbound connection slots for or for us to wish to prioritize keeping - * their connection around. - * - * Relevant service flags may be peer- and state-specific in that the - * version of the peer may determine which flags are required (eg in the - * case of NODE_NETWORK_LIMITED where we seek out NODE_NETWORK peers - * unless they set NODE_NETWORK_LIMITED and we are out of IBD, in which - * case NODE_NETWORK_LIMITED suffices). - * - * Thus, generally, avoid calling with peerServices == NODE_NONE, unless - * state-specific flags must absolutely be avoided. When called with - * peerServices == NODE_NONE, the returned desirable service flags are - * guaranteed to not change dependent on state - ie they are suitable for - * use when describing peers which we know to be desirable, but for which - * we do not have a confirmed set of service flags. - * - * If the NODE_NONE return value is changed, contrib/seeds/makeseeds.py - * should be updated appropriately to filter for the same nodes. - */ -ServiceFlags GetDesirableServiceFlags(ServiceFlags services); - -/** Set the current IBD status in order to figure out the desirable service flags */ -void SetServiceFlagsIBDCache(bool status); - -/** - * A shortcut for (services & GetDesirableServiceFlags(services)) - * == GetDesirableServiceFlags(services), ie determines whether the given - * set of service flags are sufficient for a peer to be "relevant". - */ -static inline bool HasAllDesirableServiceFlags(ServiceFlags services) -{ - return !(GetDesirableServiceFlags(services) & (~services)); -} + * State independent service flags. + * If the return value is changed, contrib/seeds/makeseeds.py + * should be updated appropriately to filter for nodes with + * desired service flags (compatible with our new flags). + */ +constexpr ServiceFlags SeedsServiceFlags() { return ServiceFlags(NODE_NETWORK); } /** * Checks if a peer with the given service flags may be capable of having a diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index 4f6b0f1ed2ff..eb3f1c308556 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -150,9 +150,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management) constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS; CConnman::Options options; - options.nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; - options.m_max_outbound_full_relay = max_outbound_full_relay; - options.nMaxFeeler = MAX_FEELER_CONNECTIONS; + options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS; const auto time_init{GetTime()}; SetMockTime(time_init); @@ -251,9 +249,7 @@ BOOST_AUTO_TEST_CASE(block_relay_only_eviction) constexpr int max_outbound_block_relay{MAX_BLOCK_RELAY_ONLY_CONNECTIONS}; constexpr int64_t MINIMUM_CONNECT_TIME{30}; CConnman::Options options; - options.nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; - options.m_max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS; - options.m_max_outbound_block_relay = max_outbound_block_relay; + options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS; connman->Init(options); std::vector vNodes; diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp index a98e65c31cf2..52eddddc28a3 100644 --- a/src/test/fs_tests.cpp +++ b/src/test/fs_tests.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include @@ -87,21 +86,6 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream) file >> input_buffer; BOOST_CHECK_EQUAL(input_buffer, "bitcoin"); } - { - fs::path p1 = GetUniquePath(tmpfolder); - fs::path p2 = GetUniquePath(tmpfolder); - fs::path p3 = GetUniquePath(tmpfolder); - - // Ensure that the parent path is always the same. - BOOST_CHECK_EQUAL(tmpfolder, p1.parent_path()); - BOOST_CHECK_EQUAL(tmpfolder, p2.parent_path()); - BOOST_CHECK_EQUAL(tmpfolder, p3.parent_path()); - - // Ensure that generated paths are actually different. - BOOST_CHECK(p1 != p2); - BOOST_CHECK(p2 != p3); - BOOST_CHECK(p1 != p3); - } { // Join an absolute path and a relative path. fs::path p = fsbridge::AbsPathJoin(tmpfolder, fs::u8path("fs_tests_∋_🏃")); @@ -125,8 +109,8 @@ BOOST_AUTO_TEST_CASE(rename) { const fs::path tmpfolder{m_args.GetDataDirBase()}; - const fs::path path1{GetUniquePath(tmpfolder)}; - const fs::path path2{GetUniquePath(tmpfolder)}; + const fs::path path1{tmpfolder / "a"}; + const fs::path path2{tmpfolder / "b"}; const std::string path1_contents{"1111"}; const std::string path2_contents{"2222"}; @@ -161,13 +145,13 @@ BOOST_AUTO_TEST_CASE(create_directories) // Test fs::create_directories workaround. const fs::path tmpfolder{m_args.GetDataDirBase()}; - const fs::path dir{GetUniquePath(tmpfolder)}; + const fs::path dir{tmpfolder / "a"}; fs::create_directory(dir); BOOST_CHECK(fs::exists(dir)); BOOST_CHECK(fs::is_directory(dir)); BOOST_CHECK(!fs::create_directories(dir)); - const fs::path symlink{GetUniquePath(tmpfolder)}; + const fs::path symlink{tmpfolder / "b"}; fs::create_directory_symlink(dir, symlink); BOOST_CHECK(fs::exists(symlink)); BOOST_CHECK(fs::is_symlink(symlink)); diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp index 1084c569a703..dd92c4f56255 100644 --- a/src/test/fuzz/descriptor_parse.cpp +++ b/src/test/fuzz/descriptor_parse.cpp @@ -9,97 +9,7 @@ #include