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};
370 mutable Mutex m_addr_send_times_mutex;
372 std::chrono::microseconds m_next_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
374 std::chrono::microseconds m_next_local_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
377 std::atomic_bool m_wants_addrv2{
false};
386 std::atomic<uint64_t> m_addr_rate_limited{0};
388 std::atomic<uint64_t> m_addr_processed{0};
394 Mutex m_getdata_requests_mutex;
396 std::deque<CInv> m_getdata_requests
GUARDED_BY(m_getdata_requests_mutex);
402 Mutex m_headers_sync_mutex;
405 std::unique_ptr<HeadersSyncState> m_headers_sync
PT_GUARDED_BY(m_headers_sync_mutex)
GUARDED_BY(m_headers_sync_mutex) {};
408 std::atomic<bool> m_sent_sendheaders{
false};
418 std::atomic<std::chrono::seconds> m_time_offset{0
s};
422 , m_our_services{our_services}
423 , m_is_inbound{is_inbound}
427 mutable Mutex m_tx_relay_mutex;
430 std::unique_ptr<TxRelay> m_tx_relay
GUARDED_BY(m_tx_relay_mutex);
433using PeerRef = std::shared_ptr<Peer>;
445 uint256 hashLastUnknownBlock{};
451 bool fSyncStarted{
false};
453 std::chrono::microseconds m_stalling_since{0us};
454 std::list<QueuedBlock> vBlocksInFlight;
456 std::chrono::microseconds m_downloading_since{0us};
458 std::chrono::microseconds m_block_download_paused_until{0us};
460 bool fPreferredDownload{
false};
462 bool m_requested_hb_cmpctblocks{
false};
464 bool m_provides_cmpctblocks{
false};
490 struct ChainSyncTimeoutState {
492 std::chrono::seconds m_timeout{0
s};
496 bool m_sent_getheaders{
false};
498 bool m_protect{
false};
501 ChainSyncTimeoutState m_chain_sync;
507struct InvToSendBucket {
508 const double count_floor{0};
509 std::vector<Wtxid> backlog;
526 static constexpr double SIZE_INIT{12'000'000};
527 static constexpr double SIZE_CAP{50'000'000};
528 static constexpr double SIZE_REFILL{20'000};
530 static constexpr double INBOUND_COUNT_SECONDS{30};
532 InvToSendBucket(
unsigned int rate,
double mult)
534 size_bucket(SIZE_REFILL * mult, SIZE_INIT, SIZE_CAP),
535 count_bucket(rate * mult, rate * INBOUND_COUNT_SECONDS, rate * INBOUND_COUNT_SECONDS)
541 return !backlog.empty() && size_bucket.
value() > 0 && count_bucket.
value() > 0;
552 bool decrement(
double size)
554 bool size_ok = size_bucket.
decrement(size, -50e3);
555 bool count_ok = count_bucket.
decrement(1, count_floor);
556 return size_ok && count_ok;
563 .count_bucket = count_bucket.
value(),
564 .size_bucket = size_bucket.
value(),
595 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);
597 EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_most_recent_block_mutex, g_msgproc_mutex, !m_tx_download_mutex, !m_inv_to_send_mutex);
612 void SetBestBlock(
int height,
std::chrono::seconds time)
override
614 m_best_height = height;
615 m_best_block_time = time;
623 const std::atomic<bool>& interruptMsgProc)
624 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);
636 void ReattemptPrivateBroadcast(
CScheduler& scheduler);
651 void Misbehaving(Peer& peer, const
std::
string& message);
662 bool via_compact_block, const
std::
string& message = "")
671 bool MaybeDiscourageAndDisconnect(
CNode& pnode, Peer& peer);
684 bool MaybeDisconnectForTxRelayCapacity(
CNode&
node, const
std::
string& msg_type,
699 bool first_time_failure)
724 bool ProcessOrphanTx(Peer& peer)
734 void ProcessHeadersMessage(
CNode& pfrom, Peer& peer,
736 bool via_compact_block)
767 bool IsContinuationOfLowWorkHeadersSync(Peer& peer,
CNode& pfrom,
781 bool TryLowWorkHeadersSync(Peer& peer,
CNode& pfrom,
796 void HeadersDirectFetchBlocks(
CNode& pfrom, const Peer& peer, const
CBlockIndex& last_header);
798 void UpdatePeerStateForReceivedHeaders(
CNode& pfrom, const
CBlockIndex& last_header,
bool received_new_header,
bool may_have_more_headers)
805 template <
typename... Args>
806 void MakeAndPushMessage(
CNode&
node, std::string msg_type, Args&&...
args)
const
810 template <
typename... Args>
811 [[maybe_unused]]
void MakeAndPushFeature(
CNode&
node, std::string_view feature_id, Args&&...
args)
const
814 std::vector<unsigned char> feature_data;
821 void PushNodeVersion(
CNode& pnode,
const Peer& peer);
869 std::unique_ptr<TxReconciliationTracker> m_txreconciliation;
872 std::atomic<int> m_best_height{-1};
874 std::atomic<std::chrono::seconds> m_best_block_time{0
s};
882 const Options m_opts;
884 bool RejectIncomingTxs(
const CNode& peer)
const;
892 mutable Mutex m_peer_mutex;
899 std::map<NodeId, PeerRef> m_peer_map
GUARDED_BY(m_peer_mutex);
909 uint32_t GetFetchFlags(
const Peer& peer)
const;
911 std::map<uint64_t, std::chrono::microseconds> m_next_inv_to_inbounds_per_network_key
GUARDED_BY(g_msgproc_mutex);
928 std::atomic<int> m_wtxid_relay_peers{0};
946 std::chrono::microseconds NextInvToInbounds(std::chrono::microseconds now,
947 std::chrono::seconds average_interval,
952 Mutex m_most_recent_block_mutex;
953 std::shared_ptr<const CBlock> m_most_recent_block
GUARDED_BY(m_most_recent_block_mutex);
954 std::shared_ptr<const CBlockHeaderAndShortTxIDs> m_most_recent_compact_block
GUARDED_BY(m_most_recent_block_mutex);
956 std::unique_ptr<const std::map<GenTxid, CTransactionRef>> m_most_recent_block_txs
GUARDED_BY(m_most_recent_block_mutex);
960 Mutex m_headers_presync_mutex;
968 using HeadersPresyncStats = std::pair<arith_uint256, std::optional<std::pair<int64_t, uint32_t>>>;
970 std::map<NodeId, HeadersPresyncStats> m_headers_presync_stats
GUARDED_BY(m_headers_presync_mutex) {};
974 std::atomic_bool m_headers_presync_should_signal{
false};
1044 std::atomic<
std::chrono::seconds> m_last_tip_update{0
s};
1050 void ProcessGetData(
CNode& pfrom, Peer& peer,
const std::atomic<bool>& interruptMsgProc)
1055 void ProcessBlock(
CNode&
node,
const std::shared_ptr<const CBlock>& block,
bool force_processing,
bool min_pow_checked);
1088 std::vector<std::pair<Wtxid, CTransactionRef>> vExtraTxnForCompact
GUARDED_BY(g_msgproc_mutex);
1090 size_t vExtraTxnForCompactIt
GUARDED_BY(g_msgproc_mutex) = 0;
1102 int64_t ApproximateBestBlockDepth() const;
1112 void ProcessGetBlockData(
CNode& pfrom, Peer& peer, const
CInv& inv)
1130 bool PrepareBlockFilterRequest(
CNode&
node, Peer& peer,
1132 const
uint256& stop_hash, uint32_t max_height_diff,
1179 void ProcessAddrs(
std::string_view msg_type,
CNode& pfrom, Peer& peer,
std::vector<
CAddress>&& vAddr, const
std::atomic<
bool>& interruptMsgProc)
1185 void LogBlockHeader(const
CBlockIndex& index, const
CNode& peer,
bool via_compact_block);
1191 InvToSendBucket m_inbound_inv_bucket
GUARDED_BY(m_inv_to_send_mutex);
1192 InvToSendBucket m_outbound_inv_bucket
GUARDED_BY(m_inv_to_send_mutex);
1193 std::atomic<
NodeClock::time_point> m_next_inv_bucket_check{NodeClock::time_point::min()};
1194 std::optional<NodeClock::time_point> m_next_inv_bucket_heartbeat
GUARDED_BY(m_inv_to_send_mutex);
1199const CNodeState* PeerManagerImpl::
State(
NodeId pnode)
const
1201 std::map<NodeId, CNodeState>::const_iterator it = m_node_states.find(pnode);
1202 if (it == m_node_states.end())
1209 return const_cast<CNodeState*
>(std::as_const(*this).State(pnode));
1217static bool IsAddrCompatible(
const Peer& peer,
const CAddress& addr)
1222void PeerManagerImpl::AddAddressKnown(Peer& peer,
const CAddress& addr)
1224 assert(peer.m_addr_known);
1225 peer.m_addr_known->insert(addr.
GetKey());
1228void PeerManagerImpl::PushAddress(Peer& peer,
const CAddress& addr)
1233 assert(peer.m_addr_known);
1234 if (addr.
IsValid() && !peer.m_addr_known->contains(addr.
GetKey()) && IsAddrCompatible(peer, addr)) {
1236 peer.m_addrs_to_send[m_rng.randrange(peer.m_addrs_to_send.size())] = addr;
1238 peer.m_addrs_to_send.push_back(addr);
1243static void AddKnownTx(Peer& peer,
const uint256& hash)
1245 auto tx_relay = peer.GetTxRelay();
1246 if (!tx_relay)
return;
1248 LOCK(tx_relay->m_tx_inventory_mutex);
1249 tx_relay->m_tx_inventory_known_filter.insert(hash);
1253static bool CanServeBlocks(
const Peer& peer)
1260static bool IsLimitedPeer(
const Peer& peer)
1267static bool CanServeWitnesses(
const Peer& peer)
1272std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
1273 std::chrono::seconds average_interval,
1274 uint64_t network_key)
1276 auto [it, inserted] = m_next_inv_to_inbounds_per_network_key.try_emplace(network_key, 0us);
1277 auto& timer{it->second};
1279 timer = now + m_rng.rand_exp_duration(average_interval);
1284bool PeerManagerImpl::IsBlockRequested(
const uint256& hash)
1286 return mapBlocksInFlight.contains(hash);
1289bool PeerManagerImpl::IsBlockRequestedFromOutbound(
const uint256& hash)
1291 for (
auto range = mapBlocksInFlight.equal_range(hash); range.first != range.second; range.first++) {
1292 auto [nodeid, block_it] = range.first->second;
1293 PeerRef peer{GetPeerRef(nodeid)};
1294 if (peer && !peer->m_is_inbound)
return true;
1300void PeerManagerImpl::RemoveBlockRequest(
const uint256& hash, std::optional<NodeId> from_peer)
1302 auto range = mapBlocksInFlight.equal_range(hash);
1303 if (range.first == range.second) {
1311 while (range.first != range.second) {
1312 const auto& [node_id, list_it]{range.first->second};
1314 if (from_peer && *from_peer != node_id) {
1321 if (state.vBlocksInFlight.begin() == list_it) {
1323 state.m_downloading_since = std::max(state.m_downloading_since, GetTime<std::chrono::microseconds>());
1325 state.vBlocksInFlight.erase(list_it);
1327 if (state.vBlocksInFlight.empty()) {
1329 m_peers_downloading_from--;
1331 state.m_stalling_since = 0us;
1333 range.first = mapBlocksInFlight.erase(range.first);
1337bool PeerManagerImpl::BlockRequested(
NodeId nodeid,
const CBlockIndex& block, std::list<QueuedBlock>::iterator** pit)
1341 CNodeState *state =
State(nodeid);
1342 assert(state !=
nullptr);
1347 for (
auto range = mapBlocksInFlight.equal_range(hash); range.first != range.second; range.first++) {
1348 if (range.first->second.first == nodeid) {
1350 *pit = &range.first->second.second;
1357 RemoveBlockRequest(hash, nodeid);
1359 std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(),
1360 {&block, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock(&m_mempool) : nullptr)});
1361 if (state->vBlocksInFlight.size() == 1) {
1363 state->m_downloading_since = GetTime<std::chrono::microseconds>();
1364 m_peers_downloading_from++;
1366 auto itInFlight = mapBlocksInFlight.insert(std::make_pair(hash, std::make_pair(nodeid, it)));
1368 *pit = &itInFlight->second.second;
1373void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid)
1380 if (m_opts.ignore_incoming_txs)
return;
1382 CNodeState* nodestate =
State(nodeid);
1383 PeerRef peer{GetPeerRef(nodeid)};
1384 if (!nodestate || !nodestate->m_provides_cmpctblocks) {
1389 int num_outbound_hb_peers = 0;
1390 for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin(); it != lNodesAnnouncingHeaderAndIDs.end(); it++) {
1391 if (*it == nodeid) {
1392 lNodesAnnouncingHeaderAndIDs.erase(it);
1393 lNodesAnnouncingHeaderAndIDs.push_back(nodeid);
1396 PeerRef peer_ref{GetPeerRef(*it)};
1397 if (peer_ref && !peer_ref->m_is_inbound) ++num_outbound_hb_peers;
1399 if (peer && peer->m_is_inbound) {
1402 if (lNodesAnnouncingHeaderAndIDs.size() >= 3 && num_outbound_hb_peers == 1) {
1403 PeerRef remove_peer{GetPeerRef(lNodesAnnouncingHeaderAndIDs.front())};
1404 if (remove_peer && !remove_peer->m_is_inbound) {
1407 std::swap(lNodesAnnouncingHeaderAndIDs.front(), *std::next(lNodesAnnouncingHeaderAndIDs.begin()));
1416 lNodesAnnouncingHeaderAndIDs.push_back(pfrom->
GetId());
1419 if (nodeid_was_appended && lNodesAnnouncingHeaderAndIDs.size() > 3) {
1422 m_connman.
ForNode(lNodesAnnouncingHeaderAndIDs.front(), [
this](
CNode* pnodeStop) {
1425 pnodeStop->m_bip152_highbandwidth_to =
false;
1428 lNodesAnnouncingHeaderAndIDs.pop_front();
1432bool PeerManagerImpl::TipMayBeStale()
1436 if (m_last_tip_update.load() == 0
s) {
1437 m_last_tip_update = GetTime<std::chrono::seconds>();
1439 return m_last_tip_update.load() < GetTime<std::chrono::seconds>() - std::chrono::seconds{consensusParams.
nPowTargetSpacing * 3} && mapBlocksInFlight.empty();
1442int64_t PeerManagerImpl::ApproximateBestBlockDepth()
const
1447bool PeerManagerImpl::CanDirectFetch()
1454 if (state->pindexBestKnownBlock && pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight))
1456 if (state->pindexBestHeaderSent && pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight))
1461void PeerManagerImpl::ProcessBlockAvailability(
NodeId nodeid) {
1462 CNodeState *state =
State(nodeid);
1463 assert(state !=
nullptr);
1465 if (!state->hashLastUnknownBlock.IsNull()) {
1468 if (state->pindexBestKnownBlock ==
nullptr || pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
1469 state->pindexBestKnownBlock = pindex;
1471 state->hashLastUnknownBlock.SetNull();
1476void PeerManagerImpl::UpdateBlockAvailability(
NodeId nodeid,
const uint256 &hash) {
1477 CNodeState *state =
State(nodeid);
1478 assert(state !=
nullptr);
1480 ProcessBlockAvailability(nodeid);
1485 if (state->pindexBestKnownBlock ==
nullptr || pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
1486 state->pindexBestKnownBlock = pindex;
1490 state->hashLastUnknownBlock = hash;
1495void PeerManagerImpl::FindNextBlocksToDownload(
const Peer& peer,
unsigned int count, std::vector<const CBlockIndex*>& vBlocks,
NodeId& nodeStaller)
1500 vBlocks.reserve(vBlocks.size() +
count);
1501 CNodeState *state =
State(peer.m_id);
1502 assert(state !=
nullptr);
1505 ProcessBlockAvailability(peer.m_id);
1507 if (state->pindexBestKnownBlock ==
nullptr || state->pindexBestKnownBlock->nChainWork < m_chainman.
ActiveChain().
Tip()->
nChainWork || state->pindexBestKnownBlock->nChainWork < m_chainman.
MinimumChainWork()) {
1518 state->pindexBestKnownBlock->GetAncestor(snap_base->nHeight) != snap_base) {
1519 LogDebug(
BCLog::NET,
"Not downloading blocks from peer=%d, which doesn't have the snapshot block in its best chain.\n", peer.m_id);
1528 if (state->pindexLastCommonBlock ==
nullptr ||
1529 fork_point->nChainWork > state->pindexLastCommonBlock->nChainWork ||
1530 state->pindexBestKnownBlock->GetAncestor(state->pindexLastCommonBlock->nHeight) != state->pindexLastCommonBlock) {
1531 state->pindexLastCommonBlock = fork_point;
1533 if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)
1536 const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
1542 FindNextBlocks(vBlocks, peer, state, pindexWalk,
count, nWindowEnd, &m_chainman.
ActiveChain(), &nodeStaller);
1545void PeerManagerImpl::TryDownloadingHistoricalBlocks(
const Peer& peer,
unsigned int count, std::vector<const CBlockIndex*>& vBlocks,
const CBlockIndex *from_tip,
const CBlockIndex* target_block)
1550 if (vBlocks.size() >=
count) {
1554 vBlocks.reserve(
count);
1557 if (state->pindexBestKnownBlock ==
nullptr || state->pindexBestKnownBlock->GetAncestor(target_block->
nHeight) != target_block) {
1574void 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)
1576 std::vector<const CBlockIndex*> vToFetch;
1577 int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
1578 bool is_limited_peer = IsLimitedPeer(peer);
1580 while (pindexWalk->
nHeight < nMaxHeight) {
1584 int nToFetch = std::min(nMaxHeight - pindexWalk->
nHeight, std::max<int>(
count - vBlocks.size(), 128));
1585 vToFetch.resize(nToFetch);
1586 pindexWalk = state->pindexBestKnownBlock->
GetAncestor(pindexWalk->
nHeight + nToFetch);
1587 vToFetch[nToFetch - 1] = pindexWalk;
1588 for (
unsigned int i = nToFetch - 1; i > 0; i--) {
1589 vToFetch[i - 1] = vToFetch[i]->
pprev;
1609 state->pindexLastCommonBlock = pindex;
1616 if (waitingfor == -1) {
1618 waitingfor = mapBlocksInFlight.lower_bound(pindex->
GetBlockHash())->second.first;
1624 if (pindex->
nHeight > nWindowEnd) {
1626 if (vBlocks.size() == 0 && waitingfor != peer.m_id) {
1628 if (nodeStaller) *nodeStaller = waitingfor;
1638 vBlocks.push_back(pindex);
1639 if (vBlocks.size() ==
count) {
1648void PeerManagerImpl::PushNodeVersion(
CNode& pnode,
const Peer& peer)
1650 uint64_t my_services;
1652 uint64_t your_services;
1654 std::string my_user_agent;
1662 my_user_agent =
"/pynode:0.0.1/";
1664 my_tx_relay =
false;
1667 my_services = peer.m_our_services;
1668 my_time = TicksSinceEpoch<std::chrono::seconds>(
NodeClock::now());
1672 my_height = m_best_height;
1673 my_tx_relay = !RejectIncomingTxs(pnode);
1692 BCLog::NET,
"send version message: version=%d, blocks=%d%s, txrelay=%d, peer=%d\n",
1695 my_tx_relay, pnode.
GetId());
1702 if (state) state->m_last_block_announcement = time;
1710 m_node_states.try_emplace(m_node_states.end(), nodeid);
1712 WITH_LOCK(m_tx_download_mutex, m_txdownloadman.CheckIsEmpty(nodeid));
1718 PeerRef peer = std::make_shared<Peer>(nodeid, our_services,
node.IsInboundConn());
1721 m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer);
1725void PeerManagerImpl::ReattemptInitialBroadcast(
CScheduler& scheduler)
1729 for (
const auto& txid : unbroadcast_txids) {
1732 if (tx !=
nullptr) {
1733 InitiateTxBroadcastToAll(tx->GetWitnessHash());
1742 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
1745void PeerManagerImpl::ReattemptPrivateBroadcast(
CScheduler& scheduler)
1749 size_t num_for_rebroadcast{0};
1750 const auto stale_txs = m_tx_for_private_broadcast.GetStale();
1751 if (!stale_txs.empty()) {
1752 for (
const auto& stale_tx : stale_txs) {
1757 if (!m_tx_for_private_broadcast.TryGrantRetry(stale_tx))
continue;
1759 "Reattempting broadcast of stale txid=%s wtxid=%s",
1760 stale_tx->GetHash().ToString(), stale_tx->GetWitnessHash().ToString());
1761 ++num_for_rebroadcast;
1764 stale_tx->GetHash().ToString(), stale_tx->GetWitnessHash().ToString(),
1765 mempool_acceptable.m_state.ToString());
1766 m_tx_for_private_broadcast.MarkResolved(stale_tx);
1775 scheduler.
scheduleFromNow([&] { ReattemptPrivateBroadcast(scheduler); }, delta);
1778void PeerManagerImpl::FinalizeNode(
const CNode&
node)
1789 PeerRef peer = RemovePeer(nodeid);
1791 m_wtxid_relay_peers -= peer->m_wtxid_relay;
1792 assert(m_wtxid_relay_peers >= 0);
1794 CNodeState *state =
State(nodeid);
1795 assert(state !=
nullptr);
1797 if (state->fSyncStarted)
1800 for (
const QueuedBlock& entry : state->vBlocksInFlight) {
1801 auto range = mapBlocksInFlight.equal_range(entry.pindex->GetBlockHash());
1802 while (range.first != range.second) {
1803 auto [node_id, list_it] = range.first->second;
1804 if (node_id != nodeid) {
1807 range.first = mapBlocksInFlight.erase(range.first);
1812 LOCK(m_tx_download_mutex);
1813 m_txdownloadman.DisconnectedPeer(nodeid);
1815 if (m_txreconciliation) m_txreconciliation->ForgetPeer(nodeid);
1816 m_num_preferred_download_peers -= state->fPreferredDownload;
1817 m_peers_downloading_from -= (!state->vBlocksInFlight.empty());
1818 assert(m_peers_downloading_from >= 0);
1819 m_outbound_peers_with_protect_from_disconnect -= state->m_chain_sync.m_protect;
1820 assert(m_outbound_peers_with_protect_from_disconnect >= 0);
1822 m_node_states.erase(nodeid);
1824 if (m_node_states.empty()) {
1826 assert(mapBlocksInFlight.empty());
1827 assert(m_num_preferred_download_peers == 0);
1828 assert(m_peers_downloading_from == 0);
1829 assert(m_outbound_peers_with_protect_from_disconnect == 0);
1830 assert(m_wtxid_relay_peers == 0);
1831 WITH_LOCK(m_tx_download_mutex, m_txdownloadman.CheckIsEmpty());
1834 if (
node.fSuccessfullyConnected &&
1835 !
node.IsBlockOnlyConn() && !
node.IsPrivateBroadcastConn() && !
node.IsInboundConn()) {
1843 LOCK(m_headers_presync_mutex);
1844 m_headers_presync_stats.erase(nodeid);
1846 if (
node.IsPrivateBroadcastConn()) {
1847 m_tx_for_private_broadcast.NodeDisconnected(nodeid);
1855 if (!
node.fSuccessfullyConnected && m_tx_for_private_broadcast.HavePendingTransactions()) {
1862bool PeerManagerImpl::HasAllDesirableServiceFlags(
ServiceFlags services)
const
1865 return !(GetDesirableServiceFlags(services) & (~services));
1879PeerRef PeerManagerImpl::GetPeerRef(
NodeId id)
const
1882 auto it = m_peer_map.find(
id);
1883 return it != m_peer_map.end() ? it->second :
nullptr;
1886PeerRef PeerManagerImpl::RemovePeer(
NodeId id)
1890 auto it = m_peer_map.find(
id);
1891 if (it != m_peer_map.end()) {
1892 ret = std::move(it->second);
1893 m_peer_map.erase(it);
1898std::vector<PeerRef> PeerManagerImpl::GetAllPeers()
const
1900 std::vector<PeerRef> peers;
1902 peers.reserve(m_peer_map.size());
1903 for (
const auto& [
_, peer] : m_peer_map) {
1904 peers.push_back(peer);
1913 const CNodeState* state =
State(nodeid);
1914 if (state ==
nullptr)
1916 stats.
nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1;
1917 stats.
nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1;
1918 for (
const QueuedBlock& queue : state->vBlocksInFlight) {
1925 PeerRef peer = GetPeerRef(nodeid);
1926 if (peer ==
nullptr)
return false;
1934 NodeClock::duration ping_wait{0us};
1935 if ((0 != peer->m_ping_nonce_sent) && (peer->m_ping_start.load() >
NodeClock::epoch)) {
1939 if (
auto tx_relay = peer->GetTxRelay(); tx_relay !=
nullptr) {
1942 LOCK(tx_relay->m_tx_inventory_mutex);
1944 stats.
m_inv_to_send = tx_relay->m_tx_inventory_to_send.size();
1956 LOCK(peer->m_headers_sync_mutex);
1957 if (peer->m_headers_sync) {
1966std::vector<node::TxOrphanage::OrphanInfo> PeerManagerImpl::GetOrphanTransactions()
1968 LOCK(m_tx_download_mutex);
1969 return m_txdownloadman.GetOrphanTransactions();
1974 LOCK(m_inv_to_send_mutex);
1977 .ignores_incoming_txs = m_opts.ignore_incoming_txs,
1978 .private_broadcast = m_opts.private_broadcast,
1979 .tx_send_rate = m_opts.tx_send_rate,
1980 .inbound_bucket = m_inbound_inv_bucket.info(),
1981 .outbound_bucket = m_outbound_inv_bucket.info(),
1985std::vector<PrivateBroadcast::TxBroadcastInfo> PeerManagerImpl::GetPrivateBroadcastInfo()
const
1987 return m_tx_for_private_broadcast.GetBroadcastInfo();
1990std::vector<CTransactionRef> PeerManagerImpl::AbortPrivateBroadcast(
const uint256&
id)
1992 const auto snapshot{m_tx_for_private_broadcast.GetBroadcastInfo()};
1993 std::vector<CTransactionRef> removed_txs;
1995 size_t connections_cancelled{0};
1996 for (
const auto& tx_info : snapshot) {
1998 if (tx->GetHash().ToUint256() !=
id && tx->GetWitnessHash().ToUint256() !=
id)
continue;
1999 if (
const auto remaining_sends{m_tx_for_private_broadcast.Remove(tx)}) {
2000 removed_txs.push_back(tx);
2001 connections_cancelled += *remaining_sends;
2009void PeerManagerImpl::AddToCompactExtraTransactions(
const CTransactionRef& tx)
2011 if (m_opts.max_extra_txs == 0)
return;
2012 if (vExtraTxnForCompact.size() < m_opts.max_extra_txs) {
2013 if (vExtraTxnForCompact.empty()) vExtraTxnForCompact.reserve(m_opts.max_extra_txs);
2014 vExtraTxnForCompact.emplace_back(tx->GetWitnessHash(), tx);
2016 vExtraTxnForCompact[vExtraTxnForCompactIt] = std::make_pair(tx->GetWitnessHash(), tx);
2018 vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
2021void PeerManagerImpl::Misbehaving(Peer& peer,
const std::string& message)
2023 LOCK(peer.m_misbehavior_mutex);
2025 const std::string message_prefixed = message.empty() ?
"" : (
": " + message);
2026 peer.m_should_discourage =
true;
2035 bool via_compact_block,
const std::string& message)
2037 PeerRef peer{GetPeerRef(nodeid)};
2048 if (!via_compact_block) {
2049 if (peer) Misbehaving(*peer, message);
2057 if (peer && !via_compact_block && !peer->m_is_inbound) {
2058 if (peer) Misbehaving(*peer, message);
2065 if (peer) Misbehaving(*peer, message);
2069 if (peer) Misbehaving(*peer, message);
2074 if (message !=
"") {
2079bool PeerManagerImpl::BlockRequestAllowed(
const CBlockIndex& block_index)
2099 PeerRef peer = GetPeerRef(peer_id);
2106 RemoveBlockRequest(block_index.
GetBlockHash(), std::nullopt);
2109 if (!BlockRequested(peer_id, block_index))
return util::Unexpected{
"Already requested from this peer"};
2132 return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman, pool, warnings, opts);
2138 : m_rng{opts.deterministic_rng},
2140 m_chainparams(chainman.GetParams()),
2144 m_chainman(chainman),
2146 m_txdownloadman{
node::TxDownloadOptions{pool, opts.deterministic_rng}},
2147 m_warnings{warnings},
2149 m_inbound_inv_bucket(m_opts.tx_send_rate, 1.0),
2154 if (opts.reconcile_txs) {
2159void PeerManagerImpl::StartScheduledTasks(
CScheduler& scheduler)
2170 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
2172 if (m_opts.private_broadcast) {
2173 scheduler.
scheduleFromNow([&] { ReattemptPrivateBroadcast(scheduler); }, 0min);
2177void PeerManagerImpl::ActiveTipChange(
const CBlockIndex& new_tip,
bool is_ibd)
2185 LOCK(m_tx_download_mutex);
2189 m_txdownloadman.ActiveTipChange();
2199void PeerManagerImpl::BlockConnected(
2201 const std::shared_ptr<const CBlock>& pblock,
2206 m_last_tip_update = GetTime<std::chrono::seconds>();
2209 auto stalling_timeout = m_block_stalling_timeout.load();
2213 if (m_block_stalling_timeout.compare_exchange_strong(stalling_timeout, new_timeout)) {
2222 LOCK(m_tx_download_mutex);
2223 m_txdownloadman.BlockConnected(pblock);
2227void PeerManagerImpl::BlockDisconnected(
const std::shared_ptr<const CBlock> &block,
const CBlockIndex* pindex)
2229 LOCK(m_tx_download_mutex);
2230 m_txdownloadman.BlockDisconnected();
2237void PeerManagerImpl::NewPoWValidBlock(
const CBlockIndex *pindex,
const std::shared_ptr<const CBlock>& pblock)
2239 auto pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs>(*pblock,
FastRandomContext().rand64());
2243 if (pindex->
nHeight <= m_highest_fast_announce)
2245 m_highest_fast_announce = pindex->
nHeight;
2249 uint256 hashBlock(pblock->GetHash());
2250 const std::shared_future<CSerializedNetMsg> lazy_ser{
2254 auto most_recent_block_txs = std::make_unique<std::map<GenTxid, CTransactionRef>>();
2255 for (
const auto& tx : pblock->vtx) {
2256 most_recent_block_txs->emplace(tx->GetHash(), tx);
2257 most_recent_block_txs->emplace(tx->GetWitnessHash(), tx);
2260 LOCK(m_most_recent_block_mutex);
2261 m_most_recent_block_hash = hashBlock;
2262 m_most_recent_block = pblock;
2263 m_most_recent_compact_block = pcmpctblock;
2264 m_most_recent_block_txs = std::move(most_recent_block_txs);
2272 ProcessBlockAvailability(pnode->
GetId());
2276 if (state.m_requested_hb_cmpctblocks && !PeerHasHeader(&state, pindex) && PeerHasHeader(&state, pindex->
pprev)) {
2278 LogDebug(
BCLog::NET,
"%s sending header-and-ids %s to peer=%d\n",
"PeerManager::NewPoWValidBlock",
2279 hashBlock.ToString(), pnode->
GetId());
2282 PushMessage(*pnode, ser_cmpctblock.Copy());
2283 state.pindexBestHeaderSent = pindex;
2292void PeerManagerImpl::UpdatedBlockTip(
const CBlockIndex *pindexNew,
const CBlockIndex *pindexFork,
bool fInitialDownload)
2294 SetBestBlock(pindexNew->
nHeight, std::chrono::seconds{pindexNew->GetBlockTime()});
2297 if (fInitialDownload)
return;
2300 std::vector<uint256> vHashes;
2302 while (pindexToAnnounce != pindexFork) {
2304 pindexToAnnounce = pindexToAnnounce->
pprev;
2314 for (
auto& it : m_peer_map) {
2315 Peer& peer = *it.second;
2316 LOCK(peer.m_block_inv_mutex);
2317 for (
const uint256& hash : vHashes | std::views::reverse) {
2318 peer.m_blocks_for_headers_relay.push_back(hash);
2330void PeerManagerImpl::BlockChecked(
const std::shared_ptr<const CBlock>& block,
const BlockValidationState& state)
2334 const uint256 hash(block->GetHash());
2335 std::map<uint256, std::pair<NodeId, bool>>::iterator it = mapBlockSource.find(hash);
2340 it != mapBlockSource.end() &&
2341 State(it->second.first)) {
2342 MaybePunishNodeForBlock( it->second.first, state, !it->second.second);
2352 mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
2353 if (it != mapBlockSource.end()) {
2354 MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
2357 if (it != mapBlockSource.end())
2358 mapBlockSource.erase(it);
2366bool PeerManagerImpl::AlreadyHaveBlock(
const uint256& block_hash)
2371void PeerManagerImpl::SendPings()
2374 for(
auto& it : m_peer_map) it.second->m_ping_queued =
true;
2377std::vector<Wtxid> InvToSendBucket::TakeForProcessing(
CTxMemPool& mempool)
2381 size_t n_to_take =
static_cast<size_t>(std::max<double>(count_bucket.
value() - count_floor, 0));
2383 std::vector<Wtxid> best;
2386 bool tokens_left =
true;
2387 for (
auto txiter : itervec) {
2388 auto& wtxid = txiter->GetTx().GetWitnessHash();
2390 best.push_back(wtxid);
2391 if (!decrement(txiter->GetTx().ComputeTotalSize())) {
2392 tokens_left =
false;
2395 backlog.push_back(wtxid);
2401 std::vector<Wtxid> dummy;
2403 dummy.swap(backlog);
2413 if (!backlog_bumped && now <= m_next_inv_bucket_check.load())
return;
2416 LOCK(m_inv_to_send_mutex);
2417 m_inbound_inv_bucket.increment(now);
2418 m_outbound_inv_bucket.increment(now);
2421 if (!m_next_inv_bucket_heartbeat.has_value()) {
2423 m_next_inv_bucket_heartbeat = now;
2426 if (m_next_inv_bucket_heartbeat.has_value() && now >= *m_next_inv_bucket_heartbeat) {
2427 LogDebug(
BCLog::NET,
"Transaction rate-limiting backlog inbound=%d itok=%.1f isz=%.1f outbound=%d otok=%.1f osz=%.1f",
2428 m_inbound_inv_bucket.backlog.size(),
2429 m_inbound_inv_bucket.count_bucket.value(),
2430 m_inbound_inv_bucket.size_bucket.value(),
2431 m_outbound_inv_bucket.backlog.size(),
2432 m_outbound_inv_bucket.count_bucket.value(),
2433 m_outbound_inv_bucket.size_bucket.value());
2434 if (m_inbound_inv_bucket.backlog.empty() && m_outbound_inv_bucket.backlog.empty()) {
2435 m_next_inv_bucket_heartbeat = std::nullopt;
2442 bool in_avail = m_inbound_inv_bucket.avail();
2443 bool out_avail = m_outbound_inv_bucket.avail();
2444 if (!in_avail && !out_avail)
return;
2446 std::vector<Wtxid> for_inbound;
2447 std::vector<Wtxid> for_outbound;
2451 if (in_avail) for_inbound = m_inbound_inv_bucket.TakeForProcessing(m_mempool);
2452 if (out_avail) for_outbound = m_outbound_inv_bucket.TakeForProcessing(m_mempool);
2455 if (!for_inbound.empty() || !for_outbound.empty()) {
2456 bool any_inbound_connected =
false;
2457 bool any_outbound_connected =
false;
2458 for (
const PeerRef& peer_ref : GetAllPeers()) {
2459 if (!peer_ref)
continue;
2460 Peer& peer{*peer_ref};
2461 auto tx_relay = peer.GetTxRelay();
2462 if (!tx_relay)
continue;
2464 LOCK(tx_relay->m_tx_inventory_mutex);
2470 if (tx_relay->m_next_inv_send_time == 0
s)
continue;
2471 if (peer.m_is_inbound) {
2472 any_inbound_connected =
true;
2474 any_outbound_connected =
true;
2476 for (
auto& i : (peer.m_is_inbound ? for_inbound : for_outbound)) {
2477 tx_relay->m_tx_inventory_to_send.push_back(i);
2484 if (!any_inbound_connected) m_inbound_inv_bucket.backlog.clear();
2485 if (!any_outbound_connected) m_outbound_inv_bucket.backlog.clear();
2489void PeerManagerImpl::InitiateTxBroadcastToAll(
const Wtxid& wtxid)
2492 LOCK(m_inv_to_send_mutex);
2493 m_inbound_inv_bucket.backlog.push_back(wtxid);
2494 m_outbound_inv_bucket.backlog.push_back(wtxid);
2501 const auto txstr{
strprintf(
"txid=%s, wtxid=%s", tx->GetHash().ToString(), tx->GetWitnessHash().ToString())};
2502 switch (m_tx_for_private_broadcast.Add(tx)) {
2517void PeerManagerImpl::RelayAddress(
NodeId originator,
2533 const auto current_time{GetTime<std::chrono::seconds>()};
2541 unsigned int nRelayNodes = (fReachable || (hasher.Finalize() & 1)) ? 2 : 1;
2543 std::array<std::pair<uint64_t, Peer*>, 2> best{{{0,
nullptr}, {0,
nullptr}}};
2544 assert(nRelayNodes <= best.size());
2548 for (
auto& [
id, peer] : m_peer_map) {
2549 if (peer->m_addr_relay_enabled &&
id != originator && IsAddrCompatible(*peer, addr)) {
2551 for (
unsigned int i = 0; i < nRelayNodes; i++) {
2552 if (hashKey > best[i].first) {
2553 std::copy(best.begin() + i, best.begin() + nRelayNodes - 1, best.begin() + i + 1);
2554 best[i] = std::make_pair(hashKey, peer.get());
2561 for (
unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
2562 PushAddress(*best[i].second, addr);
2566void PeerManagerImpl::ProcessGetBlockData(
CNode& pfrom, Peer& peer,
const CInv& inv)
2576 std::shared_ptr<const CBlock> a_recent_block;
2577 std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
2579 LOCK(m_most_recent_block_mutex);
2580 a_recent_block = m_most_recent_block;
2581 a_recent_compact_block = m_most_recent_compact_block;
2584 bool need_activate_chain =
false;
2596 need_activate_chain =
true;
2600 if (need_activate_chain) {
2602 if (!m_chainman.
ActiveChainstate().ActivateBestChain(state, a_recent_block)) {
2609 bool can_direct_fetch{
false};
2617 if (!BlockRequestAllowed(*pindex)) {
2618 LogDebug(
BCLog::NET,
"%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom.
GetId());
2645 can_direct_fetch = CanDirectFetch();
2649 std::shared_ptr<const CBlock> pblock;
2650 if (a_recent_block && a_recent_block->GetHash() == inv.
hash) {
2651 pblock = a_recent_block;
2669 std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
2679 pblock = pblockRead;
2687 bool sendMerkleBlock =
false;
2689 if (
auto tx_relay = peer.GetTxRelay(); tx_relay !=
nullptr) {
2690 LOCK(tx_relay->m_bloom_filter_mutex);
2691 if (tx_relay->m_bloom_filter) {
2692 sendMerkleBlock =
true;
2693 merkleBlock =
CMerkleBlock(*pblock, *tx_relay->m_bloom_filter);
2696 if (sendMerkleBlock) {
2704 for (
const auto& [tx_idx,
_] : merkleBlock.
vMatchedTxn)
2715 if (a_recent_compact_block && a_recent_compact_block->header.GetHash() == inv.
hash) {
2728 LOCK(peer.m_block_inv_mutex);
2730 if (inv.
hash == peer.m_continuation_block) {
2734 std::vector<CInv> vInv;
2735 vInv.emplace_back(
MSG_BLOCK, tip->GetBlockHash());
2737 peer.m_continuation_block.SetNull();
2745 auto txinfo{std::visit(
2746 [&](
const auto&
id) {
2747 return m_mempool.
info_for_relay(
id,
WITH_LOCK(tx_relay.m_tx_inventory_mutex,
return tx_relay.m_last_inv_sequence));
2751 return std::move(txinfo.tx);
2756 LOCK(m_most_recent_block_mutex);
2757 if (m_most_recent_block_txs !=
nullptr) {
2758 auto it = m_most_recent_block_txs->find(gtxid);
2759 if (it != m_most_recent_block_txs->end())
return it->second;
2766void PeerManagerImpl::ProcessGetData(
CNode& pfrom, Peer& peer,
const std::atomic<bool>& interruptMsgProc)
2770 auto tx_relay = peer.GetTxRelay();
2772 std::deque<CInv>::iterator it = peer.m_getdata_requests.begin();
2773 std::vector<CInv> vNotFound;
2778 while (it != peer.m_getdata_requests.end() && it->IsGenTxMsg()) {
2779 if (interruptMsgProc)
return;
2784 const CInv &inv = *it++;
2786 if (tx_relay ==
nullptr) {
2792 if (
auto tx{FindTxForGetData(*tx_relay,
ToGenTxid(inv))}) {
2795 MakeAndPushMessage(pfrom,
NetMsgType::TX, maybe_with_witness(*tx));
2798 vNotFound.push_back(inv);
2804 if (it != peer.m_getdata_requests.end() && !pfrom.
fPauseSend) {
2805 const CInv &inv = *it++;
2807 ProcessGetBlockData(pfrom, peer, inv);
2816 peer.m_getdata_requests.erase(peer.m_getdata_requests.begin(), it);
2818 if (!vNotFound.empty()) {
2837uint32_t PeerManagerImpl::GetFetchFlags(
const Peer& peer)
const
2839 uint32_t nFetchFlags = 0;
2840 if (CanServeWitnesses(peer)) {
2849 for (
size_t i = 0; i < req.
indexes.size(); i++) {
2851 Misbehaving(peer,
"getblocktxn with out-of-bounds tx indices");
2858 uint32_t tx_requested_size{0};
2859 for (
const auto& tx : resp.txn) tx_requested_size += tx->ComputeTotalSize();
2862 const std::string missing_txids{
util::Join(resp.txn,
", ", [](
const auto& tx) { return tx->GetHash().ToString(); })};
2869bool PeerManagerImpl::CheckHeadersPoW(
const std::vector<CBlockHeader>&
headers, Peer& peer)
2873 Misbehaving(peer,
"header with invalid proof of work");
2878 if (!CheckHeadersAreContinuous(
headers)) {
2879 Misbehaving(peer,
"non-continuous headers sequence");
2904void PeerManagerImpl::HandleUnconnectingHeaders(
CNode& pfrom, Peer& peer,
2905 const std::vector<CBlockHeader>&
headers)
2909 if (MaybeSendGetHeaders(pfrom,
GetLocator(best_header), peer)) {
2910 LogDebug(
BCLog::NET,
"received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d)\n",
2912 headers[0].hashPrevBlock.ToString(),
2913 best_header->nHeight,
2923bool PeerManagerImpl::CheckHeadersAreContinuous(
const std::vector<CBlockHeader>&
headers)
const
2927 if (!hashLastBlock.
IsNull() && header.hashPrevBlock != hashLastBlock) {
2930 hashLastBlock = header.GetHash();
2935bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(Peer& peer,
CNode& pfrom, std::vector<CBlockHeader>&
headers)
2937 if (peer.m_headers_sync) {
2938 auto result = peer.m_headers_sync->ProcessNextHeaders(
headers,
headers.size() == m_opts.max_headers_result);
2940 if (result.success) peer.m_last_getheaders_timestamp = {};
2941 if (result.request_more) {
2942 auto locator = peer.m_headers_sync->NextHeadersRequestLocator();
2944 Assume(!locator.vHave.empty());
2947 if (!locator.vHave.empty()) {
2950 bool sent_getheaders = MaybeSendGetHeaders(pfrom, locator, peer);
2953 locator.vHave.front().ToString(), pfrom.
GetId());
2958 peer.m_headers_sync.reset(
nullptr);
2963 LOCK(m_headers_presync_mutex);
2964 m_headers_presync_stats.erase(pfrom.
GetId());
2967 HeadersPresyncStats stats;
2968 stats.first = peer.m_headers_sync->GetPresyncWork();
2970 stats.second = {peer.m_headers_sync->GetPresyncHeight(),
2971 peer.m_headers_sync->GetPresyncTime()};
2975 LOCK(m_headers_presync_mutex);
2976 m_headers_presync_stats[pfrom.
GetId()] = stats;
2977 auto best_it = m_headers_presync_stats.find(m_headers_presync_bestpeer);
2978 bool best_updated =
false;
2979 if (best_it == m_headers_presync_stats.end()) {
2983 const HeadersPresyncStats* stat_best{
nullptr};
2984 for (
const auto& [peer, stat] : m_headers_presync_stats) {
2985 if (!stat_best || stat > *stat_best) {
2990 m_headers_presync_bestpeer = peer_best;
2991 best_updated = (peer_best == pfrom.
GetId());
2992 }
else if (best_it->first == pfrom.
GetId() || stats > best_it->second) {
2994 m_headers_presync_bestpeer = pfrom.
GetId();
2995 best_updated =
true;
2997 if (best_updated && stats.second.has_value()) {
2999 m_headers_presync_should_signal =
true;
3003 if (result.success) {
3006 headers.swap(result.pow_validated_headers);
3009 return result.success;
3017bool PeerManagerImpl::TryLowWorkHeadersSync(Peer& peer,
CNode& pfrom,
const CBlockIndex& chain_start_header, std::vector<CBlockHeader>&
headers)
3024 arith_uint256 minimum_chain_work = GetAntiDoSWorkThreshold();
3028 if (total_work < minimum_chain_work) {
3032 if (
headers.size() == m_opts.max_headers_result) {
3042 LOCK(peer.m_headers_sync_mutex);
3045 m_chainparams.
HeadersSync(), chain_start_header, minimum_chain_work));
3051 const auto msg{
strprintf(
"Failure when attempting to initiate headers sync: %s", e.what())};
3052 std::cerr <<
msg << std::endl;
3060 (void)IsContinuationOfLowWorkHeadersSync(peer, pfrom,
headers);
3074bool PeerManagerImpl::IsAncestorOfBestHeaderOrTip(
const CBlockIndex* header)
3076 if (header ==
nullptr) {
3078 }
else if (m_chainman.m_best_header !=
nullptr && header == m_chainman.m_best_header->GetAncestor(header->
nHeight)) {
3086bool PeerManagerImpl::MaybeSendGetHeaders(
CNode& pfrom,
const CBlockLocator& locator, Peer& peer)
3094 peer.m_last_getheaders_timestamp = current_time;
3105void PeerManagerImpl::HeadersDirectFetchBlocks(
CNode& pfrom,
const Peer& peer,
const CBlockIndex& last_header)
3108 CNodeState *nodestate =
State(pfrom.
GetId());
3111 std::vector<const CBlockIndex*> vToFetch;
3119 vToFetch.push_back(pindexWalk);
3121 pindexWalk = pindexWalk->
pprev;
3133 std::vector<CInv> vGetData;
3135 for (
const CBlockIndex* pindex : vToFetch | std::views::reverse) {
3140 uint32_t nFetchFlags = GetFetchFlags(peer);
3142 BlockRequested(pfrom.
GetId(), *pindex);
3146 if (vGetData.size() > 1) {
3151 if (vGetData.size() > 0) {
3152 if (!m_opts.ignore_incoming_txs &&
3153 nodestate->m_provides_cmpctblocks &&
3154 vGetData.size() == 1 &&
3155 mapBlocksInFlight.size() == 1 &&
3171void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(
CNode& pfrom,
3172 const CBlockIndex& last_header,
bool received_new_header,
bool may_have_more_headers)
3175 CNodeState *nodestate =
State(pfrom.
GetId());
3192 if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < m_chainman.
MinimumChainWork()) {
3214 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) {
3216 nodestate->m_chain_sync.m_protect =
true;
3217 ++m_outbound_peers_with_protect_from_disconnect;
3222void PeerManagerImpl::ProcessHeadersMessage(
CNode& pfrom, Peer& peer,
3223 std::vector<CBlockHeader>&&
headers,
3224 bool via_compact_block)
3226 size_t nCount =
headers.size();
3233 LOCK(peer.m_headers_sync_mutex);
3234 if (peer.m_headers_sync) {
3235 peer.m_headers_sync.reset(
nullptr);
3236 LOCK(m_headers_presync_mutex);
3237 m_headers_presync_stats.erase(pfrom.
GetId());
3241 peer.m_last_getheaders_timestamp = {};
3249 if (!CheckHeadersPoW(
headers, peer)) {
3264 bool already_validated_work =
false;
3267 bool have_headers_sync =
false;
3269 LOCK(peer.m_headers_sync_mutex);
3271 already_validated_work = IsContinuationOfLowWorkHeadersSync(peer, pfrom,
headers);
3287 have_headers_sync = !!peer.m_headers_sync;
3292 bool headers_connect_blockindex{chain_start_header !=
nullptr};
3294 if (!headers_connect_blockindex) {
3298 HandleUnconnectingHeaders(pfrom, peer,
headers);
3305 peer.m_last_getheaders_timestamp = {};
3315 already_validated_work = already_validated_work || IsAncestorOfBestHeaderOrTip(last_received_header);
3322 already_validated_work =
true;
3328 if (!already_validated_work && TryLowWorkHeadersSync(peer, pfrom,
3329 *chain_start_header,
headers)) {
3341 bool received_new_header{last_received_header ==
nullptr};
3347 state, &pindexLast)};
3353 "If this happens with all peers, consider database corruption (that -reindex may fix) "
3354 "or a potential consensus incompatibility.",
3357 MaybePunishNodeForBlock(pfrom.
GetId(), state, via_compact_block,
"invalid header received");
3363 if (processed && received_new_header) {
3364 LogBlockHeader(*pindexLast, pfrom,
false);
3368 if (nCount == m_opts.max_headers_result && !have_headers_sync) {
3370 if (MaybeSendGetHeaders(pfrom,
GetLocator(pindexLast), peer)) {
3375 UpdatePeerStateForReceivedHeaders(pfrom, *pindexLast, received_new_header, nCount == m_opts.max_headers_result);
3378 HeadersDirectFetchBlocks(pfrom, peer, *pindexLast);
3384 bool first_time_failure)
3390 PeerRef peer{GetPeerRef(nodeid)};
3393 ptx->GetHash().ToString(),
3394 ptx->GetWitnessHash().ToString(),
3398 const auto& [add_extra_compact_tx, unique_parents, package_to_validate] = m_txdownloadman.MempoolRejectedTx(ptx, state, nodeid, first_time_failure);
3401 AddToCompactExtraTransactions(ptx);
3403 for (
const Txid& parent_txid : unique_parents) {
3404 if (peer) AddKnownTx(*peer, parent_txid.ToUint256());
3407 return package_to_validate;
3410void PeerManagerImpl::ProcessValidTx(
NodeId nodeid,
const CTransactionRef& tx,
const std::list<CTransactionRef>& replaced_transactions)
3416 m_txdownloadman.MempoolAcceptedTx(tx);
3420 tx->GetHash().ToString(),
3421 tx->GetWitnessHash().ToString(),
3424 InitiateTxBroadcastToAll(tx->GetWitnessHash());
3427 AddToCompactExtraTransactions(removedTx);
3437 const auto&
package = package_to_validate.m_txns;
3438 const auto& senders = package_to_validate.
m_senders;
3441 m_txdownloadman.MempoolRejectedPackage(package);
3444 if (!
Assume(package.size() == 2))
return;
3448 auto package_iter = package.rbegin();
3449 auto senders_iter = senders.rbegin();
3450 while (package_iter != package.rend()) {
3451 const auto& tx = *package_iter;
3452 const NodeId nodeid = *senders_iter;
3453 const auto it_result{package_result.
m_tx_results.find(tx->GetWitnessHash())};
3457 const auto& tx_result = it_result->second;
3458 switch (tx_result.m_result_type) {
3461 ProcessValidTx(nodeid, tx, tx_result.m_replaced_transactions);
3471 ProcessInvalidTx(nodeid, tx, tx_result.m_state,
false);
3489bool PeerManagerImpl::ProcessOrphanTx(Peer& peer)
3494 while (
CTransactionRef porphanTx = m_txdownloadman.GetTxToReconsider(peer.m_id)) {
3497 const Txid& orphanHash = porphanTx->GetHash();
3498 const Wtxid& orphan_wtxid = porphanTx->GetWitnessHash();
3515 ProcessInvalidTx(peer.m_id, porphanTx, state,
false);
3524bool PeerManagerImpl::PrepareBlockFilterRequest(
CNode&
node, Peer& peer,
3526 const uint256& stop_hash, uint32_t max_height_diff,
3530 const bool supported_filter_type =
3533 if (!supported_filter_type) {
3535 static_cast<uint8_t
>(filter_type),
node.DisconnectMsg());
3536 node.fDisconnect =
true;
3545 if (!stop_index || !BlockRequestAllowed(*stop_index)) {
3548 node.fDisconnect =
true;
3553 uint32_t stop_height = stop_index->
nHeight;
3554 if (start_height > stop_height) {
3556 "start height %d and stop height %d, %s",
3557 start_height, stop_height,
node.DisconnectMsg());
3558 node.fDisconnect =
true;
3561 if (stop_height - start_height >= max_height_diff) {
3563 stop_height - start_height + 1, max_height_diff,
node.DisconnectMsg());
3564 node.fDisconnect =
true;
3569 if (!filter_index) {
3579 uint8_t filter_type_ser;
3580 uint32_t start_height;
3583 vRecv >> filter_type_ser >> start_height >> stop_hash;
3589 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height, stop_hash,
3594 std::vector<BlockFilter> filters;
3596 LogDebug(
BCLog::NET,
"Failed to find block filter in index: filter_type=%s, start_height=%d, stop_hash=%s\n",
3601 for (
const auto& filter : filters) {
3608 uint8_t filter_type_ser;
3609 uint32_t start_height;
3612 vRecv >> filter_type_ser >> start_height >> stop_hash;
3618 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height, stop_hash,
3624 if (start_height > 0) {
3626 stop_index->
GetAncestor(
static_cast<int>(start_height - 1));
3628 LogDebug(
BCLog::NET,
"Failed to find block filter header in index: filter_type=%s, block_hash=%s\n",
3634 std::vector<uint256> filter_hashes;
3636 LogDebug(
BCLog::NET,
"Failed to find block filter hashes in index: filter_type=%s, start_height=%d, stop_hash=%s\n",
3650 uint8_t filter_type_ser;
3653 vRecv >> filter_type_ser >> stop_hash;
3659 if (!PrepareBlockFilterRequest(
node, peer, filter_type, 0, stop_hash,
3660 std::numeric_limits<uint32_t>::max(),
3661 stop_index, filter_index)) {
3669 for (
int i =
int(
headers.size()) - 1; i >= 0; i--) {
3674 LogDebug(
BCLog::NET,
"Failed to find block filter header in index: filter_type=%s, block_hash=%s\n",
3688 bool new_block{
false};
3689 m_chainman.
ProcessNewBlock(block, force_processing, min_pow_checked, &new_block);
3691 node.m_last_block_time = GetTime<std::chrono::seconds>();
3696 RemoveBlockRequest(block->GetHash(), std::nullopt);
3699 mapBlockSource.erase(block->GetHash());
3703void PeerManagerImpl::ProcessCompactBlockTxns(
CNode& pfrom, Peer& peer,
const BlockTransactions& block_transactions)
3705 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
3706 bool fBlockRead{
false};
3710 auto range_flight = mapBlocksInFlight.equal_range(block_transactions.
blockhash);
3711 size_t already_in_flight = std::distance(range_flight.first, range_flight.second);
3712 bool requested_block_from_this_peer{
false};
3715 bool first_in_flight = already_in_flight == 0 || (range_flight.first->second.first == pfrom.
GetId());
3717 while (range_flight.first != range_flight.second) {
3718 auto [node_id, block_it] = range_flight.first->second;
3719 if (node_id == pfrom.
GetId() && block_it->partialBlock) {
3720 requested_block_from_this_peer =
true;
3723 range_flight.first++;
3726 if (!requested_block_from_this_peer) {
3738 Misbehaving(peer,
"previous compact block reconstruction attempt failed");
3749 Misbehaving(peer,
"invalid compact block/non-matching block transactions");
3752 if (first_in_flight) {
3757 std::vector<CInv> invs;
3762 LogDebug(
BCLog::NET,
"Peer %d sent us a compact block but it failed to reconstruct, waiting on first download to complete\n", pfrom.
GetId());
3775 mapBlockSource.emplace(block_transactions.
blockhash, std::make_pair(pfrom.
GetId(),
false));
3790void PeerManagerImpl::LogBlockHeader(
const CBlockIndex& index,
const CNode& peer,
bool via_compact_block) {
3802 "Saw new %sheader hash=%s height=%d %s",
3803 via_compact_block ?
"cmpctblock " :
"",
3815void PeerManagerImpl::PushPrivateBroadcastTx(
CNode&
node)
3819 const auto opt_tx{m_tx_for_private_broadcast.PickTxForSend(
node.GetId(),
CService{node.addr})};
3822 node.fDisconnect =
true;
3828 tx->GetHash().ToString(), tx->HasWitness() ?
strprintf(
", wtxid=%s", tx->GetWitnessHash().ToString()) :
"",
3834void PeerManagerImpl::ProcessMessage(Peer& peer,
CNode& pfrom,
const std::string& msg_type,
DataStream& vRecv,
3836 const std::atomic<bool>& interruptMsgProc)
3851 uint64_t nNonce = 1;
3854 std::string cleanSubVer;
3855 int starting_height = -1;
3858 vRecv >> nVersion >> Using<CustomUintFormatter<8>>(nServices) >> nTime;
3873 LogDebug(
BCLog::NET,
"peer does not offer the expected services (%08x offered, %08x expected), %s",
3875 GetDesirableServiceFlags(nServices),
3888 if (!vRecv.
empty()) {
3896 if (!vRecv.
empty()) {
3897 std::string strSubVer;
3901 if (!vRecv.
empty()) {
3902 vRecv >> starting_height;
3922 PushNodeVersion(pfrom, peer);
3926 const int greatest_common_version = std::min(nVersion, pfrom.
AdvertisedVersion());
3931 peer.m_their_services = nServices;
3935 pfrom.cleanSubVer = cleanSubVer;
3946 (fRelay || (peer.m_our_services &
NODE_BLOOM))) {
3947 auto*
const tx_relay = peer.SetTxRelay();
3949 LOCK(tx_relay->m_bloom_filter_mutex);
3950 tx_relay->m_relay_txs = fRelay;
3956 LogDebug(
BCLog::NET,
"receive version message: %s: version %d, blocks=%d, us=%s, txrelay=%d, %s%s",
3957 cleanSubVer.empty() ?
"<no user agent>" : cleanSubVer, pfrom.
nVersion,
3959 (mapped_as ?
strprintf(
", mapped_as=%d", mapped_as) :
""));
3977 if (greatest_common_version >= 70016) {
3992 const auto* tx_relay = peer.GetTxRelay();
3993 if (tx_relay &&
WITH_LOCK(tx_relay->m_bloom_filter_mutex,
return tx_relay->m_relay_txs) &&
3995 const uint64_t recon_salt = m_txreconciliation->PreRegisterPeer(pfrom.
GetId());
4008 if (MaybeDisconnectForTxRelayCapacity(pfrom, msg_type, pfrom.
GetId()))
return;
4016 m_num_preferred_download_peers += state->fPreferredDownload;
4022 bool send_getaddr{
false};
4024 send_getaddr = SetupAddressRelay(pfrom, peer);
4057 peer.m_time_offset =
NodeSeconds{std::chrono::seconds{nTime}} - Now<NodeSeconds>();
4061 m_outbound_time_offsets.Add(peer.m_time_offset);
4062 m_outbound_time_offsets.WarnIfOutOfSync();
4066 if (greatest_common_version <= 70012) {
4067 constexpr auto finalAlert{
"60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50"_hex};
4068 MakeAndPushMessage(pfrom,
"alert", finalAlert);
4091 auto new_peer_msg = [&]() {
4093 return strprintf(
"New %s peer connected: transport: %s, version: %d, %s%s",
4097 (mapped_as ?
strprintf(
", mapped_as=%d", mapped_as) :
""));
4105 LogInfo(
"%s", new_peer_msg());
4108 if (
auto tx_relay = peer.GetTxRelay()) {
4117 tx_relay->m_tx_inventory_mutex,
4118 return tx_relay->m_tx_inventory_to_send.empty() &&
4119 tx_relay->m_next_inv_send_time == 0
s));
4129 PushPrivateBroadcastTx(pfrom);
4142 if (m_txreconciliation) {
4143 if (!peer.m_wtxid_relay || !m_txreconciliation->IsPeerRegistered(pfrom.
GetId())) {
4147 m_txreconciliation->ForgetPeer(pfrom.
GetId());
4153 const CNodeState* state =
State(pfrom.
GetId());
4155 .m_preferred = state->fPreferredDownload,
4156 .m_relay_permissions = pfrom.HasPermission(NetPermissionFlags::Relay),
4157 .m_wtxid_relay = peer.m_wtxid_relay,
4166 peer.m_prefers_headers =
true;
4171 uint8_t sendcmpct_hb{0};
4172 uint64_t sendcmpct_version{0};
4173 vRecv >> sendcmpct_hb >> sendcmpct_version;
4177 if (sendcmpct_hb > 1) {
4178 Misbehaving(peer,
"invalid sendcmpct announce field");
4186 CNodeState* nodestate =
State(pfrom.
GetId());
4187 nodestate->m_provides_cmpctblocks =
true;
4188 nodestate->m_requested_hb_cmpctblocks = sendcmpct_hb;
4205 if (!peer.m_wtxid_relay) {
4206 peer.m_wtxid_relay =
true;
4207 m_wtxid_relay_peers++;
4226 peer.m_wants_addrv2 =
true;
4243 std::string feature_id;
4247 std::vector<unsigned char> feature_data_vec;
4250 }
catch (
const std::exception&) {
4253 if (feature_id.size() < 4 || !vRecv.
empty()) {
4273 if (!m_txreconciliation) {
4274 LogDebug(
BCLog::NET,
"sendtxrcncl from peer=%d ignored, as our node does not have txreconciliation enabled\n", pfrom.
GetId());
4285 if (RejectIncomingTxs(pfrom)) {
4294 const auto* tx_relay = peer.GetTxRelay();
4295 if (!tx_relay || !
WITH_LOCK(tx_relay->m_bloom_filter_mutex,
return tx_relay->m_relay_txs)) {
4301 uint32_t peer_txreconcl_version;
4302 uint64_t remote_salt;
4303 vRecv >> peer_txreconcl_version >> remote_salt;
4306 peer_txreconcl_version, remote_salt);
4338 const auto ser_params{
4346 std::vector<CAddress> vAddr;
4347 vRecv >> ser_params(vAddr);
4348 ProcessAddrs(msg_type, pfrom, peer, std::move(vAddr), interruptMsgProc);
4353 std::vector<CInv> vInv;
4357 Misbehaving(peer,
strprintf(
"inv message size = %u", vInv.size()));
4361 const bool reject_tx_invs{RejectIncomingTxs(pfrom)};
4362 std::unordered_set<uint256, SaltedUint256Hasher> seen_txids{0, m_txhash_hasher};
4363 std::unordered_set<uint256, SaltedUint256Hasher> seen_wtxids{0, m_txhash_hasher};
4367 const auto current_time{GetTime<std::chrono::microseconds>()};
4370 for (
CInv& inv : vInv) {
4371 if (interruptMsgProc)
return;
4376 if (peer.m_wtxid_relay) {
4383 const bool fAlreadyHave = AlreadyHaveBlock(inv.
hash);
4386 UpdateBlockAvailability(pfrom.
GetId(), inv.
hash);
4394 best_block = &inv.
hash;
4397 if (reject_tx_invs) {
4403 auto& seen_hashes{inv.
IsMsgWtx() ? seen_wtxids : seen_txids};
4404 if (!seen_hashes.insert(inv.
hash).second)
continue;
4406 AddKnownTx(peer, inv.
hash);
4409 const bool fAlreadyHave{m_txdownloadman.AddTxAnnouncement(pfrom.
GetId(), gtxid, current_time)};
4417 if (best_block !=
nullptr) {
4429 if (state.fSyncStarted || (!peer.m_inv_triggered_getheaders_before_sync && *best_block != m_last_block_inv_triggering_headers_sync)) {
4430 if (MaybeSendGetHeaders(pfrom,
GetLocator(m_chainman.m_best_header), peer)) {
4432 m_chainman.m_best_header->nHeight, best_block->ToString(),
4435 if (!state.fSyncStarted) {
4436 peer.m_inv_triggered_getheaders_before_sync =
true;
4440 m_last_block_inv_triggering_headers_sync = *best_block;
4449 std::vector<CInv> vInv;
4453 Misbehaving(peer,
strprintf(
"getdata message size = %u", vInv.size()));
4459 if (vInv.size() > 0) {
4464 const auto pushed_tx_opt{m_tx_for_private_broadcast.GetTxForNode(pfrom.
GetId())};
4465 if (!pushed_tx_opt) {
4476 if (vInv.size() == 1 && vInv[0].IsMsgTx() && vInv[0].hash == pushed_tx->GetHash().ToUint256()) {
4480 peer.m_ping_queued =
true;
4491 LOCK(peer.m_getdata_requests_mutex);
4492 peer.m_getdata_requests.insert(peer.m_getdata_requests.end(), vInv.begin(), vInv.end());
4493 ProcessGetData(pfrom, peer, interruptMsgProc);
4502 vRecv >> locator >> hashStop;
4518 std::shared_ptr<const CBlock> a_recent_block;
4520 LOCK(m_most_recent_block_mutex);
4521 a_recent_block = m_most_recent_block;
4524 if (!m_chainman.
ActiveChainstate().ActivateBestChain(state, a_recent_block)) {
4539 for (; pindex; pindex = m_chainman.
ActiveChain().Next(*pindex))
4554 if (--nLimit <= 0) {
4558 WITH_LOCK(peer.m_block_inv_mutex, {peer.m_continuation_block = pindex->GetBlockHash();});
4578 for (
size_t i = 1; i < req.
indexes.size(); ++i) {
4582 std::shared_ptr<const CBlock> recent_block;
4584 LOCK(m_most_recent_block_mutex);
4585 if (m_most_recent_block_hash == req.
blockhash)
4586 recent_block = m_most_recent_block;
4590 SendBlockTransactions(pfrom, peer, *recent_block, req);
4609 if (!block_pos.IsNull()) {
4616 SendBlockTransactions(pfrom, peer, block, req);
4629 WITH_LOCK(peer.m_getdata_requests_mutex, peer.m_getdata_requests.push_back(inv));
4637 vRecv >> locator >> hashStop;
4655 if (m_chainman.
ActiveTip() ==
nullptr ||
4657 LogDebug(
BCLog::NET,
"Ignoring getheaders from peer=%d because active chain has too little work; sending empty response\n", pfrom.
GetId());
4664 CNodeState *nodestate =
State(pfrom.
GetId());
4673 if (!BlockRequestAllowed(*pindex)) {
4674 LogDebug(
BCLog::NET,
"%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom.
GetId());
4687 std::vector<CBlock> vHeaders;
4688 int nLimit = m_opts.max_headers_result;
4690 for (; pindex; pindex = m_chainman.
ActiveChain().Next(*pindex))
4693 if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
4708 nodestate->pindexBestHeaderSent = pindex ? pindex : m_chainman.
ActiveChain().
Tip();
4714 if (RejectIncomingTxs(pfrom)) {
4728 const Txid& txid = ptx->GetHash();
4729 const Wtxid& wtxid = ptx->GetWitnessHash();
4732 AddKnownTx(peer, hash);
4734 if (m_tx_for_private_broadcast.MarkResolved(ptx)) {
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());
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);
5414bool PeerManagerImpl::MaybeDisconnectForTxRelayCapacity(
CNode&
node,
const std::string& msg_type, std::optional<NodeId> protect_peer)
5416 if (!
node.IsInboundConn() || !
node.m_relays_txs)
return false;
5419 LogDebug(
BCLog::NET,
"failed to find a tx-relaying eviction candidate - connection dropped after %s message, peer=%d\n", msg_type,
node.GetId());
5420 node.fDisconnect =
true;
5424bool PeerManagerImpl::ProcessMessages(
CNode&
node, std::atomic<bool>& interruptMsgProc)
5429 PeerRef maybe_peer{GetPeerRef(
node.GetId())};
5430 if (maybe_peer ==
nullptr)
return false;
5431 Peer& peer{*maybe_peer};
5435 if (!
node.IsInboundConn() && !peer.m_outbound_version_message_sent)
return false;
5438 LOCK(peer.m_getdata_requests_mutex);
5439 if (!peer.m_getdata_requests.empty()) {
5440 ProcessGetData(
node, peer, interruptMsgProc);
5444 const bool processed_orphan = ProcessOrphanTx(peer);
5446 if (
node.fDisconnect)
5449 if (processed_orphan)
return true;
5454 LOCK(peer.m_getdata_requests_mutex);
5455 if (!peer.m_getdata_requests.empty())
return true;
5459 if (
node.fPauseSend)
return false;
5461 auto poll_result{
node.PollMessage()};
5468 bool fMoreWork = poll_result->second;
5472 node.m_addr_name.c_str(),
5473 node.ConnectionTypeAsString().c_str(),
5479 if (m_opts.capture_messages) {
5484 ProcessMessage(peer,
node,
msg.m_type,
msg.m_recv,
msg.m_time, interruptMsgProc);
5485 if (interruptMsgProc)
return false;
5487 LOCK(peer.m_getdata_requests_mutex);
5488 if (!peer.m_getdata_requests.empty()) fMoreWork =
true;
5495 LOCK(m_tx_download_mutex);
5496 if (m_txdownloadman.HaveMoreWork(peer.m_id)) fMoreWork =
true;
5497 }
catch (
const std::exception& e) {
5506void PeerManagerImpl::ConsiderEviction(
CNode& pto, Peer& peer, std::chrono::seconds time_in_seconds)
5519 if (state.pindexBestKnownBlock !=
nullptr && state.pindexBestKnownBlock->nChainWork >= m_chainman.
ActiveChain().
Tip()->
nChainWork) {
5521 if (state.m_chain_sync.m_timeout != 0
s) {
5522 state.m_chain_sync.m_timeout = 0
s;
5523 state.m_chain_sync.m_work_header =
nullptr;
5524 state.m_chain_sync.m_sent_getheaders =
false;
5526 }
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)) {
5534 state.m_chain_sync.m_work_header = m_chainman.
ActiveChain().
Tip();
5535 state.m_chain_sync.m_sent_getheaders =
false;
5536 }
else if (state.m_chain_sync.m_timeout > 0
s && time_in_seconds > state.m_chain_sync.m_timeout) {
5540 if (state.m_chain_sync.m_sent_getheaders) {
5542 LogInfo(
"Outbound peer has old chain, best known block = %s, %s", state.pindexBestKnownBlock !=
nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() :
"<none>", pto.
DisconnectMsg());
5545 assert(state.m_chain_sync.m_work_header);
5550 MaybeSendGetHeaders(pto,
5551 GetLocator(state.m_chain_sync.m_work_header->pprev),
5553 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());
5554 state.m_chain_sync.m_sent_getheaders =
true;
5575 std::pair<NodeId, std::chrono::seconds> youngest_peer{-1, 0}, next_youngest_peer{-1, 0};
5579 if (pnode->
GetId() > youngest_peer.first) {
5580 next_youngest_peer = youngest_peer;
5581 youngest_peer.first = pnode->GetId();
5582 youngest_peer.second = pnode->m_last_block_time;
5585 NodeId to_disconnect = youngest_peer.first;
5586 if (youngest_peer.second > next_youngest_peer.second) {
5589 to_disconnect = next_youngest_peer.first;
5598 CNodeState *node_state =
State(pnode->
GetId());
5599 if (node_state ==
nullptr ||
5602 LogDebug(
BCLog::NET,
"disconnecting extra block-relay-only peer=%d (last block received at time %d)\n",
5606 LogDebug(
BCLog::NET,
"keeping block-relay-only peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n",
5607 pnode->
GetId(), TicksSinceEpoch<std::chrono::seconds>(pnode->
m_connected), node_state->vBlocksInFlight.size());
5625 std::optional<WorstPeer> worst_peer;
5634 if (state ==
nullptr)
return;
5636 if (state->m_chain_sync.m_protect)
return;
5640 if (!worst_peer.has_value() ||
5641 (state->m_last_block_announcement < (*worst_peer).oldest_block_announcement) ||
5642 ((state->m_last_block_announcement == (*worst_peer).oldest_block_announcement) && pnode->
GetId() > (*worst_peer).node)) {
5643 worst_peer = WorstPeer{pnode->
GetId(), state->m_last_block_announcement};
5646 if (worst_peer.has_value()) {
5657 LogDebug(
BCLog::NET,
"disconnecting extra outbound peer=%d (last block announcement received at time %d)\n",
5658 pnode->
GetId(), TicksSinceEpoch<std::chrono::seconds>((*worst_peer).oldest_block_announcement));
5662 LogDebug(
BCLog::NET,
"keeping outbound peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n",
5663 pnode->
GetId(), TicksSinceEpoch<std::chrono::seconds>(pnode->
m_connected), state.vBlocksInFlight.size());
5679void PeerManagerImpl::CheckForStaleTipAndEvictPeers()
5684 auto now{GetTime<std::chrono::seconds>()};
5686 EvictExtraOutboundPeers(current_time);
5688 if (now > m_stale_tip_check_time) {
5692 LogInfo(
"Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n",
5701 if (!m_initial_sync_finished && CanDirectFetch()) {
5703 m_initial_sync_finished =
true;
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 && 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);
6057bool PeerManagerImpl::SendMessages(
CNode&
node)
6062 PeerRef maybe_peer{GetPeerRef(
node.GetId())};
6063 if (!maybe_peer)
return false;
6064 Peer& peer{*maybe_peer};
6069 if (MaybeDiscourageAndDisconnect(
node, peer))
return true;
6072 if (!
node.IsInboundConn() && !peer.m_outbound_version_message_sent) {
6073 PushNodeVersion(
node, peer);
6074 peer.m_outbound_version_message_sent =
true;
6078 if (!
node.fSuccessfullyConnected ||
node.fDisconnect)
6082 const auto current_time{GetTime<std::chrono::microseconds>()};
6087 if (
node.IsPrivateBroadcastConn()) {
6091 node.fDisconnect =
true;
6098 node.fDisconnect =
true;
6102 MaybeSendPing(
node, peer, now);
6104 MaybeSendAddr(
node, peer, current_time);
6106 MaybeSendSendHeaders(
node, peer);
6108 ProcessInvBacklog(now);
6113 CNodeState &state = *
State(
node.GetId());
6116 if (m_chainman.m_best_header ==
nullptr) {
6123 bool sync_blocks_and_headers_from_peer =
false;
6124 if (state.fPreferredDownload) {
6125 sync_blocks_and_headers_from_peer =
true;
6126 }
else if (CanServeBlocks(peer) && !
node.IsAddrFetchConn()) {
6136 if (m_num_preferred_download_peers == 0 || mapBlocksInFlight.empty()) {
6137 sync_blocks_and_headers_from_peer =
true;
6143 if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) || m_chainman.m_best_header->Time() >
NodeClock::now() - 24h) {
6144 const CBlockIndex* pindexStart = m_chainman.m_best_header;
6152 if (pindexStart->
pprev)
6153 pindexStart = pindexStart->
pprev;
6157 state.fSyncStarted =
true;
6181 LOCK(peer.m_block_inv_mutex);
6182 std::vector<CBlock> vHeaders;
6183 bool fRevertToInv = ((!peer.m_prefers_headers &&
6184 (!state.m_requested_hb_cmpctblocks || peer.m_blocks_for_headers_relay.size() > 1)) ||
6187 ProcessBlockAvailability(
node.GetId());
6189 if (!fRevertToInv) {
6190 bool fFoundStartingHeader =
false;
6194 for (
const uint256& hash : peer.m_blocks_for_headers_relay) {
6199 fRevertToInv =
true;
6202 if (pBestIndex !=
nullptr && pindex->
pprev != pBestIndex) {
6214 fRevertToInv =
true;
6217 pBestIndex = pindex;
6218 if (fFoundStartingHeader) {
6221 }
else if (PeerHasHeader(&state, pindex)) {
6223 }
else if (pindex->
pprev ==
nullptr || PeerHasHeader(&state, pindex->
pprev)) {
6226 fFoundStartingHeader =
true;
6231 fRevertToInv =
true;
6236 if (!fRevertToInv && !vHeaders.empty()) {
6237 if (vHeaders.size() == 1 && state.m_requested_hb_cmpctblocks) {
6241 vHeaders.front().GetHash().ToString(),
node.GetId());
6243 std::optional<CSerializedNetMsg> cached_cmpctblock_msg;
6245 LOCK(m_most_recent_block_mutex);
6246 if (m_most_recent_block_hash == pBestIndex->
GetBlockHash()) {
6250 if (cached_cmpctblock_msg.has_value()) {
6251 PushMessage(
node, std::move(cached_cmpctblock_msg.value()));
6259 state.pindexBestHeaderSent = pBestIndex;
6260 }
else if (peer.m_prefers_headers) {
6261 if (vHeaders.size() > 1) {
6264 vHeaders.front().GetHash().ToString(),
6265 vHeaders.back().GetHash().ToString(),
node.GetId());
6268 vHeaders.front().GetHash().ToString(),
node.GetId());
6271 state.pindexBestHeaderSent = pBestIndex;
6273 fRevertToInv =
true;
6279 if (!peer.m_blocks_for_headers_relay.empty()) {
6280 const uint256& hashToAnnounce = peer.m_blocks_for_headers_relay.back();
6293 if (!PeerHasHeader(&state, pindex)) {
6294 peer.m_blocks_for_inv_relay.push_back(hashToAnnounce);
6300 peer.m_blocks_for_headers_relay.clear();
6306 std::vector<CInv> vInv;
6308 LOCK(peer.m_block_inv_mutex);
6309 vInv.reserve(peer.m_blocks_for_inv_relay.size());
6312 for (
const uint256& hash : peer.m_blocks_for_inv_relay) {
6319 peer.m_blocks_for_inv_relay.clear();
6322 if (
auto tx_relay = peer.GetTxRelay(); tx_relay !=
nullptr) {
6323 LOCK(tx_relay->m_tx_inventory_mutex);
6326 if (tx_relay->m_next_inv_send_time < current_time) {
6327 fSendTrickle =
true;
6328 if (
node.IsInboundConn()) {
6337 LOCK(tx_relay->m_bloom_filter_mutex);
6338 if (!tx_relay->m_relay_txs) tx_relay->m_tx_inventory_to_send.clear();
6342 if (fSendTrickle && tx_relay->m_send_mempool) {
6343 auto vtxinfo = m_mempool.
infoAll();
6348 tx_relay->m_send_mempool =
false;
6349 const CFeeRate filterrate{tx_relay->m_fee_filter_received.load()};
6352 tx_relay->m_tx_inventory_to_send.clear();
6354 LOCK(tx_relay->m_bloom_filter_mutex);
6356 for (
const auto& txinfo : vtxinfo) {
6357 const Txid& txid{txinfo.tx->GetHash()};
6358 const Wtxid& wtxid{txinfo.tx->GetWitnessHash()};
6359 const auto inv = peer.m_wtxid_relay ?
6364 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
6367 if (tx_relay->m_bloom_filter) {
6368 if (!tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx))
continue;
6370 tx_relay->m_tx_inventory_known_filter.insert(inv.
hash);
6371 vInv.push_back(inv);
6383 const CFeeRate filterrate{tx_relay->m_fee_filter_received.load()};
6386 auto& invs = tx_relay->m_tx_inventory_to_send;
6387 std::vector<CTransactionRef> res;
6389 if (invs.size() == 0)
return res;
6392 if (invs.capacity() > 2 * invs.size()) invs.shrink_to_fit();
6396 res.reserve(txiters.size());
6397 for (
auto txiter : txiters) {
6398 if (txiter->GetFee() < filterrate.GetFee(txiter->GetTxSize())) {
6401 res.push_back(txiter->GetSharedTx());
6404 tx_relay->m_last_inv_sequence = m_mempool.
GetSequence();
6408 LOCK(tx_relay->m_bloom_filter_mutex);
6409 vInv.reserve(std::min<size_t>(
MAX_INV_SZ, vInv.size() + inv_tx.size()));
6410 for (
auto& tx : inv_tx) {
6414 const auto inv = peer.m_wtxid_relay ?
6418 if (tx_relay->m_tx_inventory_known_filter.contains(inv.
hash)) {
6421 if (tx_relay->m_bloom_filter && !tx_relay->m_bloom_filter->IsRelevantAndUpdate(*tx))
continue;
6423 vInv.push_back(inv);
6428 tx_relay->m_tx_inventory_known_filter.insert(inv.
hash);
6436 auto stalling_timeout = m_block_stalling_timeout.load();
6437 if (state.m_stalling_since.count() && state.m_stalling_since < current_time - stalling_timeout) {
6441 if (
node.IsManualConn()) {
6444 while (!state.vBlocksInFlight.empty()) {
6445 RemoveBlockRequest(state.vBlocksInFlight.front().pindex->GetBlockHash(),
node.GetId());
6448 LogInfo(
"Peer is stalling block download, %s",
node.DisconnectMsg());
6449 node.fDisconnect =
true;
6454 if (stalling_timeout != new_timeout && m_block_stalling_timeout.compare_exchange_strong(stalling_timeout, new_timeout)) {
6464 if (state.vBlocksInFlight.size() > 0) {
6465 QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
6466 int nOtherPeersWithValidatedDownloads = m_peers_downloading_from - 1;
6468 LogInfo(
"Timeout downloading block %s, %s", queuedBlock.pindex->GetBlockHash().ToString(),
node.DisconnectMsg());
6469 node.fDisconnect =
true;
6476 if (state.vBlocksInFlight.empty() &&
6479 peer.m_ping_nonce_sent &&
6484 LogDebug(
BCLog::NET,
"ping timeout: %fs, %s", Ticks<SecondsDouble>(now - peer.m_ping_start.load()),
node.DisconnectMsg());
6485 node.fDisconnect =
true;
6489 if (state.fSyncStarted && peer.m_headers_sync_timeout < std::chrono::microseconds::max()) {
6491 if (m_chainman.m_best_header->Time() <=
NodeClock::now() - 24h) {
6492 if (current_time > peer.m_headers_sync_timeout && nSyncStarted == 1 && (m_num_preferred_download_peers - state.fPreferredDownload >= 1)) {
6499 LogInfo(
"Timeout downloading headers, %s",
node.DisconnectMsg());
6500 node.fDisconnect =
true;
6503 LogInfo(
"Timeout downloading headers from noban peer, not %s",
node.DisconnectMsg());
6509 state.fSyncStarted =
false;
6511 peer.m_headers_sync_timeout = 0us;
6517 peer.m_headers_sync_timeout = std::chrono::microseconds::max();
6523 ConsiderEviction(
node, peer, GetTime<std::chrono::seconds>());
6528 std::vector<CInv> vGetData;
6529 const bool can_request_blocks_from_peer{current_time >= state.m_block_download_paused_until};
6531 std::vector<const CBlockIndex*> vToDownload;
6533 auto get_inflight_budget = [&state]() {
6540 FindNextBlocksToDownload(peer, get_inflight_budget(), vToDownload, staller);
6541 auto historical_blocks{m_chainman.GetHistoricalBlockRange()};
6542 if (historical_blocks && !IsLimitedPeer(peer)) {
6546 TryDownloadingHistoricalBlocks(
6548 get_inflight_budget(),
6549 vToDownload, from_tip, historical_blocks->second);
6552 uint32_t nFetchFlags = GetFetchFlags(peer);
6554 BlockRequested(
node.GetId(), *pindex);
6558 if (state.vBlocksInFlight.empty() && staller != -1) {
6559 if (
State(staller)->m_stalling_since == 0us) {
6560 State(staller)->m_stalling_since = current_time;
6570 LOCK(m_tx_download_mutex);
6571 for (
const GenTxid& gtxid : m_txdownloadman.GetRequestsToSend(
node.GetId(), current_time)) {
6580 if (!vGetData.empty())
6583 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 MultipleManualOrFullOutboundConns(Network net) const EXCLUSIVE_LOCKS_REQUIRED(m_nodes_mutex)
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
enum Network GetNetwork() const
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.
const util::NotNullUniquePtr< Transport > m_transport
Transport serializer/deserializer.
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 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 a copy of the unbroadcast txid 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 void UpdateLastBlockAnnounceTime(NodeId node, NodeClock::time_point time)=0
This function is used for testing the stale tip eviction logic, see denialofservice_tests....
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 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.
static constexpr size_t INITIAL_CONNECTION_COUNT
Number of connections to make for initial broadcast.
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 LogTrace(category,...)
#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)
Return whether messages with specified category should be debug logged.
bool ShouldTraceLog(Category)
Return whether messages with specified category should be trace logged.
std::string ToString(const T &t)
Locale-independent version of std::to_string.
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
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 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 constexpr auto POST_BLOCK_PONG_GRACE
Time to wait for a pong after the last block a peer delivered, before applying the ping timeout.
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::time_point m_last_block_announcement
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.
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...