107 "Max protocol message length must be greater than largest "
108 "possible INV message");
162 std::chrono::seconds(2),
163 std::chrono::seconds(2),
164 std::chrono::seconds(60),
171 std::chrono::seconds(2),
172 std::chrono::seconds(2),
173 std::chrono::seconds(60),
265 std::chrono::seconds{1},
266 "INVENTORY_RELAY_MAX too low");
317 std::unique_ptr<PartiallyDownloadedBlock> partialBlock;
355 std::atomic<ServiceFlags> m_their_services{
NODE_NONE};
358 Mutex m_misbehavior_mutex;
360 int m_misbehavior_score
GUARDED_BY(m_misbehavior_mutex){0};
363 bool m_should_discourage
GUARDED_BY(m_misbehavior_mutex){
false};
366 Mutex m_block_inv_mutex;
372 std::vector<BlockHash> m_blocks_for_inv_relay
GUARDED_BY(m_block_inv_mutex);
378 std::vector<BlockHash>
379 m_blocks_for_headers_relay
GUARDED_BY(m_block_inv_mutex);
390 std::atomic<int> m_starting_height{-1};
393 std::atomic<uint64_t> m_ping_nonce_sent{0};
395 std::atomic<std::chrono::microseconds> m_ping_start{0us};
397 std::atomic<bool> m_ping_queued{
false};
407 std::chrono::microseconds m_next_send_feefilter
420 bool m_relay_txs
GUARDED_BY(m_bloom_filter_mutex){
false};
425 std::unique_ptr<CBloomFilter>
441 GUARDED_BY(m_tx_inventory_mutex){50000, 0.000001};
447 std::set<TxId> m_tx_inventory_to_send
GUARDED_BY(m_tx_inventory_mutex);
453 bool m_send_mempool
GUARDED_BY(m_tx_inventory_mutex){
false};
455 std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
460 std::chrono::microseconds m_next_inv_send_time
467 std::atomic<Amount> m_fee_filter_received{
Amount::zero()};
475 LOCK(m_tx_relay_mutex);
477 m_tx_relay = std::make_unique<Peer::TxRelay>();
478 return m_tx_relay.get();
482 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
484 const TxRelay *GetTxRelay() const
486 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
491 std::set<avalanche::ProofId>
492 m_proof_inventory_to_send
GUARDED_BY(m_proof_inventory_mutex);
495 GUARDED_BY(m_proof_inventory_mutex){10000, 0.000001};
502 std::chrono::microseconds m_next_inv_send_time{0};
506 std::atomic<std::chrono::seconds> lastSharedProofsUpdate{0s};
507 std::atomic<bool> compactproofs_requested{
false};
514 const std::unique_ptr<ProofRelay> m_proof_relay;
519 std::vector<CAddress>
531 std::unique_ptr<CRollingBloomFilter>
549 std::atomic_bool m_addr_relay_enabled{
false};
553 mutable Mutex m_addr_send_times_mutex;
555 std::chrono::microseconds
556 m_next_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
558 std::chrono::microseconds
559 m_next_local_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
564 std::atomic_bool m_wants_addrv2{
false};
568 mutable Mutex m_addr_token_bucket_mutex;
573 double m_addr_token_bucket
GUARDED_BY(m_addr_token_bucket_mutex){1.0};
575 std::chrono::microseconds
577 GetTime<std::chrono::microseconds>()};
579 std::atomic<uint64_t> m_addr_rate_limited{0};
584 std::atomic<uint64_t> m_addr_processed{0};
590 bool m_inv_triggered_getheaders_before_sync
594 Mutex m_getdata_requests_mutex;
596 std::deque<CInv> m_getdata_requests
GUARDED_BY(m_getdata_requests_mutex);
603 Mutex m_headers_sync_mutex;
608 std::unique_ptr<HeadersSyncState>
613 std::atomic<bool> m_sent_sendheaders{
false};
616 int m_num_unconnecting_headers_msgs
620 std::chrono::microseconds m_headers_sync_timeout
631 : m_id(id), m_our_services{our_services},
632 m_proof_relay(fRelayProofs ?
std::make_unique<ProofRelay>()
636 mutable Mutex m_tx_relay_mutex;
643 std::unique_ptr<TxRelay> m_tx_relay
GUARDED_BY(m_tx_relay_mutex);
646 using PeerRef = std::shared_ptr<Peer>;
664 bool fSyncStarted{
false};
667 std::chrono::microseconds m_stalling_since{0us};
668 std::list<QueuedBlock> vBlocksInFlight;
671 std::chrono::microseconds m_downloading_since{0us};
672 int nBlocksInFlight{0};
674 bool fPreferredDownload{
false};
679 bool m_requested_hb_cmpctblocks{
false};
681 bool m_provides_cmpctblocks{
false};
709 struct ChainSyncTimeoutState {
712 std::chrono::seconds m_timeout{0s};
716 bool m_sent_getheaders{
false};
719 bool m_protect{
false};
722 ChainSyncTimeoutState m_chain_sync;
725 int64_t m_last_block_announcement{0};
728 const bool m_is_inbound;
730 CNodeState(
bool is_inbound) : m_is_inbound(is_inbound) {}
748 bool fInitialDownload)
override
754 const std::shared_ptr<const CBlock> &pblock)
override
763 !m_headers_presync_mutex);
765 std::atomic<bool> &interrupt)
override
767 !m_recent_confirmed_transactions_mutex,
768 !m_most_recent_block_mutex, !cs_proofrequest,
769 !m_headers_presync_mutex, g_msgproc_mutex);
772 !m_recent_confirmed_transactions_mutex,
773 !m_most_recent_block_mutex, !cs_proofrequest,
779 std::optional<std::string>
786 void RelayTransaction(const
TxId &txid) override
788 void RelayProof(const
avalanche::ProofId &proofid) override
790 void SetBestHeight(
int height)
override { m_best_height = height; };
793 Misbehaving(*
Assert(GetPeerRef(peer_id)), howmuch,
"");
797 const std::chrono::microseconds time_received,
798 const std::atomic<bool> &interruptMsgProc)
override
800 !m_recent_confirmed_transactions_mutex,
801 !m_most_recent_block_mutex, !cs_proofrequest,
802 !m_headers_presync_mutex, g_msgproc_mutex);
804 int64_t time_in_seconds)
override;
811 void ConsiderEviction(
CNode &pto, Peer &peer,
812 std::chrono::seconds time_in_seconds)
819 void EvictExtraOutboundPeers(std::chrono::seconds now)
826 void ReattemptInitialBroadcast(
CScheduler &scheduler)
832 void UpdateAvalancheStatistics()
const;
837 void AvalanchePeriodicNetworking(
CScheduler &scheduler)
const;
856 void Misbehaving(Peer &peer,
int howmuch,
const std::string &message);
870 bool MaybePunishNodeForBlock(
NodeId nodeid,
872 bool via_compact_block,
873 const std::string &message =
"")
883 const
std::
string &message = "")
895 bool MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer);
912 bool maybe_add_extra_compact_tx)
915 struct PackageToValidate {
917 const std::vector<NodeId> m_senders;
922 : m_txns{parent, child}, m_senders{parent_sender, child_sender} {}
925 Assume(m_txns.size() == 2);
927 "parent %s (sender=%d) + child %s (sender=%d)",
928 m_txns.front()->GetId().ToString(), m_senders.front(),
929 m_txns.back()->GetId().ToString(), m_senders.back());
938 void ProcessPackageResult(
const PackageToValidate &package_to_validate,
948 std::optional<PackageToValidate> Find1P1CPackage(
const CTransactionRef &ptx,
975 bool ProcessOrphanTx(
const Config &config, Peer &peer)
988 void ProcessHeadersMessage(
const Config &config,
CNode &pfrom, Peer &peer,
989 std::vector<CBlockHeader> &&headers,
990 bool via_compact_block)
1000 bool CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
1010 void HandleFewUnconnectingHeaders(
CNode &pfrom, Peer &peer,
1011 const std::vector<CBlockHeader> &headers)
1015 CheckHeadersAreContinuous(
const std::vector<CBlockHeader> &headers)
const;
1035 bool IsContinuationOfLowWorkHeadersSync(Peer &peer,
CNode &pfrom,
1036 std::vector<CBlockHeader> &headers)
1038 !m_headers_presync_mutex, g_msgproc_mutex);
1053 bool TryLowWorkHeadersSync(Peer &peer,
CNode &pfrom,
1055 std::vector<CBlockHeader> &headers)
1057 !m_headers_presync_mutex, g_msgproc_mutex);
1063 bool IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header)
1077 void HeadersDirectFetchBlocks(
const Config &config,
CNode &pfrom,
1080 void UpdatePeerStateForReceivedHeaders(
CNode &pfrom, Peer &peer,
1082 bool received_new_header,
1083 bool may_have_more_headers)
1086 void SendBlockTransactions(
CNode &pfrom, Peer &peer,
const CBlock &block,
1095 std::chrono::microseconds current_time)
1105 std::chrono::microseconds current_time,
bool preferred)
1109 void PushNodeVersion(
const Config &config,
CNode &pnode,
const Peer &peer);
1117 void MaybeSendPing(
CNode &node_to, Peer &peer,
1118 std::chrono::microseconds now);
1121 void MaybeSendAddr(
CNode &
node, Peer &peer,
1122 std::chrono::microseconds current_time)
1129 void MaybeSendSendHeaders(
CNode &
node, Peer &peer)
1133 void MaybeSendFeefilter(
CNode &
node, Peer &peer,
1134 std::chrono::microseconds current_time)
1146 void RelayAddress(
NodeId originator,
const CAddress &addr,
bool fReachable)
1167 Mutex cs_proofrequest;
1172 std::atomic<int> m_best_height{-1};
1175 std::chrono::seconds m_stale_tip_check_time{0s};
1177 const Options m_opts;
1183 bool m_initial_sync_finished{
false};
1189 mutable Mutex m_peer_mutex;
1196 std::map<NodeId, PeerRef> m_peer_map
GUARDED_BY(m_peer_mutex);
1205 const CNodeState *State(
NodeId pnode)
const
1210 std::atomic<std::chrono::microseconds> m_next_inv_to_inbounds{0us};
1217 m_last_block_inv_triggering_headers_sync
GUARDED_BY(g_msgproc_mutex){};
1225 std::map<BlockHash, std::pair<NodeId, bool>>
1235 std::atomic<std::chrono::seconds> m_block_stalling_timeout{
1248 bool AlreadyHaveTx(
const TxId &txid,
bool include_reconsiderable)
1250 !m_recent_confirmed_transactions_mutex);
1306 120'000, 0.000'001};
1313 mutable Mutex m_recent_confirmed_transactions_mutex;
1315 GUARDED_BY(m_recent_confirmed_transactions_mutex){24'000, 0.000'001};
1324 std::chrono::microseconds
1325 NextInvToInbounds(std::chrono::microseconds now,
1326 std::chrono::seconds average_interval);
1330 mutable Mutex m_most_recent_block_mutex;
1331 std::shared_ptr<const CBlock>
1332 m_most_recent_block
GUARDED_BY(m_most_recent_block_mutex);
1333 std::shared_ptr<const CBlockHeaderAndShortTxIDs>
1334 m_most_recent_compact_block
GUARDED_BY(m_most_recent_block_mutex);
1340 Mutex m_headers_presync_mutex;
1351 using HeadersPresyncStats =
1352 std::pair<arith_uint256, std::optional<std::pair<int64_t, uint32_t>>>;
1354 std::map<NodeId, HeadersPresyncStats>
1355 m_headers_presync_stats
GUARDED_BY(m_headers_presync_mutex){};
1359 std::atomic_bool m_headers_presync_should_signal{
false};
1367 bool IsBlockRequested(
const BlockHash &hash)
1375 void RemoveBlockRequest(
const BlockHash &hash)
1384 bool BlockRequested(
const Config &config,
NodeId nodeid,
1386 std::list<QueuedBlock>::iterator **pit =
nullptr)
1395 void FindNextBlocksToDownload(
NodeId nodeid,
unsigned int count,
1404 std::atomic<
std::chrono::seconds> m_last_tip_update{0s};
1411 const std::chrono::seconds mempool_req,
1412 const std::chrono::seconds now)
1416 void ProcessGetData(
const Config &config,
CNode &pfrom, Peer &peer,
1417 const std::atomic<bool> &interruptMsgProc)
1419 peer.m_getdata_requests_mutex,
1425 const std::shared_ptr<const CBlock> &block,
1426 bool force_processing,
bool min_pow_checked);
1429 typedef std::map<TxId, CTransactionRef> MapRelay;
1436 std::deque<std::pair<std::chrono::microseconds, MapRelay::iterator>>
1445 void MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid)
1467 std::vector<std::pair<TxHash, CTransactionRef>>
1468 vExtraTxnForCompact
GUARDED_BY(g_msgproc_mutex);
1470 size_t vExtraTxnForCompactIt
GUARDED_BY(g_msgproc_mutex) = 0;
1475 void ProcessBlockAvailability(
NodeId nodeid)
1490 bool BlockRequestAllowed(const
CBlockIndex *pindex)
1492 bool AlreadyHaveBlock(const
BlockHash &block_hash)
1494 bool AlreadyHaveProof(const
avalanche::ProofId &proofid);
1495 void ProcessGetBlockData(const
Config &config,
CNode &pfrom, Peer &peer,
1518 bool PrepareBlockFilterRequest(
CNode &
node, Peer &peer,
1520 uint32_t start_height,
1522 uint32_t max_height_diff,
1563 uint32_t GetAvalancheVoteForBlock(const
BlockHash &hash) const
1572 uint32_t GetAvalancheVoteForTx(const
TxId &
id) const
1574 !m_recent_confirmed_transactions_mutex);
1583 bool SetupAddressRelay(const
CNode &
node, Peer &peer)
1586 void AddAddressKnown(Peer &peer, const
CAddress &addr)
1588 void PushAddress(Peer &peer, const
CAddress &addr)
1596 bool ReceivedAvalancheProof(
CNode &
node, Peer &peer,
1602 const
std::chrono::seconds now)
1605 bool isPreferredDownloadPeer(const
CNode &pfrom);
1608 const CNodeState *PeerManagerImpl::State(
NodeId pnode) const
1610 std::map<NodeId, CNodeState>::const_iterator it = m_node_states.find(pnode);
1611 if (it == m_node_states.end()) {
1618 CNodeState *PeerManagerImpl::State(
NodeId pnode)
1620 return const_cast<CNodeState *
>(std::as_const(*this).State(pnode));
1628 static bool IsAddrCompatible(
const Peer &peer,
const CAddress &addr) {
1632 void PeerManagerImpl::AddAddressKnown(Peer &peer,
const CAddress &addr) {
1633 assert(peer.m_addr_known);
1634 peer.m_addr_known->insert(addr.
GetKey());
1637 void PeerManagerImpl::PushAddress(Peer &peer,
const CAddress &addr) {
1641 assert(peer.m_addr_known);
1642 if (addr.
IsValid() && !peer.m_addr_known->contains(addr.
GetKey()) &&
1643 IsAddrCompatible(peer, addr)) {
1644 if (peer.m_addrs_to_send.size() >= m_opts.max_addr_to_send) {
1645 peer.m_addrs_to_send[m_rng.randrange(peer.m_addrs_to_send.size())] =
1648 peer.m_addrs_to_send.push_back(addr);
1653 static void AddKnownTx(Peer &peer,
const TxId &txid) {
1654 auto tx_relay = peer.GetTxRelay();
1659 LOCK(tx_relay->m_tx_inventory_mutex);
1660 tx_relay->m_tx_inventory_known_filter.insert(txid);
1664 if (peer.m_proof_relay !=
nullptr) {
1665 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
1666 peer.m_proof_relay->m_proof_inventory_known_filter.insert(proofid);
1670 bool PeerManagerImpl::isPreferredDownloadPeer(
const CNode &pfrom) {
1672 const CNodeState *state = State(pfrom.
GetId());
1673 return state && state->fPreferredDownload;
1676 static bool CanServeBlocks(
const Peer &peer) {
1684 static bool IsLimitedPeer(
const Peer &peer) {
1689 std::chrono::microseconds
1690 PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
1691 std::chrono::seconds average_interval) {
1692 if (m_next_inv_to_inbounds.load() < now) {
1699 return m_next_inv_to_inbounds;
1702 bool PeerManagerImpl::IsBlockRequested(
const BlockHash &hash) {
1703 return mapBlocksInFlight.find(hash) != mapBlocksInFlight.end();
1706 void PeerManagerImpl::RemoveBlockRequest(
const BlockHash &hash) {
1707 auto it = mapBlocksInFlight.find(hash);
1709 if (it == mapBlocksInFlight.end()) {
1714 auto [node_id, list_it] = it->second;
1715 CNodeState *state = State(node_id);
1716 assert(state !=
nullptr);
1718 if (state->vBlocksInFlight.begin() == list_it) {
1721 state->m_downloading_since = std::max(
1722 state->m_downloading_since, GetTime<std::chrono::microseconds>());
1724 state->vBlocksInFlight.erase(list_it);
1726 state->nBlocksInFlight--;
1727 if (state->nBlocksInFlight == 0) {
1729 m_peers_downloading_from--;
1731 state->m_stalling_since = 0us;
1732 mapBlocksInFlight.erase(it);
1735 bool PeerManagerImpl::BlockRequested(
const Config &config,
NodeId nodeid,
1737 std::list<QueuedBlock>::iterator **pit) {
1740 CNodeState *state = State(nodeid);
1741 assert(state !=
nullptr);
1745 std::pair<NodeId, std::list<QueuedBlock>::iterator>>::iterator
1746 itInFlight = mapBlocksInFlight.find(hash);
1747 if (itInFlight != mapBlocksInFlight.end() &&
1748 itInFlight->second.first == nodeid) {
1750 *pit = &itInFlight->second.second;
1756 RemoveBlockRequest(hash);
1758 std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(
1759 state->vBlocksInFlight.end(),
1760 {&block, std::unique_ptr<PartiallyDownloadedBlock>(
1761 pit ? new PartiallyDownloadedBlock(config, &m_mempool)
1763 state->nBlocksInFlight++;
1764 if (state->nBlocksInFlight == 1) {
1766 state->m_downloading_since = GetTime<std::chrono::microseconds>();
1767 m_peers_downloading_from++;
1770 itInFlight = mapBlocksInFlight
1771 .insert(std::make_pair(hash, std::make_pair(nodeid, it)))
1775 *pit = &itInFlight->second.second;
1781 void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid) {
1787 if (m_opts.ignore_incoming_txs) {
1791 CNodeState *nodestate = State(nodeid);
1796 if (!nodestate->m_provides_cmpctblocks) {
1799 int num_outbound_hb_peers = 0;
1800 for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin();
1801 it != lNodesAnnouncingHeaderAndIDs.end(); it++) {
1802 if (*it == nodeid) {
1803 lNodesAnnouncingHeaderAndIDs.erase(it);
1804 lNodesAnnouncingHeaderAndIDs.push_back(nodeid);
1807 CNodeState *state = State(*it);
1808 if (state !=
nullptr && !state->m_is_inbound) {
1809 ++num_outbound_hb_peers;
1812 if (nodestate->m_is_inbound) {
1815 if (lNodesAnnouncingHeaderAndIDs.size() >= 3 &&
1816 num_outbound_hb_peers == 1) {
1817 CNodeState *remove_node =
1818 State(lNodesAnnouncingHeaderAndIDs.front());
1819 if (remove_node !=
nullptr && !remove_node->m_is_inbound) {
1822 std::swap(lNodesAnnouncingHeaderAndIDs.front(),
1823 *std::next(lNodesAnnouncingHeaderAndIDs.begin()));
1830 if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
1834 lNodesAnnouncingHeaderAndIDs.front(), [
this](
CNode *pnodeStop) {
1835 m_connman.PushMessage(
1836 pnodeStop, CNetMsgMaker(pnodeStop->GetCommonVersion())
1837 .Make(NetMsgType::SENDCMPCT,
1839 CMPCTBLOCKS_VERSION));
1842 pnodeStop->m_bip152_highbandwidth_to = false;
1845 lNodesAnnouncingHeaderAndIDs.pop_front();
1854 lNodesAnnouncingHeaderAndIDs.push_back(pfrom->
GetId());
1859 bool PeerManagerImpl::TipMayBeStale() {
1862 if (m_last_tip_update.load() == 0s) {
1863 m_last_tip_update = GetTime<std::chrono::seconds>();
1865 return m_last_tip_update.load() <
1866 GetTime<std::chrono::seconds>() -
1869 mapBlocksInFlight.empty();
1872 bool PeerManagerImpl::CanDirectFetch() {
1878 static bool PeerHasHeader(CNodeState *state,
const CBlockIndex *pindex)
1880 if (state->pindexBestKnownBlock &&
1881 pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) {
1884 if (state->pindexBestHeaderSent &&
1885 pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight)) {
1891 void PeerManagerImpl::ProcessBlockAvailability(
NodeId nodeid) {
1892 CNodeState *state = State(nodeid);
1893 assert(state !=
nullptr);
1895 if (!state->hashLastUnknownBlock.IsNull()) {
1899 if (state->pindexBestKnownBlock ==
nullptr ||
1900 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
1901 state->pindexBestKnownBlock = pindex;
1903 state->hashLastUnknownBlock.SetNull();
1908 void PeerManagerImpl::UpdateBlockAvailability(
NodeId nodeid,
1910 CNodeState *state = State(nodeid);
1911 assert(state !=
nullptr);
1913 ProcessBlockAvailability(nodeid);
1918 if (state->pindexBestKnownBlock ==
nullptr ||
1919 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
1920 state->pindexBestKnownBlock = pindex;
1925 state->hashLastUnknownBlock = hash;
1929 void PeerManagerImpl::FindNextBlocksToDownload(
1931 std::vector<const CBlockIndex *> &vBlocks,
NodeId &nodeStaller) {
1936 vBlocks.reserve(vBlocks.size() +
count);
1937 CNodeState *state = State(nodeid);
1938 assert(state !=
nullptr);
1941 ProcessBlockAvailability(nodeid);
1943 if (state->pindexBestKnownBlock ==
nullptr ||
1944 state->pindexBestKnownBlock->nChainWork <
1946 state->pindexBestKnownBlock->nChainWork <
1952 if (state->pindexLastCommonBlock ==
nullptr) {
1955 state->pindexLastCommonBlock =
1957 .
ActiveChain()[std::min(state->pindexBestKnownBlock->nHeight,
1964 state->pindexLastCommonBlock, state->pindexBestKnownBlock);
1965 if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) {
1969 std::vector<const CBlockIndex *> vToFetch;
1970 const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
1978 std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
1980 while (pindexWalk->
nHeight < nMaxHeight) {
1985 int nToFetch = std::min(nMaxHeight - pindexWalk->
nHeight,
1986 std::max<int>(
count - vBlocks.size(), 128));
1987 vToFetch.resize(nToFetch);
1988 pindexWalk = state->pindexBestKnownBlock->
GetAncestor(
1989 pindexWalk->
nHeight + nToFetch);
1990 vToFetch[nToFetch - 1] = pindexWalk;
1991 for (
unsigned int i = nToFetch - 1; i > 0; i--) {
1992 vToFetch[i - 1] = vToFetch[i]->
pprev;
2005 if (pindex->nStatus.hasData() ||
2008 state->pindexLastCommonBlock = pindex;
2010 }
else if (!IsBlockRequested(pindex->
GetBlockHash())) {
2012 if (pindex->
nHeight > nWindowEnd) {
2014 if (vBlocks.size() == 0 && waitingfor != nodeid) {
2017 nodeStaller = waitingfor;
2021 vBlocks.push_back(pindex);
2022 if (vBlocks.size() ==
count) {
2025 }
else if (waitingfor == -1) {
2027 waitingfor = mapBlocksInFlight[pindex->
GetBlockHash()].first;
2035 template <
class InvId>
2039 return !
node.HasPermission(
2052 template <
class InvId>
2053 static std::chrono::microseconds
2057 std::chrono::microseconds current_time,
bool preferred) {
2058 auto delay = std::chrono::microseconds{0};
2070 return current_time + delay;
2073 void PeerManagerImpl::PushNodeVersion(
const Config &config,
CNode &pnode,
2075 uint64_t my_services{peer.m_our_services};
2076 const int64_t nTime{
count_seconds(GetTime<std::chrono::seconds>())};
2078 const int nNodeStartingHeight{m_best_height};
2089 const bool tx_relay = !m_opts.ignore_incoming_txs &&
2098 nTime, your_services, addr_you, my_services,
2100 nNodeStartingHeight, tx_relay, extraEntropy));
2104 "send version message: version %d, blocks=%d, them=%s, "
2105 "txrelay=%d, peer=%d\n",
2110 "send version message: version %d, blocks=%d, "
2111 "txrelay=%d, peer=%d\n",
2116 void PeerManagerImpl::AddTxAnnouncement(
2118 std::chrono::microseconds current_time) {
2126 const bool preferred = isPreferredDownloadPeer(
node);
2128 current_time, preferred);
2130 m_txrequest.ReceivedInv(
node.GetId(), txid, preferred, reqtime);
2133 void PeerManagerImpl::AddProofAnnouncement(
2135 std::chrono::microseconds current_time,
bool preferred) {
2146 m_proofrequest.ReceivedInv(
node.GetId(), proofid, preferred, reqtime);
2149 void PeerManagerImpl::UpdateLastBlockAnnounceTime(
NodeId node,
2150 int64_t time_in_seconds) {
2152 CNodeState *state = State(
node);
2154 state->m_last_block_announcement = time_in_seconds;
2158 void PeerManagerImpl::InitializeNode(
const Config &config,
CNode &
node,
2163 m_node_states.emplace_hint(m_node_states.end(),
2164 std::piecewise_construct,
2165 std::forward_as_tuple(nodeid),
2166 std::forward_as_tuple(
node.IsInboundConn()));
2167 assert(m_txrequest.Count(nodeid) == 0);
2169 PeerRef peer = std::make_shared<Peer>(nodeid, our_services, !!m_avalanche);
2172 m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer);
2174 if (!
node.IsInboundConn()) {
2175 PushNodeVersion(config,
node, *peer);
2179 void PeerManagerImpl::ReattemptInitialBroadcast(
CScheduler &scheduler) {
2182 for (
const TxId &txid : unbroadcast_txids) {
2184 if (m_mempool.
exists(txid)) {
2185 RelayTransaction(txid);
2196 auto unbroadcasted_proofids =
2200 auto it = unbroadcasted_proofids.begin();
2201 while (it != unbroadcasted_proofids.end()) {
2204 if (!pm.isBoundToPeer(*it)) {
2205 pm.removeUnbroadcastProof(*it);
2206 it = unbroadcasted_proofids.erase(it);
2213 return unbroadcasted_proofids;
2217 for (
const auto &proofid : unbroadcasted_proofids) {
2218 RelayProof(proofid);
2225 const auto reattemptBroadcastInterval = 10min +
GetRandMillis(5min);
2226 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2227 reattemptBroadcastInterval);
2230 void PeerManagerImpl::UpdateAvalancheStatistics()
const {
2257 void PeerManagerImpl::AvalanchePeriodicNetworking(
CScheduler &scheduler)
const {
2258 const auto now = GetTime<std::chrono::seconds>();
2259 std::vector<NodeId> avanode_ids;
2260 bool fQuorumEstablished;
2261 bool fShouldRequestMoreNodes;
2271 fShouldRequestMoreNodes =
2279 avanode_ids.push_back(pnode->GetId());
2282 PeerRef peer = GetPeerRef(pnode->
GetId());
2283 if (peer ==
nullptr) {
2287 if (peer->m_proof_relay &&
2288 now > (peer->m_proof_relay->lastSharedProofsUpdate.load() +
2290 peer->m_proof_relay->sharedProofs = {};
2294 if (avanode_ids.empty()) {
2302 for (
NodeId avanodeId : avanode_ids) {
2303 const bool sentGetavaaddr =
2306 m_connman.PushMessage(
2307 pavanode, CNetMsgMaker(pavanode->GetCommonVersion())
2308 .Make(NetMsgType::GETAVAADDR));
2309 PeerRef peer = GetPeerRef(avanodeId);
2310 WITH_LOCK(peer->m_addr_token_bucket_mutex,
2311 peer->m_addr_token_bucket +=
2312 m_opts.max_addr_to_send);
2320 if (sentGetavaaddr && fQuorumEstablished && !fShouldRequestMoreNodes) {
2325 if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
2335 avanode_ids.resize(std::min<size_t>(avanode_ids.size(), 3));
2338 for (
NodeId nodeid : avanode_ids) {
2341 PeerRef peer = GetPeerRef(nodeid);
2342 if (peer->m_proof_relay) {
2347 peer->m_proof_relay->compactproofs_requested =
true;
2357 const auto avalanchePeriodicNetworkingInterval = 2min +
GetRandMillis(3min);
2358 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2359 avalanchePeriodicNetworkingInterval);
2362 void PeerManagerImpl::FinalizeNode(
const Config &config,
const CNode &
node) {
2373 PeerRef peer = RemovePeer(nodeid);
2375 misbehavior =
WITH_LOCK(peer->m_misbehavior_mutex,
2376 return peer->m_misbehavior_score);
2378 m_peer_map.erase(nodeid);
2380 CNodeState *state = State(nodeid);
2381 assert(state !=
nullptr);
2383 if (state->fSyncStarted) {
2387 for (
const QueuedBlock &entry : state->vBlocksInFlight) {
2388 mapBlocksInFlight.erase(entry.pindex->GetBlockHash());
2391 m_txrequest.DisconnectedPeer(nodeid);
2392 m_num_preferred_download_peers -= state->fPreferredDownload;
2393 m_peers_downloading_from -= (state->nBlocksInFlight != 0);
2394 assert(m_peers_downloading_from >= 0);
2395 m_outbound_peers_with_protect_from_disconnect -=
2396 state->m_chain_sync.m_protect;
2397 assert(m_outbound_peers_with_protect_from_disconnect >= 0);
2399 m_node_states.erase(nodeid);
2401 if (m_node_states.empty()) {
2403 assert(mapBlocksInFlight.empty());
2404 assert(m_num_preferred_download_peers == 0);
2405 assert(m_peers_downloading_from == 0);
2406 assert(m_outbound_peers_with_protect_from_disconnect == 0);
2407 assert(m_txrequest.Size() == 0);
2412 if (
node.fSuccessfullyConnected && misbehavior == 0 &&
2413 !
node.IsBlockOnlyConn() && !
node.IsInboundConn()) {
2420 LOCK(m_headers_presync_mutex);
2421 m_headers_presync_stats.erase(nodeid);
2424 WITH_LOCK(cs_proofrequest, m_proofrequest.DisconnectedPeer(nodeid));
2429 PeerRef PeerManagerImpl::GetPeerRef(
NodeId id)
const {
2431 auto it = m_peer_map.find(
id);
2432 return it != m_peer_map.end() ? it->second :
nullptr;
2435 PeerRef PeerManagerImpl::RemovePeer(
NodeId id) {
2438 auto it = m_peer_map.find(
id);
2439 if (it != m_peer_map.end()) {
2440 ret = std::move(it->second);
2441 m_peer_map.erase(it);
2446 bool PeerManagerImpl::GetNodeStateStats(
NodeId nodeid,
2450 const CNodeState *state = State(nodeid);
2451 if (state ==
nullptr) {
2455 ? state->pindexBestKnownBlock->nHeight
2458 ? state->pindexLastCommonBlock->nHeight
2460 for (
const QueuedBlock &queue : state->vBlocksInFlight) {
2467 PeerRef peer = GetPeerRef(nodeid);
2468 if (peer ==
nullptr) {
2480 auto ping_wait{0us};
2481 if ((0 != peer->m_ping_nonce_sent) &&
2482 (0 != peer->m_ping_start.load().count())) {
2484 GetTime<std::chrono::microseconds>() - peer->m_ping_start.load();
2487 if (
auto tx_relay = peer->GetTxRelay()) {
2489 return tx_relay->m_relay_txs);
2501 LOCK(peer->m_headers_sync_mutex);
2502 if (peer->m_headers_sync) {
2510 void PeerManagerImpl::AddToCompactExtraTransactions(
const CTransactionRef &tx) {
2511 if (m_opts.max_extra_txs <= 0) {
2515 if (!vExtraTxnForCompact.size()) {
2516 vExtraTxnForCompact.resize(m_opts.max_extra_txs);
2519 vExtraTxnForCompact[vExtraTxnForCompactIt] =
2520 std::make_pair(tx->GetHash(), tx);
2521 vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
2524 void PeerManagerImpl::Misbehaving(Peer &peer,
int howmuch,
2525 const std::string &message) {
2528 LOCK(peer.m_misbehavior_mutex);
2529 const int score_before{peer.m_misbehavior_score};
2530 peer.m_misbehavior_score += howmuch;
2531 const int score_now{peer.m_misbehavior_score};
2533 const std::string message_prefixed =
2534 message.empty() ?
"" : (
": " + message);
2535 std::string warning;
2539 warning =
" DISCOURAGE THRESHOLD EXCEEDED";
2540 peer.m_should_discourage =
true;
2544 score_before, score_now, warning, message_prefixed);
2547 bool PeerManagerImpl::MaybePunishNodeForBlock(
NodeId nodeid,
2549 bool via_compact_block,
2550 const std::string &message) {
2551 PeerRef peer{GetPeerRef(nodeid)};
2562 if (!via_compact_block) {
2564 Misbehaving(*peer, 100, message);
2571 CNodeState *node_state = State(nodeid);
2572 if (node_state ==
nullptr) {
2579 if (!via_compact_block && !node_state->m_is_inbound) {
2581 Misbehaving(*peer, 100, message);
2591 Misbehaving(*peer, 100, message);
2599 Misbehaving(*peer, 10, message);
2605 if (message !=
"") {
2611 bool PeerManagerImpl::MaybePunishNodeForTx(
NodeId nodeid,
2613 const std::string &message) {
2614 PeerRef peer{GetPeerRef(nodeid)};
2621 Misbehaving(*peer, 100, message);
2638 if (message !=
"") {
2644 bool PeerManagerImpl::BlockRequestAllowed(
const CBlockIndex *pindex) {
2650 (m_chainman.m_best_header !=
nullptr) &&
2651 (m_chainman.m_best_header->GetBlockTime() - pindex->
GetBlockTime() <
2654 *m_chainman.m_best_header, *pindex, *m_chainman.m_best_header,
2658 std::optional<std::string>
2659 PeerManagerImpl::FetchBlock(
const Config &config,
NodeId peer_id,
2662 return "Loading blocks ...";
2667 CNodeState *state = State(peer_id);
2668 if (state ==
nullptr) {
2669 return "Peer does not exist";
2674 if (!BlockRequested(config, peer_id, block_index)) {
2675 return "Already requested from this peer";
2684 const CNetMsgMaker msgMaker(node->GetCommonVersion());
2685 this->m_connman.PushMessage(
2686 node, msgMaker.Make(NetMsgType::GETDATA, invs));
2689 return "Node not fully connected";
2694 return std::nullopt;
2697 std::unique_ptr<PeerManager>
2701 return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman,
2710 : m_rng{opts.deterministic_rng},
2712 m_chainparams(chainman.GetParams()), m_connman(connman),
2713 m_addrman(addrman), m_banman(banman), m_chainman(chainman),
2714 m_mempool(pool), m_avalanche(
avalanche), m_opts{opts} {}
2716 void PeerManagerImpl::StartScheduledTasks(
CScheduler &scheduler) {
2723 "peer eviction timer should be less than stale tip check timer");
2726 this->CheckForStaleTipAndEvictPeers();
2732 const auto reattemptBroadcastInterval = 10min +
GetRandMillis(5min);
2733 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2734 reattemptBroadcastInterval);
2739 UpdateAvalancheStatistics();
2745 const auto avalanchePeriodicNetworkingInterval = 2min +
GetRandMillis(3min);
2746 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2747 avalanchePeriodicNetworkingInterval);
2756 void PeerManagerImpl::BlockConnected(
2757 const std::shared_ptr<const CBlock> &pblock,
const CBlockIndex *pindex) {
2759 m_last_tip_update = GetTime<std::chrono::seconds>();
2762 LOCK(m_recent_confirmed_transactions_mutex);
2764 m_recent_confirmed_transactions.insert(ptx->GetId());
2769 for (
const auto &ptx : pblock->vtx) {
2770 m_txrequest.ForgetInvId(ptx->GetId());
2776 auto stalling_timeout = m_block_stalling_timeout.load();
2779 const auto new_timeout =
2780 std::max(std::chrono::duration_cast<std::chrono::seconds>(
2781 stalling_timeout * 0.85),
2783 if (m_block_stalling_timeout.compare_exchange_strong(stalling_timeout,
2791 void PeerManagerImpl::BlockDisconnected(
2792 const std::shared_ptr<const CBlock> &block,
const CBlockIndex *pindex) {
2801 LOCK(m_recent_confirmed_transactions_mutex);
2802 m_recent_confirmed_transactions.reset();
2809 void PeerManagerImpl::NewPoWValidBlock(
2810 const CBlockIndex *pindex,
const std::shared_ptr<const CBlock> &pblock) {
2811 std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock =
2812 std::make_shared<const CBlockHeaderAndShortTxIDs>(*pblock);
2817 if (pindex->
nHeight <= m_highest_fast_announce) {
2820 m_highest_fast_announce = pindex->
nHeight;
2823 const std::shared_future<CSerializedNetMsg> lazy_ser{
2824 std::async(std::launch::deferred, [&] {
2829 LOCK(m_most_recent_block_mutex);
2830 m_most_recent_block_hash = hashBlock;
2831 m_most_recent_block = pblock;
2832 m_most_recent_compact_block = pcmpctblock;
2836 [
this, pindex, &lazy_ser, &hashBlock](
CNode *pnode)
2844 ProcessBlockAvailability(pnode->
GetId());
2845 CNodeState &state = *State(pnode->
GetId());
2849 if (state.m_requested_hb_cmpctblocks &&
2850 !PeerHasHeader(&state, pindex) &&
2851 PeerHasHeader(&state, pindex->
pprev)) {
2853 "%s sending header-and-ids %s to peer=%d\n",
2854 "PeerManager::NewPoWValidBlock",
2855 hashBlock.ToString(), pnode->
GetId());
2858 m_connman.
PushMessage(pnode, ser_cmpctblock.Copy());
2859 state.pindexBestHeaderSent = pindex;
2868 void PeerManagerImpl::UpdatedBlockTip(
const CBlockIndex *pindexNew,
2870 bool fInitialDownload) {
2871 SetBestHeight(pindexNew->
nHeight);
2875 if (fInitialDownload) {
2880 std::vector<BlockHash> vHashes;
2882 while (pindexToAnnounce != pindexFork) {
2884 pindexToAnnounce = pindexToAnnounce->
pprev;
2894 for (
auto &it : m_peer_map) {
2895 Peer &peer = *it.second;
2896 LOCK(peer.m_block_inv_mutex);
2898 peer.m_blocks_for_headers_relay.push_back(hash);
2910 void PeerManagerImpl::BlockChecked(
const CBlock &block,
2915 std::map<BlockHash, std::pair<NodeId, bool>>::iterator it =
2916 mapBlockSource.find(hash);
2920 if (state.
IsInvalid() && it != mapBlockSource.end() &&
2921 State(it->second.first)) {
2922 MaybePunishNodeForBlock(it->second.first, state,
2923 !it->second.second);
2932 !m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
2933 mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
2934 if (it != mapBlockSource.end()) {
2935 MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
2939 if (it != mapBlockSource.end()) {
2940 mapBlockSource.erase(it);
2949 bool PeerManagerImpl::AlreadyHaveTx(
const TxId &txid,
2950 bool include_reconsiderable) {
2952 hashRecentRejectsChainTip) {
2957 hashRecentRejectsChainTip =
2959 m_recent_rejects.reset();
2960 m_recent_rejects_reconsiderable.reset();
2963 if (m_orphanage.
HaveTx(txid)) {
2967 if (include_reconsiderable &&
2968 m_recent_rejects_reconsiderable.contains(txid)) {
2973 LOCK(m_recent_confirmed_transactions_mutex);
2974 if (m_recent_confirmed_transactions.contains(txid)) {
2979 return m_recent_rejects.contains(txid) || m_mempool.
exists(txid);
2982 bool PeerManagerImpl::AlreadyHaveBlock(
const BlockHash &block_hash) {
2990 if (localProof && localProof->getId() == proofid) {
2999 void PeerManagerImpl::SendPings() {
3001 for (
auto &it : m_peer_map) {
3002 it.second->m_ping_queued =
true;
3006 void PeerManagerImpl::RelayTransaction(
const TxId &txid) {
3008 for (
auto &it : m_peer_map) {
3009 Peer &peer = *it.second;
3010 auto tx_relay = peer.GetTxRelay();
3014 LOCK(tx_relay->m_tx_inventory_mutex);
3015 if (!tx_relay->m_tx_inventory_known_filter.contains(txid)) {
3016 tx_relay->m_tx_inventory_to_send.insert(txid);
3023 for (
auto &it : m_peer_map) {
3024 Peer &peer = *it.second;
3026 if (!peer.m_proof_relay) {
3029 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
3030 if (!peer.m_proof_relay->m_proof_inventory_known_filter.contains(
3032 peer.m_proof_relay->m_proof_inventory_to_send.insert(proofid);
3037 void PeerManagerImpl::RelayAddress(
NodeId originator,
const CAddress &addr,
3053 const auto current_time{GetTime<std::chrono::seconds>()};
3056 const uint64_t time_addr{
3057 (
static_cast<uint64_t
>(
count_seconds(current_time)) + hash_addr) /
3067 unsigned int nRelayNodes = (fReachable || (hasher.Finalize() & 1)) ? 2 : 1;
3068 std::array<std::pair<uint64_t, Peer *>, 2> best{
3069 {{0,
nullptr}, {0,
nullptr}}};
3070 assert(nRelayNodes <= best.size());
3074 for (
auto &[
id, peer] : m_peer_map) {
3075 if (peer->m_addr_relay_enabled &&
id != originator &&
3076 IsAddrCompatible(*peer, addr)) {
3078 for (
unsigned int i = 0; i < nRelayNodes; i++) {
3079 if (hashKey > best[i].first) {
3080 std::copy(best.begin() + i, best.begin() + nRelayNodes - 1,
3081 best.begin() + i + 1);
3082 best[i] = std::make_pair(hashKey, peer.get());
3089 for (
unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
3090 PushAddress(*best[i].second, addr);
3094 void PeerManagerImpl::ProcessGetBlockData(
const Config &config,
CNode &pfrom,
3095 Peer &peer,
const CInv &inv) {
3098 std::shared_ptr<const CBlock> a_recent_block;
3099 std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
3101 LOCK(m_most_recent_block_mutex);
3102 a_recent_block = m_most_recent_block;
3103 a_recent_compact_block = m_most_recent_compact_block;
3106 bool need_activate_chain =
false;
3120 need_activate_chain =
true;
3124 if (need_activate_chain) {
3126 if (!m_chainman.ActiveChainstate().ActivateBestChain(
3127 state, a_recent_block, m_avalanche)) {
3138 if (!BlockRequestAllowed(pindex)) {
3140 "%s: ignoring request from peer=%i for old "
3141 "block that isn't in the main chain\n",
3142 __func__, pfrom.
GetId());
3149 (((m_chainman.m_best_header !=
nullptr) &&
3150 (m_chainman.m_best_header->GetBlockTime() - pindex->
GetBlockTime() >
3156 "historical block serving limit reached, disconnect peer=%d\n",
3171 "Ignore block request below NODE_NETWORK_LIMITED "
3172 "threshold, disconnect peer=%d\n",
3182 if (!pindex->nStatus.hasData()) {
3185 std::shared_ptr<const CBlock> pblock;
3186 if (a_recent_block && a_recent_block->GetHash() == pindex->
GetBlockHash()) {
3187 pblock = a_recent_block;
3190 std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
3192 assert(!
"cannot load block from disk");
3194 pblock = pblockRead;
3200 bool sendMerkleBlock =
false;
3202 if (
auto tx_relay = peer.GetTxRelay()) {
3203 LOCK(tx_relay->m_bloom_filter_mutex);
3204 if (tx_relay->m_bloom_filter) {
3205 sendMerkleBlock =
true;
3206 merkleBlock =
CMerkleBlock(*pblock, *tx_relay->m_bloom_filter);
3209 if (sendMerkleBlock) {
3221 typedef std::pair<size_t, uint256> PairType;
3236 if (CanDirectFetch() &&
3239 if (a_recent_compact_block &&
3240 a_recent_compact_block->header.GetHash() ==
3244 *a_recent_compact_block));
3258 LOCK(peer.m_block_inv_mutex);
3261 if (hash == peer.m_continuation_block) {
3265 std::vector<CInv> vInv;
3266 vInv.push_back(
CInv(
3269 peer.m_continuation_block =
BlockHash();
3275 PeerManagerImpl::FindTxForGetData(
const Peer &peer,
const TxId &txid,
3276 const std::chrono::seconds mempool_req,
3277 const std::chrono::seconds now) {
3278 auto txinfo = m_mempool.
info(txid);
3283 if ((mempool_req.count() && txinfo.m_time <= mempool_req) ||
3285 return std::move(txinfo.tx);
3293 if (
Assume(peer.GetTxRelay())
3294 ->m_recently_announced_invs.contains(txid)) {
3297 return std::move(txinfo.tx);
3300 auto mi = mapRelay.find(txid);
3301 if (mi != mapRelay.end()) {
3313 PeerManagerImpl::FindProofForGetData(
const Peer &peer,
3315 const std::chrono::seconds now) {
3318 bool send_unconditionally =
3344 if (send_unconditionally) {
3349 if (peer.m_proof_relay->m_recently_announced_proofs.contains(proofid)) {
3356 void PeerManagerImpl::ProcessGetData(
3358 const std::atomic<bool> &interruptMsgProc) {
3361 auto tx_relay = peer.GetTxRelay();
3363 std::deque<CInv>::iterator it = peer.m_getdata_requests.begin();
3364 std::vector<CInv> vNotFound;
3367 const auto now{GetTime<std::chrono::seconds>()};
3369 const auto mempool_req = tx_relay !=
nullptr
3370 ? tx_relay->m_last_mempool_req.load()
3371 : std::chrono::seconds::min();
3376 while (it != peer.m_getdata_requests.end()) {
3377 if (interruptMsgProc) {
3386 const CInv &inv = *it;
3388 if (it->IsMsgProof()) {
3390 vNotFound.push_back(inv);
3395 auto proof = FindProofForGetData(peer, proofid, now);
3403 vNotFound.push_back(inv);
3410 if (it->IsMsgTx()) {
3411 if (tx_relay ==
nullptr) {
3427 std::vector<TxId> parent_ids_to_add;
3430 auto txiter = m_mempool.
GetIter(tx->GetId());
3432 auto &pentry = *txiter;
3434 (*pentry)->GetMemPoolParentsConst();
3435 parent_ids_to_add.reserve(parents.size());
3436 for (
const auto &parent : parents) {
3437 if (parent.get()->GetTime() >
3439 parent_ids_to_add.push_back(
3440 parent.get()->GetTx().GetId());
3445 for (
const TxId &parent_txid : parent_ids_to_add) {
3448 if (
WITH_LOCK(tx_relay->m_tx_inventory_mutex,
3449 return !tx_relay->m_tx_inventory_known_filter
3450 .contains(parent_txid))) {
3451 tx_relay->m_recently_announced_invs.insert(parent_txid);
3455 vNotFound.push_back(inv);
3468 if (it != peer.m_getdata_requests.end() && !pfrom.
fPauseSend) {
3469 const CInv &inv = *it++;
3471 ProcessGetBlockData(config, pfrom, peer, inv);
3477 peer.m_getdata_requests.erase(peer.m_getdata_requests.begin(), it);
3479 if (!vNotFound.empty()) {
3497 void PeerManagerImpl::SendBlockTransactions(
3501 for (
size_t i = 0; i < req.
indices.size(); i++) {
3503 Misbehaving(peer, 100,
"getblocktxn with out-of-bounds tx indices");
3515 bool PeerManagerImpl::CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
3520 Misbehaving(peer, 100,
"header with invalid proof of work");
3525 if (!CheckHeadersAreContinuous(headers)) {
3526 Misbehaving(peer, 20,
"non-continuous headers sequence");
3539 near_chaintip_work =
3558 void PeerManagerImpl::HandleFewUnconnectingHeaders(
3559 CNode &pfrom, Peer &peer,
const std::vector<CBlockHeader> &headers) {
3562 peer.m_num_unconnecting_headers_msgs++;
3566 if (MaybeSendGetHeaders(pfrom,
GetLocator(best_header), peer)) {
3569 "received header %s: missing prev block %s, sending getheaders "
3570 "(%d) to end (peer=%d, m_num_unconnecting_headers_msgs=%d)\n",
3572 headers[0].hashPrevBlock.ToString(), best_header->nHeight,
3573 pfrom.
GetId(), peer.m_num_unconnecting_headers_msgs);
3580 UpdateBlockAvailability(pfrom.
GetId(), headers.back().GetHash()));
3584 if (peer.m_num_unconnecting_headers_msgs %
3587 Misbehaving(peer, 20,
3589 peer.m_num_unconnecting_headers_msgs));
3593 bool PeerManagerImpl::CheckHeadersAreContinuous(
3594 const std::vector<CBlockHeader> &headers)
const {
3597 if (!hashLastBlock.
IsNull() && header.hashPrevBlock != hashLastBlock) {
3600 hashLastBlock = header.GetHash();
3605 bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(
3606 Peer &peer,
CNode &pfrom, std::vector<CBlockHeader> &headers) {
3607 if (peer.m_headers_sync) {
3608 auto result = peer.m_headers_sync->ProcessNextHeaders(
3610 if (result.request_more) {
3611 auto locator = peer.m_headers_sync->NextHeadersRequestLocator();
3614 Assume(!locator.vHave.empty());
3615 if (!locator.vHave.empty()) {
3622 bool sent_getheaders =
3623 MaybeSendGetHeaders(pfrom, locator, peer);
3624 if (sent_getheaders) {
3626 "more getheaders (from %s) to peer=%d\n",
3627 locator.vHave.front().ToString(), pfrom.
GetId());
3630 "error sending next getheaders (from %s) to "
3631 "continue sync with peer=%d\n",
3632 locator.vHave.front().ToString(), pfrom.
GetId());
3638 peer.m_headers_sync.reset(
nullptr);
3643 LOCK(m_headers_presync_mutex);
3644 m_headers_presync_stats.erase(pfrom.
GetId());
3647 HeadersPresyncStats stats;
3648 stats.first = peer.m_headers_sync->GetPresyncWork();
3649 if (peer.m_headers_sync->GetState() ==
3651 stats.second = {peer.m_headers_sync->GetPresyncHeight(),
3652 peer.m_headers_sync->GetPresyncTime()};
3656 LOCK(m_headers_presync_mutex);
3657 m_headers_presync_stats[pfrom.
GetId()] = stats;
3659 m_headers_presync_stats.find(m_headers_presync_bestpeer);
3660 bool best_updated =
false;
3661 if (best_it == m_headers_presync_stats.end()) {
3666 const HeadersPresyncStats *stat_best{
nullptr};
3667 for (
const auto &[_peer, _stat] : m_headers_presync_stats) {
3668 if (!stat_best || _stat > *stat_best) {
3673 m_headers_presync_bestpeer = peer_best;
3674 best_updated = (peer_best == pfrom.
GetId());
3675 }
else if (best_it->first == pfrom.
GetId() ||
3676 stats > best_it->second) {
3679 m_headers_presync_bestpeer = pfrom.
GetId();
3680 best_updated =
true;
3682 if (best_updated && stats.second.has_value()) {
3685 m_headers_presync_should_signal =
true;
3689 if (result.success) {
3692 headers.swap(result.pow_validated_headers);
3695 return result.success;
3703 bool PeerManagerImpl::TryLowWorkHeadersSync(
3705 std::vector<CBlockHeader> &headers) {
3712 arith_uint256 minimum_chain_work = GetAntiDoSWorkThreshold();
3716 if (total_work < minimum_chain_work) {
3730 LOCK(peer.m_headers_sync_mutex);
3731 peer.m_headers_sync.reset(
3733 chain_start_header, minimum_chain_work));
3737 return IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
3741 "Ignoring low-work chain (height=%u) from peer=%d\n",
3742 chain_start_header->
nHeight + headers.size(), pfrom.
GetId());
3751 bool PeerManagerImpl::IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header) {
3752 return header !=
nullptr &&
3753 ((m_chainman.m_best_header !=
nullptr &&
3755 m_chainman.m_best_header->GetAncestor(header->
nHeight)) ||
3759 bool PeerManagerImpl::MaybeSendGetHeaders(
CNode &pfrom,
3768 if (current_time - peer.m_last_getheaders_timestamp >
3772 peer.m_last_getheaders_timestamp = current_time;
3784 void PeerManagerImpl::HeadersDirectFetchBlocks(
const Config &config,
3790 CNodeState *nodestate = State(pfrom.
GetId());
3794 std::vector<const CBlockIndex *> vToFetch;
3800 if (!pindexWalk->nStatus.hasData() &&
3803 vToFetch.push_back(pindexWalk);
3805 pindexWalk = pindexWalk->
pprev;
3816 std::vector<CInv> vGetData;
3819 if (nodestate->nBlocksInFlight >=
3825 BlockRequested(config, pfrom.
GetId(), *pindex);
3829 if (vGetData.size() > 1) {
3831 "Downloading blocks toward %s (%d) via headers "
3836 if (vGetData.size() > 0) {
3837 if (!m_opts.ignore_incoming_txs &&
3838 nodestate->m_provides_cmpctblocks && vGetData.size() == 1 &&
3839 mapBlocksInFlight.size() == 1 &&
3857 void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(
3859 bool received_new_header,
bool may_have_more_headers) {
3860 if (peer.m_num_unconnecting_headers_msgs > 0) {
3863 "peer=%d: resetting m_num_unconnecting_headers_msgs (%d -> 0)\n",
3864 pfrom.
GetId(), peer.m_num_unconnecting_headers_msgs);
3866 peer.m_num_unconnecting_headers_msgs = 0;
3870 CNodeState *nodestate = State(pfrom.
GetId());
3879 if (received_new_header &&
3881 nodestate->m_last_block_announcement =
GetTime();
3886 if (m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
3887 !may_have_more_headers) {
3890 if (nodestate->pindexBestKnownBlock &&
3891 nodestate->pindexBestKnownBlock->nChainWork <
3902 LogPrintf(
"Disconnecting outbound peer %d -- headers "
3903 "chain has insufficient work\n",
3917 nodestate->pindexBestKnownBlock !=
nullptr) {
3918 if (m_outbound_peers_with_protect_from_disconnect <
3920 nodestate->pindexBestKnownBlock->nChainWork >=
3922 !nodestate->m_chain_sync.m_protect) {
3925 nodestate->m_chain_sync.m_protect =
true;
3926 ++m_outbound_peers_with_protect_from_disconnect;
3931 void PeerManagerImpl::ProcessHeadersMessage(
const Config &config,
CNode &pfrom,
3933 std::vector<CBlockHeader> &&headers,
3934 bool via_compact_block) {
3935 size_t nCount = headers.size();
3943 LOCK(peer.m_headers_sync_mutex);
3944 if (peer.m_headers_sync) {
3945 peer.m_headers_sync.reset(
nullptr);
3946 LOCK(m_headers_presync_mutex);
3947 m_headers_presync_stats.erase(pfrom.
GetId());
3956 if (!CheckHeadersPoW(headers, m_chainparams.
GetConsensus(), peer)) {
3971 bool already_validated_work =
false;
3974 bool have_headers_sync =
false;
3976 LOCK(peer.m_headers_sync_mutex);
3978 already_validated_work =
3979 IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
3991 if (headers.empty()) {
3995 have_headers_sync = !!peer.m_headers_sync;
4001 headers[0].hashPrevBlock))};
4002 bool headers_connect_blockindex{chain_start_header !=
nullptr};
4004 if (!headers_connect_blockindex) {
4009 HandleFewUnconnectingHeaders(pfrom, peer, headers);
4011 Misbehaving(peer, 10,
"invalid header received");
4023 last_received_header =
4025 if (IsAncestorOfBestHeaderOrTip(last_received_header)) {
4026 already_validated_work =
true;
4034 already_validated_work =
true;
4040 if (!already_validated_work &&
4041 TryLowWorkHeadersSync(peer, pfrom, chain_start_header, headers)) {
4053 bool received_new_header{last_received_header ==
nullptr};
4058 state, &pindexLast)) {
4060 MaybePunishNodeForBlock(pfrom.
GetId(), state, via_compact_block,
4061 "invalid header received");
4071 if (MaybeSendGetHeaders(pfrom,
GetLocator(pindexLast), peer)) {
4074 "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
4075 pindexLast->
nHeight, pfrom.
GetId(), peer.m_starting_height);
4079 UpdatePeerStateForReceivedHeaders(pfrom, peer, pindexLast,
4080 received_new_header,
4084 HeadersDirectFetchBlocks(config, pfrom, pindexLast);
4087 void PeerManagerImpl::ProcessInvalidTx(
NodeId nodeid,
4090 bool maybe_add_extra_compact_tx) {
4096 ptx->GetHash().ToString(), nodeid, state.
ToString());
4107 m_recent_rejects_reconsiderable.insert(ptx->GetId());
4109 m_recent_rejects.insert(ptx->GetId());
4111 m_txrequest.ForgetInvId(ptx->GetId());
4114 AddToCompactExtraTransactions(ptx);
4117 MaybePunishNodeForTx(nodeid, state);
4122 if (m_orphanage.
EraseTx(ptx->GetId()) > 0) {
4124 ptx->GetHash().ToString());
4135 m_txrequest.ForgetInvId(tx->GetId());
4140 m_orphanage.
EraseTx(tx->GetId());
4144 "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
4145 nodeid, tx->GetHash().ToString(), m_mempool.
size(),
4148 RelayTransaction(tx->GetId());
4151 void PeerManagerImpl::ProcessPackageResult(
4152 const PackageToValidate &package_to_validate,
4158 const auto &
package = package_to_validate.m_txns;
4159 const auto &senders = package_to_validate.m_senders;
4166 if (!
Assume(package.size() == 2)) {
4172 auto package_iter = package.rbegin();
4173 auto senders_iter = senders.rbegin();
4174 while (package_iter != package.rend()) {
4175 const auto &tx = *package_iter;
4176 const NodeId nodeid = *senders_iter;
4177 const auto it_result{package_result.
m_tx_results.find(tx->GetId())};
4181 const auto &tx_result = it_result->second;
4182 switch (tx_result.m_result_type) {
4184 ProcessValidTx(nodeid, tx);
4194 ProcessInvalidTx(nodeid, tx, tx_result.m_state,
4211 std::optional<PeerManagerImpl::PackageToValidate>
4217 const auto &parent_txid{ptx->GetId()};
4219 Assume(m_recent_rejects_reconsiderable.contains(parent_txid));
4225 const auto cpfp_candidates_same_peer{
4229 for (
const auto &child : cpfp_candidates_same_peer) {
4230 Package maybe_cpfp_package{ptx, child};
4231 if (!m_recent_rejects_reconsiderable.contains(
4233 return PeerManagerImpl::PackageToValidate{ptx, child, nodeid,
4247 const auto cpfp_candidates_different_peer{
4255 std::vector<size_t> tx_indices(cpfp_candidates_different_peer.size());
4256 std::iota(tx_indices.begin(), tx_indices.end(), 0);
4257 Shuffle(tx_indices.begin(), tx_indices.end(), m_rng);
4259 for (
const auto index : tx_indices) {
4262 const auto [child_tx, child_sender] =
4263 cpfp_candidates_different_peer.at(index);
4264 Package maybe_cpfp_package{ptx, child_tx};
4265 if (!m_recent_rejects_reconsiderable.contains(
4267 return PeerManagerImpl::PackageToValidate{ptx, child_tx, nodeid,
4271 return std::nullopt;
4274 bool PeerManagerImpl::ProcessOrphanTx(
const Config &config, Peer &peer) {
4283 const TxId &orphanTxId = porphanTx->GetId();
4288 ProcessValidTx(peer.m_id, porphanTx);
4294 " invalid orphan tx %s from peer=%d. %s\n",
4301 ProcessInvalidTx(peer.m_id, porphanTx, state,
4312 bool PeerManagerImpl::PrepareBlockFilterRequest(
4314 const BlockHash &stop_hash, uint32_t max_height_diff,
4316 const bool supported_filter_type =
4319 if (!supported_filter_type) {
4321 "peer %d requested unsupported block filter type: %d\n",
4322 node.GetId(),
static_cast<uint8_t
>(filter_type));
4323 node.fDisconnect =
true;
4333 if (!stop_index || !BlockRequestAllowed(stop_index)) {
4336 node.fDisconnect =
true;
4341 uint32_t stop_height = stop_index->
nHeight;
4342 if (start_height > stop_height) {
4345 "peer %d sent invalid getcfilters/getcfheaders with "
4347 "start height %d and stop height %d\n",
4348 node.GetId(), start_height, stop_height);
4349 node.fDisconnect =
true;
4352 if (stop_height - start_height >= max_height_diff) {
4354 "peer %d requested too many cfilters/cfheaders: %d / %d\n",
4355 node.GetId(), stop_height - start_height + 1, max_height_diff);
4356 node.fDisconnect =
true;
4361 if (!filter_index) {
4370 void PeerManagerImpl::ProcessGetCFilters(
CNode &
node, Peer &peer,
4372 uint8_t filter_type_ser;
4373 uint32_t start_height;
4376 vRecv >> filter_type_ser >> start_height >> stop_hash;
4383 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4389 std::vector<BlockFilter> filters;
4392 "Failed to find block filter in index: filter_type=%s, "
4393 "start_height=%d, stop_hash=%s\n",
4399 for (
const auto &filter : filters) {
4406 void PeerManagerImpl::ProcessGetCFHeaders(
CNode &
node, Peer &peer,
4408 uint8_t filter_type_ser;
4409 uint32_t start_height;
4412 vRecv >> filter_type_ser >> start_height >> stop_hash;
4419 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4426 if (start_height > 0) {
4428 stop_index->
GetAncestor(
static_cast<int>(start_height - 1));
4431 "Failed to find block filter header in index: "
4432 "filter_type=%s, block_hash=%s\n",
4439 std::vector<uint256> filter_hashes;
4443 "Failed to find block filter hashes in index: filter_type=%s, "
4444 "start_height=%d, stop_hash=%s\n",
4453 stop_index->
GetBlockHash(), prev_header, filter_hashes);
4457 void PeerManagerImpl::ProcessGetCFCheckPt(
CNode &
node, Peer &peer,
4459 uint8_t filter_type_ser;
4462 vRecv >> filter_type_ser >> stop_hash;
4469 if (!PrepareBlockFilterRequest(
4470 node, peer, filter_type, 0, stop_hash,
4471 std::numeric_limits<uint32_t>::max(),
4472 stop_index, filter_index)) {
4480 for (
int i = headers.size() - 1; i >= 0; i--) {
4486 "Failed to find block filter header in index: "
4487 "filter_type=%s, block_hash=%s\n",
4512 PeerManagerImpl::GetAvalancheVoteForBlock(
const BlockHash &hash)
const {
4523 if (pindex->nStatus.isInvalid()) {
4528 if (pindex->nStatus.isOnParkedChain()) {
4536 if (pindex == pindexFork) {
4541 if (pindexFork != pindexTip) {
4546 if (!pindex->nStatus.hasData()) {
4555 uint32_t PeerManagerImpl::GetAvalancheVoteForTx(
const TxId &
id)
const {
4557 if (m_mempool.
exists(
id) ||
4558 WITH_LOCK(m_recent_confirmed_transactions_mutex,
4559 return m_recent_confirmed_transactions.contains(
id))) {
4564 if (m_recent_rejects.contains(
id)) {
4569 if (m_orphanage.
HaveTx(
id)) {
4619 const std::shared_ptr<const CBlock> &block,
4620 bool force_processing,
4621 bool min_pow_checked) {
4622 bool new_block{
false};
4624 &new_block, m_avalanche);
4626 node.m_last_block_time = GetTime<std::chrono::seconds>();
4629 mapBlockSource.erase(block->GetHash());
4633 void PeerManagerImpl::ProcessMessage(
4634 const Config &config,
CNode &pfrom,
const std::string &msg_type,
4635 CDataStream &vRecv,
const std::chrono::microseconds time_received,
4636 const std::atomic<bool> &interruptMsgProc) {
4642 PeerRef peer = GetPeerRef(pfrom.
GetId());
4643 if (peer ==
nullptr) {
4650 "Avalanche is not initialized, ignoring %s message\n",
4664 Misbehaving(*peer, 1,
"redundant version message");
4670 uint64_t nNonce = 1;
4673 std::string cleanSubVer;
4674 int starting_height = -1;
4676 uint64_t nExtraEntropy = 1;
4678 vRecv >> nVersion >> Using<CustomUintFormatter<8>>(nServices) >> nTime;
4691 "peer=%d does not offer the expected services "
4692 "(%08x offered, %08x expected); disconnecting\n",
4693 pfrom.
GetId(), nServices,
4703 "peer=%d does not offer the avalanche service; disconnecting\n",
4712 "peer=%d using obsolete version %i; disconnecting\n",
4713 pfrom.
GetId(), nVersion);
4718 if (!vRecv.
empty()) {
4727 if (!vRecv.
empty()) {
4728 std::string strSubVer;
4732 if (!vRecv.
empty()) {
4733 vRecv >> starting_height;
4735 if (!vRecv.
empty()) {
4738 if (!vRecv.
empty()) {
4739 vRecv >> nExtraEntropy;
4743 LogPrintf(
"connected to self at %s, disconnecting\n",
4756 PushNodeVersion(config, pfrom, *peer);
4760 const int greatest_common_version =
4774 peer->m_their_services = nServices;
4778 pfrom.cleanSubVer = cleanSubVer;
4780 peer->m_starting_height = starting_height;
4787 (fRelay || (peer->m_our_services &
NODE_BLOOM))) {
4788 auto *
const tx_relay = peer->SetTxRelay();
4790 LOCK(tx_relay->m_bloom_filter_mutex);
4792 tx_relay->m_relay_txs = fRelay;
4805 CNodeState *state = State(pfrom.
GetId());
4806 state->fPreferredDownload =
4810 m_num_preferred_download_peers += state->fPreferredDownload;
4814 if (!pfrom.
IsInboundConn() && SetupAddressRelay(pfrom, *peer)) {
4827 !m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
4832 "ProcessMessages: advertising address %s\n",
4834 PushAddress(*peer, addr);
4843 "ProcessMessages: advertising address %s\n",
4845 PushAddress(*peer, addr);
4852 peer->m_getaddr_sent =
true;
4856 WITH_LOCK(peer->m_addr_token_bucket_mutex,
4857 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
4878 std::string remoteAddr;
4884 "receive version message: [%s] %s: version %d, blocks=%d, "
4885 "us=%s, txrelay=%d, peer=%d%s\n",
4887 peer->m_starting_height, addrMe.ToString(), fRelay,
4888 pfrom.
GetId(), remoteAddr);
4890 int64_t currentTime =
GetTime();
4891 int64_t nTimeOffset = nTime - currentTime;
4896 Misbehaving(*peer, 20,
4897 "Ignoring invalid timestamp in version message");
4907 "feeler connection completed peer=%d; disconnecting\n",
4916 Misbehaving(*peer, 10,
"non-version message before version handshake");
4926 "ignoring redundant verack message from peer=%d\n",
4933 "New outbound peer connected: version: %d, blocks=%d, "
4935 pfrom.
nVersion.load(), peer->m_starting_height, pfrom.
GetId(),
4957 AddKnownProof(*peer, localProof->getId());
4961 peer->m_proof_relay->m_recently_announced_proofs.insert(
4962 localProof->getId());
4973 Misbehaving(*peer, 10,
"non-verack message before version handshake");
4987 std::vector<CAddress> vAddr;
4991 if (!SetupAddressRelay(pfrom, *peer)) {
4997 if (vAddr.size() > m_opts.max_addr_to_send) {
5000 strprintf(
"%s message size = %u", msg_type, vAddr.size()));
5005 std::vector<CAddress> vAddrOk;
5009 const auto current_time = GetTime<std::chrono::microseconds>();
5011 LOCK(peer->m_addr_token_bucket_mutex);
5014 const auto time_diff =
5015 std::max(current_time - peer->m_addr_token_timestamp, 0us);
5016 const double increment =
5018 peer->m_addr_token_bucket =
5019 std::min<double>(peer->m_addr_token_bucket + increment,
5023 peer->m_addr_token_timestamp = current_time;
5025 const bool rate_limited =
5027 uint64_t num_proc = 0;
5028 uint64_t num_rate_limit = 0;
5029 Shuffle(vAddr.begin(), vAddr.end(), m_rng);
5031 if (interruptMsgProc) {
5036 LOCK(peer->m_addr_token_bucket_mutex);
5038 if (peer->m_addr_token_bucket < 1.0) {
5044 peer->m_addr_token_bucket -= 1.0;
5057 addr.
nTime > current_a_time + 10min) {
5058 addr.
nTime = current_a_time - 5 * 24h;
5060 AddAddressKnown(*peer, addr);
5069 if (addr.
nTime > current_a_time - 10min && !peer->m_getaddr_sent &&
5072 RelayAddress(pfrom.
GetId(), addr, fReachable);
5076 vAddrOk.push_back(addr);
5079 peer->m_addr_processed += num_proc;
5080 peer->m_addr_rate_limited += num_rate_limit;
5082 "Received addr: %u addresses (%u processed, %u rate-limited) "
5084 vAddr.size(), num_proc, num_rate_limit, pfrom.
GetId());
5086 m_addrman.
Add(vAddrOk, pfrom.
addr, 2h);
5087 if (vAddr.size() < 1000) {
5088 peer->m_getaddr_sent =
false;
5095 "addrfetch connection completed peer=%d; disconnecting\n",
5103 peer->m_wants_addrv2 =
true;
5108 peer->m_prefers_headers =
true;
5113 bool sendcmpct_hb{
false};
5114 uint64_t sendcmpct_version{0};
5115 vRecv >> sendcmpct_hb >> sendcmpct_version;
5122 CNodeState *nodestate = State(pfrom.
GetId());
5123 nodestate->m_provides_cmpctblocks =
true;
5124 nodestate->m_requested_hb_cmpctblocks = sendcmpct_hb;
5133 std::vector<CInv> vInv;
5136 Misbehaving(*peer, 20,
5137 strprintf(
"inv message size = %u", vInv.size()));
5143 bool reject_tx_invs{m_opts.ignore_incoming_txs ||
5149 reject_tx_invs =
false;
5152 const auto current_time{GetTime<std::chrono::microseconds>()};
5153 std::optional<BlockHash> best_block;
5155 auto logInv = [&](
const CInv &inv,
bool fAlreadyHave) {
5157 fAlreadyHave ?
"have" :
"new", pfrom.
GetId());
5160 for (
CInv &inv : vInv) {
5161 if (interruptMsgProc) {
5167 const bool fAlreadyHave = AlreadyHaveBlock(
BlockHash(inv.
hash));
5168 logInv(inv, fAlreadyHave);
5171 UpdateBlockAvailability(pfrom.
GetId(), hash);
5173 !IsBlockRequested(hash)) {
5180 best_block = std::move(hash);
5188 const bool fAlreadyHave = AlreadyHaveProof(proofid);
5189 logInv(inv, fAlreadyHave);
5190 AddKnownProof(*peer, proofid);
5192 if (!fAlreadyHave && m_avalanche &&
5193 !m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
5194 const bool preferred = isPreferredDownloadPeer(pfrom);
5196 LOCK(cs_proofrequest);
5197 AddProofAnnouncement(pfrom, proofid, current_time,
5206 const bool fAlreadyHave =
5207 AlreadyHaveTx(txid,
true);
5208 logInv(inv, fAlreadyHave);
5210 AddKnownTx(*peer, txid);
5211 if (reject_tx_invs) {
5213 "transaction (%s) inv sent in violation of "
5214 "protocol, disconnecting peer=%d\n",
5218 }
else if (!fAlreadyHave && !m_chainman.ActiveChainstate()
5219 .IsInitialBlockDownload()) {
5220 AddTxAnnouncement(pfrom, txid, current_time);
5227 "Unknown inv type \"%s\" received from peer=%d\n",
5244 if (state.fSyncStarted ||
5245 (!peer->m_inv_triggered_getheaders_before_sync &&
5246 *best_block != m_last_block_inv_triggering_headers_sync)) {
5247 if (MaybeSendGetHeaders(
5248 pfrom,
GetLocator(m_chainman.m_best_header), *peer)) {
5250 m_chainman.m_best_header->nHeight,
5251 best_block->ToString(), pfrom.
GetId());
5253 if (!state.fSyncStarted) {
5254 peer->m_inv_triggered_getheaders_before_sync =
true;
5258 m_last_block_inv_triggering_headers_sync = *best_block;
5267 std::vector<CInv> vInv;
5270 Misbehaving(*peer, 20,
5271 strprintf(
"getdata message size = %u", vInv.size()));
5276 vInv.size(), pfrom.
GetId());
5278 if (vInv.size() > 0) {
5284 LOCK(peer->m_getdata_requests_mutex);
5285 peer->m_getdata_requests.insert(peer->m_getdata_requests.end(),
5286 vInv.begin(), vInv.end());
5287 ProcessGetData(config, pfrom, *peer, interruptMsgProc);
5296 vRecv >> locator >> hashStop;
5300 "getblocks locator size %lld > %d, disconnect peer=%d\n",
5314 std::shared_ptr<const CBlock> a_recent_block;
5316 LOCK(m_most_recent_block_mutex);
5317 a_recent_block = m_most_recent_block;
5320 if (!m_chainman.ActiveChainstate().ActivateBestChain(
5321 state, a_recent_block, m_avalanche)) {
5331 m_chainman.ActiveChainstate().FindForkInGlobalIndex(locator);
5339 (pindex ? pindex->
nHeight : -1),
5342 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5351 const int nPrunedBlocksLikelyToHave =
5355 (!pindex->nStatus.hasData() ||
5357 nPrunedBlocksLikelyToHave)) {
5360 " getblocks stopping, pruned or too old block at %d %s\n",
5365 peer->m_block_inv_mutex,
5366 peer->m_blocks_for_inv_relay.push_back(pindex->
GetBlockHash()));
5367 if (--nLimit <= 0) {
5373 peer->m_continuation_block = pindex->GetBlockHash();
5385 std::shared_ptr<const CBlock> recent_block;
5387 LOCK(m_most_recent_block_mutex);
5388 if (m_most_recent_block_hash == req.
blockhash) {
5389 recent_block = m_most_recent_block;
5394 SendBlockTransactions(pfrom, *peer, *recent_block, req);
5403 if (!pindex || !pindex->nStatus.hasData()) {
5406 "Peer %d sent us a getblocktxn for a block we don't have\n",
5418 SendBlockTransactions(pfrom, *peer, block, req);
5431 "Peer %d sent us a getblocktxn for a block > %i deep\n",
5436 WITH_LOCK(peer->m_getdata_requests_mutex,
5437 peer->m_getdata_requests.push_back(inv));
5446 vRecv >> locator >> hashStop;
5450 "getheaders locator size %lld > %d, disconnect peer=%d\n",
5459 "Ignoring getheaders from peer=%d while importing/reindexing\n",
5473 if (m_chainman.
ActiveTip() ==
nullptr ||
5478 "Ignoring getheaders from peer=%d because active chain "
5479 "has too little work; sending empty response\n",
5484 std::vector<CBlock>()));
5488 CNodeState *nodestate = State(pfrom.
GetId());
5497 if (!BlockRequestAllowed(pindex)) {
5499 "%s: ignoring request from peer=%i for old block "
5500 "header that isn't in the main chain\n",
5501 __func__, pfrom.
GetId());
5507 m_chainman.ActiveChainstate().FindForkInGlobalIndex(locator);
5515 std::vector<CBlock> vHeaders;
5518 (pindex ? pindex->
nHeight : -1),
5521 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5523 if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) {
5540 nodestate->pindexBestHeaderSent =
5551 if ((m_opts.ignore_incoming_txs &&
5555 "transaction sent in violation of protocol peer=%d\n",
5565 if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
5573 AddKnownTx(*peer, txid);
5577 m_txrequest.ReceivedResponse(pfrom.
GetId(), txid);
5579 if (AlreadyHaveTx(txid,
true)) {
5586 LogPrintf(
"Not relaying non-mempool transaction %s from "
5587 "forcerelay peer=%d\n",
5590 LogPrintf(
"Force relaying tx %s from peer=%d\n",
5592 RelayTransaction(tx.
GetId());
5596 if (m_recent_rejects_reconsiderable.contains(txid)) {
5602 "found tx %s in reconsiderable rejects, looking for "
5603 "child in orphanage\n",
5605 if (
auto package_to_validate{
5606 Find1P1CPackage(ptx, pfrom.
GetId())}) {
5608 m_chainman.ActiveChainstate(), m_mempool,
5609 package_to_validate->m_txns,
false)};
5611 "package evaluation for %s: %s (%s)\n",
5612 package_to_validate->ToString(),
5614 ?
"package accepted"
5615 :
"package rejected",
5617 ProcessPackageResult(package_to_validate.value(),
5644 ProcessValidTx(pfrom.
GetId(), ptx);
5649 bool fRejectedParents =
false;
5653 std::vector<TxId> unique_parents;
5654 unique_parents.reserve(tx.
vin.size());
5659 std::sort(unique_parents.begin(), unique_parents.end());
5660 unique_parents.erase(
5661 std::unique(unique_parents.begin(), unique_parents.end()),
5662 unique_parents.end());
5669 std::optional<TxId> rejected_parent_reconsiderable;
5670 for (
const TxId &parent_txid : unique_parents) {
5671 if (m_recent_rejects.contains(parent_txid)) {
5672 fRejectedParents =
true;
5676 if (m_recent_rejects_reconsiderable.contains(parent_txid) &&
5677 !m_mempool.
exists(parent_txid)) {
5681 if (rejected_parent_reconsiderable.has_value()) {
5682 fRejectedParents =
true;
5685 rejected_parent_reconsiderable = parent_txid;
5688 if (!fRejectedParents) {
5689 const auto current_time{GetTime<std::chrono::microseconds>()};
5691 for (
const TxId &parent_txid : unique_parents) {
5693 AddKnownTx(*peer, parent_txid);
5697 if (!AlreadyHaveTx(parent_txid,
5699 AddTxAnnouncement(pfrom, parent_txid, current_time);
5704 AddToCompactExtraTransactions(ptx);
5709 m_txrequest.ForgetInvId(tx.
GetId());
5711 unsigned int nEvicted =
5712 m_orphanage.
LimitOrphans(m_opts.max_orphan_txs, m_rng);
5715 "orphanage overflow, removed %u tx\n", nEvicted);
5719 "not keeping orphan with rejected parents %s\n",
5723 m_recent_rejects.insert(tx.
GetId());
5724 m_txrequest.ForgetInvId(tx.
GetId());
5728 ProcessInvalidTx(pfrom.
GetId(), ptx, state,
5736 "tx %s failed but reconsiderable, looking for child in "
5739 if (
auto package_to_validate{Find1P1CPackage(ptx, pfrom.
GetId())}) {
5741 m_chainman.ActiveChainstate(), m_mempool,
5742 package_to_validate->m_txns,
false)};
5744 "package evaluation for %s: %s (%s)\n",
5745 package_to_validate->ToString(),
5747 :
"package rejected",
5749 ProcessPackageResult(package_to_validate.value(),
5761 "Unexpected cmpctblock message received from peer %d\n",
5768 vRecv >> cmpctblock;
5769 }
catch (std::ios_base::failure &e) {
5771 Misbehaving(*peer, 100,
"cmpctblock-bad-indexes");
5775 bool received_new_header =
false;
5786 if (!m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
5787 MaybeSendGetHeaders(
5788 pfrom,
GetLocator(m_chainman.m_best_header), *peer);
5794 GetAntiDoSWorkThreshold()) {
5798 "Ignoring low-work compact block from peer %d\n",
5805 received_new_header =
true;
5815 MaybePunishNodeForBlock(pfrom.
GetId(), state,
5817 "invalid header via cmpctblock");
5826 bool fProcessBLOCKTXN =
false;
5832 bool fRevertToHeaderProcessing =
false;
5836 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
5837 bool fBlockReconstructed =
false;
5845 CNodeState *nodestate = State(pfrom.
GetId());
5849 if (received_new_header &&
5852 nodestate->m_last_block_announcement =
GetTime();
5856 std::pair<NodeId, std::list<QueuedBlock>::iterator>>::
5857 iterator blockInFlightIt =
5859 bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.
end();
5861 if (pindex->nStatus.hasData()) {
5872 if (fAlreadyInFlight) {
5876 std::vector<CInv> vInv(1);
5886 if (!fAlreadyInFlight && !CanDirectFetch()) {
5893 if ((!fAlreadyInFlight && nodestate->nBlocksInFlight <
5895 (fAlreadyInFlight &&
5896 blockInFlightIt->second.first == pfrom.
GetId())) {
5897 std::list<QueuedBlock>::iterator *queuedBlockIt =
nullptr;
5898 if (!BlockRequested(config, pfrom.
GetId(), *pindex,
5900 if (!(*queuedBlockIt)->partialBlock) {
5902 ->partialBlock.reset(
5909 "we were already syncing!\n");
5915 *(*queuedBlockIt)->partialBlock;
5917 partialBlock.
InitData(cmpctblock, vExtraTxnForCompact);
5922 Misbehaving(*peer, 100,
"invalid compact block");
5927 std::vector<CInv> vInv(1);
5935 for (
size_t i = 0; i < cmpctblock.
BlockTxCount(); i++) {
5946 fProcessBLOCKTXN =
true;
5960 tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
5965 std::vector<CTransactionRef> dummy;
5966 status = tempBlock.FillBlock(*pblock, dummy);
5968 fBlockReconstructed =
true;
5972 if (fAlreadyInFlight) {
5976 std::vector<CInv> vInv(1);
5984 fRevertToHeaderProcessing =
true;
5989 if (fProcessBLOCKTXN) {
5991 blockTxnMsg, time_received, interruptMsgProc);
5994 if (fRevertToHeaderProcessing) {
6000 return ProcessHeadersMessage(config, pfrom, *peer,
6005 if (fBlockReconstructed) {
6010 mapBlockSource.emplace(pblock->GetHash(),
6011 std::make_pair(pfrom.
GetId(),
false));
6022 ProcessBlock(config, pfrom, pblock,
true,
6031 RemoveBlockRequest(pblock->GetHash());
6041 "Unexpected blocktxn message received from peer %d\n",
6049 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6050 bool fBlockRead =
false;
6055 std::pair<NodeId, std::list<QueuedBlock>::iterator>>::
6056 iterator it = mapBlocksInFlight.find(resp.
blockhash);
6057 if (it == mapBlocksInFlight.end() ||
6058 !it->second.second->partialBlock ||
6059 it->second.first != pfrom.
GetId()) {
6061 "Peer %d sent us block transactions for block "
6062 "we weren't expecting\n",
6068 *it->second.second->partialBlock;
6076 "invalid compact block/non-matching block transactions");
6080 std::vector<CInv> invs;
6113 std::make_pair(pfrom.
GetId(),
false));
6124 ProcessBlock(config, pfrom, pblock,
true,
6134 "Unexpected headers message received from peer %d\n",
6141 peer->m_last_getheaders_timestamp = {};
6143 std::vector<CBlockHeader> headers;
6149 Misbehaving(*peer, 20,
6150 strprintf(
"too-many-headers: headers message size = %u",
6154 headers.resize(nCount);
6155 for (
unsigned int n = 0; n < nCount; n++) {
6156 vRecv >> headers[n];
6161 ProcessHeadersMessage(config, pfrom, *peer, std::move(headers),
6167 if (m_headers_presync_should_signal.exchange(
false)) {
6168 HeadersPresyncStats stats;
6170 LOCK(m_headers_presync_mutex);
6172 m_headers_presync_stats.find(m_headers_presync_bestpeer);
6173 if (it != m_headers_presync_stats.end()) {
6178 m_chainman.ReportHeadersPresync(
6179 stats.first, stats.second->first, stats.second->second);
6190 "Unexpected block message received from peer %d\n",
6195 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6199 pblock->GetHash().ToString(), pfrom.
GetId());
6205 bool forceProcessing =
6207 !m_chainman.ActiveChainstate().IsInitialBlockDownload();
6208 const BlockHash hash = pblock->GetHash();
6209 bool min_pow_checked =
false;
6214 forceProcessing = IsBlockRequested(hash);
6215 RemoveBlockRequest(hash);
6219 mapBlockSource.emplace(hash, std::make_pair(pfrom.
GetId(),
true));
6227 GetAntiDoSWorkThreshold()) {
6228 min_pow_checked =
true;
6231 ProcessBlock(config, pfrom, pblock, forceProcessing, min_pow_checked);
6241 if (pfrom.m_avalanche_pubkey.has_value()) {
6244 "Ignoring avahello from peer %d: already in our node set\n",
6250 vRecv >> delegation;
6257 if (!delegation.
verify(state, pubkey)) {
6258 Misbehaving(*peer, 100,
"invalid-delegation");
6261 pfrom.m_avalanche_pubkey = std::move(pubkey);
6264 sighasher << delegation.
getId();
6272 if (!(*pfrom.m_avalanche_pubkey)
6273 .VerifySchnorr(sighasher.GetHash(),
sig)) {
6274 Misbehaving(*peer, 100,
"invalid-avahello-signature");
6281 if (!AlreadyHaveProof(proofid)) {
6282 const bool preferred = isPreferredDownloadPeer(pfrom);
6283 LOCK(cs_proofrequest);
6284 AddProofAnnouncement(pfrom, proofid,
6285 GetTime<std::chrono::microseconds>(),
6304 WITH_LOCK(peer->m_addr_token_bucket_mutex,
6305 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
6307 if (peer->m_proof_relay &&
6308 !m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
6311 peer->m_proof_relay->compactproofs_requested =
true;
6322 const auto now = Now<SteadyMilliseconds>();
6328 last_poll + std::chrono::milliseconds(m_opts.avalanche_cooldown)) {
6330 "Ignoring repeated avapoll from peer %d: cooldown not "
6345 strprintf(
"too-many-ava-poll: poll message size = %u", nCount));
6349 std::vector<avalanche::Vote> votes;
6350 votes.reserve(nCount);
6352 for (
unsigned int n = 0; n < nCount; n++) {
6360 if (!quorum_established) {
6361 votes.emplace_back(vote, inv.
hash);
6368 if (m_opts.avalanche_preconsensus) {
6383 "poll inv type %d unknown from peer=%d\n",
6388 votes.emplace_back(vote, inv.
hash);
6414 if (!pfrom.m_avalanche_pubkey.has_value() ||
6415 !(*pfrom.m_avalanche_pubkey)
6416 .VerifySchnorr(verifier.GetHash(),
sig)) {
6417 Misbehaving(*peer, 100,
"invalid-ava-response-signature");
6422 auto now = GetTime<std::chrono::seconds>();
6424 std::vector<avalanche::VoteItemUpdate> updates;
6431 Misbehaving(*peer, banscore,
error);
6447 Misbehaving(*peer, 2,
error);
6459 auto logVoteUpdate = [](
const auto &voteUpdate,
6460 const std::string &voteItemTypeStr,
6461 const auto &voteItemId) {
6462 std::string voteOutcome;
6463 switch (voteUpdate.getStatus()) {
6465 voteOutcome =
"invalidated";
6468 voteOutcome =
"rejected";
6471 voteOutcome =
"accepted";
6474 voteOutcome =
"finalized";
6477 voteOutcome =
"stalled";
6485 voteItemTypeStr, voteItemId.ToString());
6488 bool shouldActivateBestChain =
false;
6490 for (
const auto &u : updates) {
6495 if (
auto pitem = std::get_if<const avalanche::ProofRef>(&item)) {
6499 logVoteUpdate(u,
"proof", proofid);
6501 auto rejectionMode =
6503 auto nextCooldownTimePoint = GetTime<std::chrono::seconds>();
6504 switch (u.getStatus()) {
6520 return pm.rejectProof(proofid,
6524 "ERROR: Failed to reject proof: %s\n",
6529 nextCooldownTimePoint += std::chrono::seconds(
6530 m_opts.avalanche_peer_replacement_cooldown);
6536 avalanche::PeerManager::
6537 RegistrationMode::FORCE_ACCEPT);
6540 [&](const avalanche::Peer &peer) {
6541 pm.updateNextPossibleConflictTime(
6543 nextCooldownTimePoint);
6544 if (u.getStatus() ==
6545 avalanche::VoteStatus::
6547 pm.setFinalized(peer.peerid);
6555 "ERROR: Failed to accept proof: %s\n",
6562 if (
auto pitem = std::get_if<const CBlockIndex *>(&item)) {
6565 shouldActivateBestChain =
true;
6569 switch (u.getStatus()) {
6573 m_chainman.ActiveChainstate().ParkBlock(state, pindex);
6575 LogPrintf(
"ERROR: Database error: %s\n",
6582 m_chainman.ActiveChainstate().UnparkBlock(pindex);
6587 m_chainman.ActiveChainstate().UnparkBlock(pindex);
6590 if (m_opts.avalanche_preconsensus) {
6593 auto pblock =
WITH_LOCK(m_most_recent_block_mutex,
6594 return m_most_recent_block);
6598 std::shared_ptr<CBlock> pblockRead =
6599 std::make_shared<CBlock>();
6601 *pblockRead, *pindex)) {
6602 assert(!
"cannot load block from disk");
6604 pblock = pblockRead;
6612 m_chainman.ActiveChainstate().AvalancheFinalizeBlock(
6613 pindex, *m_avalanche);
6623 if (!m_opts.avalanche_preconsensus) {
6627 if (
auto pitem = std::get_if<const CTransactionRef>(&item)) {
6631 const TxId &txid = tx->GetId();
6632 logVoteUpdate(u,
"tx", txid);
6634 switch (u.getStatus()) {
6643 auto it = m_mempool.
GetIter(txid);
6644 if (it.has_value()) {
6655 auto it = m_mempool.
GetIter(txid);
6656 if (!it.has_value()) {
6658 "Error: finalized tx (%s) is not in the "
6674 if (shouldActivateBestChain) {
6676 if (!m_chainman.ActiveChainstate().ActivateBestChain(
6677 state,
nullptr, m_avalanche)) {
6692 ReceivedAvalancheProof(pfrom, *peer, proof);
6701 if (peer->m_proof_relay ==
nullptr) {
6705 peer->m_proof_relay->lastSharedProofsUpdate =
6706 GetTime<std::chrono::seconds>();
6708 peer->m_proof_relay->sharedProofs =
6714 peer->m_proof_relay->sharedProofs);
6725 if (peer->m_proof_relay ==
nullptr) {
6730 if (!peer->m_proof_relay->compactproofs_requested) {
6734 peer->m_proof_relay->compactproofs_requested =
false;
6738 vRecv >> compactProofs;
6739 }
catch (std::ios_base::failure &e) {
6741 Misbehaving(*peer, 100,
"avaproofs-bad-indexes");
6746 std::set<uint32_t> prefilledIndexes;
6748 if (!ReceivedAvalancheProof(pfrom, *peer, prefilledProof.proof)) {
6759 "Got an avaproofs message with no shortid (peer %d)\n",
6781 auto shortIdProcessor =
6785 if (shortIdProcessor.hasOutOfBoundIndex()) {
6788 Misbehaving(*peer, 100,
"avaproofs-bad-indexes");
6791 if (!shortIdProcessor.isEvenlyDistributed()) {
6796 std::vector<std::pair<avalanche::ProofId, bool>> remoteProofsStatus;
6803 shortIdProcessor.matchKnownItem(shortid, peer.
proof);
6810 remoteProofsStatus.emplace_back(peer.
getProofId(),
6821 for (
size_t i = 0; i < compactProofs.
size(); i++) {
6822 if (shortIdProcessor.getItem(i) ==
nullptr) {
6839 return pfrom.m_avalanche_pubkey.has_value())) {
6842 for (
const auto &[proofid, present] : remoteProofsStatus) {
6852 if (peer->m_proof_relay ==
nullptr) {
6859 auto requestedIndiceIt = proofreq.
indices.begin();
6860 uint32_t treeIndice = 0;
6861 peer->m_proof_relay->sharedProofs.forEachLeaf([&](
const auto &proof) {
6862 if (requestedIndiceIt == proofreq.
indices.end()) {
6867 if (treeIndice++ == *requestedIndiceIt) {
6870 requestedIndiceIt++;
6876 peer->m_proof_relay->sharedProofs = {};
6889 "Ignoring \"getaddr\" from %s connection. peer=%d\n",
6896 Assume(SetupAddressRelay(pfrom, *peer));
6900 if (peer->m_getaddr_recvd) {
6905 peer->m_getaddr_recvd =
true;
6907 peer->m_addrs_to_send.clear();
6908 std::vector<CAddress> vAddr;
6909 const size_t maxAddrToSend = m_opts.max_addr_to_send;
6917 for (
const CAddress &addr : vAddr) {
6918 PushAddress(*peer, addr);
6924 auto now = GetTime<std::chrono::seconds>();
6929 "Ignoring repeated getavaaddr from peer %d\n",
6937 if (!SetupAddressRelay(pfrom, *peer)) {
6939 "Ignoring getavaaddr message from %s peer=%d\n",
6944 auto availabilityScoreComparator = [](
const CNode *lhs,
6947 double scoreRhs = rhs->getAvailabilityScore();
6949 if (scoreLhs != scoreRhs) {
6950 return scoreLhs > scoreRhs;
6959 std::set<
const CNode *, decltype(availabilityScoreComparator)> avaNodes(
6960 availabilityScoreComparator);
6967 avaNodes.insert(pnode);
6968 if (avaNodes.size() > m_opts.max_addr_to_send) {
6969 avaNodes.erase(std::prev(avaNodes.end()));
6973 peer->m_addrs_to_send.clear();
6974 for (
const CNode *pnode : avaNodes) {
6975 PushAddress(*peer, pnode->
addr);
6986 "mempool request with bloom filters disabled, "
6987 "disconnect peer=%d\n",
6998 "mempool request with bandwidth limit reached, "
6999 "disconnect peer=%d\n",
7006 if (
auto tx_relay = peer->GetTxRelay()) {
7007 LOCK(tx_relay->m_tx_inventory_mutex);
7008 tx_relay->m_send_mempool =
true;
7038 const auto ping_end = time_received;
7041 bool bPingFinished =
false;
7042 std::string sProblem;
7044 if (nAvail >=
sizeof(nonce)) {
7049 if (peer->m_ping_nonce_sent != 0) {
7050 if (nonce == peer->m_ping_nonce_sent) {
7053 bPingFinished =
true;
7054 const auto ping_time = ping_end - peer->m_ping_start.load();
7055 if (ping_time.count() >= 0) {
7060 sProblem =
"Timing mishap";
7064 sProblem =
"Nonce mismatch";
7068 bPingFinished =
true;
7069 sProblem =
"Nonce zero";
7073 sProblem =
"Unsolicited pong without ping";
7078 bPingFinished =
true;
7079 sProblem =
"Short payload";
7082 if (!(sProblem.empty())) {
7084 "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
7085 pfrom.
GetId(), sProblem, peer->m_ping_nonce_sent, nonce,
7088 if (bPingFinished) {
7089 peer->m_ping_nonce_sent = 0;
7097 "filterload received despite not offering bloom services "
7098 "from peer=%d; disconnecting\n",
7108 Misbehaving(*peer, 100,
"too-large bloom filter");
7109 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7111 LOCK(tx_relay->m_bloom_filter_mutex);
7112 tx_relay->m_bloom_filter.reset(
new CBloomFilter(filter));
7113 tx_relay->m_relay_txs =
true;
7123 "filteradd received despite not offering bloom services "
7124 "from peer=%d; disconnecting\n",
7129 std::vector<uint8_t> vData;
7138 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7139 LOCK(tx_relay->m_bloom_filter_mutex);
7140 if (tx_relay->m_bloom_filter) {
7141 tx_relay->m_bloom_filter->insert(vData);
7149 Misbehaving(*peer, 100,
"bad filteradd message");
7157 "filterclear received despite not offering bloom services "
7158 "from peer=%d; disconnecting\n",
7163 auto tx_relay = peer->GetTxRelay();
7169 LOCK(tx_relay->m_bloom_filter_mutex);
7170 tx_relay->m_bloom_filter =
nullptr;
7171 tx_relay->m_relay_txs =
true;
7180 vRecv >> newFeeFilter;
7182 if (
auto tx_relay = peer->GetTxRelay()) {
7183 tx_relay->m_fee_filter_received = newFeeFilter;
7192 ProcessGetCFilters(pfrom, *peer, vRecv);
7197 ProcessGetCFHeaders(pfrom, *peer, vRecv);
7202 ProcessGetCFCheckPt(pfrom, *peer, vRecv);
7207 std::vector<CInv> vInv;
7213 for (
CInv &inv : vInv) {
7219 m_txrequest.ReceivedResponse(pfrom.
GetId(),
TxId(inv.
hash));
7223 LOCK(cs_proofrequest);
7224 m_proofrequest.ReceivedResponse(
7238 bool PeerManagerImpl::MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer) {
7240 LOCK(peer.m_misbehavior_mutex);
7243 if (!peer.m_should_discourage) {
7247 peer.m_should_discourage =
false;
7253 LogPrintf(
"Warning: not punishing noban peer %d!\n", peer.m_id);
7259 LogPrintf(
"Warning: not punishing manually connected peer %d!\n",
7268 "Warning: disconnecting but not discouraging %s peer %d!\n",
7285 bool PeerManagerImpl::ProcessMessages(
const Config &config,
CNode *pfrom,
7286 std::atomic<bool> &interruptMsgProc) {
7297 bool fMoreWork =
false;
7299 PeerRef peer = GetPeerRef(pfrom->
GetId());
7300 if (peer ==
nullptr) {
7305 LOCK(peer->m_getdata_requests_mutex);
7306 if (!peer->m_getdata_requests.empty()) {
7307 ProcessGetData(config, *pfrom, *peer, interruptMsgProc);
7311 const bool processed_orphan = ProcessOrphanTx(config, *peer);
7317 if (processed_orphan) {
7324 LOCK(peer->m_getdata_requests_mutex);
7325 if (!peer->m_getdata_requests.empty()) {
7335 std::list<CNetMessage> msgs;
7338 if (pfrom->vProcessMsg.empty()) {
7342 msgs.splice(msgs.begin(), pfrom->vProcessMsg,
7343 pfrom->vProcessMsg.begin());
7347 fMoreWork = !pfrom->vProcessMsg.empty();
7353 msg.m_recv.size(), msg.m_recv.
data());
7355 if (m_opts.capture_messages) {
7363 if (!msg.m_valid_netmagic) {
7365 "PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n",
7379 if (!msg.m_valid_header) {
7387 if (!msg.m_valid_checksum) {
7399 ProcessMessage(config, *pfrom, msg.
m_type, vRecv, msg.m_time,
7401 if (interruptMsgProc) {
7406 LOCK(peer->m_getdata_requests_mutex);
7407 if (!peer->m_getdata_requests.empty()) {
7418 }
catch (
const std::exception &e) {
7421 e.what(),
typeid(e).name());
7430 void PeerManagerImpl::ConsiderEviction(
CNode &pto, Peer &peer,
7431 std::chrono::seconds time_in_seconds) {
7434 CNodeState &state = *State(pto.
GetId());
7438 state.fSyncStarted) {
7445 if (state.pindexBestKnownBlock !=
nullptr &&
7446 state.pindexBestKnownBlock->nChainWork >=
7448 if (state.m_chain_sync.m_timeout != 0s) {
7449 state.m_chain_sync.m_timeout = 0s;
7450 state.m_chain_sync.m_work_header =
nullptr;
7451 state.m_chain_sync.m_sent_getheaders =
false;
7453 }
else if (state.m_chain_sync.m_timeout == 0s ||
7454 (state.m_chain_sync.m_work_header !=
nullptr &&
7455 state.pindexBestKnownBlock !=
nullptr &&
7456 state.pindexBestKnownBlock->nChainWork >=
7457 state.m_chain_sync.m_work_header->nChainWork)) {
7463 state.m_chain_sync.m_work_header = m_chainman.
ActiveChain().
Tip();
7464 state.m_chain_sync.m_sent_getheaders =
false;
7465 }
else if (state.m_chain_sync.m_timeout > 0s &&
7466 time_in_seconds > state.m_chain_sync.m_timeout) {
7471 if (state.m_chain_sync.m_sent_getheaders) {
7474 "Disconnecting outbound peer %d for old chain, best known "
7477 state.pindexBestKnownBlock !=
nullptr
7478 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
7482 assert(state.m_chain_sync.m_work_header);
7487 MaybeSendGetHeaders(
7488 pto,
GetLocator(state.m_chain_sync.m_work_header->pprev),
7492 "sending getheaders to outbound peer=%d to verify chain "
7493 "work (current best known block:%s, benchmark blockhash: "
7496 state.pindexBestKnownBlock !=
nullptr
7497 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
7499 state.m_chain_sync.m_work_header->GetBlockHash()
7501 state.m_chain_sync.m_sent_getheaders =
true;
7508 state.m_chain_sync.m_timeout =
7515 void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now) {
7524 std::pair<NodeId, std::chrono::seconds> youngest_peer{-1, 0},
7525 next_youngest_peer{-1, 0};
7531 if (pnode->
GetId() > youngest_peer.first) {
7532 next_youngest_peer = youngest_peer;
7533 youngest_peer.first = pnode->GetId();
7534 youngest_peer.second = pnode->m_last_block_time;
7538 NodeId to_disconnect = youngest_peer.first;
7539 if (youngest_peer.second > next_youngest_peer.second) {
7542 to_disconnect = next_youngest_peer.first;
7554 CNodeState *node_state = State(pnode->
GetId());
7555 if (node_state ==
nullptr ||
7557 node_state->nBlocksInFlight == 0)) {
7560 "disconnecting extra block-relay-only peer=%d "
7561 "(last block received at time %d)\n",
7568 "keeping block-relay-only peer=%d chosen for eviction "
7569 "(connect time: %d, blocks_in_flight: %d)\n",
7571 node_state->nBlocksInFlight);
7587 int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
7598 CNodeState *state = State(pnode->
GetId());
7599 if (state ==
nullptr) {
7604 if (state->m_chain_sync.m_protect) {
7607 if (state->m_last_block_announcement < oldest_block_announcement ||
7608 (state->m_last_block_announcement == oldest_block_announcement &&
7609 pnode->
GetId() > worst_peer)) {
7610 worst_peer = pnode->
GetId();
7611 oldest_block_announcement = state->m_last_block_announcement;
7615 if (worst_peer == -1) {
7619 bool disconnected = m_connman.
ForNode(
7627 CNodeState &state = *State(pnode->
GetId());
7629 state.nBlocksInFlight == 0) {
7631 "disconnecting extra outbound peer=%d (last block "
7632 "announcement received at time %d)\n",
7633 pnode->
GetId(), oldest_block_announcement);
7638 "keeping outbound peer=%d chosen for eviction "
7639 "(connect time: %d, blocks_in_flight: %d)\n",
7641 state.nBlocksInFlight);
7656 void PeerManagerImpl::CheckForStaleTipAndEvictPeers() {
7659 auto now{GetTime<std::chrono::seconds>()};
7661 EvictExtraOutboundPeers(now);
7663 if (now > m_stale_tip_check_time) {
7669 LogPrintf(
"Potential stale tip detected, will try using extra "
7670 "outbound peer (last tip update: %d seconds ago)\n",
7679 if (!m_initial_sync_finished && CanDirectFetch()) {
7681 m_initial_sync_finished =
true;
7685 void PeerManagerImpl::MaybeSendPing(
CNode &node_to, Peer &peer,
7686 std::chrono::microseconds now) {
7688 node_to, std::chrono::duration_cast<std::chrono::seconds>(now)) &&
7689 peer.m_ping_nonce_sent &&
7701 bool pingSend =
false;
7703 if (peer.m_ping_queued) {
7708 if (peer.m_ping_nonce_sent == 0 &&
7717 nonce = GetRand<uint64_t>();
7718 }
while (nonce == 0);
7719 peer.m_ping_queued =
false;
7720 peer.m_ping_start = now;
7722 peer.m_ping_nonce_sent = nonce;
7728 peer.m_ping_nonce_sent = 0;
7734 void PeerManagerImpl::MaybeSendAddr(
CNode &
node, Peer &peer,
7735 std::chrono::microseconds current_time) {
7737 if (!peer.m_addr_relay_enabled) {
7741 LOCK(peer.m_addr_send_times_mutex);
7742 if (
fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
7743 peer.m_next_local_addr_send < current_time) {
7750 if (peer.m_next_local_addr_send != 0us) {
7751 peer.m_addr_known->reset();
7754 CAddress local_addr{*local_service, peer.m_our_services,
7756 PushAddress(peer, local_addr);
7763 if (current_time <= peer.m_next_addr_send) {
7767 peer.m_next_addr_send =
7770 const size_t max_addr_to_send = m_opts.max_addr_to_send;
7771 if (!
Assume(peer.m_addrs_to_send.size() <= max_addr_to_send)) {
7774 peer.m_addrs_to_send.resize(max_addr_to_send);
7779 auto addr_already_known =
7782 bool ret = peer.m_addr_known->contains(addr.
GetKey());
7784 peer.m_addr_known->insert(addr.
GetKey());
7788 peer.m_addrs_to_send.erase(std::remove_if(peer.m_addrs_to_send.begin(),
7789 peer.m_addrs_to_send.end(),
7790 addr_already_known),
7791 peer.m_addrs_to_send.end());
7794 if (peer.m_addrs_to_send.empty()) {
7798 const char *msg_type;
7800 if (peer.m_wants_addrv2) {
7809 .
Make(make_flags, msg_type, peer.m_addrs_to_send));
7810 peer.m_addrs_to_send.clear();
7813 if (peer.m_addrs_to_send.capacity() > 40) {
7814 peer.m_addrs_to_send.shrink_to_fit();
7818 void PeerManagerImpl::MaybeSendSendHeaders(
CNode &
node, Peer &peer) {
7823 if (!peer.m_sent_sendheaders &&
7826 CNodeState &state = *State(
node.GetId());
7827 if (state.pindexBestKnownBlock !=
nullptr &&
7828 state.pindexBestKnownBlock->nChainWork >
7836 peer.m_sent_sendheaders =
true;
7841 void PeerManagerImpl::MaybeSendFeefilter(
7842 CNode &pto, Peer &peer, std::chrono::microseconds current_time) {
7843 if (m_opts.ignore_incoming_txs) {
7862 if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
7867 static const Amount MAX_FILTER{m_fee_filter_rounder.round(
MAX_MONEY)};
7868 if (peer.m_fee_filter_sent == MAX_FILTER) {
7871 peer.m_next_send_feefilter = 0us;
7874 if (current_time > peer.m_next_send_feefilter) {
7875 Amount filterToSend = m_fee_filter_rounder.round(currentFilter);
7879 if (filterToSend != peer.m_fee_filter_sent) {
7883 peer.m_fee_filter_sent = filterToSend;
7885 peer.m_next_send_feefilter =
7892 peer.m_next_send_feefilter &&
7893 (currentFilter < 3 * peer.m_fee_filter_sent / 4 ||
7894 currentFilter > 4 * peer.m_fee_filter_sent / 3)) {
7895 peer.m_next_send_feefilter =
7896 current_time + GetRandomDuration<std::chrono::microseconds>(
7902 class CompareInvMempoolOrder {
7906 explicit CompareInvMempoolOrder(
CTxMemPool *_mempool) : mp(_mempool) {}
7908 bool operator()(std::set<TxId>::iterator a, std::set<TxId>::iterator b) {
7918 bool PeerManagerImpl::SetupAddressRelay(
const CNode &
node, Peer &peer) {
7922 if (
node.IsBlockOnlyConn()) {
7926 if (!peer.m_addr_relay_enabled.exchange(
true)) {
7929 peer.m_addr_known = std::make_unique<CRollingBloomFilter>(5000, 0.001);
7935 bool PeerManagerImpl::SendMessages(
const Config &config,
CNode *pto) {
7938 PeerRef peer = GetPeerRef(pto->
GetId());
7947 if (MaybeDiscourageAndDisconnect(*pto, *peer)) {
7960 const auto current_time{GetTime<std::chrono::microseconds>()};
7965 "addrfetch connection timeout; disconnecting peer=%d\n",
7971 MaybeSendPing(*pto, *peer, current_time);
7978 bool sync_blocks_and_headers_from_peer =
false;
7980 MaybeSendAddr(*pto, *peer, current_time);
7982 MaybeSendSendHeaders(*pto, *peer);
7987 CNodeState &state = *State(pto->
GetId());
7990 if (m_chainman.m_best_header ==
nullptr) {
7997 if (state.fPreferredDownload) {
7998 sync_blocks_and_headers_from_peer =
true;
8009 if (m_num_preferred_download_peers == 0 ||
8010 mapBlocksInFlight.empty()) {
8011 sync_blocks_and_headers_from_peer =
true;
8015 if (!state.fSyncStarted && CanServeBlocks(*peer) &&
8019 if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) ||
8021 const CBlockIndex *pindexStart = m_chainman.m_best_header;
8030 if (pindexStart->
pprev) {
8031 pindexStart = pindexStart->
pprev;
8033 if (MaybeSendGetHeaders(*pto,
GetLocator(pindexStart), *peer)) {
8036 "initial getheaders (%d) to peer=%d (startheight:%d)\n",
8038 peer->m_starting_height);
8040 state.fSyncStarted =
true;
8041 peer->m_headers_sync_timeout =
8046 std::chrono::microseconds{
8048 Ticks<std::chrono::seconds>(
8050 m_chainman.m_best_header->Time()) /
8067 LOCK(peer->m_block_inv_mutex);
8068 std::vector<CBlock> vHeaders;
8070 ((!peer->m_prefers_headers &&
8071 (!state.m_requested_hb_cmpctblocks ||
8072 peer->m_blocks_for_headers_relay.size() > 1)) ||
8073 peer->m_blocks_for_headers_relay.size() >
8078 ProcessBlockAvailability(pto->
GetId());
8080 if (!fRevertToInv) {
8081 bool fFoundStartingHeader =
false;
8085 for (
const BlockHash &hash : peer->m_blocks_for_headers_relay) {
8091 fRevertToInv =
true;
8094 if (pBestIndex !=
nullptr && pindex->
pprev != pBestIndex) {
8105 fRevertToInv =
true;
8108 pBestIndex = pindex;
8109 if (fFoundStartingHeader) {
8112 }
else if (PeerHasHeader(&state, pindex)) {
8115 }
else if (pindex->
pprev ==
nullptr ||
8116 PeerHasHeader(&state, pindex->
pprev)) {
8119 fFoundStartingHeader =
true;
8124 fRevertToInv =
true;
8129 if (!fRevertToInv && !vHeaders.empty()) {
8130 if (vHeaders.size() == 1 && state.m_requested_hb_cmpctblocks) {
8135 "%s sending header-and-ids %s to peer=%d\n",
8136 __func__, vHeaders.front().GetHash().ToString(),
8139 std::optional<CSerializedNetMsg> cached_cmpctblock_msg;
8141 LOCK(m_most_recent_block_mutex);
8142 if (m_most_recent_block_hash ==
8144 cached_cmpctblock_msg =
8146 *m_most_recent_compact_block);
8149 if (cached_cmpctblock_msg.has_value()) {
8151 pto, std::move(cached_cmpctblock_msg.value()));
8155 block, *pBestIndex)};
8162 state.pindexBestHeaderSent = pBestIndex;
8163 }
else if (peer->m_prefers_headers) {
8164 if (vHeaders.size() > 1) {
8166 "%s: %u headers, range (%s, %s), to peer=%d\n",
8167 __func__, vHeaders.size(),
8168 vHeaders.front().GetHash().ToString(),
8169 vHeaders.back().GetHash().ToString(),
8173 "%s: sending header %s to peer=%d\n", __func__,
8174 vHeaders.front().GetHash().ToString(),
8179 state.pindexBestHeaderSent = pBestIndex;
8181 fRevertToInv =
true;
8188 if (!peer->m_blocks_for_headers_relay.empty()) {
8190 peer->m_blocks_for_headers_relay.back();
8201 "Announcing block %s not on main chain (tip=%s)\n",
8210 if (!PeerHasHeader(&state, pindex)) {
8211 peer->m_blocks_for_inv_relay.push_back(hashToAnnounce);
8213 "%s: sending inv peer=%d hash=%s\n", __func__,
8218 peer->m_blocks_for_headers_relay.clear();
8225 std::vector<CInv> vInv;
8226 auto addInvAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
8227 vInv.emplace_back(type, hash);
8239 LOCK(peer->m_block_inv_mutex);
8241 vInv.reserve(std::max<size_t>(peer->m_blocks_for_inv_relay.size(),
8247 for (
const BlockHash &hash : peer->m_blocks_for_inv_relay) {
8250 peer->m_blocks_for_inv_relay.clear();
8253 auto computeNextInvSendTime =
8254 [&](std::chrono::microseconds &next) ->
bool {
8257 if (next < current_time) {
8258 fSendTrickle =
true;
8260 next = NextInvToInbounds(
8265 next = current_time;
8269 return fSendTrickle;
8273 if (peer->m_proof_relay !=
nullptr) {
8274 LOCK(peer->m_proof_relay->m_proof_inventory_mutex);
8276 if (computeNextInvSendTime(
8277 peer->m_proof_relay->m_next_inv_send_time)) {
8279 peer->m_proof_relay->m_proof_inventory_to_send.begin();
8281 peer->m_proof_relay->m_proof_inventory_to_send.end()) {
8284 it = peer->m_proof_relay->m_proof_inventory_to_send.erase(
8287 if (peer->m_proof_relay->m_proof_inventory_known_filter
8288 .contains(proofid)) {
8292 peer->m_proof_relay->m_proof_inventory_known_filter.insert(
8295 peer->m_proof_relay->m_recently_announced_proofs.insert(
8301 if (
auto tx_relay = peer->GetTxRelay()) {
8302 LOCK(tx_relay->m_tx_inventory_mutex);
8304 const bool fSendTrickle =
8305 computeNextInvSendTime(tx_relay->m_next_inv_send_time);
8310 LOCK(tx_relay->m_bloom_filter_mutex);
8311 if (!tx_relay->m_relay_txs) {
8312 tx_relay->m_tx_inventory_to_send.clear();
8317 if (fSendTrickle && tx_relay->m_send_mempool) {
8318 auto vtxinfo = m_mempool.
infoAll();
8319 tx_relay->m_send_mempool =
false;
8321 tx_relay->m_fee_filter_received.load()};
8323 LOCK(tx_relay->m_bloom_filter_mutex);
8325 for (
const auto &txinfo : vtxinfo) {
8326 const TxId &txid = txinfo.tx->GetId();
8327 tx_relay->m_tx_inventory_to_send.erase(txid);
8330 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
8333 if (tx_relay->m_bloom_filter &&
8334 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
8338 tx_relay->m_tx_inventory_known_filter.insert(txid);
8341 addInvAndMaybeFlush(
MSG_TX, txid);
8343 tx_relay->m_last_mempool_req =
8344 std::chrono::duration_cast<std::chrono::seconds>(
8351 std::vector<std::set<TxId>::iterator> vInvTx;
8352 vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size());
8353 for (std::set<TxId>::iterator it =
8354 tx_relay->m_tx_inventory_to_send.begin();
8355 it != tx_relay->m_tx_inventory_to_send.end(); it++) {
8356 vInvTx.push_back(it);
8359 tx_relay->m_fee_filter_received.load()};
8364 CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool);
8365 std::make_heap(vInvTx.begin(), vInvTx.end(),
8366 compareInvMempoolOrder);
8370 unsigned int nRelayedTransactions = 0;
8371 LOCK(tx_relay->m_bloom_filter_mutex);
8372 while (!vInvTx.empty() &&
8377 std::pop_heap(vInvTx.begin(), vInvTx.end(),
8378 compareInvMempoolOrder);
8379 std::set<TxId>::iterator it = vInvTx.back();
8381 const TxId txid = *it;
8383 tx_relay->m_tx_inventory_to_send.erase(it);
8385 if (tx_relay->m_tx_inventory_known_filter.contains(txid)) {
8389 auto txinfo = m_mempool.
info(txid);
8395 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
8398 if (tx_relay->m_bloom_filter &&
8399 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
8404 tx_relay->m_recently_announced_invs.insert(txid);
8405 addInvAndMaybeFlush(
MSG_TX, txid);
8406 nRelayedTransactions++;
8409 while (!g_relay_expiration.empty() &&
8410 g_relay_expiration.front().first <
8412 mapRelay.erase(g_relay_expiration.front().second);
8413 g_relay_expiration.pop_front();
8416 auto ret = mapRelay.insert(
8417 std::make_pair(txid, std::move(txinfo.tx)));
8419 g_relay_expiration.push_back(std::make_pair(
8423 tx_relay->m_tx_inventory_known_filter.insert(txid);
8429 if (!vInv.empty()) {
8436 CNodeState &state = *State(pto->
GetId());
8439 auto stalling_timeout = m_block_stalling_timeout.load();
8440 if (state.m_stalling_since.count() &&
8441 state.m_stalling_since < current_time - stalling_timeout) {
8446 LogPrintf(
"Peer=%d is stalling block download, disconnecting\n",
8451 const auto new_timeout =
8453 if (stalling_timeout != new_timeout &&
8454 m_block_stalling_timeout.compare_exchange_strong(
8455 stalling_timeout, new_timeout)) {
8458 "Increased stalling timeout temporarily to %d seconds\n",
8470 if (state.vBlocksInFlight.size() > 0) {
8471 QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
8472 int nOtherPeersWithValidatedDownloads =
8473 m_peers_downloading_from - 1;
8475 state.m_downloading_since +
8476 std::chrono::seconds{consensusParams.nPowTargetSpacing} *
8479 nOtherPeersWithValidatedDownloads)) {
8480 LogPrintf(
"Timeout downloading block %s from peer=%d, "
8482 queuedBlock.pindex->GetBlockHash().ToString(),
8490 if (state.fSyncStarted &&
8491 peer->m_headers_sync_timeout < std::chrono::microseconds::max()) {
8494 if (current_time > peer->m_headers_sync_timeout &&
8495 nSyncStarted == 1 &&
8496 (m_num_preferred_download_peers -
8497 state.fPreferredDownload >=
8506 LogPrintf(
"Timeout downloading headers from peer=%d, "
8512 LogPrintf(
"Timeout downloading headers from noban "
8513 "peer=%d, not disconnecting\n",
8519 state.fSyncStarted =
false;
8521 peer->m_headers_sync_timeout = 0us;
8527 peer->m_headers_sync_timeout = std::chrono::microseconds::max();
8533 ConsiderEviction(*pto, *peer, GetTime<std::chrono::seconds>());
8536 std::vector<CInv> vGetData;
8544 CNodeState &state = *State(pto->
GetId());
8546 if (CanServeBlocks(*peer) &&
8547 ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) ||
8548 !m_chainman.ActiveChainstate().IsInitialBlockDownload()) &&
8550 std::vector<const CBlockIndex *> vToDownload;
8552 FindNextBlocksToDownload(pto->
GetId(),
8554 state.nBlocksInFlight,
8555 vToDownload, staller);
8558 BlockRequested(config, pto->
GetId(), *pindex);
8563 if (state.nBlocksInFlight == 0 && staller != -1) {
8564 if (State(staller)->m_stalling_since == 0us) {
8565 State(staller)->m_stalling_since = current_time;
8572 auto addGetDataAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
8573 CInv inv(type, hash);
8576 vGetData.push_back(std::move(inv));
8588 LOCK(cs_proofrequest);
8589 std::vector<std::pair<NodeId, avalanche::ProofId>> expired;
8591 m_proofrequest.GetRequestable(pto->
GetId(), current_time, &expired);
8592 for (
const auto &entry : expired) {
8594 "timeout of inflight proof %s from peer=%d\n",
8595 entry.second.ToString(), entry.first);
8597 for (
const auto &proofid : requestable) {
8598 if (!AlreadyHaveProof(proofid)) {
8600 m_proofrequest.RequestedData(
8601 pto->
GetId(), proofid,
8608 m_proofrequest.ForgetInvId(proofid);
8618 std::vector<std::pair<NodeId, TxId>> expired;
8620 m_txrequest.GetRequestable(pto->
GetId(), current_time, &expired);
8621 for (
const auto &entry : expired) {
8623 entry.second.ToString(), entry.first);
8625 for (
const TxId &txid : requestable) {
8629 if (!AlreadyHaveTx(txid,
false)) {
8630 addGetDataAndMaybeFlush(
MSG_TX, txid);
8631 m_txrequest.RequestedData(
8638 m_txrequest.ForgetInvId(txid);
8642 if (!vGetData.empty()) {
8648 MaybeSendFeefilter(*pto, *peer, current_time);
8652 bool PeerManagerImpl::ReceivedAvalancheProof(
CNode &
node, Peer &peer,
8654 assert(proof !=
nullptr);
8658 AddKnownProof(peer, proofid);
8660 if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
8670 return node.m_avalanche_pubkey.has_value());
8671 auto saveProofIfStaker = [
this, isStaker](
const CNode &
node,
8673 const NodeId nodeid) ->
bool {
8685 LOCK(cs_proofrequest);
8686 m_proofrequest.ReceivedResponse(nodeid, proofid);
8688 if (AlreadyHaveProof(proofid)) {
8689 m_proofrequest.ForgetInvId(proofid);
8690 saveProofIfStaker(
node, proofid, nodeid);
8700 return pm.registerProof(proof, state);
8702 WITH_LOCK(cs_proofrequest, m_proofrequest.ForgetInvId(proofid));
8703 RelayProof(proofid);
8705 node.m_last_proof_time = GetTime<std::chrono::seconds>();
8708 nodeid, proofid.ToString());
8726 "Not polling the avalanche proof (%s): peer=%d, proofid %s\n",
8727 state.
IsValid() ?
"not-worth-polling"
8729 nodeid, proofid.ToString());
8732 saveProofIfStaker(
node, proofid, nodeid);
bool MoneyRange(const Amount nValue)
static constexpr Amount MAX_MONEY
No amount larger than this (in satoshi) is valid.
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.
static constexpr int CFCHECKPT_INTERVAL
Interval between compact filter checkpoints.
@ CHAIN
Outputs do not overspend inputs, no double spends, coinbase output ok, no immature coinbase spends,...
@ TRANSACTIONS
Only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid,...
@ SCRIPTS
Scripts & signatures ok.
@ TREE
All parent headers found, difficulty matches, timestamp >= median previous, checkpoint.
arith_uint256 GetBlockProof(const CBlockIndex &block)
CBlockLocator GetLocator(const CBlockIndex *index)
Get a locator for a block index entry.
const CBlockIndex * LastCommonAncestor(const CBlockIndex *pa, const CBlockIndex *pb)
Find the last common ancestor two blocks have.
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...
#define Assert(val)
Identity function.
#define Assume(val)
Assume is the identity function.
Stochastic address manager.
void Good(const CService &addr, bool test_before_evict=true, NodeSeconds time=AdjustedTime())
Mark an entry as accessible, possibly moving it from "new" to "tried".
void Connected(const CService &addr, NodeSeconds time=AdjustedTime())
We have successfully connected to this peer.
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.
void Discourage(const CNetAddr &net_addr)
bool IsBanned(const CNetAddr &net_addr)
Return whether net_addr is banned.
bool IsDiscouraged(const CNetAddr &net_addr)
Return whether net_addr is discouraged.
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< uint32_t > indices
A CService with information about it as peer.
ServiceFlags nServices
Serialized as uint64_t in V1, and as CompactSize in V2.
NodeSeconds nTime
Always included in serialization, except in the network format on INIT_PROTO_VERSION.
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 BlockValidity nUpTo=BlockValidity::TRANSACTIONS) 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 HaveTxsDownloaded() const
Check whether this block's and all previous blocks' transactions have been downloaded (and stored to ...
int64_t GetBlockTime() const
unsigned int nTx
Number of transactions in this block.
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
BlockHash GetBlockHash() const
int nHeight
height of the entry in the chain. The genesis block has height 0
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...
CBlockIndex * Next(const CBlockIndex *pindex) const
Find the successor of a block in this chain, or nullptr if the given index is not found or is the tip...
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
int Height() const
Return the maximal height in the chain.
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
const Consensus::Params & GetConsensus() const
const CBlock & GenesisBlock() const
void ForEachNode(const NodeFn &func)
bool OutboundTargetReached(bool historicalBlockServingLimit) const
check if the outbound target is reached.
bool ForNode(NodeId id, std::function< bool(CNode *pnode)> func)
bool GetNetworkActive() const
bool GetTryNewOutboundPeer() const
void SetTryNewOutboundPeer(bool flag)
unsigned int GetReceiveFloodSize() const
int GetExtraBlockRelayCount() const
void WakeMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc)
void StartExtraBlockRelayPeers()
bool DisconnectNode(const std::string &node)
CSipHasher GetDeterministicRandomizer(uint64_t id) const
Get a unique deterministic randomizer.
int GetExtraFullOutboundCount() const
std::vector< CAddress > GetAddresses(size_t max_addresses, size_t max_pct, std::optional< Network > network) const
Return all or many randomly selected addresses, optionally by network.
bool CheckIncomingNonce(uint64_t nonce)
bool ShouldRunInactivityChecks(const CNode &node, std::chrono::seconds now) const
Return true if we should disconnect the peer for failing an inactivity check.
void PushMessage(CNode *pnode, CSerializedNetMsg &&msg)
bool GetUseAddrmanOutgoing() const
Double ended buffer combining vector and stream-like interfaces.
Fee rate in satoshis per kilobyte: Amount / kB.
Amount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
Reads data from an underlying stream, while hashing the read data.
Inv(ventory) message data.
bool IsMsgCmpctBlk() const
std::string ToString() const
bool IsMsgFilteredBlk() const
Used to create a Merkle proof (usually from a subset of transactions), which consists of a block head...
std::vector< std::pair< size_t, uint256 > > 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.
void SetIP(const CNetAddr &ip)
bool IsAddrV1Compatible() const
Check if the current object can be serialized in pre-ADDRv2/BIP155 format.
Transport protocol agnostic message container.
CSerializedNetMsg Make(int nFlags, std::string msg_type, Args &&...args) const
Information about a peer.
RecursiveMutex cs_vProcessMsg
Mutex cs_avalanche_pubkey
bool IsFeelerConn() const
const std::chrono::seconds m_connected
Unix epoch time at peer connection.
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::atomic_bool fPauseRecv
bool IsOutboundOrBlockRelayConn() const
bool IsManualConn() const
std::atomic< int64_t > nTimeOffset
const std::string m_addr_name
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 (their version message did not include fRelay=false...
std::atomic< bool > m_bip152_highbandwidth_from
void PongReceived(std::chrono::microseconds ping_time)
A ping-pong round trip has completed successfully.
std::atomic_bool fSuccessfullyConnected
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.
bool IsBlockOnlyConn() const
int GetCommonVersion() const
bool IsFullOutboundConn() const
uint64_t nRemoteHostNonce
Mutex m_subver_mutex
cleanSubVer is a sanitized string of the user agent byte array we read from the wire.
std::atomic_bool fPauseSend
std::chrono::seconds m_nextGetAvaAddr
uint64_t nRemoteExtraEntropy
uint64_t GetLocalExtraEntropy() const
SteadyMilliseconds m_last_poll
double getAvailabilityScore() const
std::atomic_bool m_bloom_filter_loaded
Whether this peer has loaded a bloom filter.
void updateAvailabilityScore(double decayFactor)
The availability score is calculated using an exponentially weighted average.
std::atomic< std::chrono::seconds > m_avalanche_last_message_fault
const bool m_inbound_onion
Whether this peer is an inbound onion, i.e.
std::atomic< int > m_avalanche_message_fault_counter
std::atomic< bool > m_avalanche_enabled
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....
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....
void invsVoted(uint32_t count)
The node voted for count invs.
bool IsAvalancheOutboundConnection() const
const TxId & GetTxId() const
An encapsulated public key.
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(Predicate p, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Repeat p until it return false.
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 ToString() const
std::vector< uint8_t > GetKey() const
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.
The basic transaction that is broadcasted on the network and contained in blocks.
const std::vector< CTxIn > vin
An input of a transaction.
std::set< std::reference_wrapper< const CTxMemPoolEntryRef >, CompareIteratorById > Parents
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
void RemoveUnbroadcastTx(const TxId &txid, const bool unchecked=false)
Removes a transaction from the unbroadcast set.
CFeeRate GetMinFee() const
The minimum fee to get into the mempool, which may itself not be enough for larger-sized transactions...
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs)
bool CompareTopologically(const TxId &txida, const TxId &txidb) const
TxMempoolInfo info(const TxId &txid) const
size_t DynamicMemoryUsage() const
std::vector< TxMempoolInfo > infoAll() const
bool setAvalancheFinalized(const CTxMemPoolEntryRef &tx) EXCLUSIVE_LOCKS_REQUIRED(cs)
bool exists(const TxId &txid) const
const CFeeRate m_min_relay_feerate
std::set< TxId > GetUnbroadcastTxs() const
Returns transactions in unbroadcast set.
void removeForFinalizedBlock(const std::vector< CTransactionRef > &vtx) EXCLUSIVE_LOCKS_REQUIRED(cs)
unsigned long size() const
std::optional< txiter > GetIter(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Returns an iterator to the given txid, if found.
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 BlockChecked(const CBlock &, const BlockValidationState &)
Notifies listeners of a block validation result.
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
Notifies listeners when the block chain tip advances.
virtual void BlockConnected(const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex)
Notifies listeners of a block being connected.
virtual void BlockDisconnected(const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex)
Notifies listeners of a block being disconnected.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
const arith_uint256 & MinimumChainWork() const
MempoolAcceptResult ProcessTransaction(const CTransactionRef &tx, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Try to add a transaction to the memory pool.
bool ProcessNewBlock(const std::shared_ptr< const CBlock > &block, bool force_processing, bool min_pow_checked, bool *new_block, avalanche::Processor *const avalanche=nullptr) LOCKS_EXCLUDED(cs_main)
Process an incoming block.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
bool ProcessNewBlockHeaders(const std::vector< CBlockHeader > &block, bool min_pow_checked, BlockValidationState &state, const CBlockIndex **ppindex=nullptr, const std::optional< CCheckpointData > &test_checkpoints=std::nullopt) LOCKS_EXCLUDED(cs_main)
Process incoming block headers.
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
virtual uint64_t GetMaxBlockSize() const =0
A writer stream (for serialization) that computes a 256-bit hash.
size_t Count(NodeId peer) const
Count how many announcements a peer has (REQUESTED, CANDIDATE, and COMPLETED combined).
size_t CountInFlight(NodeId peer) const
Count how many REQUESTED announcements a peer has.
Interface for message handling.
static Mutex g_msgproc_mutex
Mutex for anything that is only accessed via the msg processing thread.
virtual bool ProcessMessages(const Config &config, CNode *pnode, std::atomic< bool > &interrupt) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex)=0
Process protocol messages received from a given node.
virtual bool SendMessages(const Config &config, CNode *pnode) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex)=0
Send queued protocol messages to a given node.
virtual void InitializeNode(const Config &config, CNode &node, ServiceFlags our_services)=0
Initialize a peer (setup state, queue any initial messages)
virtual void FinalizeNode(const Config &config, const CNode &node)=0
Handle removal of a peer (clear state)
ReadStatus InitData(const CBlockHeaderAndShortTxIDs &cmpctblock, const std::vector< std::pair< TxHash, CTransactionRef >> &extra_txn)
bool IsTxAvailable(size_t index) const
ReadStatus FillBlock(CBlock &block, const std::vector< CTransactionRef > &vtx_missing)
virtual void SendPings()=0
Send ping message to all peers.
static std::unique_ptr< PeerManager > make(CConnman &connman, AddrMan &addrman, BanMan *banman, ChainstateManager &chainman, CTxMemPool &pool, avalanche::Processor *const avalanche, Options opts)
virtual void ProcessMessage(const Config &config, CNode &pfrom, const std::string &msg_type, CDataStream &vRecv, const std::chrono::microseconds time_received, const std::atomic< bool > &interruptMsgProc) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex)=0
Process a single message from a peer.
virtual void StartScheduledTasks(CScheduler &scheduler)=0
Begin running background tasks, should only be called once.
virtual bool IgnoresIncomingTxs()=0
Whether this node ignores txs received over p2p.
virtual void UnitTestMisbehaving(const NodeId peer_id, const int howmuch)=0
Public for unit testing.
virtual std::optional< std::string > FetchBlock(const Config &config, NodeId peer_id, const CBlockIndex &block_index)=0
Attempt to manually fetch block from a given peer.
virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) const =0
Get statistics from node state.
virtual void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds)=0
This function is used for testing the stale tip eviction logic, see denialofservice_tests....
virtual void CheckForStaleTipAndEvictPeers()=0
Evict extra outbound peers.
static RCUPtr make(Args &&...args)
Construct a new object that is owned by the pointer.
A class to track orphan transactions (failed on TX_MISSING_INPUTS) Since we cannot distinguish orphan...
bool HaveTxToReconsider(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Does this peer have any work to do?
void AddChildrenToWorkSet(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Add any orphans that list a particular tx as a parent into the from peer's work set.
unsigned int LimitOrphans(unsigned int max_orphans, FastRandomContext &rng) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Limit the orphanage to the given maximum.
void EraseForBlock(const CBlock &block) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Erase all orphans included in or invalidated by a new block.
bool AddTx(const CTransactionRef &tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Add a new orphan transaction.
std::vector< std::pair< CTransactionRef, NodeId > > GetChildrenFromDifferentPeer(const CTransactionRef &parent, NodeId nodeid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get all children that spend from this tx but were not received from nodeid.
size_t Size() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Return how many entries exist in the orphange.
int EraseTx(const TxId &txid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Erase an orphan by txid.
bool HaveTx(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Check if we already have an orphan transaction.
CTransactionRef GetTxToReconsider(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Extract a transaction from a peer's work set.
void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Erase all orphans announced by a peer (eg, after that peer disconnects)
std::vector< CTransactionRef > GetChildrenFromSamePeer(const CTransactionRef &parent, NodeId nodeid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get all children that spend from this tx and were received from nodeid.
std::string GetRejectReason() const
std::string ToString() const
256-bit unsigned big integer.
const std::vector< uint64_t > & getShortIDs() const
uint64_t getShortID(const ProofId &proofid) const
const std::vector< PrefilledProof > & getPrefilledProofs() const
ProofId getProofId() const
bool verify(DelegationState &state, CPubKey &auth) const
const LimitedProofId & getLimitedProofId() const
const DelegationId & getId() const
bool shouldRequestMoreNodes()
Returns true if we encountered a lack of node since the last call.
bool exists(const ProofId &proofid) const
bool forPeer(const ProofId &proofid, Callable &&func) const
bool addNode(NodeId nodeid, const ProofId &proofid)
Node API.
void removeUnbroadcastProof(const ProofId &proofid)
bool isBoundToPeer(const ProofId &proofid) const
bool saveRemoteProof(const ProofId &proofid, const NodeId nodeid, const bool present)
void forEachPeer(Callable &&func) const
void setInvalid(const ProofId &proofid)
bool isInvalid(const ProofId &proofid) const
bool isImmature(const ProofId &proofid) const
const ProofRadixTree & getShareableProofsSnapshot() const
void updateAvailabilityScores(const double decayFactor, Callable &&getNodeAvailabilityScore)
auto getUnbroadcastProofs() const
bool isInConflictingPool(const ProofId &proofid) const
void sendResponse(CNode *pfrom, Response response) const
int64_t getAvaproofsNodeCounter() const
bool registerVotes(NodeId nodeid, const Response &response, std::vector< VoteItemUpdate > &updates, int &banscore, std::string &error) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
bool sendHello(CNode *pfrom) EXCLUSIVE_LOCKS_REQUIRED(!cs_delayedAvahelloNodeIds)
Send a avahello message.
bool isQuorumEstablished() LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
ProofRef getLocalProof() const
bool reconcileOrFinalize(const ProofRef &proof) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Wrapper around the addToReconcile for proofs that adds back the finalization flag to the peer if it i...
void sendDelayedAvahello() EXCLUSIVE_LOCKS_REQUIRED(!cs_delayedAvahelloNodeIds)
auto withPeerManager(Callable &&func) const EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
void avaproofsSent(NodeId nodeid) LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
std::vector< uint32_t > indices
std::string ToString() const
std::string GetHex() const
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool LoadingBlocks() const
bool IsPruneMode() const
Whether running in -prune mode.
static const uint256 ZERO
@ BLOCK_CHECKPOINT
the block failed to meet one of our checkpoints
@ 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_CHILD_BEFORE_PARENT
This tx outputs are already spent in the mempool.
@ TX_MEMPOOL_POLICY
violated mempool's fee/size/descendant/etc limits
@ TX_UNKNOWN
transaction was not validated because package failed
@ TX_PREMATURE_SPEND
transaction spends a coinbase too early, or violates locktime/sequence locks
@ TX_DUPLICATE
Tx already in mempool or in the chain.
@ TX_INPUTS_NOT_STANDARD
inputs failed policy rules
@ TX_CONFLICT
Tx conflicts with another mempool tx, i.e.
@ TX_NOT_STANDARD
otherwise didn't meet our local policy rules
@ 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
@ TX_CONSENSUS
invalid by consensus rules
@ TX_RECONSIDERABLE
fails some policy, but might be acceptable if submitted in a (different) package
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.
std::array< uint8_t, CPubKey::SCHNORR_SIZE > SchnorrSig
a Schnorr signature
bool error(const char *fmt, const Args &...args)
#define LogPrint(category,...)
const char * FILTERLOAD
The filterload message tells the receiving peer to filter all relayed transactions and requested merk...
const char * CFHEADERS
cfheaders is a response to a getcfheaders request containing a filter header and a vector of filter h...
const char * AVAPROOFSREQ
Request for missing avalanche proofs after an avaproofs message has been processed.
const char * CFILTER
cfilter is a response to a getcfilters request containing a single compact filter.
const char * BLOCK
The block message transmits a single serialized block.
const char * FILTERCLEAR
The filterclear message tells the receiving peer to remove a previously-set bloom filter.
const char * HEADERS
The headers message sends one or more block headers to a node which previously requested certain head...
const char * ADDRV2
The addrv2 message relays connection information for peers on the network just like the addr message,...
const char * SENDHEADERS
Indicates that a node prefers to receive new block announcements via a "headers" message rather than ...
const char * AVAPROOFS
The avaproofs message the proof short ids of all the valid proofs that we know.
const char * PONG
The pong message replies to a ping message, proving to the pinging node that the ponging node is stil...
const char * GETAVAPROOFS
The getavaproofs message requests an avaproofs message that provides the proof short ids of all the v...
const char * SENDCMPCT
Contains a 1-byte bool and 8-byte LE version number.
const char * GETADDR
The getaddr message requests an addr message from the receiving node, preferably one with lots of IP ...
const char * GETCFCHECKPT
getcfcheckpt requests evenly spaced compact filter headers, enabling parallelized download and valida...
const char * NOTFOUND
The notfound message is a reply to a getdata message which requested an object the receiving node doe...
const char * GETAVAADDR
The getavaaddr message requests an addr message from the receiving node, containing IP addresses of t...
const char * CMPCTBLOCK
Contains a CBlockHeaderAndShortTxIDs object - providing a header and list of "short txids".
const char * MEMPOOL
The mempool message requests the TXIDs of transactions that the receiving node has verified as valid ...
const char * GETCFILTERS
getcfilters requests compact filters for a range of blocks.
const char * TX
The tx message transmits a single transaction.
const char * AVAHELLO
Contains a delegation and a signature.
const char * FILTERADD
The filteradd message tells the receiving peer to add a single element to a previously-set bloom filt...
const char * ADDR
The addr (IP address) message relays connection information for peers on the network.
const char * VERSION
The version message provides information about the transmitting node to the receiving node at the beg...
const char * GETBLOCKS
The getblocks message requests an inv message that provides block header hashes starting from a parti...
const char * FEEFILTER
The feefilter message tells the receiving peer not to inv us any txs which do not meet the specified ...
const char * GETHEADERS
The getheaders message requests a headers message that provides block headers starting from a particu...
const char * AVARESPONSE
Contains an avalanche::Response.
const char * GETDATA
The getdata message requests one or more data objects from another node.
const char * VERACK
The verack message acknowledges a previously-received version message, informing the connecting node ...
const char * BLOCKTXN
Contains a BlockTransactions.
const char * GETCFHEADERS
getcfheaders requests a compact filter header and the filter hashes for a range of blocks,...
const char * SENDADDRV2
The sendaddrv2 message signals support for receiving ADDRV2 messages (BIP155).
const char * PING
The ping message is sent periodically to help confirm that the receiving peer is still connected.
const char * AVAPOLL
Contains an avalanche::Poll.
const char * MERKLEBLOCK
The merkleblock message is a reply to a getdata message which requested a block using the inventory t...
const char * AVAPROOF
Contains an avalanche::Proof.
const char * CFCHECKPT
cfcheckpt is a response to a getcfcheckpt request containing a vector of evenly spaced filter headers...
const char * GETBLOCKTXN
Contains a BlockTransactionsRequest Peer should respond with "blocktxn" message.
const char * INV
The inv message (inventory message) transmits one or more inventories of objects known to the transmi...
ShortIdProcessor< PrefilledProof, ShortIdProcessorPrefilledProofAdapter, ProofRefCompare > ProofShortIdProcessor
std::variant< const ProofRef, const CBlockIndex *, const CTransactionRef > AnyVoteItem
RCUPtr< const Proof > ProofRef
Implement std::hash so RCUPtr can be used as a key for maps or sets.
bool IsPeerAddrLocalGood(CNode *pnode)
CService GetLocalAddress(const CNetAddr &addrPeer)
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, Span< const uint8_t > data, bool is_incoming)> CaptureMessage
Defaults to CaptureMessageToFile(), but can be overridden by unit tests.
std::string userAgent(const Config &config)
bool IsReachable(enum Network net)
bool SeenLocal(const CService &addr)
vote for a local address
static const unsigned int MAX_SUBVERSION_LENGTH
Maximum length of the user agent string in version message.
static constexpr std::chrono::minutes TIMEOUT_INTERVAL
Time after which to disconnect, after waiting for a ping response (or inactivity).
@ BypassProofRequestLimits
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_PROCESSING_TOKEN_BUCKET
The soft limit of the address processing token bucket (the regular MAX_ADDR_RATE_PER_SECOND based inc...
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 GETAVAADDR_INTERVAL
Minimum time between 2 successives getavaaddr messages from the same peer.
static constexpr auto AVG_FEEFILTER_BROADCAST_INTERVAL
Verify that INVENTORY_MAX_RECENT_RELAY is enough to cache everything typically relayed before uncondi...
static constexpr unsigned int INVENTORY_BROADCAST_MAX_PER_MB
Maximum number of inventory items to send per transmission.
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 uint32_t getAvalancheVoteForProof(const avalanche::Processor &avalanche, const avalanche::ProofId &id)
Decide a response for an Avalanche poll about the given proof.
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 const int MAX_NUM_UNCONNECTING_HEADERS_MSGS
Maximum number of unconnecting headers announcements before DoS score.
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 RELAY_TX_CACHE_TIME
How long to cache transactions in mapRelay for normal relay.
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 uint64_t CMPCTBLOCKS_VERSION
The compactblocks version we support.
bool IsAvalancheMessageType(const std::string &msg_type)
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 std::chrono::microseconds ComputeRequestTime(const CNode &node, const InvRequestTracker< InvId > &requestTracker, const DataRequestParameters &requestParams, std::chrono::microseconds current_time, bool preferred)
Compute the request time for this announcement, current time plus delays for:
static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL
Average delay between trickled inventory transmissions for inbound peers.
static constexpr DataRequestParameters TX_REQUEST_PARAMS
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 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 AVALANCHE_AVAPROOFS_TIMEOUT
If no proof was requested from a compact proof message after this timeout expired,...
static constexpr auto STALE_CHECK_INTERVAL
How frequently to check for stale tips.
static constexpr unsigned int INVENTORY_MAX_RECENT_RELAY
The number of most recently announced transactions a peer can request.
static constexpr auto UNCONDITIONAL_RELAY_DELAY
How long a transaction has to be in the mempool before it can unconditionally be relayed (even when n...
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 const int MAX_CMPCTBLOCK_DEPTH
Maximum depth of blocks we're willing to serve as compact blocks to peers when requested.
static constexpr DataRequestParameters PROOF_REQUEST_PARAMS
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE
Maximum number of headers to announce when relaying blocks with headers message.
static bool TooManyAnnouncements(const CNode &node, const InvRequestTracker< InvId > &requestTracker, const DataRequestParameters &requestParams)
static constexpr uint32_t MAX_GETCFHEADERS_SIZE
Maximum number of cf hashes that may be requested with one getcfheaders.
static constexpr auto BLOCK_STALLING_TIMEOUT_MAX
Maximum timeout for stalling block download.
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER
static constexpr uint64_t RANDOMIZER_ID_ADDRESS_RELAY
SHA256("main address relay")[0:8].
static constexpr size_t MAX_PCT_ADDR_TO_SEND
the maximum percentage of addresses from our addrman to return in response to a getaddr message.
static const unsigned int MAX_INV_SZ
The maximum number of entries in an 'inv' protocol message.
static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND
Maximum rate of inventory items to send per second.
static constexpr size_t MAX_ADDR_TO_SEND
The maximum number of address records permitted in an ADDR message.
static const int DISCOURAGEMENT_THRESHOLD
Threshold for marking a node to be discouraged, e.g.
static const unsigned int MAX_HEADERS_RESULTS
Number of headers sent in one getheaders result.
static constexpr int ADDRV2_FORMAT
A flag that is ORed into the protocol version to designate that addresses should be serialized in (un...
bool IsProxy(const CNetAddr &addr)
uint256 GetPackageHash(const Package &package)
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
static constexpr Amount DEFAULT_MIN_RELAY_TX_FEE_PER_KB(1000 *SATOSHI)
Default for -minrelaytxfee, minimum relay fee for transactions.
std::shared_ptr< const CTransaction > CTransactionRef
static constexpr size_t AVALANCHE_MAX_ELEMENT_POLL
Maximum item that can be polled at once.
void SetServiceFlagsIBDCache(bool state)
Set the current IBD status in order to figure out the desirable service flags.
ServiceFlags GetDesirableServiceFlags(ServiceFlags services)
Gets the set of service flags which are "desirable" for a given peer.
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH
Maximum length of incoming protocol messages (Currently 2MB).
static bool HasAllDesirableServiceFlags(ServiceFlags services)
A shortcut for (services & GetDesirableServiceFlags(services)) == GetDesirableServiceFlags(services),...
@ MSG_CMPCT_BLOCK
Defined in BIP152.
ServiceFlags
nServices flags.
static bool MayHaveUsefulAddressDB(ServiceFlags services)
Checks if a peer with the given service flags may be capable of having a robust address-storage DB.
std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval)
Return a timestamp in the future sampled from an exponential distribution (https://en....
constexpr auto GetRandMillis
void Shuffle(I first, I last, R &&rng)
More efficient than using std::shuffle on a FastRandomContext.
reverse_range< T > reverse_iterate(T &x)
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE
void Unserialize(Stream &, char)=delete
#define LIMITED_STRING(obj, n)
uint64_t ReadCompactSize(Stream &is, bool range_check=true)
Decode a CompactSize-encoded variable-length integer.
constexpr auto MakeUCharSpan(V &&v) -> decltype(UCharSpanCast(Span{std::forward< V >(v)}))
Like the Span constructor, but for (const) uint8_t member types only.
static const double AVALANCHE_STATISTICS_DECAY_FACTOR
Pre-computed decay factor for the avalanche statistics computation.
static constexpr std::chrono::minutes AVALANCHE_STATISTICS_REFRESH_PERIOD
Refresh period for the avalanche statistics computation.
std::string SanitizeString(const std::string &str, int rule)
Remove unsafe chars.
std::string ToString(const T &t)
Locale-independent version of std::to_string.
static constexpr Amount zero() noexcept
A BlockHash is a unqiue identifier for a block.
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
std::vector< BlockHash > vHave
std::chrono::microseconds m_ping_wait
Amount m_fee_filter_received
std::vector< int > vHeightInFlight
bool m_addr_relay_enabled
uint64_t m_addr_rate_limited
uint64_t m_addr_processed
ServiceFlags their_services
std::vector< uint8_t > data
Parameters that influence chain consensus.
int64_t nPowTargetSpacing
std::chrono::seconds PowTargetSpacing() const
const std::chrono::seconds overloaded_peer_delay
How long to delay requesting data from overloaded peers (see max_peer_request_in_flight).
const size_t max_peer_announcements
Maximum number of inventories to consider for requesting, per peer.
const std::chrono::seconds nonpref_peer_delay
How long to delay requesting data from non-preferred peers.
const NetPermissionFlags bypass_request_limits_permissions
Permission flags a peer requires to bypass the request limits tracking limits and delay penalty.
const std::chrono::microseconds getdata_interval
How long to wait (in microseconds) before a data request from an additional peer.
const size_t max_peer_request_in_flight
Maximum number of in-flight data requests from a peer.
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.
@ MEMPOOL_ENTRY
Valid, transaction was already in the mempool.
@ VALID
Fully validated, valid.
static time_point now() noexcept
Return current system time or mocked time, if set.
std::chrono::time_point< NodeClock > time_point
Validation result for package mempool acceptance.
PackageValidationState m_state
std::map< TxId, MempoolAcceptResult > m_tx_results
Map from txid to finished MempoolAcceptResults.
This is a radix tree storing values identified by a unique key.
A TxId is the identifier of a transaction.
std::chrono::seconds registration_time
const ProofId & getProofId() const
#define AssertLockNotHeld(cs)
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
#define EXCLUSIVE_LOCKS_REQUIRED(...)
#define LOCKS_EXCLUDED(...)
constexpr int64_t count_microseconds(std::chrono::microseconds t)
constexpr int64_t count_seconds(std::chrono::seconds t)
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
double CountSecondsDouble(SecondsDouble t)
Helper to count the seconds in any std::chrono::duration type.
NodeClock::time_point GetAdjustedTime()
void AddTimeData(const CNetAddr &ip, int64_t nOffsetSample)
NodeSeconds AdjustedTime()
#define TRACE6(context, event, a, b, c, d, e, f)
@ AVALANCHE
Removed by avalanche vote.
arith_uint256 CalculateHeadersWork(const std::vector< CBlockHeader > &headers)
Return the sum of the work on a given set of headers.
bool HasValidProofOfWork(const std::vector< CBlockHeader > &headers, const Consensus::Params &consensusParams)
Check with the proof of work on each blockheader matches the value in nBits.
PackageMempoolAcceptResult ProcessNewPackage(Chainstate &active_chainstate, CTxMemPool &pool, const Package &package, bool test_accept)
Validate (and maybe submit) a package to the mempool.
static const unsigned int MIN_BLOCKS_TO_KEEP
Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pr...
static const int INIT_PROTO_VERSION
initial proto version, to be increased after version/verack negotiation
static const int SHORT_IDS_BLOCKS_VERSION
short-id-based block download starts with this version
static const int SENDHEADERS_VERSION
"sendheaders" command and announcing blocks with headers starts with this version
static const int PROTOCOL_VERSION
network protocol versioning
static const int FEEFILTER_VERSION
"feefilter" tells peers to filter invs to you by fee starts with this version
static const int MIN_PEER_PROTO_VERSION
disconnect from peers older than this proto version
static const int INVALID_CB_NO_BAN_VERSION
not banning for invalid compact blocks starts with this version
static const int BIP0031_VERSION
BIP 0031, pong message, is enabled for all versions AFTER this one.