76#include <initializer_list>
89#include <unordered_set>
216 std::unique_ptr<PartiallyDownloadedBlock> partialBlock;
250 std::atomic<ServiceFlags> m_their_services{
NODE_NONE};
253 const bool m_is_inbound;
256 Mutex m_misbehavior_mutex;
258 bool m_should_discourage
GUARDED_BY(m_misbehavior_mutex){
false};
261 Mutex m_block_inv_mutex;
265 std::vector<uint256> m_blocks_for_inv_relay
GUARDED_BY(m_block_inv_mutex);
269 std::vector<uint256> m_blocks_for_headers_relay
GUARDED_BY(m_block_inv_mutex);
280 std::atomic<uint64_t> m_ping_nonce_sent{0};
284 std::atomic<bool> m_ping_queued{
false};
287 std::atomic<bool> m_wtxid_relay{
false};
299 bool m_relay_txs
GUARDED_BY(m_bloom_filter_mutex){
false};
301 std::unique_ptr<CBloomFilter> m_bloom_filter
PT_GUARDED_BY(m_bloom_filter_mutex)
GUARDED_BY(m_bloom_filter_mutex){
nullptr};
312 std::vector<Wtxid> m_tx_inventory_to_send
GUARDED_BY(m_tx_inventory_mutex);
316 bool m_send_mempool
GUARDED_BY(m_tx_inventory_mutex){
false};
319 std::chrono::microseconds m_next_inv_send_time
GUARDED_BY(m_tx_inventory_mutex){0};
322 uint64_t m_last_inv_sequence
GUARDED_BY(m_tx_inventory_mutex){1};
325 std::atomic<CAmount> m_fee_filter_received{0};
331 LOCK(m_tx_relay_mutex);
333 m_tx_relay = std::make_unique<Peer::TxRelay>();
334 return m_tx_relay.get();
339 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
368 std::atomic_bool m_addr_relay_enabled{
false};
372 mutable Mutex m_addr_send_times_mutex;
374 std::chrono::microseconds m_next_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
376 std::chrono::microseconds m_next_local_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
379 std::atomic_bool m_wants_addrv2{
false};
388 std::atomic<uint64_t> m_addr_rate_limited{0};
390 std::atomic<uint64_t> m_addr_processed{0};
396 Mutex m_getdata_requests_mutex;
398 std::deque<CInv> m_getdata_requests
GUARDED_BY(m_getdata_requests_mutex);
404 Mutex m_headers_sync_mutex;
407 std::unique_ptr<HeadersSyncState> m_headers_sync
PT_GUARDED_BY(m_headers_sync_mutex)
GUARDED_BY(m_headers_sync_mutex) {};
410 std::atomic<bool> m_sent_sendheaders{
false};
420 std::atomic<std::chrono::seconds> m_time_offset{0
s};
424 , m_our_services{our_services}
425 , m_is_inbound{is_inbound}
429 mutable Mutex m_tx_relay_mutex;
432 std::unique_ptr<TxRelay> m_tx_relay
GUARDED_BY(m_tx_relay_mutex);
435using PeerRef = std::shared_ptr<Peer>;
447 uint256 hashLastUnknownBlock{};
453 bool fSyncStarted{
false};
455 std::chrono::microseconds m_stalling_since{0us};
456 std::list<QueuedBlock> vBlocksInFlight;
458 std::chrono::microseconds m_downloading_since{0us};
460 std::chrono::microseconds m_block_download_paused_until{0us};
462 bool fPreferredDownload{
false};
464 bool m_requested_hb_cmpctblocks{
false};
466 bool m_provides_cmpctblocks{
false};
492 struct ChainSyncTimeoutState {
494 std::chrono::seconds m_timeout{0
s};
498 bool m_sent_getheaders{
false};
500 bool m_protect{
false};
503 ChainSyncTimeoutState m_chain_sync;
506 int64_t m_last_block_announcement{0};
509struct InvToSendBucket {
510 const double count_floor{0};
511 std::vector<Wtxid> backlog;
528 static constexpr double SIZE_INIT{12'000'000};
529 static constexpr double SIZE_CAP{50'000'000};
530 static constexpr double SIZE_REFILL{20'000};
532 static constexpr double INBOUND_COUNT_SECONDS{30};
534 InvToSendBucket(
unsigned int rate,
double mult)
536 size_bucket(SIZE_REFILL * mult, SIZE_INIT, SIZE_CAP),
537 count_bucket(rate * mult, rate * INBOUND_COUNT_SECONDS, rate * INBOUND_COUNT_SECONDS)
543 return !backlog.empty() && size_bucket.
value() > 0 && count_bucket.
value() > 0;
554 bool decrement(
double size)
556 bool size_ok = size_bucket.
decrement(size, -50e3);
557 bool count_ok = count_bucket.
decrement(1, count_floor);
558 return size_ok && count_ok;
565 .count_bucket = count_bucket.
value(),
566 .size_bucket = size_bucket.
value(),
597 EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex, !m_inv_to_send_mutex);
599 EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_most_recent_block_mutex, g_msgproc_mutex, !m_tx_download_mutex, !m_inv_to_send_mutex);
614 void SetBestBlock(
int height,
std::chrono::seconds time)
override
616 m_best_height = height;
617 m_best_block_time = time;
625 const std::atomic<bool>& interruptMsgProc)
626 EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex, !m_inv_to_send_mutex);
638 void ReattemptPrivateBroadcast(
CScheduler& scheduler);
653 void Misbehaving(Peer& peer, const
std::
string& message);
664 bool via_compact_block, const
std::
string& message = "")
673 bool MaybeDiscourageAndDisconnect(
CNode& pnode, Peer& peer);
686 bool MaybeDisconnectForTxRelayCapacity(
CNode&
node, const
std::
string& msg_type,
701 bool first_time_failure)
726 bool ProcessOrphanTx(Peer& peer)
736 void ProcessHeadersMessage(
CNode& pfrom, Peer& peer,
738 bool via_compact_block)
769 bool IsContinuationOfLowWorkHeadersSync(Peer& peer,
CNode& pfrom,
783 bool TryLowWorkHeadersSync(Peer& peer,
CNode& pfrom,
798 void HeadersDirectFetchBlocks(
CNode& pfrom, const Peer& peer, const
CBlockIndex& last_header);
800 void UpdatePeerStateForReceivedHeaders(
CNode& pfrom, const
CBlockIndex& last_header,
bool received_new_header,
bool may_have_more_headers)
807 template <
typename... Args>
808 void MakeAndPushMessage(
CNode&
node, std::string msg_type, Args&&...
args)
const
812 template <
typename... Args>
813 [[maybe_unused]]
void MakeAndPushFeature(
CNode&
node, std::string_view feature_id, Args&&...
args)
const
816 std::vector<unsigned char> feature_data;
823 void PushNodeVersion(
CNode& pnode,
const Peer& peer);
874 std::unique_ptr<TxReconciliationTracker> m_txreconciliation;
877 std::atomic<int> m_best_height{-1};
879 std::atomic<std::chrono::seconds> m_best_block_time{0
s};
887 const Options m_opts;
889 bool RejectIncomingTxs(
const CNode& peer)
const;
897 mutable Mutex m_peer_mutex;
904 std::map<NodeId, PeerRef> m_peer_map
GUARDED_BY(m_peer_mutex);
914 uint32_t GetFetchFlags(
const Peer& peer)
const;
916 std::map<uint64_t, std::chrono::microseconds> m_next_inv_to_inbounds_per_network_key
GUARDED_BY(g_msgproc_mutex);
933 std::atomic<int> m_wtxid_relay_peers{0};
951 std::chrono::microseconds NextInvToInbounds(std::chrono::microseconds now,
952 std::chrono::seconds average_interval,
957 Mutex m_most_recent_block_mutex;
958 std::shared_ptr<const CBlock> m_most_recent_block
GUARDED_BY(m_most_recent_block_mutex);
959 std::shared_ptr<const CBlockHeaderAndShortTxIDs> m_most_recent_compact_block
GUARDED_BY(m_most_recent_block_mutex);
961 std::unique_ptr<const std::map<GenTxid, CTransactionRef>> m_most_recent_block_txs
GUARDED_BY(m_most_recent_block_mutex);
965 Mutex m_headers_presync_mutex;
973 using HeadersPresyncStats = std::pair<arith_uint256, std::optional<std::pair<int64_t, uint32_t>>>;
975 std::map<NodeId, HeadersPresyncStats> m_headers_presync_stats
GUARDED_BY(m_headers_presync_mutex) {};
979 std::atomic_bool m_headers_presync_should_signal{
false};
1049 std::atomic<
std::chrono::seconds> m_last_tip_update{0
s};
1055 void ProcessGetData(
CNode& pfrom, Peer& peer,
const std::atomic<bool>& interruptMsgProc)
1060 void ProcessBlock(
CNode&
node,
const std::shared_ptr<const CBlock>& block,
bool force_processing,
bool min_pow_checked);
1093 std::vector<std::pair<Wtxid, CTransactionRef>> vExtraTxnForCompact
GUARDED_BY(g_msgproc_mutex);
1095 size_t vExtraTxnForCompactIt
GUARDED_BY(g_msgproc_mutex) = 0;
1107 int64_t ApproximateBestBlockDepth() const;
1117 void ProcessGetBlockData(
CNode& pfrom, Peer& peer, const
CInv& inv)
1135 bool PrepareBlockFilterRequest(
CNode&
node, Peer& peer,
1137 const
uint256& stop_hash, uint32_t max_height_diff,
1184 void ProcessAddrs(
std::string_view msg_type,
CNode& pfrom, Peer& peer,
std::vector<
CAddress>&& vAddr, const
std::atomic<
bool>& interruptMsgProc)
1190 void LogBlockHeader(const
CBlockIndex& index, const
CNode& peer,
bool via_compact_block);
1196 InvToSendBucket m_inbound_inv_bucket
GUARDED_BY(m_inv_to_send_mutex);
1197 InvToSendBucket m_outbound_inv_bucket
GUARDED_BY(m_inv_to_send_mutex);
1198 std::atomic<
NodeClock::time_point> m_next_inv_bucket_check{NodeClock::time_point::min()};
1199 std::optional<NodeClock::time_point> m_next_inv_bucket_heartbeat
GUARDED_BY(m_inv_to_send_mutex);
1204const CNodeState* PeerManagerImpl::
State(
NodeId pnode)
const
1206 std::map<NodeId, CNodeState>::const_iterator it = m_node_states.find(pnode);
1207 if (it == m_node_states.end())
1214 return const_cast<CNodeState*
>(std::as_const(*this).State(pnode));
1222static bool IsAddrCompatible(
const Peer& peer,
const CAddress& addr)
1227void PeerManagerImpl::AddAddressKnown(Peer& peer,
const CAddress& addr)
1229 assert(peer.m_addr_known);
1230 peer.m_addr_known->insert(addr.
GetKey());
1233void PeerManagerImpl::PushAddress(Peer& peer,
const CAddress& addr)
1238 assert(peer.m_addr_known);
1239 if (addr.
IsValid() && !peer.m_addr_known->contains(addr.
GetKey()) && IsAddrCompatible(peer, addr)) {
1241 peer.m_addrs_to_send[m_rng.randrange(peer.m_addrs_to_send.size())] = addr;
1243 peer.m_addrs_to_send.push_back(addr);
1248static void AddKnownTx(Peer& peer,
const uint256& hash)
1250 auto tx_relay = peer.GetTxRelay();
1251 if (!tx_relay)
return;
1253 LOCK(tx_relay->m_tx_inventory_mutex);
1254 tx_relay->m_tx_inventory_known_filter.insert(hash);
1258static bool CanServeBlocks(
const Peer& peer)
1265static bool IsLimitedPeer(
const Peer& peer)
1272static bool CanServeWitnesses(
const Peer& peer)
1277std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
1278 std::chrono::seconds average_interval,
1279 uint64_t network_key)
1281 auto [it, inserted] = m_next_inv_to_inbounds_per_network_key.try_emplace(network_key, 0us);
1282 auto& timer{it->second};
1284 timer = now + m_rng.rand_exp_duration(average_interval);
1289bool PeerManagerImpl::IsBlockRequested(
const uint256& hash)
1291 return mapBlocksInFlight.contains(hash);
1294bool PeerManagerImpl::IsBlockRequestedFromOutbound(
const uint256& hash)
1296 for (
auto range = mapBlocksInFlight.equal_range(hash); range.first != range.second; range.first++) {
1297 auto [nodeid, block_it] = range.first->second;
1298 PeerRef peer{GetPeerRef(nodeid)};
1299 if (peer && !peer->m_is_inbound)
return true;
1305void PeerManagerImpl::RemoveBlockRequest(
const uint256& hash, std::optional<NodeId> from_peer)
1307 auto range = mapBlocksInFlight.equal_range(hash);
1308 if (range.first == range.second) {
1316 while (range.first != range.second) {
1317 const auto& [node_id, list_it]{range.first->second};
1319 if (from_peer && *from_peer != node_id) {
1326 if (state.vBlocksInFlight.begin() == list_it) {
1328 state.m_downloading_since = std::max(state.m_downloading_since, GetTime<std::chrono::microseconds>());
1330 state.vBlocksInFlight.erase(list_it);
1332 if (state.vBlocksInFlight.empty()) {
1334 m_peers_downloading_from--;
1336 state.m_stalling_since = 0us;
1338 range.first = mapBlocksInFlight.erase(range.first);
1342bool PeerManagerImpl::BlockRequested(
NodeId nodeid,
const CBlockIndex& block, std::list<QueuedBlock>::iterator** pit)
1346 CNodeState *state =
State(nodeid);
1347 assert(state !=
nullptr);
1352 for (
auto range = mapBlocksInFlight.equal_range(hash); range.first != range.second; range.first++) {
1353 if (range.first->second.first == nodeid) {
1355 *pit = &range.first->second.second;
1362 RemoveBlockRequest(hash, nodeid);
1364 std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(),
1365 {&block, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock(&m_mempool) : nullptr)});
1366 if (state->vBlocksInFlight.size() == 1) {
1368 state->m_downloading_since = GetTime<std::chrono::microseconds>();
1369 m_peers_downloading_from++;
1371 auto itInFlight = mapBlocksInFlight.insert(std::make_pair(hash, std::make_pair(nodeid, it)));
1373 *pit = &itInFlight->second.second;
1378void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid)
1385 if (m_opts.ignore_incoming_txs)
return;
1387 CNodeState* nodestate =
State(nodeid);
1388 PeerRef peer{GetPeerRef(nodeid)};
1389 if (!nodestate || !nodestate->m_provides_cmpctblocks) {
1394 int num_outbound_hb_peers = 0;
1395 for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin(); it != lNodesAnnouncingHeaderAndIDs.end(); it++) {
1396 if (*it == nodeid) {
1397 lNodesAnnouncingHeaderAndIDs.erase(it);
1398 lNodesAnnouncingHeaderAndIDs.push_back(nodeid);
1401 PeerRef peer_ref{GetPeerRef(*it)};
1402 if (peer_ref && !peer_ref->m_is_inbound) ++num_outbound_hb_peers;
1404 if (peer && peer->m_is_inbound) {
1407 if (lNodesAnnouncingHeaderAndIDs.size() >= 3 && num_outbound_hb_peers == 1) {
1408 PeerRef remove_peer{GetPeerRef(lNodesAnnouncingHeaderAndIDs.front())};
1409 if (remove_peer && !remove_peer->m_is_inbound) {
1412 std::swap(lNodesAnnouncingHeaderAndIDs.front(), *std::next(lNodesAnnouncingHeaderAndIDs.begin()));
1421 lNodesAnnouncingHeaderAndIDs.push_back(pfrom->
GetId());
1424 if (nodeid_was_appended && lNodesAnnouncingHeaderAndIDs.size() > 3) {
1427 m_connman.
ForNode(lNodesAnnouncingHeaderAndIDs.front(), [
this](
CNode* pnodeStop) {
1430 pnodeStop->m_bip152_highbandwidth_to =
false;
1433 lNodesAnnouncingHeaderAndIDs.pop_front();
1437bool PeerManagerImpl::TipMayBeStale()
1441 if (m_last_tip_update.load() == 0
s) {
1442 m_last_tip_update = GetTime<std::chrono::seconds>();
1444 return m_last_tip_update.load() < GetTime<std::chrono::seconds>() - std::chrono::seconds{consensusParams.
nPowTargetSpacing * 3} && mapBlocksInFlight.empty();
1447int64_t PeerManagerImpl::ApproximateBestBlockDepth()
const
1452bool PeerManagerImpl::CanDirectFetch()
1459 if (state->pindexBestKnownBlock && pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight))
1461 if (state->pindexBestHeaderSent && pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight))
1466void PeerManagerImpl::ProcessBlockAvailability(
NodeId nodeid) {
1467 CNodeState *state =
State(nodeid);
1468 assert(state !=
nullptr);
1470 if (!state->hashLastUnknownBlock.IsNull()) {
1473 if (state->pindexBestKnownBlock ==
nullptr || pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
1474 state->pindexBestKnownBlock = pindex;
1476 state->hashLastUnknownBlock.SetNull();
1481void PeerManagerImpl::UpdateBlockAvailability(
NodeId nodeid,
const uint256 &hash) {
1482 CNodeState *state =
State(nodeid);
1483 assert(state !=
nullptr);
1485 ProcessBlockAvailability(nodeid);
1490 if (state->pindexBestKnownBlock ==
nullptr || pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
1491 state->pindexBestKnownBlock = pindex;
1495 state->hashLastUnknownBlock = hash;
1500void PeerManagerImpl::FindNextBlocksToDownload(
const Peer& peer,
unsigned int count, std::vector<const CBlockIndex*>& vBlocks,
NodeId& nodeStaller)
1505 vBlocks.reserve(vBlocks.size() +
count);
1506 CNodeState *state =
State(peer.m_id);
1507 assert(state !=
nullptr);
1510 ProcessBlockAvailability(peer.m_id);
1512 if (state->pindexBestKnownBlock ==
nullptr || state->pindexBestKnownBlock->nChainWork < m_chainman.
ActiveChain().
Tip()->
nChainWork || state->pindexBestKnownBlock->nChainWork < m_chainman.
MinimumChainWork()) {
1523 state->pindexBestKnownBlock->GetAncestor(snap_base->nHeight) != snap_base) {
1524 LogDebug(
BCLog::NET,
"Not downloading blocks from peer=%d, which doesn't have the snapshot block in its best chain.\n", peer.m_id);
1533 if (state->pindexLastCommonBlock ==
nullptr ||
1534 fork_point->nChainWork > state->pindexLastCommonBlock->nChainWork ||
1535 state->pindexBestKnownBlock->GetAncestor(state->pindexLastCommonBlock->nHeight) != state->pindexLastCommonBlock) {
1536 state->pindexLastCommonBlock = fork_point;
1538 if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)
1541 const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
1547 FindNextBlocks(vBlocks, peer, state, pindexWalk,
count, nWindowEnd, &m_chainman.
ActiveChain(), &nodeStaller);
1550void PeerManagerImpl::TryDownloadingHistoricalBlocks(
const Peer& peer,
unsigned int count, std::vector<const CBlockIndex*>& vBlocks,
const CBlockIndex *from_tip,
const CBlockIndex* target_block)
1555 if (vBlocks.size() >=
count) {
1559 vBlocks.reserve(
count);
1562 if (state->pindexBestKnownBlock ==
nullptr || state->pindexBestKnownBlock->GetAncestor(target_block->
nHeight) != target_block) {
1579void PeerManagerImpl::FindNextBlocks(std::vector<const CBlockIndex*>& vBlocks,
const Peer& peer, CNodeState *state,
const CBlockIndex *pindexWalk,
unsigned int count,
int nWindowEnd,
const CChain* activeChain,
NodeId* nodeStaller)
1581 std::vector<const CBlockIndex*> vToFetch;
1582 int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
1583 bool is_limited_peer = IsLimitedPeer(peer);
1585 while (pindexWalk->
nHeight < nMaxHeight) {
1589 int nToFetch = std::min(nMaxHeight - pindexWalk->
nHeight, std::max<int>(
count - vBlocks.size(), 128));
1590 vToFetch.resize(nToFetch);
1591 pindexWalk = state->pindexBestKnownBlock->
GetAncestor(pindexWalk->
nHeight + nToFetch);
1592 vToFetch[nToFetch - 1] = pindexWalk;
1593 for (
unsigned int i = nToFetch - 1; i > 0; i--) {
1594 vToFetch[i - 1] = vToFetch[i]->
pprev;
1614 state->pindexLastCommonBlock = pindex;
1621 if (waitingfor == -1) {
1623 waitingfor = mapBlocksInFlight.lower_bound(pindex->
GetBlockHash())->second.first;
1629 if (pindex->
nHeight > nWindowEnd) {
1631 if (vBlocks.size() == 0 && waitingfor != peer.m_id) {
1633 if (nodeStaller) *nodeStaller = waitingfor;
1643 vBlocks.push_back(pindex);
1644 if (vBlocks.size() ==
count) {
1653void PeerManagerImpl::PushNodeVersion(
CNode& pnode,
const Peer& peer)
1655 uint64_t my_services;
1657 uint64_t your_services;
1659 std::string my_user_agent;
1667 my_user_agent =
"/pynode:0.0.1/";
1669 my_tx_relay =
false;
1672 my_services = peer.m_our_services;
1673 my_time = TicksSinceEpoch<std::chrono::seconds>(
NodeClock::now());
1677 my_height = m_best_height;
1678 my_tx_relay = !RejectIncomingTxs(pnode);
1697 BCLog::NET,
"send version message: version=%d, blocks=%d%s, txrelay=%d, peer=%d\n",
1700 my_tx_relay, pnode.
GetId());
1703void PeerManagerImpl::UpdateLastBlockAnnounceTime(
NodeId node, int64_t time_in_seconds)
1707 if (state) state->m_last_block_announcement = time_in_seconds;
1715 m_node_states.try_emplace(m_node_states.end(), nodeid);
1717 WITH_LOCK(m_tx_download_mutex, m_txdownloadman.CheckIsEmpty(nodeid));
1723 PeerRef peer = std::make_shared<Peer>(nodeid, our_services,
node.IsInboundConn());
1726 m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer);
1730void PeerManagerImpl::ReattemptInitialBroadcast(
CScheduler& scheduler)
1734 for (
const auto& txid : unbroadcast_txids) {
1737 if (tx !=
nullptr) {
1738 InitiateTxBroadcastToAll(tx->GetWitnessHash());
1747 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
1750void PeerManagerImpl::ReattemptPrivateBroadcast(
CScheduler& scheduler)
1754 size_t num_for_rebroadcast{0};
1755 const auto stale_txs = m_tx_for_private_broadcast.GetStale();
1756 if (!stale_txs.empty()) {
1757 for (
const auto& stale_tx : stale_txs) {
1763 "Reattempting broadcast of stale txid=%s wtxid=%s",
1764 stale_tx->GetHash().ToString(), stale_tx->GetWitnessHash().ToString());
1765 ++num_for_rebroadcast;
1768 stale_tx->GetHash().ToString(), stale_tx->GetWitnessHash().ToString(),
1769 mempool_acceptable.m_state.ToString());
1770 m_tx_for_private_broadcast.Remove(stale_tx);
1779 scheduler.
scheduleFromNow([&] { ReattemptPrivateBroadcast(scheduler); }, delta);
1782void PeerManagerImpl::FinalizeNode(
const CNode&
node)
1793 PeerRef peer = RemovePeer(nodeid);
1795 m_wtxid_relay_peers -= peer->m_wtxid_relay;
1796 assert(m_wtxid_relay_peers >= 0);
1798 CNodeState *state =
State(nodeid);
1799 assert(state !=
nullptr);
1801 if (state->fSyncStarted)
1804 for (
const QueuedBlock& entry : state->vBlocksInFlight) {
1805 auto range = mapBlocksInFlight.equal_range(entry.pindex->GetBlockHash());
1806 while (range.first != range.second) {
1807 auto [node_id, list_it] = range.first->second;
1808 if (node_id != nodeid) {
1811 range.first = mapBlocksInFlight.erase(range.first);
1816 LOCK(m_tx_download_mutex);
1817 m_txdownloadman.DisconnectedPeer(nodeid);
1819 if (m_txreconciliation) m_txreconciliation->ForgetPeer(nodeid);
1820 m_num_preferred_download_peers -= state->fPreferredDownload;
1821 m_peers_downloading_from -= (!state->vBlocksInFlight.empty());
1822 assert(m_peers_downloading_from >= 0);
1823 m_outbound_peers_with_protect_from_disconnect -= state->m_chain_sync.m_protect;
1824 assert(m_outbound_peers_with_protect_from_disconnect >= 0);
1826 m_node_states.erase(nodeid);
1828 if (m_node_states.empty()) {
1830 assert(mapBlocksInFlight.empty());
1831 assert(m_num_preferred_download_peers == 0);
1832 assert(m_peers_downloading_from == 0);
1833 assert(m_outbound_peers_with_protect_from_disconnect == 0);
1834 assert(m_wtxid_relay_peers == 0);
1835 WITH_LOCK(m_tx_download_mutex, m_txdownloadman.CheckIsEmpty());
1838 if (
node.fSuccessfullyConnected &&
1839 !
node.IsBlockOnlyConn() && !
node.IsPrivateBroadcastConn() && !
node.IsInboundConn()) {
1847 LOCK(m_headers_presync_mutex);
1848 m_headers_presync_stats.erase(nodeid);
1850 if (
node.IsPrivateBroadcastConn() &&
1851 !m_tx_for_private_broadcast.DidNodeConfirmReception(nodeid) &&
1852 m_tx_for_private_broadcast.HavePendingTransactions()) {
1859bool PeerManagerImpl::HasAllDesirableServiceFlags(
ServiceFlags services)
const
1862 return !(GetDesirableServiceFlags(services) & (~services));
1876PeerRef PeerManagerImpl::GetPeerRef(
NodeId id)
const
1879 auto it = m_peer_map.find(
id);
1880 return it != m_peer_map.end() ? it->second :
nullptr;
1883PeerRef PeerManagerImpl::RemovePeer(
NodeId id)
1887 auto it = m_peer_map.find(
id);
1888 if (it != m_peer_map.end()) {
1889 ret = std::move(it->second);
1890 m_peer_map.erase(it);
1895std::vector<PeerRef> PeerManagerImpl::GetAllPeers()
const
1897 std::vector<PeerRef> peers;
1899 peers.reserve(m_peer_map.size());
1900 for (
const auto& [
_, peer] : m_peer_map) {
1901 peers.push_back(peer);
1910 const CNodeState* state =
State(nodeid);
1911 if (state ==
nullptr)
1913 stats.
nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1;
1914 stats.
nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1;
1915 for (
const QueuedBlock& queue : state->vBlocksInFlight) {
1921 PeerRef peer = GetPeerRef(nodeid);
1922 if (peer ==
nullptr)
return false;
1930 NodeClock::duration ping_wait{0us};
1931 if ((0 != peer->m_ping_nonce_sent) && (peer->m_ping_start.load() >
NodeClock::epoch)) {
1935 if (
auto tx_relay = peer->GetTxRelay(); tx_relay !=
nullptr) {
1938 LOCK(tx_relay->m_tx_inventory_mutex);
1940 stats.
m_inv_to_send = tx_relay->m_tx_inventory_to_send.size();
1952 LOCK(peer->m_headers_sync_mutex);
1953 if (peer->m_headers_sync) {
1962std::vector<node::TxOrphanage::OrphanInfo> PeerManagerImpl::GetOrphanTransactions()
1964 LOCK(m_tx_download_mutex);
1965 return m_txdownloadman.GetOrphanTransactions();
1970 LOCK(m_inv_to_send_mutex);
1973 .ignores_incoming_txs = m_opts.ignore_incoming_txs,
1974 .private_broadcast = m_opts.private_broadcast,
1975 .tx_send_rate = m_opts.tx_send_rate,
1976 .inbound_bucket = m_inbound_inv_bucket.info(),
1977 .outbound_bucket = m_outbound_inv_bucket.info(),
1981std::vector<PrivateBroadcast::TxBroadcastInfo> PeerManagerImpl::GetPrivateBroadcastInfo()
const
1983 return m_tx_for_private_broadcast.GetBroadcastInfo();
1986std::vector<CTransactionRef> PeerManagerImpl::AbortPrivateBroadcast(
const uint256&
id)
1988 const auto snapshot{m_tx_for_private_broadcast.GetBroadcastInfo()};
1989 std::vector<CTransactionRef> removed_txs;
1991 size_t connections_cancelled{0};
1992 for (
const auto& tx_info : snapshot) {
1994 if (tx->GetHash().ToUint256() !=
id && tx->GetWitnessHash().ToUint256() !=
id)
continue;
1995 if (
const auto peer_acks{m_tx_for_private_broadcast.Remove(tx)}) {
1996 removed_txs.push_back(tx);
2007void PeerManagerImpl::AddToCompactExtraTransactions(
const CTransactionRef& tx)
2009 if (m_opts.max_extra_txs == 0)
return;
2010 if (vExtraTxnForCompact.size() < m_opts.max_extra_txs) {
2011 if (vExtraTxnForCompact.empty()) vExtraTxnForCompact.reserve(m_opts.max_extra_txs);
2012 vExtraTxnForCompact.emplace_back(tx->GetWitnessHash(), tx);
2014 vExtraTxnForCompact[vExtraTxnForCompactIt] = std::make_pair(tx->GetWitnessHash(), tx);
2016 vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
2019void PeerManagerImpl::Misbehaving(Peer& peer,
const std::string& message)
2021 LOCK(peer.m_misbehavior_mutex);
2023 const std::string message_prefixed = message.empty() ?
"" : (
": " + message);
2024 peer.m_should_discourage =
true;
2033 bool via_compact_block,
const std::string& message)
2035 PeerRef peer{GetPeerRef(nodeid)};
2046 if (!via_compact_block) {
2047 if (peer) Misbehaving(*peer, message);
2055 if (peer && !via_compact_block && !peer->m_is_inbound) {
2056 if (peer) Misbehaving(*peer, message);
2063 if (peer) Misbehaving(*peer, message);
2067 if (peer) Misbehaving(*peer, message);
2072 if (message !=
"") {
2077bool PeerManagerImpl::BlockRequestAllowed(
const CBlockIndex& block_index)
2097 PeerRef peer = GetPeerRef(peer_id);
2104 RemoveBlockRequest(block_index.
GetBlockHash(), std::nullopt);
2107 if (!BlockRequested(peer_id, block_index))
return util::Unexpected{
"Already requested from this peer"};
2130 return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman, pool, warnings, opts);
2136 : m_rng{opts.deterministic_rng},
2138 m_chainparams(chainman.GetParams()),
2142 m_chainman(chainman),
2144 m_txdownloadman{
node::TxDownloadOptions{pool, opts.deterministic_rng}},
2145 m_warnings{warnings},
2147 m_inbound_inv_bucket(m_opts.tx_send_rate, 1.0),
2152 if (opts.reconcile_txs) {
2157void PeerManagerImpl::StartScheduledTasks(
CScheduler& scheduler)
2168 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
2170 if (m_opts.private_broadcast) {
2171 scheduler.
scheduleFromNow([&] { ReattemptPrivateBroadcast(scheduler); }, 0min);
2175void PeerManagerImpl::ActiveTipChange(
const CBlockIndex& new_tip,
bool is_ibd)
2183 LOCK(m_tx_download_mutex);
2187 m_txdownloadman.ActiveTipChange();
2197void PeerManagerImpl::BlockConnected(
2199 const std::shared_ptr<const CBlock>& pblock,
2204 m_last_tip_update = GetTime<std::chrono::seconds>();
2207 auto stalling_timeout = m_block_stalling_timeout.load();
2211 if (m_block_stalling_timeout.compare_exchange_strong(stalling_timeout, new_timeout)) {
2220 LOCK(m_tx_download_mutex);
2221 m_txdownloadman.BlockConnected(pblock);
2225void PeerManagerImpl::BlockDisconnected(
const std::shared_ptr<const CBlock> &block,
const CBlockIndex* pindex)
2227 LOCK(m_tx_download_mutex);
2228 m_txdownloadman.BlockDisconnected();
2235void PeerManagerImpl::NewPoWValidBlock(
const CBlockIndex *pindex,
const std::shared_ptr<const CBlock>& pblock)
2237 auto pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs>(*pblock,
FastRandomContext().rand64());
2241 if (pindex->
nHeight <= m_highest_fast_announce)
2243 m_highest_fast_announce = pindex->
nHeight;
2247 uint256 hashBlock(pblock->GetHash());
2248 const std::shared_future<CSerializedNetMsg> lazy_ser{
2252 auto most_recent_block_txs = std::make_unique<std::map<GenTxid, CTransactionRef>>();
2253 for (
const auto& tx : pblock->vtx) {
2254 most_recent_block_txs->emplace(tx->GetHash(), tx);
2255 most_recent_block_txs->emplace(tx->GetWitnessHash(), tx);
2258 LOCK(m_most_recent_block_mutex);
2259 m_most_recent_block_hash = hashBlock;
2260 m_most_recent_block = pblock;
2261 m_most_recent_compact_block = pcmpctblock;
2262 m_most_recent_block_txs = std::move(most_recent_block_txs);
2270 ProcessBlockAvailability(pnode->
GetId());
2274 if (state.m_requested_hb_cmpctblocks && !PeerHasHeader(&state, pindex) && PeerHasHeader(&state, pindex->
pprev)) {
2276 LogDebug(
BCLog::NET,
"%s sending header-and-ids %s to peer=%d\n",
"PeerManager::NewPoWValidBlock",
2277 hashBlock.ToString(), pnode->
GetId());
2280 PushMessage(*pnode, ser_cmpctblock.Copy());
2281 state.pindexBestHeaderSent = pindex;
2290void PeerManagerImpl::UpdatedBlockTip(
const CBlockIndex *pindexNew,
const CBlockIndex *pindexFork,
bool fInitialDownload)
2292 SetBestBlock(pindexNew->
nHeight, std::chrono::seconds{pindexNew->GetBlockTime()});
2295 if (fInitialDownload)
return;
2298 std::vector<uint256> vHashes;
2300 while (pindexToAnnounce != pindexFork) {
2302 pindexToAnnounce = pindexToAnnounce->
pprev;
2312 for (
auto& it : m_peer_map) {
2313 Peer& peer = *it.second;
2314 LOCK(peer.m_block_inv_mutex);
2315 for (
const uint256& hash : vHashes | std::views::reverse) {
2316 peer.m_blocks_for_headers_relay.push_back(hash);
2328void PeerManagerImpl::BlockChecked(
const std::shared_ptr<const CBlock>& block,
const BlockValidationState& state)
2332 const uint256 hash(block->GetHash());
2333 std::map<uint256, std::pair<NodeId, bool>>::iterator it = mapBlockSource.find(hash);
2338 it != mapBlockSource.end() &&
2339 State(it->second.first)) {
2340 MaybePunishNodeForBlock( it->second.first, state, !it->second.second);
2350 mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
2351 if (it != mapBlockSource.end()) {
2352 MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
2355 if (it != mapBlockSource.end())
2356 mapBlockSource.erase(it);
2364bool PeerManagerImpl::AlreadyHaveBlock(
const uint256& block_hash)
2369void PeerManagerImpl::SendPings()
2372 for(
auto& it : m_peer_map) it.second->m_ping_queued =
true;
2375std::vector<Wtxid> InvToSendBucket::TakeForProcessing(
CTxMemPool& mempool)
2379 size_t n_to_take =
static_cast<size_t>(std::max<double>(count_bucket.
value() - count_floor, 0));
2381 std::vector<Wtxid> best;
2384 bool tokens_left =
true;
2385 for (
auto txiter : itervec) {
2386 auto& wtxid = txiter->GetTx().GetWitnessHash();
2388 best.push_back(wtxid);
2389 if (!decrement(txiter->GetTx().ComputeTotalSize())) {
2390 tokens_left =
false;
2393 backlog.push_back(wtxid);
2399 std::vector<Wtxid> dummy;
2401 dummy.swap(backlog);
2411 if (!backlog_bumped && now <= m_next_inv_bucket_check.load())
return;
2414 LOCK(m_inv_to_send_mutex);
2415 m_inbound_inv_bucket.increment(now);
2416 m_outbound_inv_bucket.increment(now);
2419 if (!m_next_inv_bucket_heartbeat.has_value()) {
2421 m_next_inv_bucket_heartbeat = now;
2424 if (m_next_inv_bucket_heartbeat.has_value() && now >= *m_next_inv_bucket_heartbeat) {
2425 LogDebug(
BCLog::NET,
"Transaction rate-limiting backlog inbound=%d itok=%.1f isz=%.1f outbound=%d otok=%.1f osz=%.1f",
2426 m_inbound_inv_bucket.backlog.size(),
2427 m_inbound_inv_bucket.count_bucket.value(),
2428 m_inbound_inv_bucket.size_bucket.value(),
2429 m_outbound_inv_bucket.backlog.size(),
2430 m_outbound_inv_bucket.count_bucket.value(),
2431 m_outbound_inv_bucket.size_bucket.value());
2432 if (m_inbound_inv_bucket.backlog.empty() && m_outbound_inv_bucket.backlog.empty()) {
2433 m_next_inv_bucket_heartbeat = std::nullopt;
2440 bool in_avail = m_inbound_inv_bucket.avail();
2441 bool out_avail = m_outbound_inv_bucket.avail();
2442 if (!in_avail && !out_avail)
return;
2444 std::vector<Wtxid> for_inbound;
2445 std::vector<Wtxid> for_outbound;
2449 if (in_avail) for_inbound = m_inbound_inv_bucket.TakeForProcessing(m_mempool);
2450 if (out_avail) for_outbound = m_outbound_inv_bucket.TakeForProcessing(m_mempool);
2453 if (!for_inbound.empty() || !for_outbound.empty()) {
2454 bool any_inbound_connected =
false;
2455 bool any_outbound_connected =
false;
2456 for (
const PeerRef& peer_ref : GetAllPeers()) {
2457 if (!peer_ref)
continue;
2458 Peer& peer{*peer_ref};
2459 auto tx_relay = peer.GetTxRelay();
2460 if (!tx_relay)
continue;
2462 LOCK(tx_relay->m_tx_inventory_mutex);
2468 if (tx_relay->m_next_inv_send_time == 0
s)
continue;
2469 if (peer.m_is_inbound) {
2470 any_inbound_connected =
true;
2472 any_outbound_connected =
true;
2474 for (
auto& i : (peer.m_is_inbound ? for_inbound : for_outbound)) {
2475 tx_relay->m_tx_inventory_to_send.push_back(i);
2482 if (!any_inbound_connected) m_inbound_inv_bucket.backlog.clear();
2483 if (!any_outbound_connected) m_outbound_inv_bucket.backlog.clear();
2487void PeerManagerImpl::InitiateTxBroadcastToAll(
const Wtxid& wtxid)
2490 LOCK(m_inv_to_send_mutex);
2491 m_inbound_inv_bucket.backlog.push_back(wtxid);
2492 m_outbound_inv_bucket.backlog.push_back(wtxid);
2499 const auto txstr{
strprintf(
"txid=%s, wtxid=%s", tx->GetHash().ToString(), tx->GetWitnessHash().ToString())};
2500 switch (m_tx_for_private_broadcast.Add(tx)) {
2515void PeerManagerImpl::RelayAddress(
NodeId originator,
2531 const auto current_time{GetTime<std::chrono::seconds>()};
2539 unsigned int nRelayNodes = (fReachable || (hasher.Finalize() & 1)) ? 2 : 1;
2541 std::array<std::pair<uint64_t, Peer*>, 2> best{{{0,
nullptr}, {0,
nullptr}}};
2542 assert(nRelayNodes <= best.size());
2546 for (
auto& [
id, peer] : m_peer_map) {
2547 if (peer->m_addr_relay_enabled &&
id != originator && IsAddrCompatible(*peer, addr)) {
2549 for (
unsigned int i = 0; i < nRelayNodes; i++) {
2550 if (hashKey > best[i].first) {
2551 std::copy(best.begin() + i, best.begin() + nRelayNodes - 1, best.begin() + i + 1);
2552 best[i] = std::make_pair(hashKey, peer.get());
2559 for (
unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
2560 PushAddress(*best[i].second, addr);
2564void PeerManagerImpl::ProcessGetBlockData(
CNode& pfrom, Peer& peer,
const CInv& inv)
2574 std::shared_ptr<const CBlock> a_recent_block;
2575 std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
2577 LOCK(m_most_recent_block_mutex);
2578 a_recent_block = m_most_recent_block;
2579 a_recent_compact_block = m_most_recent_compact_block;
2582 bool need_activate_chain =
false;
2594 need_activate_chain =
true;
2598 if (need_activate_chain) {
2600 if (!m_chainman.
ActiveChainstate().ActivateBestChain(state, a_recent_block)) {
2607 bool can_direct_fetch{
false};
2615 if (!BlockRequestAllowed(*pindex)) {
2616 LogDebug(
BCLog::NET,
"%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom.
GetId());
2643 can_direct_fetch = CanDirectFetch();
2647 std::shared_ptr<const CBlock> pblock;
2648 if (a_recent_block && a_recent_block->GetHash() == inv.
hash) {
2649 pblock = a_recent_block;
2667 std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
2677 pblock = pblockRead;
2685 bool sendMerkleBlock =
false;
2687 if (
auto tx_relay = peer.GetTxRelay(); tx_relay !=
nullptr) {
2688 LOCK(tx_relay->m_bloom_filter_mutex);
2689 if (tx_relay->m_bloom_filter) {
2690 sendMerkleBlock =
true;
2691 merkleBlock =
CMerkleBlock(*pblock, *tx_relay->m_bloom_filter);
2694 if (sendMerkleBlock) {
2702 for (
const auto& [tx_idx,
_] : merkleBlock.
vMatchedTxn)
2713 if (a_recent_compact_block && a_recent_compact_block->header.GetHash() == inv.
hash) {
2726 LOCK(peer.m_block_inv_mutex);
2728 if (inv.
hash == peer.m_continuation_block) {
2732 std::vector<CInv> vInv;
2733 vInv.emplace_back(
MSG_BLOCK, tip->GetBlockHash());
2735 peer.m_continuation_block.SetNull();
2743 auto txinfo{std::visit(
2744 [&](
const auto&
id) {
2745 return m_mempool.
info_for_relay(
id,
WITH_LOCK(tx_relay.m_tx_inventory_mutex,
return tx_relay.m_last_inv_sequence));
2749 return std::move(txinfo.tx);
2754 LOCK(m_most_recent_block_mutex);
2755 if (m_most_recent_block_txs !=
nullptr) {
2756 auto it = m_most_recent_block_txs->find(gtxid);
2757 if (it != m_most_recent_block_txs->end())
return it->second;
2764void PeerManagerImpl::ProcessGetData(
CNode& pfrom, Peer& peer,
const std::atomic<bool>& interruptMsgProc)
2768 auto tx_relay = peer.GetTxRelay();
2770 std::deque<CInv>::iterator it = peer.m_getdata_requests.begin();
2771 std::vector<CInv> vNotFound;
2776 while (it != peer.m_getdata_requests.end() && it->IsGenTxMsg()) {
2777 if (interruptMsgProc)
return;
2782 const CInv &inv = *it++;
2784 if (tx_relay ==
nullptr) {
2790 if (
auto tx{FindTxForGetData(*tx_relay,
ToGenTxid(inv))}) {
2793 MakeAndPushMessage(pfrom,
NetMsgType::TX, maybe_with_witness(*tx));
2796 vNotFound.push_back(inv);
2802 if (it != peer.m_getdata_requests.end() && !pfrom.
fPauseSend) {
2803 const CInv &inv = *it++;
2805 ProcessGetBlockData(pfrom, peer, inv);
2814 peer.m_getdata_requests.erase(peer.m_getdata_requests.begin(), it);
2816 if (!vNotFound.empty()) {
2835uint32_t PeerManagerImpl::GetFetchFlags(
const Peer& peer)
const
2837 uint32_t nFetchFlags = 0;
2838 if (CanServeWitnesses(peer)) {
2847 for (
size_t i = 0; i < req.
indexes.size(); i++) {
2849 Misbehaving(peer,
"getblocktxn with out-of-bounds tx indices");
2856 uint32_t tx_requested_size{0};
2857 for (
const auto& tx : resp.txn) tx_requested_size += tx->ComputeTotalSize();
2863bool PeerManagerImpl::CheckHeadersPoW(
const std::vector<CBlockHeader>&
headers, Peer& peer)
2867 Misbehaving(peer,
"header with invalid proof of work");
2872 if (!CheckHeadersAreContinuous(
headers)) {
2873 Misbehaving(peer,
"non-continuous headers sequence");
2898void PeerManagerImpl::HandleUnconnectingHeaders(
CNode& pfrom, Peer& peer,
2899 const std::vector<CBlockHeader>&
headers)
2903 if (MaybeSendGetHeaders(pfrom,
GetLocator(best_header), peer)) {
2904 LogDebug(
BCLog::NET,
"received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d)\n",
2906 headers[0].hashPrevBlock.ToString(),
2907 best_header->nHeight,
2917bool PeerManagerImpl::CheckHeadersAreContinuous(
const std::vector<CBlockHeader>&
headers)
const
2921 if (!hashLastBlock.
IsNull() && header.hashPrevBlock != hashLastBlock) {
2924 hashLastBlock = header.GetHash();
2929bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(Peer& peer,
CNode& pfrom, std::vector<CBlockHeader>&
headers)
2931 if (peer.m_headers_sync) {
2932 auto result = peer.m_headers_sync->ProcessNextHeaders(
headers,
headers.size() == m_opts.max_headers_result);
2934 if (result.success) peer.m_last_getheaders_timestamp = {};
2935 if (result.request_more) {
2936 auto locator = peer.m_headers_sync->NextHeadersRequestLocator();
2938 Assume(!locator.vHave.empty());
2941 if (!locator.vHave.empty()) {
2944 bool sent_getheaders = MaybeSendGetHeaders(pfrom, locator, peer);
2947 locator.vHave.front().ToString(), pfrom.
GetId());
2952 peer.m_headers_sync.reset(
nullptr);
2957 LOCK(m_headers_presync_mutex);
2958 m_headers_presync_stats.erase(pfrom.
GetId());
2961 HeadersPresyncStats stats;
2962 stats.first = peer.m_headers_sync->GetPresyncWork();
2964 stats.second = {peer.m_headers_sync->GetPresyncHeight(),
2965 peer.m_headers_sync->GetPresyncTime()};
2969 LOCK(m_headers_presync_mutex);
2970 m_headers_presync_stats[pfrom.
GetId()] = stats;
2971 auto best_it = m_headers_presync_stats.find(m_headers_presync_bestpeer);
2972 bool best_updated =
false;
2973 if (best_it == m_headers_presync_stats.end()) {
2977 const HeadersPresyncStats* stat_best{
nullptr};
2978 for (
const auto& [peer, stat] : m_headers_presync_stats) {
2979 if (!stat_best || stat > *stat_best) {
2984 m_headers_presync_bestpeer = peer_best;
2985 best_updated = (peer_best == pfrom.
GetId());
2986 }
else if (best_it->first == pfrom.
GetId() || stats > best_it->second) {
2988 m_headers_presync_bestpeer = pfrom.
GetId();
2989 best_updated =
true;
2991 if (best_updated && stats.second.has_value()) {
2993 m_headers_presync_should_signal =
true;
2997 if (result.success) {
3000 headers.swap(result.pow_validated_headers);
3003 return result.success;
3011bool PeerManagerImpl::TryLowWorkHeadersSync(Peer& peer,
CNode& pfrom,
const CBlockIndex& chain_start_header, std::vector<CBlockHeader>&
headers)
3018 arith_uint256 minimum_chain_work = GetAntiDoSWorkThreshold();
3022 if (total_work < minimum_chain_work) {
3026 if (
headers.size() == m_opts.max_headers_result) {
3036 LOCK(peer.m_headers_sync_mutex);
3039 m_chainparams.
HeadersSync(), chain_start_header, minimum_chain_work));
3045 const auto msg{
strprintf(
"Failure when attempting to initiate headers sync: %s", e.what())};
3046 std::cerr <<
msg << std::endl;
3054 (void)IsContinuationOfLowWorkHeadersSync(peer, pfrom,
headers);
3068bool PeerManagerImpl::IsAncestorOfBestHeaderOrTip(
const CBlockIndex* header)
3070 if (header ==
nullptr) {
3072 }
else if (m_chainman.m_best_header !=
nullptr && header == m_chainman.m_best_header->GetAncestor(header->
nHeight)) {
3080bool PeerManagerImpl::MaybeSendGetHeaders(
CNode& pfrom,
const CBlockLocator& locator, Peer& peer)
3088 peer.m_last_getheaders_timestamp = current_time;
3099void PeerManagerImpl::HeadersDirectFetchBlocks(
CNode& pfrom,
const Peer& peer,
const CBlockIndex& last_header)
3102 CNodeState *nodestate =
State(pfrom.
GetId());
3105 std::vector<const CBlockIndex*> vToFetch;
3113 vToFetch.push_back(pindexWalk);
3115 pindexWalk = pindexWalk->
pprev;
3127 std::vector<CInv> vGetData;
3129 for (
const CBlockIndex* pindex : vToFetch | std::views::reverse) {
3134 uint32_t nFetchFlags = GetFetchFlags(peer);
3136 BlockRequested(pfrom.
GetId(), *pindex);
3140 if (vGetData.size() > 1) {
3145 if (vGetData.size() > 0) {
3146 if (!m_opts.ignore_incoming_txs &&
3147 nodestate->m_provides_cmpctblocks &&
3148 vGetData.size() == 1 &&
3149 mapBlocksInFlight.size() == 1 &&
3165void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(
CNode& pfrom,
3166 const CBlockIndex& last_header,
bool received_new_header,
bool may_have_more_headers)
3169 CNodeState *nodestate =
State(pfrom.
GetId());
3178 nodestate->m_last_block_announcement =
GetTime();
3186 if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < m_chainman.
MinimumChainWork()) {
3208 if (m_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= m_chainman.
ActiveChain().
Tip()->
nChainWork && !nodestate->m_chain_sync.m_protect) {
3210 nodestate->m_chain_sync.m_protect =
true;
3211 ++m_outbound_peers_with_protect_from_disconnect;
3216void PeerManagerImpl::ProcessHeadersMessage(
CNode& pfrom, Peer& peer,
3217 std::vector<CBlockHeader>&&
headers,
3218 bool via_compact_block)
3220 size_t nCount =
headers.size();
3227 LOCK(peer.m_headers_sync_mutex);
3228 if (peer.m_headers_sync) {
3229 peer.m_headers_sync.reset(
nullptr);
3230 LOCK(m_headers_presync_mutex);
3231 m_headers_presync_stats.erase(pfrom.
GetId());
3235 peer.m_last_getheaders_timestamp = {};
3243 if (!CheckHeadersPoW(
headers, peer)) {
3258 bool already_validated_work =
false;
3261 bool have_headers_sync =
false;
3263 LOCK(peer.m_headers_sync_mutex);
3265 already_validated_work = IsContinuationOfLowWorkHeadersSync(peer, pfrom,
headers);
3281 have_headers_sync = !!peer.m_headers_sync;
3286 bool headers_connect_blockindex{chain_start_header !=
nullptr};
3288 if (!headers_connect_blockindex) {
3292 HandleUnconnectingHeaders(pfrom, peer,
headers);
3299 peer.m_last_getheaders_timestamp = {};
3309 already_validated_work = already_validated_work || IsAncestorOfBestHeaderOrTip(last_received_header);
3316 already_validated_work =
true;
3322 if (!already_validated_work && TryLowWorkHeadersSync(peer, pfrom,
3323 *chain_start_header,
headers)) {
3335 bool received_new_header{last_received_header ==
nullptr};
3341 state, &pindexLast)};
3347 "If this happens with all peers, consider database corruption (that -reindex may fix) "
3348 "or a potential consensus incompatibility.",
3351 MaybePunishNodeForBlock(pfrom.
GetId(), state, via_compact_block,
"invalid header received");
3357 if (processed && received_new_header) {
3358 LogBlockHeader(*pindexLast, pfrom,
false);
3362 if (nCount == m_opts.max_headers_result && !have_headers_sync) {
3364 if (MaybeSendGetHeaders(pfrom,
GetLocator(pindexLast), peer)) {
3369 UpdatePeerStateForReceivedHeaders(pfrom, *pindexLast, received_new_header, nCount == m_opts.max_headers_result);
3372 HeadersDirectFetchBlocks(pfrom, peer, *pindexLast);
3378 bool first_time_failure)
3384 PeerRef peer{GetPeerRef(nodeid)};
3387 ptx->GetHash().ToString(),
3388 ptx->GetWitnessHash().ToString(),
3392 const auto& [add_extra_compact_tx, unique_parents, package_to_validate] = m_txdownloadman.MempoolRejectedTx(ptx, state, nodeid, first_time_failure);
3395 AddToCompactExtraTransactions(ptx);
3397 for (
const Txid& parent_txid : unique_parents) {
3398 if (peer) AddKnownTx(*peer, parent_txid.ToUint256());
3401 return package_to_validate;
3404void PeerManagerImpl::ProcessValidTx(
NodeId nodeid,
const CTransactionRef& tx,
const std::list<CTransactionRef>& replaced_transactions)
3410 m_txdownloadman.MempoolAcceptedTx(tx);
3414 tx->GetHash().ToString(),
3415 tx->GetWitnessHash().ToString(),
3418 InitiateTxBroadcastToAll(tx->GetWitnessHash());
3421 AddToCompactExtraTransactions(removedTx);
3431 const auto&
package = package_to_validate.m_txns;
3432 const auto& senders = package_to_validate.
m_senders;
3435 m_txdownloadman.MempoolRejectedPackage(package);
3438 if (!
Assume(package.size() == 2))
return;
3442 auto package_iter = package.rbegin();
3443 auto senders_iter = senders.rbegin();
3444 while (package_iter != package.rend()) {
3445 const auto& tx = *package_iter;
3446 const NodeId nodeid = *senders_iter;
3447 const auto it_result{package_result.
m_tx_results.find(tx->GetWitnessHash())};
3451 const auto& tx_result = it_result->second;
3452 switch (tx_result.m_result_type) {
3455 ProcessValidTx(nodeid, tx, tx_result.m_replaced_transactions);
3465 ProcessInvalidTx(nodeid, tx, tx_result.m_state,
false);
3483bool PeerManagerImpl::ProcessOrphanTx(Peer& peer)
3488 while (
CTransactionRef porphanTx = m_txdownloadman.GetTxToReconsider(peer.m_id)) {
3491 const Txid& orphanHash = porphanTx->GetHash();
3492 const Wtxid& orphan_wtxid = porphanTx->GetWitnessHash();
3509 ProcessInvalidTx(peer.m_id, porphanTx, state,
false);
3518bool PeerManagerImpl::PrepareBlockFilterRequest(
CNode&
node, Peer& peer,
3520 const uint256& stop_hash, uint32_t max_height_diff,
3524 const bool supported_filter_type =
3527 if (!supported_filter_type) {
3529 static_cast<uint8_t
>(filter_type),
node.DisconnectMsg());
3530 node.fDisconnect =
true;
3539 if (!stop_index || !BlockRequestAllowed(*stop_index)) {
3542 node.fDisconnect =
true;
3547 uint32_t stop_height = stop_index->
nHeight;
3548 if (start_height > stop_height) {
3550 "start height %d and stop height %d, %s",
3551 start_height, stop_height,
node.DisconnectMsg());
3552 node.fDisconnect =
true;
3555 if (stop_height - start_height >= max_height_diff) {
3557 stop_height - start_height + 1, max_height_diff,
node.DisconnectMsg());
3558 node.fDisconnect =
true;
3563 if (!filter_index) {
3573 uint8_t filter_type_ser;
3574 uint32_t start_height;
3577 vRecv >> filter_type_ser >> start_height >> stop_hash;
3583 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height, stop_hash,
3588 std::vector<BlockFilter> filters;
3590 LogDebug(
BCLog::NET,
"Failed to find block filter in index: filter_type=%s, start_height=%d, stop_hash=%s\n",
3595 for (
const auto& filter : filters) {
3602 uint8_t filter_type_ser;
3603 uint32_t start_height;
3606 vRecv >> filter_type_ser >> start_height >> stop_hash;
3612 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height, stop_hash,
3618 if (start_height > 0) {
3620 stop_index->
GetAncestor(
static_cast<int>(start_height - 1));
3622 LogDebug(
BCLog::NET,
"Failed to find block filter header in index: filter_type=%s, block_hash=%s\n",
3628 std::vector<uint256> filter_hashes;
3630 LogDebug(
BCLog::NET,
"Failed to find block filter hashes in index: filter_type=%s, start_height=%d, stop_hash=%s\n",
3644 uint8_t filter_type_ser;
3647 vRecv >> filter_type_ser >> stop_hash;
3653 if (!PrepareBlockFilterRequest(
node, peer, filter_type, 0, stop_hash,
3654 std::numeric_limits<uint32_t>::max(),
3655 stop_index, filter_index)) {
3663 for (
int i =
headers.size() - 1; i >= 0; i--) {
3668 LogDebug(
BCLog::NET,
"Failed to find block filter header in index: filter_type=%s, block_hash=%s\n",
3682 bool new_block{
false};
3683 m_chainman.
ProcessNewBlock(block, force_processing, min_pow_checked, &new_block);
3685 node.m_last_block_time = GetTime<std::chrono::seconds>();
3690 RemoveBlockRequest(block->GetHash(), std::nullopt);
3693 mapBlockSource.erase(block->GetHash());
3697void PeerManagerImpl::ProcessCompactBlockTxns(
CNode& pfrom, Peer& peer,
const BlockTransactions& block_transactions)
3699 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
3700 bool fBlockRead{
false};
3704 auto range_flight = mapBlocksInFlight.equal_range(block_transactions.
blockhash);
3705 size_t already_in_flight = std::distance(range_flight.first, range_flight.second);
3706 bool requested_block_from_this_peer{
false};
3709 bool first_in_flight = already_in_flight == 0 || (range_flight.first->second.first == pfrom.
GetId());
3711 while (range_flight.first != range_flight.second) {
3712 auto [node_id, block_it] = range_flight.first->second;
3713 if (node_id == pfrom.
GetId() && block_it->partialBlock) {
3714 requested_block_from_this_peer =
true;
3717 range_flight.first++;
3720 if (!requested_block_from_this_peer) {
3732 Misbehaving(peer,
"previous compact block reconstruction attempt failed");
3743 Misbehaving(peer,
"invalid compact block/non-matching block transactions");
3746 if (first_in_flight) {
3751 std::vector<CInv> invs;
3756 LogDebug(
BCLog::NET,
"Peer %d sent us a compact block but it failed to reconstruct, waiting on first download to complete\n", pfrom.
GetId());
3769 mapBlockSource.emplace(block_transactions.
blockhash, std::make_pair(pfrom.
GetId(),
false));
3784void PeerManagerImpl::LogBlockHeader(
const CBlockIndex& index,
const CNode& peer,
bool via_compact_block) {
3796 "Saw new %sheader hash=%s height=%d %s",
3797 via_compact_block ?
"cmpctblock " :
"",
3809void PeerManagerImpl::PushPrivateBroadcastTx(
CNode&
node)
3813 const auto opt_tx{m_tx_for_private_broadcast.PickTxForSend(
node.GetId(),
CService{node.addr})};
3816 node.fDisconnect =
true;
3822 tx->GetHash().ToString(), tx->HasWitness() ?
strprintf(
", wtxid=%s", tx->GetWitnessHash().ToString()) :
"",
3828void PeerManagerImpl::ProcessMessage(Peer& peer,
CNode& pfrom,
const std::string& msg_type,
DataStream& vRecv,
3830 const std::atomic<bool>& interruptMsgProc)
3845 uint64_t nNonce = 1;
3848 std::string cleanSubVer;
3849 int starting_height = -1;
3852 vRecv >> nVersion >> Using<CustomUintFormatter<8>>(nServices) >> nTime;
3867 LogDebug(
BCLog::NET,
"peer does not offer the expected services (%08x offered, %08x expected), %s",
3869 GetDesirableServiceFlags(nServices),
3882 if (!vRecv.
empty()) {
3890 if (!vRecv.
empty()) {
3891 std::string strSubVer;
3895 if (!vRecv.
empty()) {
3896 vRecv >> starting_height;
3916 PushNodeVersion(pfrom, peer);
3920 const int greatest_common_version = std::min(nVersion, pfrom.
AdvertisedVersion());
3925 peer.m_their_services = nServices;
3929 pfrom.cleanSubVer = cleanSubVer;
3940 (fRelay || (peer.m_our_services &
NODE_BLOOM))) {
3941 auto*
const tx_relay = peer.SetTxRelay();
3943 LOCK(tx_relay->m_bloom_filter_mutex);
3944 tx_relay->m_relay_txs = fRelay;
3950 LogDebug(
BCLog::NET,
"receive version message: %s: version %d, blocks=%d, us=%s, txrelay=%d, %s%s",
3951 cleanSubVer.empty() ?
"<no user agent>" : cleanSubVer, pfrom.
nVersion,
3953 (mapped_as ?
strprintf(
", mapped_as=%d", mapped_as) :
""));
3971 if (greatest_common_version >= 70016) {
3986 const auto* tx_relay = peer.GetTxRelay();
3987 if (tx_relay &&
WITH_LOCK(tx_relay->m_bloom_filter_mutex,
return tx_relay->m_relay_txs) &&
3989 const uint64_t recon_salt = m_txreconciliation->PreRegisterPeer(pfrom.
GetId());
4002 if (MaybeDisconnectForTxRelayCapacity(pfrom, msg_type, pfrom.
GetId()))
return;
4010 m_num_preferred_download_peers += state->fPreferredDownload;
4016 bool send_getaddr{
false};
4018 send_getaddr = SetupAddressRelay(pfrom, peer);
4028 peer.m_getaddr_sent =
true;
4052 peer.m_time_offset =
NodeSeconds{std::chrono::seconds{nTime}} - Now<NodeSeconds>();
4056 m_outbound_time_offsets.Add(peer.m_time_offset);
4057 m_outbound_time_offsets.WarnIfOutOfSync();
4061 if (greatest_common_version <= 70012) {
4062 constexpr auto finalAlert{
"60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50"_hex};
4063 MakeAndPushMessage(pfrom,
"alert", finalAlert);
4086 auto new_peer_msg = [&]() {
4088 return strprintf(
"New %s peer connected: transport: %s, version: %d, %s%s",
4092 (mapped_as ?
strprintf(
", mapped_as=%d", mapped_as) :
""));
4100 LogInfo(
"%s", new_peer_msg());
4103 if (
auto tx_relay = peer.GetTxRelay()) {
4112 tx_relay->m_tx_inventory_mutex,
4113 return tx_relay->m_tx_inventory_to_send.empty() &&
4114 tx_relay->m_next_inv_send_time == 0
s));
4124 PushPrivateBroadcastTx(pfrom);
4137 if (m_txreconciliation) {
4138 if (!peer.m_wtxid_relay || !m_txreconciliation->IsPeerRegistered(pfrom.
GetId())) {
4142 m_txreconciliation->ForgetPeer(pfrom.
GetId());
4148 const CNodeState* state =
State(pfrom.
GetId());
4150 .m_preferred = state->fPreferredDownload,
4151 .m_relay_permissions = pfrom.HasPermission(NetPermissionFlags::Relay),
4152 .m_wtxid_relay = peer.m_wtxid_relay,
4161 peer.m_prefers_headers =
true;
4166 uint8_t sendcmpct_hb{0};
4167 uint64_t sendcmpct_version{0};
4168 vRecv >> sendcmpct_hb >> sendcmpct_version;
4172 if (sendcmpct_hb > 1) {
4173 Misbehaving(peer,
"invalid sendcmpct announce field");
4181 CNodeState* nodestate =
State(pfrom.
GetId());
4182 nodestate->m_provides_cmpctblocks =
true;
4183 nodestate->m_requested_hb_cmpctblocks = sendcmpct_hb;
4200 if (!peer.m_wtxid_relay) {
4201 peer.m_wtxid_relay =
true;
4202 m_wtxid_relay_peers++;
4221 peer.m_wants_addrv2 =
true;
4238 std::string feature_id;
4242 std::vector<unsigned char> feature_data_vec;
4245 }
catch (
const std::exception&) {
4248 if (feature_id.size() < 4 || !vRecv.
empty()) {
4268 if (!m_txreconciliation) {
4269 LogDebug(
BCLog::NET,
"sendtxrcncl from peer=%d ignored, as our node does not have txreconciliation enabled\n", pfrom.
GetId());
4280 if (RejectIncomingTxs(pfrom)) {
4289 const auto* tx_relay = peer.GetTxRelay();
4290 if (!tx_relay || !
WITH_LOCK(tx_relay->m_bloom_filter_mutex,
return tx_relay->m_relay_txs)) {
4296 uint32_t peer_txreconcl_version;
4297 uint64_t remote_salt;
4298 vRecv >> peer_txreconcl_version >> remote_salt;
4301 peer_txreconcl_version, remote_salt);
4333 const auto ser_params{
4341 std::vector<CAddress> vAddr;
4342 vRecv >> ser_params(vAddr);
4343 ProcessAddrs(msg_type, pfrom, peer, std::move(vAddr), interruptMsgProc);
4348 std::vector<CInv> vInv;
4352 Misbehaving(peer,
strprintf(
"inv message size = %u", vInv.size()));
4356 const bool reject_tx_invs{RejectIncomingTxs(pfrom)};
4357 std::unordered_set<uint256, SaltedUint256Hasher> seen_txids{0, m_txhash_hasher};
4358 std::unordered_set<uint256, SaltedUint256Hasher> seen_wtxids{0, m_txhash_hasher};
4362 const auto current_time{GetTime<std::chrono::microseconds>()};
4365 for (
CInv& inv : vInv) {
4366 if (interruptMsgProc)
return;
4371 if (peer.m_wtxid_relay) {
4378 const bool fAlreadyHave = AlreadyHaveBlock(inv.
hash);
4381 UpdateBlockAvailability(pfrom.
GetId(), inv.
hash);
4389 best_block = &inv.
hash;
4392 if (reject_tx_invs) {
4398 auto& seen_hashes{inv.
IsMsgWtx() ? seen_wtxids : seen_txids};
4399 if (!seen_hashes.insert(inv.
hash).second)
continue;
4401 AddKnownTx(peer, inv.
hash);
4404 const bool fAlreadyHave{m_txdownloadman.AddTxAnnouncement(pfrom.
GetId(), gtxid, current_time)};
4412 if (best_block !=
nullptr) {
4424 if (state.fSyncStarted || (!peer.m_inv_triggered_getheaders_before_sync && *best_block != m_last_block_inv_triggering_headers_sync)) {
4425 if (MaybeSendGetHeaders(pfrom,
GetLocator(m_chainman.m_best_header), peer)) {
4427 m_chainman.m_best_header->nHeight, best_block->ToString(),
4430 if (!state.fSyncStarted) {
4431 peer.m_inv_triggered_getheaders_before_sync =
true;
4435 m_last_block_inv_triggering_headers_sync = *best_block;
4444 std::vector<CInv> vInv;
4448 Misbehaving(peer,
strprintf(
"getdata message size = %u", vInv.size()));
4454 if (vInv.size() > 0) {
4459 const auto pushed_tx_opt{m_tx_for_private_broadcast.GetTxForNode(pfrom.
GetId())};
4460 if (!pushed_tx_opt) {
4471 if (vInv.size() == 1 && vInv[0].IsMsgTx() && vInv[0].hash == pushed_tx->GetHash().ToUint256()) {
4475 peer.m_ping_queued =
true;
4486 LOCK(peer.m_getdata_requests_mutex);
4487 peer.m_getdata_requests.insert(peer.m_getdata_requests.end(), vInv.begin(), vInv.end());
4488 ProcessGetData(pfrom, peer, interruptMsgProc);
4497 vRecv >> locator >> hashStop;
4513 std::shared_ptr<const CBlock> a_recent_block;
4515 LOCK(m_most_recent_block_mutex);
4516 a_recent_block = m_most_recent_block;
4519 if (!m_chainman.
ActiveChainstate().ActivateBestChain(state, a_recent_block)) {
4534 for (; pindex; pindex = m_chainman.
ActiveChain().Next(*pindex))
4549 if (--nLimit <= 0) {
4553 WITH_LOCK(peer.m_block_inv_mutex, {peer.m_continuation_block = pindex->GetBlockHash();});
4573 for (
size_t i = 1; i < req.
indexes.size(); ++i) {
4577 std::shared_ptr<const CBlock> recent_block;
4579 LOCK(m_most_recent_block_mutex);
4580 if (m_most_recent_block_hash == req.
blockhash)
4581 recent_block = m_most_recent_block;
4585 SendBlockTransactions(pfrom, peer, *recent_block, req);
4604 if (!block_pos.IsNull()) {
4611 SendBlockTransactions(pfrom, peer, block, req);
4624 WITH_LOCK(peer.m_getdata_requests_mutex, peer.m_getdata_requests.push_back(inv));
4632 vRecv >> locator >> hashStop;
4650 if (m_chainman.
ActiveTip() ==
nullptr ||
4652 LogDebug(
BCLog::NET,
"Ignoring getheaders from peer=%d because active chain has too little work; sending empty response\n", pfrom.
GetId());
4659 CNodeState *nodestate =
State(pfrom.
GetId());
4668 if (!BlockRequestAllowed(*pindex)) {
4669 LogDebug(
BCLog::NET,
"%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom.
GetId());
4682 std::vector<CBlock> vHeaders;
4683 int nLimit = m_opts.max_headers_result;
4685 for (; pindex; pindex = m_chainman.
ActiveChain().Next(*pindex))
4688 if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
4703 nodestate->pindexBestHeaderSent = pindex ? pindex : m_chainman.
ActiveChain().
Tip();
4709 if (RejectIncomingTxs(pfrom)) {
4723 const Txid& txid = ptx->GetHash();
4724 const Wtxid& wtxid = ptx->GetWitnessHash();
4727 AddKnownTx(peer, hash);
4729 if (
const auto num_broadcasted{m_tx_for_private_broadcast.Remove(ptx)}) {
4731 "network from %s; stopping private broadcast attempts",
4742 const auto& [should_validate, package_to_validate] = m_txdownloadman.ReceivedTx(pfrom.
GetId(), ptx);
4743 if (!should_validate) {
4748 if (!m_mempool.
exists(txid)) {
4749 LogInfo(
"Not relaying non-mempool transaction %s (wtxid=%s) from forcerelay peer=%d\n",
4752 LogInfo(
"Force relaying tx %s (wtxid=%s) from peer=%d\n",
4754 InitiateTxBroadcastToAll(wtxid);
4758 if (package_to_validate) {
4761 package_result.
m_state.
IsValid() ?
"package accepted" :
"package rejected");
4762 ProcessPackageResult(package_to_validate.value(), package_result);
4768 Assume(!package_to_validate.has_value());
4778 if (
auto package_to_validate{ProcessInvalidTx(pfrom.
GetId(), ptx, state,
true)}) {
4781 package_result.
m_state.
IsValid() ?
"package accepted" :
"package rejected");
4782 ProcessPackageResult(package_to_validate.value(), package_result);
4795 }
else if (m_opts.ignore_incoming_txs) {
4802 const CNodeState *nodestate =
State(pfrom.
GetId());
4803 if (!nodestate->m_provides_cmpctblocks) {
4810 vRecv >> cmpctblock;
4812 bool received_new_header =
false;
4822 MaybeSendGetHeaders(pfrom,
GetLocator(m_chainman.m_best_header), peer);
4832 received_new_header =
true;
4840 MaybePunishNodeForBlock(pfrom.
GetId(), state,
true,
"invalid header via cmpctblock");
4847 if (received_new_header) {
4848 LogBlockHeader(*pindex, pfrom,
true);
4851 bool fProcessBLOCKTXN =
false;
4855 bool fRevertToHeaderProcessing =
false;
4859 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
4860 bool fBlockReconstructed =
false;
4866 CNodeState *nodestate =
State(pfrom.
GetId());
4871 nodestate->m_last_block_announcement =
GetTime();
4877 auto range_flight = mapBlocksInFlight.equal_range(pindex->
GetBlockHash());
4878 size_t already_in_flight = std::distance(range_flight.first, range_flight.second);
4879 bool requested_block_from_this_peer{
false};
4882 bool first_in_flight = already_in_flight == 0 || (range_flight.first->second.first == pfrom.
GetId());
4884 while (range_flight.first != range_flight.second) {
4885 if (range_flight.first->second.first == pfrom.
GetId()) {
4886 requested_block_from_this_peer =
true;
4889 range_flight.first++;
4899 if (requested_block_from_this_peer) {
4902 std::vector<CInv> vInv(1);
4910 if (!already_in_flight && !CanDirectFetch()) {
4918 requested_block_from_this_peer) {
4919 std::list<QueuedBlock>::iterator* queuedBlockIt =
nullptr;
4920 if (!BlockRequested(pfrom.
GetId(), *pindex, &queuedBlockIt)) {
4921 if (!(*queuedBlockIt)->partialBlock)
4934 Misbehaving(peer,
"invalid compact block");
4937 if (first_in_flight) {
4939 std::vector<CInv> vInv(1);
4950 for (
size_t i = 0; i < cmpctblock.
BlockTxCount(); i++) {
4955 fProcessBLOCKTXN =
true;
4956 }
else if (first_in_flight) {
4963 IsBlockRequestedFromOutbound(blockhash) ||
4982 ReadStatus status = tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
4987 std::vector<CTransactionRef> dummy;
4989 status = tempBlock.FillBlock(*pblock, dummy,
4992 fBlockReconstructed =
true;
4996 if (requested_block_from_this_peer) {
4999 std::vector<CInv> vInv(1);
5005 fRevertToHeaderProcessing =
true;
5010 if (fProcessBLOCKTXN) {
5013 return ProcessCompactBlockTxns(pfrom, peer, txn);
5016 if (fRevertToHeaderProcessing) {
5022 return ProcessHeadersMessage(pfrom, peer, {cmpctblock.
header},
true);
5025 if (fBlockReconstructed) {
5030 mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom.
GetId(),
false));
5048 RemoveBlockRequest(pblock->GetHash(), std::nullopt);
5065 return ProcessCompactBlockTxns(pfrom, peer, resp);
5076 std::vector<CBlockHeader>
headers;
5080 if (nCount > m_opts.max_headers_result) {
5081 Misbehaving(peer,
strprintf(
"headers message size = %u", nCount));
5085 for (
unsigned int n = 0; n < nCount; n++) {
5090 ProcessHeadersMessage(pfrom, peer, std::move(
headers),
false);
5094 if (m_headers_presync_should_signal.exchange(
false)) {
5095 HeadersPresyncStats stats;
5097 LOCK(m_headers_presync_mutex);
5098 auto it = m_headers_presync_stats.find(m_headers_presync_bestpeer);
5099 if (it != m_headers_presync_stats.end()) stats = it->second;
5117 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
5128 Misbehaving(peer,
"mutated block");
5133 bool forceProcessing =
false;
5134 const uint256 hash(pblock->GetHash());
5135 bool min_pow_checked =
false;
5140 forceProcessing = IsBlockRequested(hash);
5141 RemoveBlockRequest(hash, pfrom.
GetId());
5145 mapBlockSource.emplace(hash, std::make_pair(pfrom.
GetId(),
true));
5149 min_pow_checked =
true;
5152 ProcessBlock(pfrom, pblock, forceProcessing, min_pow_checked);
5169 Assume(SetupAddressRelay(pfrom, peer));
5173 if (peer.m_getaddr_recvd) {
5177 peer.m_getaddr_recvd =
true;
5179 peer.m_addrs_to_send.clear();
5180 std::vector<CAddress> vAddr;
5186 for (
const CAddress &addr : vAddr) {
5187 PushAddress(peer, addr);
5215 if (
auto tx_relay = peer.GetTxRelay(); tx_relay !=
nullptr) {
5216 LOCK(tx_relay->m_tx_inventory_mutex);
5217 tx_relay->m_send_mempool =
true;
5243 ProcessPong(pfrom, peer, time_received, vRecv);
5259 Misbehaving(peer,
"too-large bloom filter");
5260 }
else if (
auto tx_relay = peer.GetTxRelay(); tx_relay !=
nullptr) {
5262 LOCK(tx_relay->m_bloom_filter_mutex);
5263 tx_relay->m_bloom_filter.reset(
new CBloomFilter(filter));
5264 tx_relay->m_relay_txs =
true;
5268 MaybeDisconnectForTxRelayCapacity(pfrom, msg_type);
5279 std::vector<unsigned char> vData;
5287 }
else if (
auto tx_relay = peer.GetTxRelay(); tx_relay !=
nullptr) {
5288 LOCK(tx_relay->m_bloom_filter_mutex);
5289 if (tx_relay->m_bloom_filter) {
5290 tx_relay->m_bloom_filter->insert(vData);
5296 Misbehaving(peer,
"bad filteradd message");
5307 auto tx_relay = peer.GetTxRelay();
5308 if (!tx_relay)
return;
5311 LOCK(tx_relay->m_bloom_filter_mutex);
5312 tx_relay->m_bloom_filter =
nullptr;
5313 tx_relay->m_relay_txs =
true;
5317 MaybeDisconnectForTxRelayCapacity(pfrom, msg_type);
5323 vRecv >> newFeeFilter;
5325 if (
auto tx_relay = peer.GetTxRelay(); tx_relay !=
nullptr) {
5326 tx_relay->m_fee_filter_received = newFeeFilter;
5334 ProcessGetCFilters(pfrom, peer, vRecv);
5339 ProcessGetCFHeaders(pfrom, peer, vRecv);
5344 ProcessGetCFCheckPt(pfrom, peer, vRecv);
5349 std::vector<CInv> vInv;
5351 std::vector<GenTxid> tx_invs;
5353 for (
CInv &inv : vInv) {
5359 LOCK(m_tx_download_mutex);
5360 m_txdownloadman.ReceivedNotFound(pfrom.
GetId(), tx_invs);
5369bool PeerManagerImpl::MaybeDiscourageAndDisconnect(
CNode& pnode, Peer& peer)
5372 LOCK(peer.m_misbehavior_mutex);
5375 if (!peer.m_should_discourage)
return false;
5377 peer.m_should_discourage =
false;
5382 LogWarning(
"Not punishing noban peer %d!", peer.m_id);
5388 LogWarning(
"Not punishing manually connected peer %d!", peer.m_id);
5408bool PeerManagerImpl::MaybeDisconnectForTxRelayCapacity(
CNode&
node,
const std::string& msg_type, std::optional<NodeId> protect_peer)
5410 if (!
node.IsInboundConn() || !
node.m_relays_txs)
return false;
5413 LogDebug(
BCLog::NET,
"failed to find a tx-relaying eviction candidate - connection dropped after %s message, peer=%d\n", msg_type,
node.GetId());
5414 node.fDisconnect =
true;
5418bool PeerManagerImpl::ProcessMessages(
CNode&
node, std::atomic<bool>& interruptMsgProc)
5423 PeerRef maybe_peer{GetPeerRef(
node.GetId())};
5424 if (maybe_peer ==
nullptr)
return false;
5425 Peer& peer{*maybe_peer};
5429 if (!
node.IsInboundConn() && !peer.m_outbound_version_message_sent)
return false;
5432 LOCK(peer.m_getdata_requests_mutex);
5433 if (!peer.m_getdata_requests.empty()) {
5434 ProcessGetData(
node, peer, interruptMsgProc);
5438 const bool processed_orphan = ProcessOrphanTx(peer);
5440 if (
node.fDisconnect)
5443 if (processed_orphan)
return true;
5448 LOCK(peer.m_getdata_requests_mutex);
5449 if (!peer.m_getdata_requests.empty())
return true;
5453 if (
node.fPauseSend)
return false;
5455 auto poll_result{
node.PollMessage()};
5462 bool fMoreWork = poll_result->second;
5466 node.m_addr_name.c_str(),
5467 node.ConnectionTypeAsString().c_str(),
5473 if (m_opts.capture_messages) {
5478 ProcessMessage(peer,
node,
msg.m_type,
msg.m_recv,
msg.m_time, interruptMsgProc);
5479 if (interruptMsgProc)
return false;
5481 LOCK(peer.m_getdata_requests_mutex);
5482 if (!peer.m_getdata_requests.empty()) fMoreWork =
true;
5489 LOCK(m_tx_download_mutex);
5490 if (m_txdownloadman.HaveMoreWork(peer.m_id)) fMoreWork =
true;
5491 }
catch (
const std::exception& e) {
5500void PeerManagerImpl::ConsiderEviction(
CNode& pto, Peer& peer, std::chrono::seconds time_in_seconds)
5513 if (state.pindexBestKnownBlock !=
nullptr && state.pindexBestKnownBlock->nChainWork >= m_chainman.
ActiveChain().
Tip()->
nChainWork) {
5515 if (state.m_chain_sync.m_timeout != 0
s) {
5516 state.m_chain_sync.m_timeout = 0
s;
5517 state.m_chain_sync.m_work_header =
nullptr;
5518 state.m_chain_sync.m_sent_getheaders =
false;
5520 }
else if (state.m_chain_sync.m_timeout == 0
s || (state.m_chain_sync.m_work_header !=
nullptr && state.pindexBestKnownBlock !=
nullptr && state.pindexBestKnownBlock->nChainWork >= state.m_chain_sync.m_work_header->nChainWork)) {
5528 state.m_chain_sync.m_work_header = m_chainman.
ActiveChain().
Tip();
5529 state.m_chain_sync.m_sent_getheaders =
false;
5530 }
else if (state.m_chain_sync.m_timeout > 0
s && time_in_seconds > state.m_chain_sync.m_timeout) {
5534 if (state.m_chain_sync.m_sent_getheaders) {
5536 LogInfo(
"Outbound peer has old chain, best known block = %s, %s", state.pindexBestKnownBlock !=
nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() :
"<none>", pto.
DisconnectMsg());
5539 assert(state.m_chain_sync.m_work_header);
5544 MaybeSendGetHeaders(pto,
5545 GetLocator(state.m_chain_sync.m_work_header->pprev),
5547 LogDebug(
BCLog::NET,
"sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto.
GetId(), state.pindexBestKnownBlock !=
nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() :
"<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString());
5548 state.m_chain_sync.m_sent_getheaders =
true;
5569 std::pair<NodeId, std::chrono::seconds> youngest_peer{-1, 0}, next_youngest_peer{-1, 0};
5573 if (pnode->
GetId() > youngest_peer.first) {
5574 next_youngest_peer = youngest_peer;
5575 youngest_peer.first = pnode->GetId();
5576 youngest_peer.second = pnode->m_last_block_time;
5579 NodeId to_disconnect = youngest_peer.first;
5580 if (youngest_peer.second > next_youngest_peer.second) {
5583 to_disconnect = next_youngest_peer.first;
5592 CNodeState *node_state =
State(pnode->
GetId());
5593 if (node_state ==
nullptr ||
5596 LogDebug(
BCLog::NET,
"disconnecting extra block-relay-only peer=%d (last block received at time %d)\n",
5600 LogDebug(
BCLog::NET,
"keeping block-relay-only peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n",
5601 pnode->
GetId(), TicksSinceEpoch<std::chrono::seconds>(pnode->
m_connected), node_state->vBlocksInFlight.size());
5616 int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
5619 AssertLockHeld(::cs_main);
5623 if (!pnode->IsFullOutboundConn() || pnode->fDisconnect) return;
5624 CNodeState *state = State(pnode->GetId());
5625 if (state == nullptr) return;
5627 if (state->m_chain_sync.m_protect) return;
5630 if (!m_connman.MultipleManualOrFullOutboundConns(pnode->addr.GetNetwork())) return;
5631 if (state->m_last_block_announcement < oldest_block_announcement || (state->m_last_block_announcement == oldest_block_announcement && pnode->GetId() > worst_peer)) {
5632 worst_peer = pnode->GetId();
5633 oldest_block_announcement = state->m_last_block_announcement;
5636 if (worst_peer != -1) {
5647 LogDebug(
BCLog::NET,
"disconnecting extra outbound peer=%d (last block announcement received at time %d)\n", pnode->
GetId(), oldest_block_announcement);
5651 LogDebug(
BCLog::NET,
"keeping outbound peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n",
5652 pnode->
GetId(), TicksSinceEpoch<std::chrono::seconds>(pnode->
m_connected), state.vBlocksInFlight.size());
5668void PeerManagerImpl::CheckForStaleTipAndEvictPeers()
5673 auto now{GetTime<std::chrono::seconds>()};
5675 EvictExtraOutboundPeers(current_time);
5677 if (now > m_stale_tip_check_time) {
5681 LogInfo(
"Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n",
5690 if (!m_initial_sync_finished && CanDirectFetch()) {
5692 m_initial_sync_finished =
true;
5699 peer.m_ping_nonce_sent &&
5709 bool pingSend =
false;
5711 if (peer.m_ping_queued) {
5716 if (peer.m_ping_nonce_sent == 0 && now > peer.m_ping_start.load() +
PING_INTERVAL) {
5725 }
while (
nonce == 0);
5726 peer.m_ping_queued =
false;
5727 peer.m_ping_start = now;
5729 peer.m_ping_nonce_sent =
nonce;
5733 peer.m_ping_nonce_sent = 0;
5739void PeerManagerImpl::MaybeSendAddr(
CNode&
node, Peer& peer, std::chrono::microseconds current_time)
5742 if (!peer.m_addr_relay_enabled)
return;
5744 LOCK(peer.m_addr_send_times_mutex);
5747 peer.m_next_local_addr_send < current_time) {
5754 if (peer.m_next_local_addr_send != 0us) {
5755 peer.m_addr_known->reset();
5758 CAddress local_addr{*local_service, peer.m_our_services, Now<NodeSeconds>()};
5759 if (peer.m_next_local_addr_send == 0us) {
5763 if (IsAddrCompatible(peer, local_addr)) {
5764 std::vector<CAddress> self_announcement{local_addr};
5765 if (peer.m_wants_addrv2) {
5773 PushAddress(peer, local_addr);
5780 if (current_time <= peer.m_next_addr_send)
return;
5793 bool ret = peer.m_addr_known->contains(addr.
GetKey());
5794 if (!
ret) peer.m_addr_known->insert(addr.
GetKey());
5797 peer.m_addrs_to_send.erase(std::remove_if(peer.m_addrs_to_send.begin(), peer.m_addrs_to_send.end(), addr_already_known),
5798 peer.m_addrs_to_send.end());
5801 if (peer.m_addrs_to_send.empty())
return;
5803 if (peer.m_wants_addrv2) {
5808 peer.m_addrs_to_send.clear();
5811 if (peer.m_addrs_to_send.capacity() > 40) {
5812 peer.m_addrs_to_send.shrink_to_fit();
5816void PeerManagerImpl::MaybeSendSendHeaders(
CNode&
node, Peer& peer)
5824 CNodeState &state = *
State(
node.GetId());
5825 if (state.pindexBestKnownBlock !=
nullptr &&
5832 peer.m_sent_sendheaders =
true;
5837void PeerManagerImpl::MaybeSendFeefilter(
CNode& pto, Peer& peer, std::chrono::microseconds current_time)
5839 if (m_opts.ignore_incoming_txs)
return;
5855 if (peer.m_fee_filter_sent == MAX_FILTER) {
5858 peer.m_next_send_feefilter = 0us;
5861 if (current_time > peer.m_next_send_feefilter) {
5862 CAmount filterToSend = m_fee_filter_rounder.round(currentFilter);
5865 if (filterToSend != peer.m_fee_filter_sent) {
5867 peer.m_fee_filter_sent = filterToSend;
5874 (currentFilter < 3 * peer.m_fee_filter_sent / 4 || currentFilter > 4 * peer.m_fee_filter_sent / 3)) {
5879bool PeerManagerImpl::RejectIncomingTxs(
const CNode& peer)
const
5892 const size_t nAvail{vRecv.
size()};
5893 bool bPingFinished =
false;
5894 std::string sProblem;
5896 if (nAvail >=
sizeof(
nonce)) {
5900 if (peer.m_ping_nonce_sent != 0) {
5901 if (
nonce == peer.m_ping_nonce_sent) {
5903 bPingFinished =
true;
5904 const auto ping_time = ping_end - peer.m_ping_start.load();
5905 if (ping_time.count() >= 0) {
5909 m_tx_for_private_broadcast.NodeConfirmedReception(pfrom.
GetId());
5916 sProblem =
"Timing mishap";
5920 sProblem =
"Nonce mismatch";
5923 bPingFinished =
true;
5924 sProblem =
"Nonce zero";
5928 sProblem =
"Unsolicited pong without ping";
5932 bPingFinished =
true;
5933 sProblem =
"Short payload";
5936 if (!(sProblem.empty())) {
5940 peer.m_ping_nonce_sent,
5944 if (bPingFinished) {
5945 peer.m_ping_nonce_sent = 0;
5949bool PeerManagerImpl::SetupAddressRelay(
const CNode&
node, Peer& peer)
5954 if (
node.IsBlockOnlyConn())
return false;
5959 if (
node.IsFeelerConn())
return false;
5961 if (!peer.m_addr_relay_enabled.exchange(
true)) {
5965 peer.m_addr_known = std::make_unique<CRollingBloomFilter>(5000, 0.001);
5971void PeerManagerImpl::ProcessAddrs(std::string_view msg_type,
CNode& pfrom, Peer& peer, std::vector<CAddress>&& vAddr,
const std::atomic<bool>& interruptMsgProc)
5976 if (!SetupAddressRelay(pfrom, peer)) {
5983 Misbehaving(peer,
strprintf(
"%s message size = %u", msg_type, vAddr.size()));
5988 std::vector<CAddress> vAddrOk;
5994 const auto time_diff{current_time - peer.m_addr_token_timestamp};
5998 peer.m_addr_token_timestamp = current_time;
6001 uint64_t num_proc = 0;
6002 uint64_t num_rate_limit = 0;
6003 std::shuffle(vAddr.begin(), vAddr.end(), m_rng);
6006 if (interruptMsgProc)
6010 if (peer.m_addr_token_bucket < 1.0) {
6016 peer.m_addr_token_bucket -= 1.0;
6025 addr.
nTime = std::chrono::time_point_cast<std::chrono::seconds>(current_time - 5 * 24h);
6027 AddAddressKnown(peer, addr);
6034 if (addr.
nTime > current_time - 10min && !peer.m_getaddr_sent && vAddr.size() <= 10 && addr.
IsRoutable()) {
6036 RelayAddress(pfrom.
GetId(), addr, reachable);
6040 vAddrOk.push_back(addr);
6043 peer.m_addr_processed += num_proc;
6044 peer.m_addr_rate_limited += num_rate_limit;
6045 LogDebug(
BCLog::NET,
"Received addr: %u addresses (%u processed, %u rate-limited) from peer=%d\n",
6046 vAddr.size(), num_proc, num_rate_limit, pfrom.
GetId());
6048 m_addrman.
Add(vAddrOk, pfrom.
addr, 2h);
6049 if (vAddr.size() < 1000) peer.m_getaddr_sent =
false;
6058bool PeerManagerImpl::SendMessages(
CNode&
node)
6063 PeerRef maybe_peer{GetPeerRef(
node.GetId())};
6064 if (!maybe_peer)
return false;
6065 Peer& peer{*maybe_peer};
6070 if (MaybeDiscourageAndDisconnect(
node, peer))
return true;
6073 if (!
node.IsInboundConn() && !peer.m_outbound_version_message_sent) {
6074 PushNodeVersion(
node, peer);
6075 peer.m_outbound_version_message_sent =
true;
6079 if (!
node.fSuccessfullyConnected ||
node.fDisconnect)
6083 const auto current_time{GetTime<std::chrono::microseconds>()};
6088 if (
node.IsPrivateBroadcastConn()) {
6092 node.fDisconnect =
true;
6099 node.fDisconnect =
true;
6103 MaybeSendPing(
node, peer, now);
6106 if (
node.fDisconnect)
return true;
6108 MaybeSendAddr(
node, peer, current_time);
6110 MaybeSendSendHeaders(
node, peer);
6112 ProcessInvBacklog(now);
6117 CNodeState &state = *
State(
node.GetId());
6120 if (m_chainman.m_best_header ==
nullptr) {
6127 bool sync_blocks_and_headers_from_peer =
false;
6128 if (state.fPreferredDownload) {
6129 sync_blocks_and_headers_from_peer =
true;
6130 }
else if (CanServeBlocks(peer) && !
node.IsAddrFetchConn()) {
6140 if (m_num_preferred_download_peers == 0 || mapBlocksInFlight.empty()) {
6141 sync_blocks_and_headers_from_peer =
true;
6147 if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) || m_chainman.m_best_header->Time() >
NodeClock::now() - 24h) {
6148 const CBlockIndex* pindexStart = m_chainman.m_best_header;
6156 if (pindexStart->
pprev)
6157 pindexStart = pindexStart->
pprev;
6161 state.fSyncStarted =
true;
6185 LOCK(peer.m_block_inv_mutex);
6186 std::vector<CBlock> vHeaders;
6187 bool fRevertToInv = ((!peer.m_prefers_headers &&
6188 (!state.m_requested_hb_cmpctblocks || peer.m_blocks_for_headers_relay.size() > 1)) ||
6191 ProcessBlockAvailability(
node.GetId());
6193 if (!fRevertToInv) {
6194 bool fFoundStartingHeader =
false;
6198 for (
const uint256& hash : peer.m_blocks_for_headers_relay) {
6203 fRevertToInv =
true;
6206 if (pBestIndex !=
nullptr && pindex->
pprev != pBestIndex) {
6218 fRevertToInv =
true;
6221 pBestIndex = pindex;
6222 if (fFoundStartingHeader) {
6225 }
else if (PeerHasHeader(&state, pindex)) {
6227 }
else if (pindex->
pprev ==
nullptr || PeerHasHeader(&state, pindex->
pprev)) {
6230 fFoundStartingHeader =
true;
6235 fRevertToInv =
true;
6240 if (!fRevertToInv && !vHeaders.empty()) {
6241 if (vHeaders.size() == 1 && state.m_requested_hb_cmpctblocks) {
6245 vHeaders.front().GetHash().ToString(),
node.GetId());
6247 std::optional<CSerializedNetMsg> cached_cmpctblock_msg;
6249 LOCK(m_most_recent_block_mutex);
6250 if (m_most_recent_block_hash == pBestIndex->
GetBlockHash()) {
6254 if (cached_cmpctblock_msg.has_value()) {
6255 PushMessage(
node, std::move(cached_cmpctblock_msg.value()));
6263 state.pindexBestHeaderSent = pBestIndex;
6264 }
else if (peer.m_prefers_headers) {
6265 if (vHeaders.size() > 1) {
6268 vHeaders.front().GetHash().ToString(),
6269 vHeaders.back().GetHash().ToString(),
node.GetId());
6272 vHeaders.front().GetHash().ToString(),
node.GetId());
6275 state.pindexBestHeaderSent = pBestIndex;
6277 fRevertToInv =
true;
6283 if (!peer.m_blocks_for_headers_relay.empty()) {
6284 const uint256& hashToAnnounce = peer.m_blocks_for_headers_relay.back();
6297 if (!PeerHasHeader(&state, pindex)) {
6298 peer.m_blocks_for_inv_relay.push_back(hashToAnnounce);
6304 peer.m_blocks_for_headers_relay.clear();
6310 std::vector<CInv> vInv;
6312 LOCK(peer.m_block_inv_mutex);
6313 vInv.reserve(peer.m_blocks_for_inv_relay.size());
6316 for (
const uint256& hash : peer.m_blocks_for_inv_relay) {
6323 peer.m_blocks_for_inv_relay.clear();
6326 if (
auto tx_relay = peer.GetTxRelay(); tx_relay !=
nullptr) {
6327 LOCK(tx_relay->m_tx_inventory_mutex);
6330 if (tx_relay->m_next_inv_send_time < current_time) {
6331 fSendTrickle =
true;
6332 if (
node.IsInboundConn()) {
6341 LOCK(tx_relay->m_bloom_filter_mutex);
6342 if (!tx_relay->m_relay_txs) tx_relay->m_tx_inventory_to_send.clear();
6346 if (fSendTrickle && tx_relay->m_send_mempool) {
6347 auto vtxinfo = m_mempool.
infoAll();
6352 tx_relay->m_send_mempool =
false;
6353 const CFeeRate filterrate{tx_relay->m_fee_filter_received.load()};
6356 tx_relay->m_tx_inventory_to_send.clear();
6358 LOCK(tx_relay->m_bloom_filter_mutex);
6360 for (
const auto& txinfo : vtxinfo) {
6361 const Txid& txid{txinfo.tx->GetHash()};
6362 const Wtxid& wtxid{txinfo.tx->GetWitnessHash()};
6363 const auto inv = peer.m_wtxid_relay ?
6368 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
6371 if (tx_relay->m_bloom_filter) {
6372 if (!tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx))
continue;
6374 tx_relay->m_tx_inventory_known_filter.insert(inv.
hash);
6375 vInv.push_back(inv);
6387 const CFeeRate filterrate{tx_relay->m_fee_filter_received.load()};
6390 auto& invs = tx_relay->m_tx_inventory_to_send;
6391 std::vector<CTransactionRef> res;
6393 if (invs.size() == 0)
return res;
6396 if (invs.capacity() > 2 * invs.size()) invs.shrink_to_fit();
6400 res.reserve(txiters.size());
6401 for (
auto txiter : txiters) {
6402 if (txiter->GetFee() < filterrate.GetFee(txiter->GetTxSize())) {
6405 res.push_back(txiter->GetSharedTx());
6408 tx_relay->m_last_inv_sequence = m_mempool.
GetSequence();
6412 LOCK(tx_relay->m_bloom_filter_mutex);
6413 vInv.reserve(std::min<size_t>(
MAX_INV_SZ, vInv.size() + inv_tx.size()));
6414 for (
auto& tx : inv_tx) {
6418 const auto inv = peer.m_wtxid_relay ?
6422 if (tx_relay->m_tx_inventory_known_filter.contains(inv.
hash)) {
6425 if (tx_relay->m_bloom_filter && !tx_relay->m_bloom_filter->IsRelevantAndUpdate(*tx))
continue;
6427 vInv.push_back(inv);
6432 tx_relay->m_tx_inventory_known_filter.insert(inv.
hash);
6440 auto stalling_timeout = m_block_stalling_timeout.load();
6441 if (state.m_stalling_since.count() && state.m_stalling_since < current_time - stalling_timeout) {
6445 if (
node.IsManualConn()) {
6448 while (!state.vBlocksInFlight.empty()) {
6449 RemoveBlockRequest(state.vBlocksInFlight.front().pindex->GetBlockHash(),
node.GetId());
6452 LogInfo(
"Peer is stalling block download, %s",
node.DisconnectMsg());
6453 node.fDisconnect =
true;
6458 if (stalling_timeout != new_timeout && m_block_stalling_timeout.compare_exchange_strong(stalling_timeout, new_timeout)) {
6468 if (state.vBlocksInFlight.size() > 0) {
6469 QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
6470 int nOtherPeersWithValidatedDownloads = m_peers_downloading_from - 1;
6472 LogInfo(
"Timeout downloading block %s, %s", queuedBlock.pindex->GetBlockHash().ToString(),
node.DisconnectMsg());
6473 node.fDisconnect =
true;
6478 if (state.fSyncStarted && peer.m_headers_sync_timeout < std::chrono::microseconds::max()) {
6480 if (m_chainman.m_best_header->Time() <=
NodeClock::now() - 24h) {
6481 if (current_time > peer.m_headers_sync_timeout && nSyncStarted == 1 && (m_num_preferred_download_peers - state.fPreferredDownload >= 1)) {
6488 LogInfo(
"Timeout downloading headers, %s",
node.DisconnectMsg());
6489 node.fDisconnect =
true;
6492 LogInfo(
"Timeout downloading headers from noban peer, not %s",
node.DisconnectMsg());
6498 state.fSyncStarted =
false;
6500 peer.m_headers_sync_timeout = 0us;
6506 peer.m_headers_sync_timeout = std::chrono::microseconds::max();
6512 ConsiderEviction(
node, peer, GetTime<std::chrono::seconds>());
6517 std::vector<CInv> vGetData;
6518 const bool can_request_blocks_from_peer{current_time >= state.m_block_download_paused_until};
6520 std::vector<const CBlockIndex*> vToDownload;
6522 auto get_inflight_budget = [&state]() {
6529 FindNextBlocksToDownload(peer, get_inflight_budget(), vToDownload, staller);
6530 auto historical_blocks{m_chainman.GetHistoricalBlockRange()};
6531 if (historical_blocks && !IsLimitedPeer(peer)) {
6535 TryDownloadingHistoricalBlocks(
6537 get_inflight_budget(),
6538 vToDownload, from_tip, historical_blocks->second);
6541 uint32_t nFetchFlags = GetFetchFlags(peer);
6543 BlockRequested(
node.GetId(), *pindex);
6547 if (state.vBlocksInFlight.empty() && staller != -1) {
6548 if (
State(staller)->m_stalling_since == 0us) {
6549 State(staller)->m_stalling_since = current_time;
6559 LOCK(m_tx_download_mutex);
6560 for (
const GenTxid& gtxid : m_txdownloadman.GetRequestsToSend(
node.GetId(), current_time)) {
6569 if (!vGetData.empty())
6572 MaybeSendFeefilter(
node, peer, current_time);
constexpr CAmount MAX_MONEY
No amount larger than this (in satoshi) is valid.
bool MoneyRange(const CAmount &nValue)
int64_t CAmount
Amount in satoshis (Can be negative)
enum ReadStatus_t ReadStatus
const std::string & BlockFilterTypeName(BlockFilterType filter_type)
Get the human-readable name for a filter type.
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
constexpr int CFCHECKPT_INTERVAL
Interval between compact filter checkpoints.
CBlockLocator GetLocator(const CBlockIndex *index)
Get a locator for a block index entry.
int64_t GetBlockProofEquivalentTime(const CBlockIndex &to, const CBlockIndex &from, const CBlockIndex &tip, const Consensus::Params ¶ms)
Return the time it would take to redo the work difference between from and to, assuming the current h...
const CBlockIndex * LastCommonAncestor(const CBlockIndex *pa, const CBlockIndex *pb)
Find the last common ancestor two blocks have.
@ BLOCK_VALID_CHAIN
Outputs do not overspend inputs, no double spends, coinbase output ok, no immature coinbase spends,...
@ BLOCK_VALID_TRANSACTIONS
Only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid,...
@ BLOCK_VALID_SCRIPTS
Scripts & signatures ok.
@ BLOCK_VALID_TREE
All parent headers found, difficulty matches, timestamp >= median previous.
@ BLOCK_HAVE_DATA
full block available in blk*.dat
arith_uint256 GetBlockProof(const CBlockIndex &block)
Compute how much work a block index entry corresponds to.
#define Assert(val)
Identity function.
#define Assume(val)
Assume is the identity function.
Stochastic address manager.
void Connected(const CService &addr, NodeSeconds time=Now< NodeSeconds >())
We have successfully connected to this peer.
bool Good(const CService &addr, NodeSeconds time=Now< NodeSeconds >())
Mark an address record as accessible and attempt to move it to addrman's tried table.
bool Add(const std::vector< CAddress > &vAddr, const CNetAddr &source, std::chrono::seconds time_penalty=0s)
Attempt to add one or more addresses to addrman's new table.
void SetServices(const CService &addr, ServiceFlags nServices)
Update an entry's service bits.
bool IsBanned(const CNetAddr &net_addr) EXCLUSIVE_LOCKS_REQUIRED(!m_banned_mutex)
Return whether net_addr is banned.
bool IsDiscouraged(const CNetAddr &net_addr) EXCLUSIVE_LOCKS_REQUIRED(!m_banned_mutex)
Return whether net_addr is discouraged.
void Discourage(const CNetAddr &net_addr) EXCLUSIVE_LOCKS_REQUIRED(!m_banned_mutex)
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
bool LookupFilterRange(int start_height, const CBlockIndex *stop_index, std::vector< BlockFilter > &filters_out) const
Get a range of filters between two heights on a chain.
bool LookupFilterHashRange(int start_height, const CBlockIndex *stop_index, std::vector< uint256 > &hashes_out) const
Get a range of filter hashes between two heights on a chain.
bool LookupFilterHeader(const CBlockIndex *block_index, uint256 &header_out) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_headers_cache)
Get a single filter header by block.
std::vector< CTransactionRef > txn
std::vector< uint16_t > indexes
A CService with information about it as peer.
ServiceFlags nServices
Serialized as uint64_t in V1, and as CompactSize in V2.
static constexpr SerParams V1_NETWORK
NodeSeconds nTime
Always included in serialization. The behavior is unspecified if the value is not representable as ui...
static constexpr SerParams V2_NETWORK
size_t BlockTxCount() const
std::vector< CTransactionRef > vtx
The block chain is a tree shaped structure starting with the genesis block at the root,...
bool IsValid(enum BlockStatus nUpTo) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
CBlockIndex * pprev
pointer to the index of the predecessor of this block
CBlockHeader GetBlockHeader() const
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
bool HaveNumChainTxs() const
Check whether this block and all previous blocks back to the genesis block or an assumeutxo snapshot ...
uint256 GetBlockHash() const
int64_t GetBlockTime() const
unsigned int nTx
Number of transactions in this block.
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
int nHeight
height of the entry in the chain. The genesis block has height 0
FlatFilePos GetBlockPos() const EXCLUSIVE_LOCKS_REQUIRED(
BloomFilter is a probabilistic filter which SPV clients provide so that we can filter the transaction...
bool IsWithinSizeConstraints() const
True if the size is <= MAX_BLOOM_FILTER_SIZE and the number of hash functions is <= MAX_HASH_FUNCS (c...
An in-memory indexed chain of blocks.
bool Contains(const CBlockIndex &index) const
Efficiently check whether a block is present in this chain.
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
CBlockIndex * Next(const CBlockIndex &index) const
Find the successor of a block in this chain, or nullptr if the given index is not found or is the tip...
int Height() const
Return the maximal height in the chain.
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
const HeadersSyncParams & HeadersSync() const
const Consensus::Params & GetConsensus() const
void NumToOpenAdd(size_t n)
Increment the number of new connections of type ConnectionType::PRIVATE_BROADCAST to be opened by CCo...
size_t NumToOpenSub(size_t n)
Decrement the number of new connections of type ConnectionType::PRIVATE_BROADCAST to be opened by CCo...
bool GetNetworkActive() const
bool GetTryNewOutboundPeer() const
class CConnman::PrivateBroadcast m_private_broadcast
bool ShouldRunInactivityChecks(const CNode &node, NodeClock::time_point now) const
Return true if we should disconnect the peer for failing an inactivity check.
std::vector< CAddress > GetAddresses(CNode &requestor, size_t max_addresses, size_t max_pct)
Return addresses from the per-requestor cache.
void SetTryNewOutboundPeer(bool flag)
void WakeMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc)
bool OutboundTargetReached(bool historicalBlockServingLimit) const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex)
check if the outbound target is reached if param historicalBlockServingLimit is set true,...
void StartExtraBlockRelayPeers()
void ForEachNode(const NodeFn &func) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex)
CSipHasher GetDeterministicRandomizer(uint64_t id) const
Get a unique deterministic randomizer.
bool EvictTxPeerIfFull(std::optional< NodeId > protect_peer=std::nullopt) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex)
If we are at capacity for inbound tx-relay peers, attempt to evict one.
uint32_t GetMappedAS(const CNetAddr &addr) const
bool ForNode(NodeId id, std::function< bool(CNode *pnode)> func) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex)
std::vector< CAddress > GetAddressesUnsafe(size_t max_addresses, size_t max_pct, std::optional< Network > network, bool filtered=true) const
Return randomly selected addresses.
int GetExtraBlockRelayCount() const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex)
bool DisconnectNode(std::string_view node) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex)
Mutex & GetNodesMutex() const LOCK_RETURNED(m_nodes_mutex)
int GetExtraFullOutboundCount() const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex)
bool GetUseAddrmanOutgoing() const
bool CheckIncomingNonce(uint64_t nonce) EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex)
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
bool IsMsgCmpctBlk() const
std::string ToString() const
bool IsMsgFilteredBlk() const
bool IsMsgWitnessBlk() const
Used to relay blocks as header + vector<merkle branch> to filtered nodes.
std::vector< std::pair< unsigned int, Txid > > vMatchedTxn
Public only for unit testing and relay testing (not relayed).
bool IsRelayable() const
Whether this address should be relayed to other peers even if we can't reach it ourselves.
static constexpr SerParams V1
bool IsAddrV1Compatible() const
Check if the current object can be serialized in pre-ADDRv2/BIP155 format.
Transport protocol agnostic message container.
Information about a peer.
bool IsFeelerConn() const
bool ExpectServicesFromConn() const
std::atomic< int > nVersion
std::atomic_bool m_has_all_wanted_services
Whether this peer provides all services that we want.
bool IsInboundConn() const
bool HasPermission(NetPermissionFlags permission) const
std::string LogPeer() const
Helper function to log the peer id, optionally including IP address.
bool IsOutboundOrBlockRelayConn() const
bool IsManualConn() const
std::string ConnectionTypeAsString() const
void SetCommonVersion(int greatest_common_version)
std::atomic< bool > m_bip152_highbandwidth_to
std::atomic_bool m_relays_txs
Whether we should relay transactions to this peer.
std::atomic< bool > m_bip152_highbandwidth_from
std::atomic_bool fSuccessfullyConnected
fSuccessfullyConnected is set to true on receiving VERACK from the peer.
bool IsAddrFetchConn() const
uint64_t GetLocalNonce() const
void SetAddrLocal(const CService &addrLocalIn) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_local_mutex)
May not be called more than once.
const NodeClock::time_point m_connected
Unix epoch time at peer connection.
bool IsBlockOnlyConn() const
int GetCommonVersion() const
bool IsFullOutboundConn() const
std::atomic_bool fPauseSend
std::string DisconnectMsg() const
Helper function to log disconnects.
void PongReceived(NodeClock::duration ping_time)
A ping-pong round trip has completed successfully. Update latest and minimum ping durations.
std::atomic_bool m_bloom_filter_loaded
Whether this peer has loaded a bloom filter.
bool IsPrivateBroadcastConn() const
const std::unique_ptr< Transport > m_transport
Transport serializer/deserializer.
const bool m_inbound_onion
Whether this peer is an inbound onion, i.e. connected via our Tor onion service.
std::atomic< std::chrono::seconds > m_last_block_time
UNIX epoch time of the last block received from this peer that we had not yet seen (e....
int AdvertisedVersion() const
Protocol version advertised in our VERSION message.
std::atomic_bool fDisconnect
std::atomic< std::chrono::seconds > m_last_tx_time
UNIX epoch time of the last transaction received from this peer that we had not yet seen (e....
RollingBloomFilter is a probabilistic "keep track of most recently inserted" set.
Simple class for background tasks that should be run periodically or once "after a while".
void scheduleEvery(Function f, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Repeat f until the scheduler is stopped.
void scheduleFromNow(Function f, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Call f once after the delta has passed.
A combination of a network address (CNetAddr) and a (TCP) port.
std::string ToStringAddrPort() const
std::vector< unsigned char > GetKey() const
General SipHash-2-4 implementation.
uint64_t Finalize() const
Compute the 64-bit SipHash-2-4 of the data written so far.
CSipHasher & Write(uint64_t data)
Hash a 64-bit integer worth of data.
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
TxMempoolInfo info_for_relay(const T &id, uint64_t last_sequence) const
Returns info for a transaction if its entry_sequence < last_sequence.
CFeeRate GetMinFee(size_t sizelimit) const
CTransactionRef get(const Txid &hash) const
Return a mempool transaction with a given hash.
size_t DynamicMemoryUsage() const
std::vector< TxMempoolInfo > infoAll() const
bool exists(const Txid &txid) const
uint64_t GetSequence() const EXCLUSIVE_LOCKS_REQUIRED(cs)
std::set< Txid > GetUnbroadcastTxs() const
Returns transactions in unbroadcast set.
unsigned long size() const
void RemoveUnbroadcastTx(const Txid &txid, bool unchecked=false)
Removes a transaction from the unbroadcast set.
std::vector< txiter > ExtractBestByMiningScoreWithTopology(std::vector< Wtxid > &wtxids, size_t n_to_sort) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Look up wtxids in the mempool and (partially) sort by mining score.
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr< const CBlock > &block)
Notifies listeners that a block which builds directly on our current tip has been received and connec...
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
Notifies listeners when the block chain tip advances.
virtual void BlockChecked(const std::shared_ptr< const CBlock > &, const BlockValidationState &)
Notifies listeners of a block validation result.
virtual void ActiveTipChange(const CBlockIndex &new_tip, bool is_ibd)
Notifies listeners any time the block chain tip changes, synchronously.
virtual void BlockDisconnected(const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex)
Notifies listeners of a block being disconnected Provides the block that was disconnected.
virtual void BlockConnected(const kernel::ChainstateRole &role, const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex)
Notifies listeners of a block being connected.
void ClearBlockIndexCandidates() EXCLUSIVE_LOCKS_REQUIRED(void PopulateBlockIndexCandidates() EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex * FindForkInGlobalIndex(const CBlockLocator &locator) const EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Populate the candidate set by calling TryAddBlockIndexCandidate on all valid block indices.
Interface for managing multiple Chainstate objects, where each chainstate is associated with chainsta...
bool IsInitialBlockDownload() const noexcept
Check whether we are doing an initial block download (synchronizing from disk or network)
MempoolAcceptResult ProcessTransaction(const CTransactionRef &tx, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Try to add a transaction to the memory pool.
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Chainstate & ActiveChainstate() const
Alternatives to CurrentChainstate() used by older code to query latest chainstate information without...
SnapshotCompletionResult MaybeValidateSnapshot(Chainstate &validated_cs, Chainstate &unvalidated_cs) EXCLUSIVE_LOCKS_REQUIRED(Chainstate & CurrentChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Try to validate an assumeutxo snapshot by using a validated historical chainstate targeted at the sna...
bool ProcessNewBlock(const std::shared_ptr< const CBlock > &block, bool force_processing, bool min_pow_checked, bool *new_block) LOCKS_EXCLUDED(cs_main)
Process an incoming block.
bool ProcessNewBlockHeaders(std::span< const CBlockHeader > headers, bool min_pow_checked, BlockValidationState &state, const CBlockIndex **ppindex=nullptr) LOCKS_EXCLUDED(cs_main)
Process incoming block headers.
const arith_uint256 & MinimumChainWork() const
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
void ReportHeadersPresync(int64_t height, int64_t timestamp)
This is used by net_processing to report pre-synchronization progress of headers, as headers are not ...
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Double ended buffer combining vector and stream-like interfaces.
void ignore(size_t num_ignore)
uint64_t rand64() noexcept
Generate a random 64-bit integer.
const uint256 & ToUint256() const LIFETIMEBOUND
static Mutex g_msgproc_mutex
Mutex for anything that is only accessed via the msg processing thread.
virtual void FinalizeNode(const CNode &node)=0
Handle removal of a peer (clear state)
virtual bool ProcessMessages(CNode &node, std::atomic< bool > &interrupt) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex)=0
Process protocol messages received from a given node.
virtual bool HasAllDesirableServiceFlags(ServiceFlags services) const =0
Callback to determine whether the given set of service flags are sufficient for a peer to be "relevan...
virtual bool SendMessages(CNode &node) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex)=0
Send queued protocol messages to a given node.
virtual void InitializeNode(const CNode &node, ServiceFlags our_services)=0
Initialize a peer (setup state)
static bool HasFlag(NetPermissionFlags flags, NetPermissionFlags f)
ReadStatus FillBlock(CBlock &block, const std::vector< CTransactionRef > &vtx_missing, bool segwit_active)
bool IsTxAvailable(size_t index) const
ReadStatus InitData(const CBlockHeaderAndShortTxIDs &cmpctblock, const std::vector< std::pair< Wtxid, CTransactionRef > > &extra_txn)
virtual util::Expected< void, std::string > FetchBlock(NodeId peer_id, const CBlockIndex &block_index)=0
Attempt to manually fetch block from a given peer.
virtual ServiceFlags GetDesirableServiceFlags(ServiceFlags services) const =0
Gets the set of service flags which are "desirable" for a given peer.
virtual void StartScheduledTasks(CScheduler &scheduler)=0
Begin running background tasks, should only be called once.
virtual std::vector< node::TxOrphanage::OrphanInfo > GetOrphanTransactions()=0
static std::unique_ptr< PeerManager > make(CConnman &connman, AddrMan &addrman, BanMan *banman, ChainstateManager &chainman, CTxMemPool &pool, node::Warnings &warnings, Options opts)
virtual void UnitTestMisbehaving(NodeId peer_id)=0
virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) const =0
Get statistics from node state.
virtual void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds)=0
This function is used for testing the stale tip eviction logic, see denialofservice_tests....
virtual void CheckForStaleTipAndEvictPeers()=0
Evict extra outbound peers.
Store a list of transactions to be broadcast privately.
@ QueueFull
Rejected: the queue is already at MAX_TRANSACTIONS.
@ AlreadyPresent
The transaction was already present with send attempts remaining; no change.
@ Added
The transaction was newly added or reset after exhausting its send attempts.
static constexpr size_t MAX_TRANSACTIONS
Maximum number of transactions tracked simultaneously.
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
bool Contains(Network net) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
std::string GetDebugMessage() const
std::string ToString() const
256-bit unsigned big integer.
constexpr bool IsNull() const
std::string ToString() const
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
CBlockFileInfo *GetBlockFileInfo(size_t n) EXCLUSIVE_LOCKS_REQUIRED(bool WriteBlockUndo(const CBlockUndo &blockundo, BlockValidationState &state, CBlockIndex &block) EXCLUSIVE_LOCKS_REQUIRED(FlatFilePos WriteBlock(const CBlock &block, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(void UpdateBlockInfo(const CBlock &block, unsigned int nHeight, const FlatFilePos &pos) EXCLUSIVE_LOCKS_REQUIRED(bool IsPruneMode() const
Get block file info entry for one block file.
bool LoadingBlocks() const
ReadRawBlockResult ReadRawBlock(const FlatFilePos &pos, std::optional< std::pair< size_t, size_t > > block_part=std::nullopt) const
bool ReadBlock(CBlock &block, const FlatFilePos &pos, const std::optional< uint256 > &expected_hash) const
Functions for disk access for blocks.
Class responsible for deciding what transactions to request and, once downloaded, whether and how to ...
Manages warning messages within a node.
std::string ToString() const
const uint256 & ToUint256() const LIFETIMEBOUND
The util::Expected class provides a standard way for low-level functions to return either error value...
A token bucket rate limiter.
bool decrement(double n=1.0, double floor=0.0)
Consume n tokens.
void increment(const time_point &now)
Refill tokens based on elapsed time since last call.
double value() const
Current token balance.
The util::Unexpected class represents an unexpected value stored in util::Expected.
std::string TransportTypeAsString(TransportProtocolType transport_type)
Convert TransportProtocolType enum to a string value.
@ BLOCK_HEADER_LOW_WORK
the block header may be on a too-little-work chain
@ BLOCK_INVALID_HEADER
invalid proof of work or time too old
@ BLOCK_CACHED_INVALID
this block was cached as being invalid and we didn't store the reason why
@ BLOCK_CONSENSUS
invalid by consensus rules (excluding any below reasons)
@ BLOCK_MISSING_PREV
We don't have the previous block the checked one is built on.
@ BLOCK_INVALID_PREV
A block this one builds on is invalid.
@ BLOCK_MUTATED
the block's data didn't match the data committed to by the PoW
@ BLOCK_TIME_FUTURE
block timestamp was > 2 hours in the future (or our clock is bad)
@ BLOCK_RESULT_UNSET
initial value. Block has not yet been rejected
@ TX_MISSING_INPUTS
transaction was missing some of its inputs
@ TX_UNKNOWN
transaction was not validated because package failed
@ TX_NO_MEMPOOL
this node does not have a mempool so can't validate the transaction
@ TX_RESULT_UNSET
initial value. Tx has not yet been rejected
static size_t RecursiveDynamicUsage(const CScript &script)
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
bool DeploymentActiveAfter(const CBlockIndex *pindexPrev, const Consensus::Params ¶ms, Consensus::BuriedDeployment dep, VersionBitsCache &versionbitscache)
Determine if a deployment is active for the next block.
bool DeploymentActiveAt(const CBlockIndex &index, const Consensus::Params ¶ms, Consensus::BuriedDeployment dep, VersionBitsCache &versionbitscache)
Determine if a deployment is active for this block.
is a home for simple enum and struct type definitions that can be used internally by functions in the...
#define LogDebug(category,...)
CSerializedNetMsg Make(std::string msg_type, Args &&... args)
constexpr const char * FILTERCLEAR
The filterclear message tells the receiving peer to remove a previously-set bloom filter.
constexpr const char * FEEFILTER
The feefilter message tells the receiving peer not to inv us any txs which do not meet the specified ...
constexpr const char * SENDHEADERS
Indicates that a node prefers to receive new block announcements via a "headers" message rather than ...
constexpr const char * GETBLOCKS
The getblocks message requests an inv message that provides block header hashes starting from a parti...
constexpr const char * HEADERS
The headers message sends one or more block headers to a node which previously requested certain head...
constexpr const char * ADDR
The addr (IP address) message relays connection information for peers on the network.
constexpr const char * GETBLOCKTXN
Contains a BlockTransactionsRequest Peer should respond with "blocktxn" message.
constexpr const char * CMPCTBLOCK
Contains a CBlockHeaderAndShortTxIDs object - providing a header and list of "short txids".
constexpr const char * CFCHECKPT
cfcheckpt is a response to a getcfcheckpt request containing a vector of evenly spaced filter headers...
constexpr const char * SENDADDRV2
The sendaddrv2 message signals support for receiving ADDRV2 messages (BIP155).
constexpr const char * GETADDR
The getaddr message requests an addr message from the receiving node, preferably one with lots of IP ...
constexpr const char * GETCFILTERS
getcfilters requests compact filters for a range of blocks.
constexpr const char * PONG
The pong message replies to a ping message, proving to the pinging node that the ponging node is stil...
constexpr const char * BLOCKTXN
Contains a BlockTransactions.
constexpr const char * CFHEADERS
cfheaders is a response to a getcfheaders request containing a filter header and a vector of filter h...
constexpr const char * PING
The ping message is sent periodically to help confirm that the receiving peer is still connected.
constexpr const char * FILTERLOAD
The filterload message tells the receiving peer to filter all relayed transactions and requested merk...
constexpr const char * SENDTXRCNCL
Contains a 4-byte version number and an 8-byte salt.
constexpr const char * ADDRV2
The addrv2 message relays connection information for peers on the network just like the addr message,...
constexpr const char * VERACK
The verack message acknowledges a previously-received version message, informing the connecting node ...
constexpr const char * GETHEADERS
The getheaders message requests a headers message that provides block headers starting from a particu...
constexpr const char * FILTERADD
The filteradd message tells the receiving peer to add a single element to a previously-set bloom filt...
constexpr const char * CFILTER
cfilter is a response to a getcfilters request containing a single compact filter.
constexpr const char * FEATURE
BIP 434 Peer feature negotiation.
constexpr const char * GETDATA
The getdata message requests one or more data objects from another node.
constexpr const char * SENDCMPCT
Contains a 1-byte bool and 8-byte LE version number.
constexpr const char * GETCFCHECKPT
getcfcheckpt requests evenly spaced compact filter headers, enabling parallelized download and valida...
constexpr const char * INV
The inv message (inventory message) transmits one or more inventories of objects known to the transmi...
constexpr const char * TX
The tx message transmits a single transaction.
constexpr const char * MEMPOOL
The mempool message requests the TXIDs of transactions that the receiving node has verified as valid ...
constexpr const char * NOTFOUND
The notfound message is a reply to a getdata message which requested an object the receiving node doe...
constexpr const char * MERKLEBLOCK
The merkleblock message is a reply to a getdata message which requested a block using the inventory t...
constexpr const char * WTXIDRELAY
Indicates that a node prefers to relay transactions via wtxid, rather than txid.
constexpr const char * BLOCK
The block message transmits a single serialized block.
constexpr const char * GETCFHEADERS
getcfheaders requests a compact filter header and the filter hashes for a range of blocks,...
constexpr const char * VERSION
The version message provides information about the transmitting node to the receiving node at the beg...
constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS
Maximum number of transactions to consider for requesting, per peer.
""_hex is a compile-time user-defined literal returning a std::array<std::byte>, equivalent to ParseH...
bool ShouldDebugLog(Category category)
Return whether messages with specified category should be debug logged.
std::string ToString(const T &t)
Locale-independent version of std::to_string.
std::string strSubVersion
Subversion as sent to the P2P network in version messages.
std::optional< CService > GetLocalAddrForPeer(CNode &node)
Returns a local address that we should advertise to this peer.
std::function< void(const CAddress &addr, const std::string &msg_type, std::span< const unsigned char > data, bool is_incoming)> CaptureMessage
Defaults to CaptureMessageToFile(), but can be overridden by unit tests.
bool SeenLocal(const CService &addr)
vote for a local address
constexpr unsigned int MAX_SUBVERSION_LENGTH
Maximum length of the user agent string in version message.
constexpr std::chrono::minutes TIMEOUT_INTERVAL
Time after which to disconnect, after waiting for a ping response (or inactivity).
static constexpr auto HEADERS_RESPONSE_TIME
How long to wait for a peer to respond to a getheaders request.
static constexpr size_t MAX_ADDR_TO_SEND
The maximum number of address records permitted in an ADDR message.
static constexpr auto INVENTORY_BUCKET_CHECK_DELAY
Delay between checking inventory bucket and backlog.
static constexpr size_t MAX_ADDR_PROCESSING_TOKEN_BUCKET
The soft limit of the address processing token bucket (the regular MAX_ADDR_RATE_PER_SECOND based inc...
static constexpr auto INVENTORY_BUCKET_BACKLOG_HEARTBEAT
Delay between inventory bucket backlog heartbeat log entries.
TRACEPOINT_SEMAPHORE(net, inbound_message)
static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER
Number of blocks that can be requested at any given time from a single peer.
static constexpr auto BLOCK_STALLING_TIMEOUT_DEFAULT
Default time during which a peer must stall block download progress before being disconnected.
static constexpr auto AVG_FEEFILTER_BROADCAST_INTERVAL
Average delay between feefilter broadcasts in seconds.
static constexpr auto EXTRA_PEER_CHECK_INTERVAL
How frequently to check for extra outbound peers and disconnect.
static const unsigned int BLOCK_DOWNLOAD_WINDOW
Size of the "block download window": how far ahead of our current height do we fetch?...
static constexpr int STALE_RELAY_AGE_LIMIT
Age after which a stale block will no longer be served if requested as protection against fingerprint...
static constexpr int HISTORICAL_BLOCK_AGE
Age after which a block is considered historical for purposes of rate limiting block relay.
static constexpr auto ROTATE_ADDR_RELAY_DEST_INTERVAL
Delay between rotating the peers we relay a particular address to.
static constexpr auto MANUAL_PEER_BLOCK_DOWNLOAD_COOLDOWN
Time to avoid requesting blocks from a manual peer after it stalls block download.
static constexpr auto MINIMUM_CONNECT_TIME
Minimum time an outbound-peer-eviction candidate must be connected for, in order to evict.
static constexpr auto CHAIN_SYNC_TIMEOUT
Timeout for (unprotected) outbound peers to sync to our chainwork.
static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL
Average delay between trickled inventory transmissions for outbound peers.
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS
Minimum blocks required to signal NODE_NETWORK_LIMITED.
static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL
Average delay between local address broadcasts.
static const int MAX_BLOCKTXN_DEPTH
Maximum depth of blocks we're willing to respond to GETBLOCKTXN requests for.
static constexpr size_t INVENTORY_BUCKET_BACKLOG_CAPACITY
Empty backlog target capacity.
static constexpr int32_t MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT
Protect at least this many outbound peers from disconnection due to slow/ behind headers chain.
static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL
Average delay between trickled inventory transmissions for inbound peers.
static constexpr size_t NUM_PRIVATE_BROADCAST_PER_TX
For private broadcast, send a transaction to this many peers.
static constexpr auto MAX_FEEFILTER_CHANGE_DELAY
Maximum feefilter broadcast delay after significant change.
static constexpr uint32_t MAX_GETCFILTERS_SIZE
Maximum number of compact filters that may be requested with one getcfilters.
static constexpr double OUTBOUND_INVENTORY_BUCKET_MULTIPLIER
Multiplier for the inventory bucket rate for outbounds.
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_BASE
Headers download timeout.
static const unsigned int MAX_GETDATA_SZ
Limit to avoid sending big packets.
static constexpr double BLOCK_DOWNLOAD_TIMEOUT_BASE
Block download timeout base, expressed in multiples of the block interval (i.e.
static constexpr auto PRIVATE_BROADCAST_MAX_CONNECTION_LIFETIME
Private broadcast connections must complete within this time.
static constexpr auto STALE_CHECK_INTERVAL
How frequently to check for stale tips.
static constexpr auto AVG_ADDRESS_BROADCAST_INTERVAL
Average delay between peer address broadcasts.
static const unsigned int MAX_LOCATOR_SZ
The maximum number of entries in a locator.
static constexpr double BLOCK_DOWNLOAD_TIMEOUT_PER_PEER
Additional block download timeout per parallel downloading peer (i.e.
static constexpr double MAX_ADDR_RATE_PER_SECOND
The maximum rate of address records we're willing to process on average.
static constexpr auto PING_INTERVAL
Time between pings automatically sent out for latency probing and keepalive.
static constexpr size_t INVENTORY_BUCKET_BACKLOG_HEARTBEAT_MIN
Minimum backlog to trigger heartbeat log entries.
static const int MAX_CMPCTBLOCK_DEPTH
Maximum depth of blocks we're willing to serve as compact blocks to peers when requested.
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE
Maximum number of headers to announce when relaying blocks with headers message.
static const unsigned int NODE_NETWORK_LIMITED_ALLOW_CONN_BLOCKS
Window, in blocks, for connecting to NODE_NETWORK_LIMITED peers.
static constexpr uint32_t MAX_GETCFHEADERS_SIZE
Maximum number of cf hashes that may be requested with one getcfheaders.
static constexpr auto BLOCK_STALLING_TIMEOUT_MAX
Maximum timeout for stalling block download.
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER
static constexpr uint64_t RANDOMIZER_ID_ADDRESS_RELAY
SHA256("main address relay")[0:8].
static constexpr size_t MAX_PCT_ADDR_TO_SEND
the maximum percentage of addresses from our addrman to return in response to a getaddr message.
static const unsigned int MAX_INV_SZ
The maximum number of entries in an 'inv' protocol message.
constexpr unsigned int MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK
Maximum number of outstanding CMPCTBLOCK requests for the same block.
constexpr uint64_t CMPCTBLOCKS_VERSION
The compactblocks version we support.
ReachableNets g_reachable_nets
bool IsProxy(const CNetAddr &addr)
constexpr unsigned int DEFAULT_MIN_RELAY_TX_FEE
Default for -minrelaytxfee, minimum relay fee for transactions.
constexpr TransactionSerParams TX_NO_WITNESS
constexpr TransactionSerParams TX_WITH_WITNESS
std::shared_ptr< const CTransaction > CTransactionRef
GenTxid ToGenTxid(const CInv &inv)
Convert a TX/WITNESS_TX/WTX CInv to a GenTxid.
constexpr size_t MAX_FEATUREDATA_LENGTH
constexpr uint32_t MSG_WITNESS_FLAG
getdata message type flags
@ MSG_WTX
Defined in BIP 339.
@ MSG_CMPCT_BLOCK
Defined in BIP152.
@ MSG_WITNESS_BLOCK
Defined in BIP144.
ServiceFlags
nServices flags
constexpr size_t MAX_FEATUREID_LENGTH
static bool MayHaveUsefulAddressDB(ServiceFlags services)
Checks if a peer with the given service flags may be capable of having a robust address-storage DB.
constexpr int MIN_PEER_PROTO_VERSION
disconnect from peers older than this proto version
constexpr int SHORT_IDS_BLOCKS_VERSION
short-id-based block download starts with this version
constexpr int BIP0031_VERSION
BIP 0031, pong message, is enabled for all versions AFTER this one.
constexpr int FEEFILTER_VERSION
"feefilter" tells peers to filter invs to you by fee starts with this version
constexpr int WTXID_RELAY_VERSION
"wtxidrelay" message type for wtxid-based relay starts with this version
constexpr int INVALID_CB_NO_BAN_VERSION
not banning for invalid compact blocks starts with this version
constexpr int FEATURE_VERSION
"feature" message type for feature negotiation starts with this version
constexpr int SENDHEADERS_VERSION
"sendheaders" message type and announcing blocks with headers starts with this version
constexpr unsigned int MAX_SCRIPT_ELEMENT_SIZE
#define LIMITED_VECTOR(obj, n)
#define LIMITED_STRING(obj, n)
uint64_t ReadCompactSize(Stream &is, bool range_check=true)
Decode a CompactSize-encoded variable-length integer.
constexpr auto MakeUCharSpan(const V &v) -> decltype(UCharSpanCast(std::span{v}))
Like the std::span constructor, but for (const) unsigned char member types only.
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
std::vector< uint256 > vHave
NodeClock::duration m_ping_wait
std::vector< int > vHeightInFlight
CAmount m_fee_filter_received
std::chrono::seconds time_offset
bool m_addr_relay_enabled
uint64_t m_addr_rate_limited
uint64_t m_addr_processed
ServiceFlags their_services
Parameters that influence chain consensus.
int64_t nPowTargetSpacing
std::chrono::seconds PowTargetSpacing() const
Validation result for a transaction evaluated by MemPoolAccept (single or package).
const ResultType m_result_type
Result type.
const TxValidationState m_state
Contains information about why the transaction failed.
@ DIFFERENT_WITNESS
Valid, transaction was already in the mempool.
@ INVALID
Fully validated, valid.
const std::list< CTransactionRef > m_replaced_transactions
Mempool transactions replaced by the tx.
Version of the system clock that is mockable in the context of tests (via FakeNodeClock or SetMockTim...
static time_point now() noexcept
Return current system time or mocked time, if set.
std::chrono::time_point< NodeClock > time_point
static constexpr time_point epoch
Validation result for package mempool acceptance.
PackageValidationState m_state
std::map< Wtxid, MempoolAcceptResult > m_tx_results
Map from wtxid to finished MempoolAcceptResults.
std::chrono::seconds median_outbound_time_offset
Information about chainstate that notifications are sent from.
bool historical
Whether this is a historical chainstate downloading old blocks to validate an assumeutxo snapshot,...
CFeeRate min_relay_feerate
A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation)
std::vector< NodeId > m_senders
std::string ToString() const
#define AssertLockNotHeld(cs)
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
COutPoint ProcessBlock(const NodeContext &node, const std::shared_ptr< CBlock > &block)
Returns the generated coin (or Null if the block was invalid).
#define EXCLUSIVE_LOCKS_REQUIRED(...)
#define LOCKS_EXCLUDED(...)
#define ACQUIRED_BEFORE(...)
#define TRACEPOINT(context,...)
consteval auto _(util::TranslatedLiteral str)
ReconciliationRegisterResult
constexpr uint32_t TXRECONCILIATION_VERSION
Supported transaction reconciliation protocol version.
std::string SanitizeString(std::string_view str, int rule)
Remove unsafe chars.
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
constexpr int64_t count_seconds(std::chrono::seconds t)
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
PackageMempoolAcceptResult ProcessNewPackage(Chainstate &active_chainstate, CTxMemPool &pool, const Package &package, bool test_accept, const std::optional< CFeeRate > &client_maxfeerate)
Validate (and maybe submit) a package to the mempool.
bool IsBlockMutated(const CBlock &block, bool check_witness_root)
Check if a block has been mutated (with respect to its merkle root and witness commitments).
bool HasValidProofOfWork(std::span< const CBlockHeader > headers, const Consensus::Params &consensusParams)
Check that the proof of work on each blockheader matches the value in nBits.
arith_uint256 CalculateClaimedHeadersWork(std::span< const CBlockHeader > headers)
Return the sum of the claimed work on a given set of headers.
@ UNVALIDATED
Blocks after an assumeutxo snapshot have been validated but the snapshot itself has not been validate...
constexpr unsigned int MIN_BLOCKS_TO_KEEP
Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pr...