54#include <boost/multi_index/hashed_index.hpp>
55#include <boost/multi_index/member.hpp>
56#include <boost/multi_index/ordered_index.hpp>
57#include <boost/multi_index_container.hpp>
114 "Max protocol message length must be greater than largest "
115 "possible INV message");
172 std::chrono::seconds(2),
173 std::chrono::seconds(2),
174 std::chrono::seconds(60),
181 std::chrono::seconds(2),
182 std::chrono::seconds(2),
183 std::chrono::seconds(60),
216 "MAX_BLOCKTXN_DEPTH too high");
275 std::chrono::seconds{1},
276 "INVENTORY_RELAY_MAX too low");
327 std::unique_ptr<PartiallyDownloadedBlock> partialBlock;
332 std::chrono::seconds timeAdded;
334 StalledTxId(
TxId txid_, std::chrono::seconds timeAdded_)
335 : txid(txid_), timeAdded(timeAdded_){};
341using StalledTxIdSet = boost::multi_index_container<
343 boost::multi_index::indexed_by<
345 boost::multi_index::hashed_unique<
346 boost::multi_index::tag<by_txid>,
347 boost::multi_index::member<StalledTxId, TxId, &StalledTxId::txid>,
350 boost::multi_index::ordered_non_unique<
351 boost::multi_index::tag<by_time>,
352 boost::multi_index::member<StalledTxId, std::chrono::seconds,
353 &StalledTxId::timeAdded>>>>;
390 std::atomic<ServiceFlags> m_their_services{
NODE_NONE};
393 Mutex m_misbehavior_mutex;
398 bool m_should_discourage
GUARDED_BY(m_misbehavior_mutex){
false};
401 Mutex m_block_inv_mutex;
407 std::vector<BlockHash> m_blocks_for_inv_relay
GUARDED_BY(m_block_inv_mutex);
413 std::vector<BlockHash>
414 m_blocks_for_headers_relay
GUARDED_BY(m_block_inv_mutex);
425 std::atomic<int> m_starting_height{-1};
428 std::atomic<uint64_t> m_ping_nonce_sent{0};
430 std::atomic<std::chrono::microseconds> m_ping_start{0us};
432 std::atomic<bool> m_ping_queued{
false};
442 std::chrono::microseconds m_next_send_feefilter
455 bool m_relay_txs
GUARDED_BY(m_bloom_filter_mutex){
false};
460 std::unique_ptr<CBloomFilter>
476 GUARDED_BY(m_tx_inventory_mutex){50000, 0.000001};
482 std::set<TxId> m_tx_inventory_to_send
GUARDED_BY(m_tx_inventory_mutex);
488 bool m_send_mempool
GUARDED_BY(m_tx_inventory_mutex){
false};
490 std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
495 std::chrono::microseconds
496 m_next_inv_send_time
GUARDED_BY(m_tx_inventory_mutex){0};
502 std::atomic<Amount> m_fee_filter_received{
Amount::zero()};
508 m_avalanche_stalled_txids
GUARDED_BY(m_tx_inventory_mutex);
516 LOCK(m_tx_relay_mutex);
518 m_tx_relay = std::make_unique<Peer::TxRelay>();
519 return m_tx_relay.get();
523 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
525 const TxRelay *GetTxRelay() const
527 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
532 std::set<avalanche::ProofId>
533 m_proof_inventory_to_send
GUARDED_BY(m_proof_inventory_mutex);
536 GUARDED_BY(m_proof_inventory_mutex){10000, 0.000001};
543 std::chrono::microseconds m_next_inv_send_time{0};
547 std::atomic<std::chrono::seconds> lastSharedProofsUpdate{0s};
548 std::atomic<bool> compactproofs_requested{
false};
555 const std::unique_ptr<ProofRelay> m_proof_relay;
560 std::vector<CAddress>
572 std::unique_ptr<CRollingBloomFilter>
590 std::atomic_bool m_addr_relay_enabled{
false};
594 mutable Mutex m_addr_send_times_mutex;
596 std::chrono::microseconds
597 m_next_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
599 std::chrono::microseconds
600 m_next_local_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
605 std::atomic_bool m_wants_addrv2{
false};
609 mutable Mutex m_addr_token_bucket_mutex;
614 double m_addr_token_bucket
GUARDED_BY(m_addr_token_bucket_mutex){1.0};
616 std::chrono::microseconds
618 GetTime<std::chrono::microseconds>()};
620 std::atomic<uint64_t> m_addr_rate_limited{0};
625 std::atomic<uint64_t> m_addr_processed{0};
631 bool m_inv_triggered_getheaders_before_sync
635 Mutex m_getdata_requests_mutex;
637 std::deque<CInv> m_getdata_requests
GUARDED_BY(m_getdata_requests_mutex);
644 Mutex m_headers_sync_mutex;
649 std::unique_ptr<HeadersSyncState>
654 std::atomic<bool> m_sent_sendheaders{
false};
657 std::chrono::microseconds m_headers_sync_timeout
668 : m_id(id), m_our_services{our_services},
669 m_proof_relay(fRelayProofs ?
std::make_unique<ProofRelay>()
673 mutable Mutex m_tx_relay_mutex;
676 std::unique_ptr<TxRelay> m_tx_relay
GUARDED_BY(m_tx_relay_mutex);
679using PeerRef = std::shared_ptr<Peer>;
697 bool fSyncStarted{
false};
700 std::chrono::microseconds m_stalling_since{0us};
701 std::list<QueuedBlock> vBlocksInFlight;
704 std::chrono::microseconds m_downloading_since{0us};
706 bool fPreferredDownload{
false};
711 bool m_requested_hb_cmpctblocks{
false};
713 bool m_provides_cmpctblocks{
false};
741 struct ChainSyncTimeoutState {
744 std::chrono::seconds m_timeout{0s};
748 bool m_sent_getheaders{
false};
751 bool m_protect{
false};
754 ChainSyncTimeoutState m_chain_sync;
757 int64_t m_last_block_announcement{0};
760 const bool m_is_inbound;
762 CNodeState(
bool is_inbound) : m_is_inbound(is_inbound) {}
773 const std::shared_ptr<const CBlock> &pblock,
781 bool fInitialDownload)
override
787 const std::shared_ptr<const CBlock> &pblock)
override
796 !m_headers_presync_mutex);
798 std::atomic<bool> &interrupt)
override
800 !m_recent_confirmed_transactions_mutex,
801 !m_most_recent_block_mutex, !cs_proofrequest,
802 !m_headers_presync_mutex, g_msgproc_mutex);
805 !m_recent_confirmed_transactions_mutex,
806 !m_most_recent_block_mutex, !cs_proofrequest,
812 std::optional<std::string>
819 void RelayTransaction(const
TxId &txid) override
821 void RelayProof(const
avalanche::ProofId &proofid) override
823 void SetBestHeight(
int height)
override { m_best_height = height; };
826 Misbehaving(*
Assert(GetPeerRef(peer_id)),
"");
830 const std::chrono::microseconds time_received,
831 const std::atomic<bool> &interruptMsgProc)
override
833 !m_recent_confirmed_transactions_mutex,
834 !m_most_recent_block_mutex, !cs_proofrequest,
835 !m_headers_presync_mutex, g_msgproc_mutex);
837 int64_t time_in_seconds)
override;
844 void ConsiderEviction(
CNode &pto, Peer &peer,
845 std::chrono::seconds time_in_seconds)
852 void EvictExtraOutboundPeers(std::chrono::seconds now)
859 void ReattemptInitialBroadcast(
CScheduler &scheduler)
865 void UpdateAvalancheStatistics()
const;
870 void AvalanchePeriodicNetworking(
CScheduler &scheduler)
const;
888 void Misbehaving(Peer &peer,
const std::string &message);
900 void MaybePunishNodeForBlock(
NodeId nodeid,
902 bool via_compact_block,
903 const std::string &message =
"")
911 const
std::
string &message = "")
923 bool MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer);
941 bool maybe_add_extra_compact_tx)
944 struct PackageToValidate {
946 const std::vector<NodeId> m_senders;
951 : m_txns{parent, child}, m_senders{parent_sender, child_sender} {}
954 Assume(m_txns.size() == 2);
956 "parent %s (sender=%d) + child %s (sender=%d)",
957 m_txns.front()->GetId().ToString(), m_senders.front(),
958 m_txns.back()->GetId().ToString(), m_senders.back());
967 void ProcessPackageResult(
const PackageToValidate &package_to_validate,
977 std::optional<PackageToValidate> Find1P1CPackage(
const CTransactionRef &ptx,
1004 bool ProcessOrphanTx(
const Config &config, Peer &peer)
1017 void ProcessHeadersMessage(
const Config &config,
CNode &pfrom, Peer &peer,
1018 std::vector<CBlockHeader> &&headers,
1019 bool via_compact_block)
1029 bool CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
1039 void HandleUnconnectingHeaders(
CNode &pfrom, Peer &peer,
1040 const std::vector<CBlockHeader> &headers)
1044 CheckHeadersAreContinuous(
const std::vector<CBlockHeader> &headers)
const;
1064 bool IsContinuationOfLowWorkHeadersSync(Peer &peer,
CNode &pfrom,
1065 std::vector<CBlockHeader> &headers)
1067 !m_headers_presync_mutex, g_msgproc_mutex);
1081 bool TryLowWorkHeadersSync(Peer &peer,
CNode &pfrom,
1083 std::vector<CBlockHeader> &headers)
1085 !m_headers_presync_mutex, g_msgproc_mutex);
1091 bool IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header)
1105 void HeadersDirectFetchBlocks(
const Config &config,
CNode &pfrom,
1108 void UpdatePeerStateForReceivedHeaders(
CNode &pfrom, Peer &peer,
1110 bool received_new_header,
1111 bool may_have_more_headers)
1114 void SendBlockTransactions(
CNode &pfrom, Peer &peer,
const CBlock &block,
1123 std::chrono::microseconds current_time)
1133 std::chrono::microseconds current_time,
bool preferred)
1137 void PushNodeVersion(
const Config &config,
CNode &pnode,
const Peer &peer);
1145 void MaybeSendPing(
CNode &node_to, Peer &peer,
1146 std::chrono::microseconds now);
1149 void MaybeSendAddr(
CNode &
node, Peer &peer,
1150 std::chrono::microseconds current_time)
1157 void MaybeSendSendHeaders(
CNode &
node, Peer &peer)
1161 void MaybeSendFeefilter(
CNode &
node, Peer &peer,
1162 std::chrono::microseconds current_time)
1174 void RelayAddress(
NodeId originator,
const CAddress &addr,
bool fReachable)
1195 Mutex cs_proofrequest;
1200 std::atomic<int> m_best_height{-1};
1205 const Options m_opts;
1207 bool RejectIncomingTxs(
const CNode &peer)
const;
1219 mutable Mutex m_peer_mutex;
1226 std::map<NodeId, PeerRef> m_peer_map
GUARDED_BY(m_peer_mutex);
1235 const CNodeState *State(
NodeId pnode)
const
1240 std::atomic<std::chrono::microseconds> m_next_inv_to_inbounds{0us};
1247 m_last_block_inv_triggering_headers_sync
GUARDED_BY(g_msgproc_mutex){};
1255 std::map<BlockHash, std::pair<NodeId, bool>>
1265 std::atomic<std::chrono::seconds> m_block_stalling_timeout{
1279 bool AlreadyHaveTx(
const TxId &txid,
bool include_reconsiderable)
1281 !m_recent_confirmed_transactions_mutex);
1345 mutable Mutex m_recent_confirmed_transactions_mutex;
1347 GUARDED_BY(m_recent_confirmed_transactions_mutex){24'000, 0.000'001};
1356 std::chrono::microseconds
1357 NextInvToInbounds(std::chrono::microseconds now,
1358 std::chrono::seconds average_interval)
1363 mutable Mutex m_most_recent_block_mutex;
1364 std::shared_ptr<const CBlock>
1365 m_most_recent_block
GUARDED_BY(m_most_recent_block_mutex);
1366 std::shared_ptr<const CBlockHeaderAndShortTxIDs>
1367 m_most_recent_compact_block
GUARDED_BY(m_most_recent_block_mutex);
1369 std::unique_ptr<const std::map<TxId, CTransactionRef>>
1370 m_most_recent_block_txs
GUARDED_BY(m_most_recent_block_mutex);
1375 Mutex m_headers_presync_mutex;
1386 using HeadersPresyncStats =
1387 std::pair<arith_uint256, std::optional<std::pair<int64_t, uint32_t>>>;
1389 std::map<NodeId, HeadersPresyncStats>
1390 m_headers_presync_stats
GUARDED_BY(m_headers_presync_mutex){};
1394 std::atomic_bool m_headers_presync_should_signal{
false};
1402 bool IsBlockRequested(
const BlockHash &hash)
1406 bool IsBlockRequestedFromOutbound(
const BlockHash &hash)
1417 void RemoveBlockRequest(
const BlockHash &hash,
1418 std::optional<NodeId> from_peer)
1427 bool BlockRequested(
const Config &config,
NodeId nodeid,
1429 std::list<QueuedBlock>::iterator **pit =
nullptr)
1438 void FindNextBlocksToDownload(const Peer &peer,
unsigned int count,
1444 void TryDownloadingHistoricalBlocks(
1445 const Peer &peer,
unsigned int count,
1479 const Peer &peer, CNodeState *state,
1481 int nWindowEnd, const
CChain *activeChain =
nullptr,
1482 NodeId *nodeStaller =
nullptr)
1492 std::atomic<
std::chrono::seconds> m_last_tip_update{0s};
1499 const std::chrono::seconds mempool_req,
1500 const std::chrono::seconds now)
1505 void ProcessGetData(
const Config &config,
CNode &pfrom, Peer &peer,
1506 const std::atomic<bool> &interruptMsgProc)
1508 peer.m_getdata_requests_mutex,
1514 const std::shared_ptr<const CBlock> &block,
1515 bool force_processing,
bool min_pow_checked);
1523 void MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid)
1542 std::vector<std::pair<TxHash, CTransactionRef>>
1543 vExtraTxnForCompact
GUARDED_BY(g_msgproc_mutex);
1545 size_t vExtraTxnForCompactIt
GUARDED_BY(g_msgproc_mutex) = 0;
1550 void ProcessBlockAvailability(
NodeId nodeid)
1565 bool BlockRequestAllowed(const
CBlockIndex *pindex)
1567 bool AlreadyHaveBlock(const
BlockHash &block_hash)
1569 bool AlreadyHaveProof(const
avalanche::ProofId &proofid);
1570 void ProcessGetBlockData(const
Config &config,
CNode &pfrom, Peer &peer,
1593 bool PrepareBlockFilterRequest(
CNode &
node, Peer &peer,
1595 uint32_t start_height,
1597 uint32_t max_height_diff,
1638 uint32_t GetAvalancheVoteForBlock(const
BlockHash &hash) const
1649 const
TxId &
id) const
1651 !m_recent_confirmed_transactions_mutex);
1660 bool SetupAddressRelay(const
CNode &
node, Peer &peer)
1663 void AddAddressKnown(Peer &peer, const
CAddress &addr)
1665 void PushAddress(Peer &peer, const
CAddress &addr)
1673 bool ReceivedAvalancheProof(
CNode &
node, Peer &peer,
1679 const
std::chrono::seconds now)
1682 bool isPreferredDownloadPeer(const
CNode &pfrom);
1685const CNodeState *PeerManagerImpl::State(
NodeId pnode) const
1687 std::map<NodeId, CNodeState>::const_iterator it = m_node_states.find(pnode);
1688 if (it == m_node_states.end()) {
1695CNodeState *PeerManagerImpl::State(
NodeId pnode)
1697 return const_cast<CNodeState *
>(std::as_const(*this).State(pnode));
1705static bool IsAddrCompatible(
const Peer &peer,
const CAddress &addr) {
1709void PeerManagerImpl::AddAddressKnown(Peer &peer,
const CAddress &addr) {
1710 assert(peer.m_addr_known);
1711 peer.m_addr_known->insert(addr.
GetKey());
1714void PeerManagerImpl::PushAddress(Peer &peer,
const CAddress &addr) {
1718 assert(peer.m_addr_known);
1719 if (addr.
IsValid() && !peer.m_addr_known->contains(addr.
GetKey()) &&
1720 IsAddrCompatible(peer, addr)) {
1721 if (peer.m_addrs_to_send.size() >= m_opts.max_addr_to_send) {
1722 peer.m_addrs_to_send[m_rng.randrange(peer.m_addrs_to_send.size())] =
1725 peer.m_addrs_to_send.push_back(addr);
1730static void AddKnownTx(Peer &peer,
const TxId &txid) {
1731 auto tx_relay = peer.GetTxRelay();
1736 LOCK(tx_relay->m_tx_inventory_mutex);
1737 tx_relay->m_tx_inventory_known_filter.insert(txid);
1741 if (peer.m_proof_relay !=
nullptr) {
1742 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
1743 peer.m_proof_relay->m_proof_inventory_known_filter.insert(proofid);
1747bool PeerManagerImpl::isPreferredDownloadPeer(
const CNode &pfrom) {
1749 const CNodeState *state = State(pfrom.
GetId());
1750 return state && state->fPreferredDownload;
1753static bool CanServeBlocks(
const Peer &peer) {
1761static bool IsLimitedPeer(
const Peer &peer) {
1766std::chrono::microseconds
1767PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
1768 std::chrono::seconds average_interval) {
1769 if (m_next_inv_to_inbounds.load() < now) {
1774 m_next_inv_to_inbounds =
1775 now + m_rng.rand_exp_duration(average_interval);
1777 return m_next_inv_to_inbounds;
1780bool PeerManagerImpl::IsBlockRequested(
const BlockHash &hash) {
1781 return mapBlocksInFlight.count(hash);
1784bool PeerManagerImpl::IsBlockRequestedFromOutbound(
const BlockHash &hash) {
1785 for (
auto range = mapBlocksInFlight.equal_range(hash);
1786 range.first != range.second; range.first++) {
1787 auto [nodeid, block_it] = range.first->second;
1788 CNodeState &nodestate = *
Assert(State(nodeid));
1789 if (!nodestate.m_is_inbound) {
1797void PeerManagerImpl::RemoveBlockRequest(
const BlockHash &hash,
1798 std::optional<NodeId> from_peer) {
1799 auto range = mapBlocksInFlight.equal_range(hash);
1800 if (range.first == range.second) {
1808 while (range.first != range.second) {
1809 auto [node_id, list_it] = range.first->second;
1811 if (from_peer && *from_peer != node_id) {
1816 CNodeState &state = *
Assert(State(node_id));
1818 if (state.vBlocksInFlight.begin() == list_it) {
1821 state.m_downloading_since =
1822 std::max(state.m_downloading_since,
1823 GetTime<std::chrono::microseconds>());
1825 state.vBlocksInFlight.erase(list_it);
1827 if (state.vBlocksInFlight.empty()) {
1829 m_peers_downloading_from--;
1831 state.m_stalling_since = 0us;
1833 range.first = mapBlocksInFlight.erase(range.first);
1837bool PeerManagerImpl::BlockRequested(
const Config &config,
NodeId nodeid,
1839 std::list<QueuedBlock>::iterator **pit) {
1842 CNodeState *state = State(nodeid);
1843 assert(state !=
nullptr);
1848 for (
auto range = mapBlocksInFlight.equal_range(hash);
1849 range.first != range.second; range.first++) {
1850 if (range.first->second.first == nodeid) {
1852 *pit = &range.first->second.second;
1859 RemoveBlockRequest(hash, nodeid);
1861 std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(
1862 state->vBlocksInFlight.end(),
1863 {&block, std::unique_ptr<PartiallyDownloadedBlock>(
1864 pit ? new PartiallyDownloadedBlock(config, &m_mempool)
1866 if (state->vBlocksInFlight.size() == 1) {
1868 state->m_downloading_since = GetTime<std::chrono::microseconds>();
1869 m_peers_downloading_from++;
1872 auto itInFlight = mapBlocksInFlight.insert(
1873 std::make_pair(hash, std::make_pair(nodeid, it)));
1876 *pit = &itInFlight->second.second;
1882void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid) {
1888 if (m_opts.ignore_incoming_txs) {
1892 CNodeState *nodestate = State(nodeid);
1897 if (!nodestate->m_provides_cmpctblocks) {
1900 int num_outbound_hb_peers = 0;
1901 for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin();
1902 it != lNodesAnnouncingHeaderAndIDs.end(); it++) {
1903 if (*it == nodeid) {
1904 lNodesAnnouncingHeaderAndIDs.erase(it);
1905 lNodesAnnouncingHeaderAndIDs.push_back(nodeid);
1908 CNodeState *state = State(*it);
1909 if (state !=
nullptr && !state->m_is_inbound) {
1910 ++num_outbound_hb_peers;
1913 if (nodestate->m_is_inbound) {
1916 if (lNodesAnnouncingHeaderAndIDs.size() >= 3 &&
1917 num_outbound_hb_peers == 1) {
1918 CNodeState *remove_node =
1919 State(lNodesAnnouncingHeaderAndIDs.front());
1920 if (remove_node !=
nullptr && !remove_node->m_is_inbound) {
1923 std::swap(lNodesAnnouncingHeaderAndIDs.front(),
1924 *std::next(lNodesAnnouncingHeaderAndIDs.begin()));
1931 if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
1935 lNodesAnnouncingHeaderAndIDs.front(), [
this](
CNode *pnodeStop) {
1936 m_connman.PushMessage(
1937 pnodeStop, CNetMsgMaker(pnodeStop->GetCommonVersion())
1938 .Make(NetMsgType::SENDCMPCT,
1940 CMPCTBLOCKS_VERSION));
1943 pnodeStop->m_bip152_highbandwidth_to = false;
1946 lNodesAnnouncingHeaderAndIDs.pop_front();
1955 lNodesAnnouncingHeaderAndIDs.push_back(pfrom->
GetId());
1960bool PeerManagerImpl::TipMayBeStale() {
1963 if (m_last_tip_update.load() == 0s) {
1964 m_last_tip_update = GetTime<std::chrono::seconds>();
1966 return m_last_tip_update.load() <
1967 GetTime<std::chrono::seconds>() -
1970 mapBlocksInFlight.empty();
1973bool PeerManagerImpl::CanDirectFetch() {
1979static bool PeerHasHeader(CNodeState *state,
const CBlockIndex *pindex)
1981 if (state->pindexBestKnownBlock &&
1982 pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) {
1985 if (state->pindexBestHeaderSent &&
1986 pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight)) {
1992void PeerManagerImpl::ProcessBlockAvailability(
NodeId nodeid) {
1993 CNodeState *state = State(nodeid);
1994 assert(state !=
nullptr);
1996 if (!state->hashLastUnknownBlock.IsNull()) {
2000 if (state->pindexBestKnownBlock ==
nullptr ||
2001 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
2002 state->pindexBestKnownBlock = pindex;
2004 state->hashLastUnknownBlock.SetNull();
2009void PeerManagerImpl::UpdateBlockAvailability(
NodeId nodeid,
2011 CNodeState *state = State(nodeid);
2012 assert(state !=
nullptr);
2014 ProcessBlockAvailability(nodeid);
2019 if (state->pindexBestKnownBlock ==
nullptr ||
2020 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
2021 state->pindexBestKnownBlock = pindex;
2026 state->hashLastUnknownBlock = hash;
2032void PeerManagerImpl::FindNextBlocksToDownload(
2033 const Peer &peer,
unsigned int count,
2034 std::vector<const CBlockIndex *> &vBlocks,
NodeId &nodeStaller) {
2039 vBlocks.reserve(vBlocks.size() +
count);
2040 CNodeState *state = State(peer.m_id);
2041 assert(state !=
nullptr);
2044 ProcessBlockAvailability(peer.m_id);
2046 if (state->pindexBestKnownBlock ==
nullptr ||
2047 state->pindexBestKnownBlock->nChainWork <
2049 state->pindexBestKnownBlock->nChainWork <
2059 const CBlockIndex *snap_base{m_chainman.GetSnapshotBaseBlock()};
2060 if (snap_base && state->pindexBestKnownBlock->GetAncestor(
2061 snap_base->nHeight) != snap_base) {
2063 "Not downloading blocks from peer=%d, which doesn't have the "
2064 "snapshot block in its best chain.\n",
2073 if (state->pindexLastCommonBlock ==
nullptr ||
2075 state->pindexLastCommonBlock->nHeight < snap_base->nHeight)) {
2076 state->pindexLastCommonBlock =
2078 .
ActiveChain()[std::min(state->pindexBestKnownBlock->nHeight,
2085 state->pindexLastCommonBlock, state->pindexBestKnownBlock);
2086 if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) {
2090 const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
2098 FindNextBlocks(vBlocks, peer, state, pindexWalk,
count, nWindowEnd,
2102void PeerManagerImpl::TryDownloadingHistoricalBlocks(
2103 const Peer &peer,
unsigned int count,
2104 std::vector<const CBlockIndex *> &vBlocks,
const CBlockIndex *from_tip,
2109 if (vBlocks.size() >=
count) {
2113 vBlocks.reserve(
count);
2114 CNodeState *state =
Assert(State(peer.m_id));
2116 if (state->pindexBestKnownBlock ==
nullptr ||
2117 state->pindexBestKnownBlock->GetAncestor(target_block->
nHeight) !=
2132 FindNextBlocks(vBlocks, peer, state, from_tip,
count,
2137void PeerManagerImpl::FindNextBlocks(std::vector<const CBlockIndex *> &vBlocks,
2138 const Peer &peer, CNodeState *state,
2140 unsigned int count,
int nWindowEnd,
2141 const CChain *activeChain,
2143 std::vector<const CBlockIndex *> vToFetch;
2145 std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
2147 while (pindexWalk->
nHeight < nMaxHeight) {
2152 int nToFetch = std::min(nMaxHeight - pindexWalk->
nHeight,
2153 std::max<int>(
count - vBlocks.size(), 128));
2154 vToFetch.resize(nToFetch);
2155 pindexWalk = state->pindexBestKnownBlock->
GetAncestor(
2156 pindexWalk->
nHeight + nToFetch);
2157 vToFetch[nToFetch - 1] = pindexWalk;
2158 for (
unsigned int i = nToFetch - 1; i > 0; i--) {
2159 vToFetch[i - 1] = vToFetch[i]->
pprev;
2172 if (pindex->nStatus.hasData() ||
2173 (activeChain && activeChain->
Contains(pindex))) {
2175 state->pindexLastCommonBlock = pindex;
2177 }
else if (!IsBlockRequested(pindex->
GetBlockHash())) {
2179 if (pindex->
nHeight > nWindowEnd) {
2181 if (vBlocks.size() == 0 && waitingfor != peer.m_id) {
2185 *nodeStaller = waitingfor;
2190 vBlocks.push_back(pindex);
2191 if (vBlocks.size() ==
count) {
2194 }
else if (waitingfor == -1) {
2206template <
class InvId>
2210 return !
node.HasPermission(
2223template <
class InvId>
2224static std::chrono::microseconds
2228 std::chrono::microseconds current_time,
bool preferred) {
2229 auto delay = std::chrono::microseconds{0};
2241 return current_time + delay;
2244void PeerManagerImpl::PushNodeVersion(
const Config &config,
CNode &pnode,
2246 uint64_t my_services{peer.m_our_services};
2247 const int64_t nTime{
count_seconds(GetTime<std::chrono::seconds>())};
2249 const int nNodeStartingHeight{m_best_height};
2260 const bool tx_relay{!RejectIncomingTxs(pnode)};
2268 nTime, your_services, addr_you, my_services,
2270 nNodeStartingHeight, tx_relay, extraEntropy));
2274 "send version message: version %d, blocks=%d, them=%s, "
2275 "txrelay=%d, peer=%d\n",
2280 "send version message: version %d, blocks=%d, "
2281 "txrelay=%d, peer=%d\n",
2286void PeerManagerImpl::AddTxAnnouncement(
2288 std::chrono::microseconds current_time) {
2296 const bool preferred = isPreferredDownloadPeer(
node);
2298 current_time, preferred);
2300 m_txrequest.ReceivedInv(
node.GetId(), txid, preferred, reqtime);
2303void PeerManagerImpl::AddProofAnnouncement(
2305 std::chrono::microseconds current_time,
bool preferred) {
2316 m_proofrequest.ReceivedInv(
node.GetId(), proofid, preferred, reqtime);
2319void PeerManagerImpl::UpdateLastBlockAnnounceTime(
NodeId node,
2320 int64_t time_in_seconds) {
2322 CNodeState *state = State(
node);
2324 state->m_last_block_announcement = time_in_seconds;
2328void PeerManagerImpl::InitializeNode(
const Config &config,
CNode &
node,
2333 m_node_states.emplace_hint(m_node_states.end(),
2334 std::piecewise_construct,
2335 std::forward_as_tuple(nodeid),
2336 std::forward_as_tuple(
node.IsInboundConn()));
2337 assert(m_txrequest.Count(nodeid) == 0);
2345 PeerRef peer = std::make_shared<Peer>(nodeid, our_services, !!m_avalanche);
2348 m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer);
2350 if (!
node.IsInboundConn()) {
2351 PushNodeVersion(config,
node, *peer);
2355void PeerManagerImpl::ReattemptInitialBroadcast(
CScheduler &scheduler) {
2358 for (
const TxId &txid : unbroadcast_txids) {
2360 if (m_mempool.
exists(txid)) {
2361 RelayTransaction(txid);
2372 auto unbroadcasted_proofids =
2376 auto it = unbroadcasted_proofids.begin();
2377 while (it != unbroadcasted_proofids.end()) {
2380 if (!pm.isBoundToPeer(*it)) {
2381 pm.removeUnbroadcastProof(*it);
2382 it = unbroadcasted_proofids.erase(it);
2389 return unbroadcasted_proofids;
2393 for (
const auto &proofid : unbroadcasted_proofids) {
2394 RelayProof(proofid);
2401 const auto reattemptBroadcastInterval =
2403 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2404 reattemptBroadcastInterval);
2407void PeerManagerImpl::UpdateAvalancheStatistics()
const {
2413void PeerManagerImpl::AvalanchePeriodicNetworking(
CScheduler &scheduler)
const {
2414 const auto now = GetTime<std::chrono::seconds>();
2415 std::vector<NodeId> avanode_ids;
2416 bool fQuorumEstablished;
2417 bool fShouldRequestMoreNodes;
2427 fShouldRequestMoreNodes =
2435 avanode_ids.push_back(pnode->GetId());
2438 PeerRef peer = GetPeerRef(pnode->
GetId());
2439 if (peer ==
nullptr) {
2443 if (peer->m_proof_relay &&
2444 now > (peer->m_proof_relay->lastSharedProofsUpdate.load() +
2446 peer->m_proof_relay->sharedProofs = {};
2450 if (avanode_ids.empty()) {
2458 for (
NodeId avanodeId : avanode_ids) {
2459 const bool sentGetavaaddr =
2462 m_connman.PushMessage(
2463 pavanode, CNetMsgMaker(pavanode->GetCommonVersion())
2464 .Make(NetMsgType::GETAVAADDR));
2465 PeerRef peer = GetPeerRef(avanodeId);
2466 WITH_LOCK(peer->m_addr_token_bucket_mutex,
2467 peer->m_addr_token_bucket +=
2468 m_opts.max_addr_to_send);
2476 if (sentGetavaaddr && fQuorumEstablished && !fShouldRequestMoreNodes) {
2491 avanode_ids.resize(std::min<size_t>(avanode_ids.size(), 3));
2494 for (
NodeId nodeid : avanode_ids) {
2497 PeerRef peer = GetPeerRef(nodeid);
2498 if (peer->m_proof_relay) {
2503 peer->m_proof_relay->compactproofs_requested =
true;
2513 const auto avalanchePeriodicNetworkingInterval =
2515 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2516 avalanchePeriodicNetworkingInterval);
2519void PeerManagerImpl::FinalizeNode(
const Config &config,
const CNode &
node) {
2529 PeerRef peer = RemovePeer(nodeid);
2532 m_peer_map.erase(nodeid);
2534 CNodeState *state = State(nodeid);
2535 assert(state !=
nullptr);
2537 if (state->fSyncStarted) {
2541 for (
const QueuedBlock &entry : state->vBlocksInFlight) {
2543 mapBlocksInFlight.equal_range(entry.pindex->GetBlockHash());
2544 while (range.first != range.second) {
2545 auto [node_id, list_it] = range.first->second;
2546 if (node_id != nodeid) {
2549 range.first = mapBlocksInFlight.erase(range.first);
2556 m_txrequest.DisconnectedPeer(nodeid);
2557 m_num_preferred_download_peers -= state->fPreferredDownload;
2558 m_peers_downloading_from -= (!state->vBlocksInFlight.empty());
2559 assert(m_peers_downloading_from >= 0);
2560 m_outbound_peers_with_protect_from_disconnect -=
2561 state->m_chain_sync.m_protect;
2562 assert(m_outbound_peers_with_protect_from_disconnect >= 0);
2564 m_node_states.erase(nodeid);
2566 if (m_node_states.empty()) {
2568 assert(mapBlocksInFlight.empty());
2569 assert(m_num_preferred_download_peers == 0);
2570 assert(m_peers_downloading_from == 0);
2571 assert(m_outbound_peers_with_protect_from_disconnect == 0);
2572 assert(m_txrequest.Size() == 0);
2574 return orphanage.Size();
2579 if (
node.fSuccessfullyConnected && !
node.IsBlockOnlyConn() &&
2580 !
node.IsInboundConn()) {
2587 LOCK(m_headers_presync_mutex);
2588 m_headers_presync_stats.erase(nodeid);
2591 WITH_LOCK(cs_proofrequest, m_proofrequest.DisconnectedPeer(nodeid));
2596PeerRef PeerManagerImpl::GetPeerRef(
NodeId id)
const {
2598 auto it = m_peer_map.find(
id);
2599 return it != m_peer_map.end() ? it->second :
nullptr;
2602PeerRef PeerManagerImpl::RemovePeer(
NodeId id) {
2605 auto it = m_peer_map.find(
id);
2606 if (it != m_peer_map.end()) {
2607 ret = std::move(it->second);
2608 m_peer_map.erase(it);
2613bool PeerManagerImpl::GetNodeStateStats(
NodeId nodeid,
2617 const CNodeState *state = State(nodeid);
2618 if (state ==
nullptr) {
2622 ? state->pindexBestKnownBlock->nHeight
2625 ? state->pindexLastCommonBlock->nHeight
2627 for (
const QueuedBlock &queue : state->vBlocksInFlight) {
2634 PeerRef peer = GetPeerRef(nodeid);
2635 if (peer ==
nullptr) {
2647 auto ping_wait{0us};
2648 if ((0 != peer->m_ping_nonce_sent) &&
2649 (0 != peer->m_ping_start.load().count())) {
2651 GetTime<std::chrono::microseconds>() - peer->m_ping_start.load();
2654 if (
auto tx_relay = peer->GetTxRelay()) {
2656 return tx_relay->m_relay_txs);
2668 LOCK(peer->m_headers_sync_mutex);
2669 if (peer->m_headers_sync) {
2677void PeerManagerImpl::AddToCompactExtraTransactions(
const CTransactionRef &tx) {
2678 if (m_opts.max_extra_txs <= 0) {
2682 if (!vExtraTxnForCompact.size()) {
2683 vExtraTxnForCompact.resize(m_opts.max_extra_txs);
2686 vExtraTxnForCompact[vExtraTxnForCompactIt] =
2687 std::make_pair(tx->GetHash(), tx);
2688 vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
2691void PeerManagerImpl::Misbehaving(Peer &peer,
const std::string &message) {
2692 LOCK(peer.m_misbehavior_mutex);
2694 const std::string message_prefixed =
2695 message.empty() ?
"" : (
": " + message);
2696 peer.m_should_discourage =
true;
2701void PeerManagerImpl::MaybePunishNodeForBlock(
NodeId nodeid,
2703 bool via_compact_block,
2704 const std::string &message) {
2705 PeerRef peer{GetPeerRef(nodeid)};
2716 if (!via_compact_block) {
2718 Misbehaving(*peer, message);
2725 CNodeState *node_state = State(nodeid);
2726 if (node_state ==
nullptr) {
2733 if (!via_compact_block && !node_state->m_is_inbound) {
2735 Misbehaving(*peer, message);
2745 Misbehaving(*peer, message);
2751 Misbehaving(*peer, message);
2757 if (message !=
"") {
2762void PeerManagerImpl::MaybePunishNodeForTx(
NodeId nodeid,
2764 const std::string &message) {
2765 PeerRef peer{GetPeerRef(nodeid)};
2772 Misbehaving(*peer, message);
2790 if (message !=
"") {
2795bool PeerManagerImpl::BlockRequestAllowed(
const CBlockIndex *pindex) {
2801 (m_chainman.m_best_header !=
nullptr) &&
2802 (m_chainman.m_best_header->GetBlockTime() - pindex->
GetBlockTime() <
2805 *m_chainman.m_best_header, *pindex, *m_chainman.m_best_header,
2809std::optional<std::string>
2810PeerManagerImpl::FetchBlock(
const Config &config,
NodeId peer_id,
2813 return "Loading blocks ...";
2819 CNodeState *state = State(peer_id);
2820 if (state ==
nullptr) {
2821 return "Peer does not exist";
2825 RemoveBlockRequest(block_index.
GetBlockHash(), std::nullopt);
2828 if (!BlockRequested(config, peer_id, block_index)) {
2829 return "Already requested from this peer";
2838 const CNetMsgMaker msgMaker(node->GetCommonVersion());
2839 this->m_connman.PushMessage(
2840 node, msgMaker.Make(NetMsgType::GETDATA, invs));
2843 return "Node not fully connected";
2848 return std::nullopt;
2851std::unique_ptr<PeerManager>
2855 return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman,
2864 : m_rng{opts.deterministic_rng},
2866 m_chainparams(chainman.GetParams()), m_connman(connman),
2867 m_addrman(addrman), m_banman(banman), m_chainman(chainman),
2868 m_mempool(pool), m_avalanche(
avalanche), m_opts{opts} {}
2870void PeerManagerImpl::StartScheduledTasks(
CScheduler &scheduler) {
2877 "peer eviction timer should be less than stale tip check timer");
2880 this->CheckForStaleTipAndEvictPeers();
2886 const auto reattemptBroadcastInterval =
2888 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2889 reattemptBroadcastInterval);
2894 UpdateAvalancheStatistics();
2900 const auto avalanchePeriodicNetworkingInterval =
2902 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2903 avalanchePeriodicNetworkingInterval);
2912void PeerManagerImpl::BlockConnected(
2913 ChainstateRole role,
const std::shared_ptr<const CBlock> &pblock,
2917 m_last_tip_update = GetTime<std::chrono::seconds>();
2921 auto stalling_timeout = m_block_stalling_timeout.load();
2924 const auto new_timeout =
2925 std::max(std::chrono::duration_cast<std::chrono::seconds>(
2926 stalling_timeout * 0.85),
2928 if (m_block_stalling_timeout.compare_exchange_strong(stalling_timeout,
2948 LOCK(m_recent_confirmed_transactions_mutex);
2950 m_recent_confirmed_transactions.insert(ptx->GetId());
2955 for (
const auto &ptx : pblock->vtx) {
2956 m_txrequest.ForgetInvId(ptx->GetId());
2961void PeerManagerImpl::BlockDisconnected(
2962 const std::shared_ptr<const CBlock> &block,
const CBlockIndex *pindex) {
2971 LOCK(m_recent_confirmed_transactions_mutex);
2972 m_recent_confirmed_transactions.reset();
2979void PeerManagerImpl::NewPoWValidBlock(
2980 const CBlockIndex *pindex,
const std::shared_ptr<const CBlock> &pblock) {
2981 std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock =
2982 std::make_shared<const CBlockHeaderAndShortTxIDs>(*pblock);
2987 if (pindex->
nHeight <= m_highest_fast_announce) {
2990 m_highest_fast_announce = pindex->
nHeight;
2993 const std::shared_future<CSerializedNetMsg> lazy_ser{
2994 std::async(std::launch::deferred, [&] {
2999 auto most_recent_block_txs =
3000 std::make_unique<std::map<TxId, CTransactionRef>>();
3001 for (
const auto &tx : pblock->vtx) {
3002 most_recent_block_txs->emplace(tx->GetId(), tx);
3005 LOCK(m_most_recent_block_mutex);
3006 m_most_recent_block_hash = hashBlock;
3007 m_most_recent_block = pblock;
3008 m_most_recent_compact_block = pcmpctblock;
3009 m_most_recent_block_txs = std::move(most_recent_block_txs);
3013 [
this, pindex, &lazy_ser, &hashBlock](
CNode *pnode)
3021 ProcessBlockAvailability(pnode->
GetId());
3022 CNodeState &state = *State(pnode->
GetId());
3026 if (state.m_requested_hb_cmpctblocks &&
3027 !PeerHasHeader(&state, pindex) &&
3028 PeerHasHeader(&state, pindex->
pprev)) {
3030 "%s sending header-and-ids %s to peer=%d\n",
3031 "PeerManager::NewPoWValidBlock",
3032 hashBlock.ToString(), pnode->
GetId());
3035 m_connman.
PushMessage(pnode, ser_cmpctblock.Copy());
3036 state.pindexBestHeaderSent = pindex;
3045void PeerManagerImpl::UpdatedBlockTip(
const CBlockIndex *pindexNew,
3047 bool fInitialDownload) {
3048 SetBestHeight(pindexNew->
nHeight);
3052 if (fInitialDownload) {
3057 std::vector<BlockHash> vHashes;
3059 while (pindexToAnnounce != pindexFork) {
3061 pindexToAnnounce = pindexToAnnounce->
pprev;
3071 for (
auto &it : m_peer_map) {
3072 Peer &peer = *it.second;
3073 LOCK(peer.m_block_inv_mutex);
3075 peer.m_blocks_for_headers_relay.push_back(hash);
3087void PeerManagerImpl::BlockChecked(
const CBlock &block,
3092 std::map<BlockHash, std::pair<NodeId, bool>>::iterator it =
3093 mapBlockSource.find(hash);
3097 if (state.
IsInvalid() && it != mapBlockSource.end() &&
3098 State(it->second.first)) {
3099 MaybePunishNodeForBlock(it->second.first, state,
3100 !it->second.second);
3109 mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
3110 if (it != mapBlockSource.end()) {
3111 MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
3115 if (it != mapBlockSource.end()) {
3116 mapBlockSource.erase(it);
3125bool PeerManagerImpl::AlreadyHaveTx(
const TxId &txid,
3126 bool include_reconsiderable) {
3128 hashRecentRejectsChainTip) {
3133 hashRecentRejectsChainTip =
3135 m_recent_rejects.reset();
3136 m_recent_rejects_package_reconsiderable.reset();
3140 return orphanage.HaveTx(txid);
3146 return conflicting.HaveTx(txid);
3151 if (include_reconsiderable &&
3152 m_recent_rejects_package_reconsiderable.contains(txid)) {
3157 LOCK(m_recent_confirmed_transactions_mutex);
3158 if (m_recent_confirmed_transactions.contains(txid)) {
3163 return m_recent_rejects.contains(txid) || m_mempool.
exists(txid);
3166bool PeerManagerImpl::AlreadyHaveBlock(
const BlockHash &block_hash) {
3171 if (!
Assume(m_avalanche)) {
3176 if (localProof && localProof->getId() == proofid) {
3185void PeerManagerImpl::SendPings() {
3187 for (
auto &it : m_peer_map) {
3188 it.second->m_ping_queued =
true;
3192void PeerManagerImpl::RelayTransaction(
const TxId &txid) {
3194 for (
auto &it : m_peer_map) {
3195 Peer &peer = *it.second;
3196 auto tx_relay = peer.GetTxRelay();
3200 LOCK(tx_relay->m_tx_inventory_mutex);
3206 if (tx_relay->m_next_inv_send_time == 0s) {
3210 if (!tx_relay->m_tx_inventory_known_filter.contains(txid) ||
3211 tx_relay->m_avalanche_stalled_txids.count(txid) > 0) {
3212 tx_relay->m_tx_inventory_to_send.insert(txid);
3219 for (
auto &it : m_peer_map) {
3220 Peer &peer = *it.second;
3222 if (!peer.m_proof_relay) {
3225 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
3226 if (!peer.m_proof_relay->m_proof_inventory_known_filter.contains(
3228 peer.m_proof_relay->m_proof_inventory_to_send.insert(proofid);
3233void PeerManagerImpl::RelayAddress(
NodeId originator,
const CAddress &addr,
3249 const auto current_time{GetTime<std::chrono::seconds>()};
3252 const uint64_t time_addr{
3253 (
static_cast<uint64_t
>(
count_seconds(current_time)) + hash_addr) /
3263 unsigned int nRelayNodes = (fReachable || (hasher.Finalize() & 1)) ? 2 : 1;
3264 std::array<std::pair<uint64_t, Peer *>, 2> best{
3265 {{0,
nullptr}, {0,
nullptr}}};
3266 assert(nRelayNodes <= best.size());
3270 for (
auto &[
id, peer] : m_peer_map) {
3271 if (peer->m_addr_relay_enabled &&
id != originator &&
3272 IsAddrCompatible(*peer, addr)) {
3274 for (
unsigned int i = 0; i < nRelayNodes; i++) {
3275 if (hashKey > best[i].first) {
3276 std::copy(best.begin() + i, best.begin() + nRelayNodes - 1,
3277 best.begin() + i + 1);
3278 best[i] = std::make_pair(hashKey, peer.get());
3285 for (
unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
3286 PushAddress(*best[i].second, addr);
3290void PeerManagerImpl::ProcessGetBlockData(
const Config &config,
CNode &pfrom,
3291 Peer &peer,
const CInv &inv) {
3294 std::shared_ptr<const CBlock> a_recent_block;
3295 std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
3297 LOCK(m_most_recent_block_mutex);
3298 a_recent_block = m_most_recent_block;
3299 a_recent_compact_block = m_most_recent_compact_block;
3302 bool need_activate_chain =
false;
3316 need_activate_chain =
true;
3320 if (need_activate_chain) {
3323 state, a_recent_block, m_avalanche)) {
3332 bool can_direct_fetch{
false};
3340 if (!BlockRequestAllowed(pindex)) {
3342 "%s: ignoring request from peer=%i for old "
3343 "block that isn't in the main chain\n",
3344 __func__, pfrom.
GetId());
3350 (((m_chainman.m_best_header !=
nullptr) &&
3351 (m_chainman.m_best_header->GetBlockTime() -
3359 "historical block serving limit reached, disconnect peer=%d\n",
3372 (tip->nHeight - pindex->
nHeight >
3375 "Ignore block request below NODE_NETWORK_LIMITED "
3376 "threshold, disconnect peer=%d\n",
3386 if (!pindex->nStatus.hasData()) {
3389 can_direct_fetch = CanDirectFetch();
3393 std::shared_ptr<const CBlock> pblock;
3394 auto handle_block_read_error = [&]() {
3396 return m_chainman.
m_blockman.IsBlockPruned(*pindex))) {
3398 "Block was pruned before it could be read, disconnect "
3402 LogError(
"Cannot load block from disk, disconnect peer=%d\n",
3408 if (a_recent_block && a_recent_block->GetHash() == pindex->
GetBlockHash()) {
3409 pblock = a_recent_block;
3413 std::vector<uint8_t> block_data;
3416 handle_block_read_error();
3424 std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
3426 handle_block_read_error();
3429 pblock = pblockRead;
3436 bool sendMerkleBlock =
false;
3438 if (
auto tx_relay = peer.GetTxRelay()) {
3439 LOCK(tx_relay->m_bloom_filter_mutex);
3440 if (tx_relay->m_bloom_filter) {
3441 sendMerkleBlock =
true;
3446 if (sendMerkleBlock) {
3459 typedef std::pair<size_t, uint256> PairType;
3463 *pblock->vtx[pair.first]));
3474 if (can_direct_fetch &&
3476 if (a_recent_compact_block &&
3477 a_recent_compact_block->header.GetHash() ==
3481 *a_recent_compact_block));
3485 msgMaker.Make(nSendFlags,
3498 LOCK(peer.m_block_inv_mutex);
3501 if (hash == peer.m_continuation_block) {
3505 std::vector<CInv> vInv;
3508 peer.m_continuation_block =
BlockHash();
3514PeerManagerImpl::FindTxForGetData(
const Peer &peer,
const TxId &txid,
3515 const std::chrono::seconds mempool_req,
3516 const std::chrono::seconds now) {
3517 auto txinfo = m_mempool.
info(txid);
3522 if ((mempool_req.count() && txinfo.m_time <= mempool_req) ||
3524 return std::move(txinfo.tx);
3533 Assume(peer.GetTxRelay())->m_recently_announced_invs.contains(txid);
3534 if (recent && txinfo.tx) {
3535 return std::move(txinfo.tx);
3540 LOCK(m_most_recent_block_mutex);
3541 if (m_most_recent_block_txs !=
nullptr) {
3542 auto it = m_most_recent_block_txs->find(txid);
3543 if (it != m_most_recent_block_txs->end()) {
3556PeerManagerImpl::FindProofForGetData(
const Peer &peer,
3558 const std::chrono::seconds now) {
3561 bool send_unconditionally =
3587 if (send_unconditionally) {
3592 if (peer.m_proof_relay->m_recently_announced_proofs.contains(proofid)) {
3599void PeerManagerImpl::ProcessGetData(
3601 const std::atomic<bool> &interruptMsgProc) {
3604 auto tx_relay = peer.GetTxRelay();
3606 std::deque<CInv>::iterator it = peer.m_getdata_requests.begin();
3607 std::vector<CInv> vNotFound;
3610 const auto now{GetTime<std::chrono::seconds>()};
3612 const auto mempool_req = tx_relay !=
nullptr
3613 ? tx_relay->m_last_mempool_req.load()
3614 : std::chrono::seconds::min();
3619 while (it != peer.m_getdata_requests.end()) {
3620 if (interruptMsgProc) {
3629 const CInv &inv = *it;
3631 if (it->IsMsgProof()) {
3633 vNotFound.push_back(inv);
3638 auto proof = FindProofForGetData(peer, proofid, now);
3646 vNotFound.push_back(inv);
3653 if (it->IsMsgTx()) {
3654 if (tx_relay ==
nullptr) {
3670 std::vector<TxId> parent_ids_to_add;
3673 auto txiter = m_mempool.
GetIter(tx->GetId());
3675 auto &pentry = *txiter;
3677 (*pentry)->GetMemPoolParentsConst();
3678 parent_ids_to_add.reserve(parents.size());
3679 for (
const auto &parent : parents) {
3680 if (parent.get()->GetTime() >
3682 parent_ids_to_add.push_back(
3683 parent.get()->GetTx().GetId());
3688 for (
const TxId &parent_txid : parent_ids_to_add) {
3691 if (
WITH_LOCK(tx_relay->m_tx_inventory_mutex,
3692 return !tx_relay->m_tx_inventory_known_filter
3693 .contains(parent_txid))) {
3694 tx_relay->m_recently_announced_invs.insert(parent_txid);
3698 vNotFound.push_back(inv);
3711 if (it != peer.m_getdata_requests.end() && !pfrom.
fPauseSend) {
3712 const CInv &inv = *it++;
3714 ProcessGetBlockData(config, pfrom, peer, inv);
3720 peer.m_getdata_requests.erase(peer.m_getdata_requests.begin(), it);
3722 if (!vNotFound.empty()) {
3740void PeerManagerImpl::SendBlockTransactions(
3744 for (
size_t i = 0; i < req.
indices.size(); i++) {
3746 Misbehaving(peer,
"getblocktxn with out-of-bounds tx indices");
3758bool PeerManagerImpl::CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
3763 Misbehaving(peer,
"header with invalid proof of work");
3768 if (!CheckHeadersAreContinuous(headers)) {
3769 Misbehaving(peer,
"non-continuous headers sequence");
3782 near_chaintip_work =
3795void PeerManagerImpl::HandleUnconnectingHeaders(
3796 CNode &pfrom, Peer &peer,
const std::vector<CBlockHeader> &headers) {
3802 if (MaybeSendGetHeaders(pfrom,
GetLocator(best_header), peer)) {
3805 "received header %s: missing prev block %s, sending getheaders "
3806 "(%d) to end (peer=%d)\n",
3808 headers[0].hashPrevBlock.ToString(), best_header->nHeight,
3816 UpdateBlockAvailability(pfrom.
GetId(), headers.back().GetHash()));
3819bool PeerManagerImpl::CheckHeadersAreContinuous(
3820 const std::vector<CBlockHeader> &headers)
const {
3823 if (!hashLastBlock.
IsNull() && header.hashPrevBlock != hashLastBlock) {
3826 hashLastBlock = header.GetHash();
3831bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(
3832 Peer &peer,
CNode &pfrom, std::vector<CBlockHeader> &headers) {
3833 if (peer.m_headers_sync) {
3834 auto result = peer.m_headers_sync->ProcessNextHeaders(
3838 if (result.success) {
3839 peer.m_last_getheaders_timestamp = {};
3841 if (result.request_more) {
3842 auto locator = peer.m_headers_sync->NextHeadersRequestLocator();
3845 Assume(!locator.vHave.empty());
3849 if (!locator.vHave.empty()) {
3852 bool sent_getheaders =
3853 MaybeSendGetHeaders(pfrom, locator, peer);
3856 locator.vHave.front().ToString(), pfrom.
GetId());
3861 peer.m_headers_sync.reset(
nullptr);
3866 LOCK(m_headers_presync_mutex);
3867 m_headers_presync_stats.erase(pfrom.
GetId());
3870 HeadersPresyncStats stats;
3871 stats.first = peer.m_headers_sync->GetPresyncWork();
3872 if (peer.m_headers_sync->GetState() ==
3874 stats.second = {peer.m_headers_sync->GetPresyncHeight(),
3875 peer.m_headers_sync->GetPresyncTime()};
3879 LOCK(m_headers_presync_mutex);
3880 m_headers_presync_stats[pfrom.
GetId()] = stats;
3882 m_headers_presync_stats.find(m_headers_presync_bestpeer);
3883 bool best_updated =
false;
3884 if (best_it == m_headers_presync_stats.end()) {
3889 const HeadersPresyncStats *stat_best{
nullptr};
3890 for (
const auto &[_peer, _stat] : m_headers_presync_stats) {
3891 if (!stat_best || _stat > *stat_best) {
3896 m_headers_presync_bestpeer = peer_best;
3897 best_updated = (peer_best == pfrom.
GetId());
3898 }
else if (best_it->first == pfrom.
GetId() ||
3899 stats > best_it->second) {
3902 m_headers_presync_bestpeer = pfrom.
GetId();
3903 best_updated =
true;
3905 if (best_updated && stats.second.has_value()) {
3908 m_headers_presync_should_signal =
true;
3912 if (result.success) {
3915 headers.swap(result.pow_validated_headers);
3918 return result.success;
3926bool PeerManagerImpl::TryLowWorkHeadersSync(
3928 std::vector<CBlockHeader> &headers) {
3935 arith_uint256 minimum_chain_work = GetAntiDoSWorkThreshold();
3939 if (total_work < minimum_chain_work) {
3953 LOCK(peer.m_headers_sync_mutex);
3954 peer.m_headers_sync.reset(
3956 chain_start_header, minimum_chain_work));
3961 (void)IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
3964 "Ignoring low-work chain (height=%u) from peer=%d\n",
3965 chain_start_header->
nHeight + headers.size(),
3977bool PeerManagerImpl::IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header) {
3978 return header !=
nullptr &&
3979 ((m_chainman.m_best_header !=
nullptr &&
3981 m_chainman.m_best_header->GetAncestor(header->
nHeight)) ||
3985bool PeerManagerImpl::MaybeSendGetHeaders(
CNode &pfrom,
3994 if (current_time - peer.m_last_getheaders_timestamp >
3998 peer.m_last_getheaders_timestamp = current_time;
4010void PeerManagerImpl::HeadersDirectFetchBlocks(
const Config &config,
4016 CNodeState *nodestate = State(pfrom.
GetId());
4020 std::vector<const CBlockIndex *> vToFetch;
4026 if (!pindexWalk->nStatus.hasData() &&
4029 vToFetch.push_back(pindexWalk);
4031 pindexWalk = pindexWalk->
pprev;
4042 std::vector<CInv> vGetData;
4045 if (nodestate->vBlocksInFlight.size() >=
4051 BlockRequested(config, pfrom.
GetId(), *pindex);
4055 if (vGetData.size() > 1) {
4057 "Downloading blocks toward %s (%d) via headers "
4062 if (vGetData.size() > 0) {
4063 if (!m_opts.ignore_incoming_txs &&
4064 nodestate->m_provides_cmpctblocks && vGetData.size() == 1 &&
4065 mapBlocksInFlight.size() == 1 &&
4083void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(
4085 bool received_new_header,
bool may_have_more_headers) {
4088 CNodeState *nodestate = State(pfrom.
GetId());
4096 if (received_new_header &&
4098 nodestate->m_last_block_announcement =
GetTime();
4106 if (nodestate->pindexBestKnownBlock &&
4107 nodestate->pindexBestKnownBlock->nChainWork <
4118 LogPrintf(
"Disconnecting outbound peer %d -- headers "
4119 "chain has insufficient work\n",
4133 nodestate->pindexBestKnownBlock !=
nullptr) {
4134 if (m_outbound_peers_with_protect_from_disconnect <
4136 nodestate->pindexBestKnownBlock->nChainWork >=
4138 !nodestate->m_chain_sync.m_protect) {
4141 nodestate->m_chain_sync.m_protect =
true;
4142 ++m_outbound_peers_with_protect_from_disconnect;
4147void PeerManagerImpl::ProcessHeadersMessage(
const Config &config,
CNode &pfrom,
4149 std::vector<CBlockHeader> &&headers,
4150 bool via_compact_block) {
4151 size_t nCount = headers.size();
4159 LOCK(peer.m_headers_sync_mutex);
4160 if (peer.m_headers_sync) {
4161 peer.m_headers_sync.reset(
nullptr);
4162 LOCK(m_headers_presync_mutex);
4163 m_headers_presync_stats.erase(pfrom.
GetId());
4168 peer.m_last_getheaders_timestamp = {};
4176 if (!CheckHeadersPoW(headers, m_chainparams.
GetConsensus(), peer)) {
4191 bool already_validated_work =
false;
4194 bool have_headers_sync =
false;
4196 LOCK(peer.m_headers_sync_mutex);
4198 already_validated_work =
4199 IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
4211 if (headers.empty()) {
4215 have_headers_sync = !!peer.m_headers_sync;
4221 headers[0].hashPrevBlock))};
4222 bool headers_connect_blockindex{chain_start_header !=
nullptr};
4224 if (!headers_connect_blockindex) {
4228 HandleUnconnectingHeaders(pfrom, peer, headers);
4236 peer.m_last_getheaders_timestamp = {};
4245 last_received_header =
4247 if (IsAncestorOfBestHeaderOrTip(last_received_header)) {
4248 already_validated_work =
true;
4256 already_validated_work =
true;
4262 if (!already_validated_work &&
4263 TryLowWorkHeadersSync(peer, pfrom, chain_start_header, headers)) {
4275 bool received_new_header{last_received_header ==
nullptr};
4280 state, &pindexLast)) {
4282 MaybePunishNodeForBlock(pfrom.
GetId(), state, via_compact_block,
4283 "invalid header received");
4293 if (MaybeSendGetHeaders(pfrom,
GetLocator(pindexLast), peer)) {
4296 "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
4297 pindexLast->
nHeight, pfrom.
GetId(), peer.m_starting_height);
4301 UpdatePeerStateForReceivedHeaders(pfrom, peer, *pindexLast,
4302 received_new_header,
4306 HeadersDirectFetchBlocks(config, pfrom, *pindexLast);
4309void PeerManagerImpl::ProcessInvalidTx(
NodeId nodeid,
4312 bool maybe_add_extra_compact_tx) {
4317 const TxId &txid = ptx->GetId();
4337 m_recent_rejects_package_reconsiderable.insert(txid);
4339 m_recent_rejects.insert(txid);
4341 m_txrequest.ForgetInvId(txid);
4344 AddToCompactExtraTransactions(ptx);
4347 MaybePunishNodeForTx(nodeid, state);
4353 return orphanage.EraseTx(txid);
4367 m_txrequest.ForgetInvId(tx->GetId());
4373 orphanage.
EraseTx(tx->GetId());
4378 "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
4379 nodeid, tx->GetId().ToString(), m_mempool.
size(),
4382 RelayTransaction(tx->GetId());
4385void PeerManagerImpl::ProcessPackageResult(
4386 const PackageToValidate &package_to_validate,
4392 const auto &
package = package_to_validate.m_txns;
4393 const auto &senders = package_to_validate.m_senders;
4396 m_recent_rejects_package_reconsiderable.insert(
GetPackageHash(package));
4400 if (!
Assume(package.size() == 2)) {
4406 auto package_iter = package.rbegin();
4407 auto senders_iter = senders.rbegin();
4408 while (package_iter != package.rend()) {
4409 const auto &tx = *package_iter;
4410 const NodeId nodeid = *senders_iter;
4411 const auto it_result{package_result.
m_tx_results.find(tx->GetId())};
4415 const auto &tx_result = it_result->second;
4416 switch (tx_result.m_result_type) {
4418 ProcessValidTx(nodeid, tx);
4428 ProcessInvalidTx(nodeid, tx, tx_result.m_state,
4445std::optional<PeerManagerImpl::PackageToValidate>
4451 const auto &parent_txid{ptx->GetId()};
4453 Assume(m_recent_rejects_package_reconsiderable.contains(parent_txid));
4459 const auto cpfp_candidates_same_peer{
4465 for (
const auto &child : cpfp_candidates_same_peer) {
4466 Package maybe_cpfp_package{ptx, child};
4467 if (!m_recent_rejects_package_reconsiderable.contains(
4469 return PeerManagerImpl::PackageToValidate{ptx, child, nodeid,
4483 const auto cpfp_candidates_different_peer{
4493 std::vector<size_t> tx_indices(cpfp_candidates_different_peer.size());
4494 std::iota(tx_indices.begin(), tx_indices.end(), 0);
4495 Shuffle(tx_indices.begin(), tx_indices.end(), m_rng);
4497 for (
const auto index : tx_indices) {
4500 const auto [child_tx, child_sender] =
4501 cpfp_candidates_different_peer.at(index);
4502 Package maybe_cpfp_package{ptx, child_tx};
4503 if (!m_recent_rejects_package_reconsiderable.contains(
4505 return PeerManagerImpl::PackageToValidate{ptx, child_tx, nodeid,
4509 return std::nullopt;
4512bool PeerManagerImpl::ProcessOrphanTx(
const Config &config, Peer &peer) {
4518 return orphanage.GetTxToReconsider(peer.m_id);
4523 const TxId &orphanTxId = porphanTx->GetId();
4528 ProcessValidTx(peer.m_id, porphanTx);
4534 " invalid orphan tx %s from peer=%d. %s\n",
4541 ProcessInvalidTx(peer.m_id, porphanTx, state,
4552bool PeerManagerImpl::PrepareBlockFilterRequest(
4554 const BlockHash &stop_hash, uint32_t max_height_diff,
4556 const bool supported_filter_type =
4559 if (!supported_filter_type) {
4561 "peer %d requested unsupported block filter type: %d\n",
4562 node.GetId(),
static_cast<uint8_t
>(filter_type));
4563 node.fDisconnect =
true;
4573 if (!stop_index || !BlockRequestAllowed(stop_index)) {
4576 node.fDisconnect =
true;
4581 uint32_t stop_height = stop_index->
nHeight;
4582 if (start_height > stop_height) {
4585 "peer %d sent invalid getcfilters/getcfheaders with "
4587 "start height %d and stop height %d\n",
4588 node.GetId(), start_height, stop_height);
4589 node.fDisconnect =
true;
4592 if (stop_height - start_height >= max_height_diff) {
4594 "peer %d requested too many cfilters/cfheaders: %d / %d\n",
4595 node.GetId(), stop_height - start_height + 1, max_height_diff);
4596 node.fDisconnect =
true;
4601 if (!filter_index) {
4610void PeerManagerImpl::ProcessGetCFilters(
CNode &
node, Peer &peer,
4612 uint8_t filter_type_ser;
4613 uint32_t start_height;
4616 vRecv >> filter_type_ser >> start_height >> stop_hash;
4623 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4629 std::vector<BlockFilter> filters;
4632 "Failed to find block filter in index: filter_type=%s, "
4633 "start_height=%d, stop_hash=%s\n",
4639 for (
const auto &filter : filters) {
4646void PeerManagerImpl::ProcessGetCFHeaders(
CNode &
node, Peer &peer,
4648 uint8_t filter_type_ser;
4649 uint32_t start_height;
4652 vRecv >> filter_type_ser >> start_height >> stop_hash;
4659 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4666 if (start_height > 0) {
4668 stop_index->
GetAncestor(
static_cast<int>(start_height - 1));
4671 "Failed to find block filter header in index: "
4672 "filter_type=%s, block_hash=%s\n",
4679 std::vector<uint256> filter_hashes;
4683 "Failed to find block filter hashes in index: filter_type=%s, "
4684 "start_height=%d, stop_hash=%s\n",
4693 stop_index->
GetBlockHash(), prev_header, filter_hashes);
4697void PeerManagerImpl::ProcessGetCFCheckPt(
CNode &
node, Peer &peer,
4699 uint8_t filter_type_ser;
4702 vRecv >> filter_type_ser >> stop_hash;
4709 if (!PrepareBlockFilterRequest(
4710 node, peer, filter_type, 0, stop_hash,
4711 std::numeric_limits<uint32_t>::max(),
4712 stop_index, filter_index)) {
4720 for (
int i = headers.size() - 1; i >= 0; i--) {
4726 "Failed to find block filter header in index: "
4727 "filter_type=%s, block_hash=%s\n",
4752PeerManagerImpl::GetAvalancheVoteForBlock(
const BlockHash &hash)
const {
4763 if (pindex->nStatus.isInvalid()) {
4768 if (pindex->nStatus.isOnParkedChain()) {
4776 if (pindex == pindexFork) {
4781 if (pindexFork != pindexTip) {
4786 if (!pindex->nStatus.hasData()) {
4797 const TxId &
id)
const {
4799 if (
WITH_LOCK(m_recent_confirmed_transactions_mutex,
4800 return m_recent_confirmed_transactions.contains(
id))) {
4809 if (m_recent_rejects.contains(
id)) {
4821 if (
auto iter = m_mempool.
GetIter(
id)) {
4822 mempool_tx = (**iter)->GetSharedTx();
4827 return conflicting.HaveTx(id);
4834 return orphanage.HaveTx(id);
4900 const std::shared_ptr<const CBlock> &block,
4901 bool force_processing,
4902 bool min_pow_checked) {
4903 bool new_block{
false};
4905 &new_block, m_avalanche);
4907 node.m_last_block_time = GetTime<std::chrono::seconds>();
4912 RemoveBlockRequest(block->GetHash(), std::nullopt);
4915 mapBlockSource.erase(block->GetHash());
4919void PeerManagerImpl::ProcessMessage(
4920 const Config &config,
CNode &pfrom,
const std::string &msg_type,
4921 CDataStream &vRecv,
const std::chrono::microseconds time_received,
4922 const std::atomic<bool> &interruptMsgProc) {
4928 PeerRef peer = GetPeerRef(pfrom.
GetId());
4929 if (peer ==
nullptr) {
4935 "Avalanche is not initialized, ignoring %s message\n",
4950 uint64_t nNonce = 1;
4953 std::string cleanSubVer;
4954 int starting_height = -1;
4956 uint64_t nExtraEntropy = 1;
4958 vRecv >> nVersion >> Using<CustomUintFormatter<8>>(nServices) >> nTime;
4971 "peer=%d does not offer the expected services "
4972 "(%08x offered, %08x expected); disconnecting\n",
4973 pfrom.
GetId(), nServices,
4983 "peer=%d does not offer the avalanche service; disconnecting\n",
4992 "peer=%d using obsolete version %i; disconnecting\n",
4993 pfrom.
GetId(), nVersion);
4998 if (!vRecv.
empty()) {
5007 if (!vRecv.
empty()) {
5008 std::string strSubVer;
5012 if (!vRecv.
empty()) {
5013 vRecv >> starting_height;
5015 if (!vRecv.
empty()) {
5018 if (!vRecv.
empty()) {
5019 vRecv >> nExtraEntropy;
5023 LogPrintf(
"connected to self at %s, disconnecting\n",
5036 PushNodeVersion(config, pfrom, *peer);
5040 const int greatest_common_version =
5054 peer->m_their_services = nServices;
5058 pfrom.cleanSubVer = cleanSubVer;
5060 peer->m_starting_height = starting_height;
5068 (fRelay || (peer->m_our_services &
NODE_BLOOM))) {
5069 auto *
const tx_relay = peer->SetTxRelay();
5071 LOCK(tx_relay->m_bloom_filter_mutex);
5073 tx_relay->m_relay_txs = fRelay;
5086 CNodeState *state = State(pfrom.
GetId());
5087 state->fPreferredDownload =
5091 m_num_preferred_download_peers += state->fPreferredDownload;
5097 bool send_getaddr{
false};
5099 send_getaddr = SetupAddressRelay(pfrom, *peer);
5111 peer->m_getaddr_sent =
true;
5115 WITH_LOCK(peer->m_addr_token_bucket_mutex,
5116 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
5137 std::string remoteAddr;
5143 "receive version message: [%s] %s: version %d, blocks=%d, "
5144 "us=%s, txrelay=%d, peer=%d%s\n",
5146 peer->m_starting_height, addrMe.ToString(), fRelay,
5147 pfrom.
GetId(), remoteAddr);
5149 int64_t currentTime =
GetTime();
5150 int64_t nTimeOffset = nTime - currentTime;
5155 Misbehaving(*peer,
"Ignoring invalid timestamp in version message");
5165 "feeler connection completed peer=%d; disconnecting\n",
5174 Misbehaving(*peer,
"non-version message before version handshake");
5184 "ignoring redundant verack message from peer=%d\n",
5191 "New outbound peer connected: version: %d, blocks=%d, "
5193 pfrom.
nVersion.load(), peer->m_starting_height, pfrom.
GetId(),
5215 AddKnownProof(*peer, localProof->getId());
5219 peer->m_proof_relay->m_recently_announced_proofs.insert(
5220 localProof->getId());
5225 if (
auto tx_relay = peer->GetTxRelay()) {
5234 return tx_relay->m_tx_inventory_to_send.empty() &&
5235 tx_relay->m_next_inv_send_time == 0s));
5244 Misbehaving(*peer,
"non-verack message before version handshake");
5258 std::vector<CAddress> vAddr;
5262 if (!SetupAddressRelay(pfrom, *peer)) {
5268 if (vAddr.size() > m_opts.max_addr_to_send) {
5269 Misbehaving(*peer,
strprintf(
"%s message size = %u", msg_type,
5275 std::vector<CAddress> vAddrOk;
5276 const auto current_a_time{Now<NodeSeconds>()};
5279 const auto current_time = GetTime<std::chrono::microseconds>();
5281 LOCK(peer->m_addr_token_bucket_mutex);
5284 const auto time_diff =
5285 std::max(current_time - peer->m_addr_token_timestamp, 0us);
5286 const double increment =
5288 peer->m_addr_token_bucket =
5289 std::min<double>(peer->m_addr_token_bucket + increment,
5293 peer->m_addr_token_timestamp = current_time;
5295 const bool rate_limited =
5297 uint64_t num_proc = 0;
5298 uint64_t num_rate_limit = 0;
5299 Shuffle(vAddr.begin(), vAddr.end(), m_rng);
5301 if (interruptMsgProc) {
5306 LOCK(peer->m_addr_token_bucket_mutex);
5308 if (peer->m_addr_token_bucket < 1.0) {
5314 peer->m_addr_token_bucket -= 1.0;
5327 addr.
nTime > current_a_time + 10min) {
5328 addr.
nTime = current_a_time - 5 * 24h;
5330 AddAddressKnown(*peer, addr);
5339 if (addr.
nTime > current_a_time - 10min && !peer->m_getaddr_sent &&
5342 RelayAddress(pfrom.
GetId(), addr, fReachable);
5346 vAddrOk.push_back(addr);
5349 peer->m_addr_processed += num_proc;
5350 peer->m_addr_rate_limited += num_rate_limit;
5352 "Received addr: %u addresses (%u processed, %u rate-limited) "
5354 vAddr.size(), num_proc, num_rate_limit, pfrom.
GetId());
5356 m_addrman.
Add(vAddrOk, pfrom.
addr, 2h);
5357 if (vAddr.size() < 1000) {
5358 peer->m_getaddr_sent =
false;
5365 "addrfetch connection completed peer=%d; disconnecting\n",
5373 peer->m_wants_addrv2 =
true;
5378 peer->m_prefers_headers =
true;
5383 bool sendcmpct_hb{
false};
5384 uint64_t sendcmpct_version{0};
5385 vRecv >> sendcmpct_hb >> sendcmpct_version;
5392 CNodeState *nodestate = State(pfrom.
GetId());
5393 nodestate->m_provides_cmpctblocks =
true;
5394 nodestate->m_requested_hb_cmpctblocks = sendcmpct_hb;
5403 std::vector<CInv> vInv;
5406 Misbehaving(*peer,
strprintf(
"inv message size = %u", vInv.size()));
5410 const bool reject_tx_invs{RejectIncomingTxs(pfrom)};
5412 const auto current_time{GetTime<std::chrono::microseconds>()};
5413 std::optional<BlockHash> best_block;
5415 auto logInv = [&](
const CInv &inv,
bool fAlreadyHave) {
5417 fAlreadyHave ?
"have" :
"new", pfrom.
GetId());
5420 for (
CInv &inv : vInv) {
5421 if (interruptMsgProc) {
5433 const bool fAlreadyHave = AlreadyHaveBlock(
BlockHash(inv.
hash));
5434 logInv(inv, fAlreadyHave);
5437 UpdateBlockAvailability(pfrom.
GetId(), hash);
5439 !IsBlockRequested(hash)) {
5446 best_block = std::move(hash);
5457 const bool fAlreadyHave = AlreadyHaveProof(proofid);
5458 logInv(inv, fAlreadyHave);
5459 AddKnownProof(*peer, proofid);
5461 if (!fAlreadyHave && m_avalanche &&
5463 const bool preferred = isPreferredDownloadPeer(pfrom);
5465 LOCK(cs_proofrequest);
5466 AddProofAnnouncement(pfrom, proofid, current_time,
5475 const bool fAlreadyHave =
5476 AlreadyHaveTx(txid,
true);
5477 logInv(inv, fAlreadyHave);
5479 AddKnownTx(*peer, txid);
5480 if (reject_tx_invs) {
5482 "transaction (%s) inv sent in violation of "
5483 "protocol, disconnecting peer=%d\n",
5487 }
else if (!fAlreadyHave &&
5489 AddTxAnnouncement(pfrom, txid, current_time);
5496 "Unknown inv type \"%s\" received from peer=%d\n",
5513 if (state.fSyncStarted ||
5514 (!peer->m_inv_triggered_getheaders_before_sync &&
5515 *best_block != m_last_block_inv_triggering_headers_sync)) {
5516 if (MaybeSendGetHeaders(
5517 pfrom,
GetLocator(m_chainman.m_best_header), *peer)) {
5519 m_chainman.m_best_header->nHeight,
5520 best_block->ToString(), pfrom.
GetId());
5522 if (!state.fSyncStarted) {
5523 peer->m_inv_triggered_getheaders_before_sync =
true;
5527 m_last_block_inv_triggering_headers_sync = *best_block;
5536 std::vector<CInv> vInv;
5540 strprintf(
"getdata message size = %u", vInv.size()));
5545 vInv.size(), pfrom.
GetId());
5547 if (vInv.size() > 0) {
5553 LOCK(peer->m_getdata_requests_mutex);
5554 peer->m_getdata_requests.insert(peer->m_getdata_requests.end(),
5555 vInv.begin(), vInv.end());
5556 ProcessGetData(config, pfrom, *peer, interruptMsgProc);
5565 vRecv >> locator >> hashStop;
5569 "getblocks locator size %lld > %d, disconnect peer=%d\n",
5583 std::shared_ptr<const CBlock> a_recent_block;
5585 LOCK(m_most_recent_block_mutex);
5586 a_recent_block = m_most_recent_block;
5590 state, a_recent_block, m_avalanche)) {
5608 (pindex ? pindex->
nHeight : -1),
5611 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5620 const int nPrunedBlocksLikelyToHave =
5624 (!pindex->nStatus.hasData() ||
5626 nPrunedBlocksLikelyToHave)) {
5629 " getblocks stopping, pruned or too old block at %d %s\n",
5634 peer->m_block_inv_mutex,
5635 peer->m_blocks_for_inv_relay.push_back(pindex->
GetBlockHash()));
5636 if (--nLimit <= 0) {
5642 peer->m_continuation_block = pindex->GetBlockHash();
5654 std::shared_ptr<const CBlock> recent_block;
5656 LOCK(m_most_recent_block_mutex);
5657 if (m_most_recent_block_hash == req.
blockhash) {
5658 recent_block = m_most_recent_block;
5663 SendBlockTransactions(pfrom, *peer, *recent_block, req);
5673 if (!pindex || !pindex->nStatus.hasData()) {
5676 "Peer %d sent us a getblocktxn for a block we don't have\n",
5687 if (!block_pos.IsNull()) {
5696 SendBlockTransactions(pfrom, *peer, block, req);
5708 "Peer %d sent us a getblocktxn for a block > %i deep\n",
5713 WITH_LOCK(peer->m_getdata_requests_mutex,
5714 peer->m_getdata_requests.push_back(inv));
5723 vRecv >> locator >> hashStop;
5727 "getheaders locator size %lld > %d, disconnect peer=%d\n",
5736 "Ignoring getheaders from peer=%d while importing/reindexing\n",
5750 if (m_chainman.
ActiveTip() ==
nullptr ||
5755 "Ignoring getheaders from peer=%d because active chain "
5756 "has too little work; sending empty response\n",
5761 std::vector<CBlock>()));
5765 CNodeState *nodestate = State(pfrom.
GetId());
5774 if (!BlockRequestAllowed(pindex)) {
5776 "%s: ignoring request from peer=%i for old block "
5777 "header that isn't in the main chain\n",
5778 __func__, pfrom.
GetId());
5792 std::vector<CBlock> vHeaders;
5795 (pindex ? pindex->
nHeight : -1),
5798 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5800 if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) {
5817 nodestate->pindexBestHeaderSent =
5825 if (RejectIncomingTxs(pfrom)) {
5827 "transaction sent in violation of protocol peer=%d\n",
5843 const CTransaction &tx = *ptx;
5844 const TxId &txid = tx.GetId();
5845 AddKnownTx(*peer, txid);
5850 m_txrequest.ReceivedResponse(pfrom.
GetId(), txid);
5852 if (AlreadyHaveTx(txid,
true)) {
5858 if (!m_mempool.
exists(tx.GetId())) {
5860 "Not relaying non-mempool transaction %s from "
5861 "forcerelay peer=%d\n",
5862 tx.GetId().ToString(), pfrom.
GetId());
5864 LogPrintf(
"Force relaying tx %s from peer=%d\n",
5865 tx.GetId().ToString(), pfrom.
GetId());
5866 RelayTransaction(tx.GetId());
5870 if (m_recent_rejects_package_reconsiderable.contains(txid)) {
5878 "found tx %s in reconsiderable rejects, looking for "
5879 "child in orphanage\n",
5881 if (
auto package_to_validate{
5882 Find1P1CPackage(ptx, pfrom.
GetId())}) {
5885 package_to_validate->m_txns,
5888 "package evaluation for %s: %s (%s)\n",
5889 package_to_validate->ToString(),
5891 ?
"package accepted"
5892 :
"package rejected",
5894 ProcessPackageResult(package_to_validate.value(),
5923 ProcessValidTx(pfrom.
GetId(), ptx);
5929 bool fRejectedParents =
false;
5933 std::vector<TxId> unique_parents;
5934 unique_parents.reserve(tx.vin.size());
5935 for (
const CTxIn &txin : tx.vin) {
5938 unique_parents.push_back(txin.prevout.GetTxId());
5940 std::sort(unique_parents.begin(), unique_parents.end());
5941 unique_parents.erase(
5942 std::unique(unique_parents.begin(), unique_parents.end()),
5943 unique_parents.end());
5951 std::optional<TxId> rejected_parent_reconsiderable;
5952 for (
const TxId &parent_txid : unique_parents) {
5953 if (m_recent_rejects.contains(parent_txid)) {
5954 fRejectedParents =
true;
5958 if (m_recent_rejects_package_reconsiderable.contains(
5960 !m_mempool.
exists(parent_txid)) {
5965 if (rejected_parent_reconsiderable.has_value()) {
5966 fRejectedParents =
true;
5969 rejected_parent_reconsiderable = parent_txid;
5972 if (!fRejectedParents) {
5973 const auto current_time{
5974 GetTime<std::chrono::microseconds>()};
5976 for (
const TxId &parent_txid : unique_parents) {
5978 AddKnownTx(*peer, parent_txid);
5982 if (!AlreadyHaveTx(parent_txid,
5984 AddTxAnnouncement(pfrom, parent_txid, current_time);
5990 if (
unsigned int nEvicted =
5994 if (orphanage.AddTx(ptx,
5996 AddToCompactExtraTransactions(ptx);
5999 m_opts.max_orphan_txs, m_rng);
6002 "orphanage overflow, removed %u tx\n",
6008 m_txrequest.ForgetInvId(tx.GetId());
6012 "not keeping orphan with rejected parents %s\n",
6013 tx.GetId().ToString());
6016 m_recent_rejects.insert(tx.GetId());
6017 m_txrequest.ForgetInvId(tx.GetId());
6021 ProcessInvalidTx(pfrom.
GetId(), ptx, state,
6031 "tx %s failed but reconsiderable, looking for child in "
6034 if (
auto package_to_validate{
6035 Find1P1CPackage(ptx, pfrom.
GetId())}) {
6038 package_to_validate->m_txns,
false)};
6040 "package evaluation for %s: %s (%s)\n",
6041 package_to_validate->ToString(),
6043 ?
"package accepted"
6044 :
"package rejected",
6046 ProcessPackageResult(package_to_validate.value(),
6055 m_txrequest.ForgetInvId(tx.GetId());
6057 unsigned int nEvicted{0};
6064 m_opts.max_conflicting_txs, m_rng);
6069 "conflicting pool overflow, removed %u tx\n",
6082 "Unexpected cmpctblock message received from peer %d\n",
6089 vRecv >> cmpctblock;
6090 }
catch (std::ios_base::failure &e) {
6092 Misbehaving(*peer,
"cmpctblock-bad-indexes");
6096 bool received_new_header =
false;
6109 MaybeSendGetHeaders(
6110 pfrom,
GetLocator(m_chainman.m_best_header), *peer);
6116 GetAntiDoSWorkThreshold()) {
6120 "Ignoring low-work compact block from peer %d\n",
6126 received_new_header =
true;
6136 MaybePunishNodeForBlock(pfrom.
GetId(), state,
6138 "invalid header via cmpctblock");
6143 if (received_new_header) {
6144 LogInfo(
"Saw new cmpctblock header hash=%s peer=%d\n",
6145 blockhash.ToString(), pfrom.
GetId());
6152 bool fProcessBLOCKTXN =
false;
6158 bool fRevertToHeaderProcessing =
false;
6162 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6163 bool fBlockReconstructed =
false;
6171 CNodeState *nodestate = State(pfrom.
GetId());
6175 if (received_new_header &&
6178 nodestate->m_last_block_announcement =
GetTime();
6181 if (pindex->nStatus.hasData()) {
6188 size_t already_in_flight =
6189 std::distance(range_flight.first, range_flight.second);
6190 bool requested_block_from_this_peer{
false};
6194 bool first_in_flight =
6195 already_in_flight == 0 ||
6196 (range_flight.first->second.first == pfrom.
GetId());
6198 while (range_flight.first != range_flight.second) {
6199 if (range_flight.first->second.first == pfrom.
GetId()) {
6200 requested_block_from_this_peer =
true;
6203 range_flight.first++;
6212 if (requested_block_from_this_peer) {
6216 std::vector<CInv> vInv(1);
6226 if (!already_in_flight && !CanDirectFetch()) {
6234 nodestate->vBlocksInFlight.size() <
6236 requested_block_from_this_peer) {
6237 std::list<QueuedBlock>::iterator *queuedBlockIt =
nullptr;
6238 if (!BlockRequested(config, pfrom.
GetId(), *pindex,
6240 if (!(*queuedBlockIt)->partialBlock) {
6242 ->partialBlock.reset(
6249 "we were already syncing!\n");
6255 *(*queuedBlockIt)->partialBlock;
6257 partialBlock.
InitData(cmpctblock, vExtraTxnForCompact);
6263 Misbehaving(*peer,
"invalid compact block");
6266 if (first_in_flight) {
6269 std::vector<CInv> vInv(1);
6283 for (
size_t i = 0; i < cmpctblock.
BlockTxCount(); i++) {
6294 fProcessBLOCKTXN =
true;
6295 }
else if (first_in_flight) {
6304 IsBlockRequestedFromOutbound(blockhash) ||
6329 tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
6334 std::vector<CTransactionRef> dummy;
6335 status = tempBlock.FillBlock(*pblock, dummy);
6337 fBlockReconstructed =
true;
6341 if (requested_block_from_this_peer) {
6345 std::vector<CInv> vInv(1);
6353 fRevertToHeaderProcessing =
true;
6358 if (fProcessBLOCKTXN) {
6360 blockTxnMsg, time_received, interruptMsgProc);
6363 if (fRevertToHeaderProcessing) {
6369 return ProcessHeadersMessage(config, pfrom, *peer,
6374 if (fBlockReconstructed) {
6379 mapBlockSource.emplace(pblock->GetHash(),
6380 std::make_pair(pfrom.
GetId(),
false));
6391 ProcessBlock(config, pfrom, pblock,
true,
6400 RemoveBlockRequest(pblock->GetHash(), std::nullopt);
6410 "Unexpected blocktxn message received from peer %d\n",
6418 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6419 bool fBlockRead =
false;
6423 auto range_flight = mapBlocksInFlight.equal_range(resp.
blockhash);
6424 size_t already_in_flight =
6425 std::distance(range_flight.first, range_flight.second);
6426 bool requested_block_from_this_peer{
false};
6430 bool first_in_flight =
6431 already_in_flight == 0 ||
6432 (range_flight.first->second.first == pfrom.
GetId());
6434 while (range_flight.first != range_flight.second) {
6435 auto [node_id, block_it] = range_flight.first->second;
6436 if (node_id == pfrom.
GetId() && block_it->partialBlock) {
6437 requested_block_from_this_peer =
true;
6440 range_flight.first++;
6443 if (!requested_block_from_this_peer) {
6445 "Peer %d sent us block transactions for block "
6446 "we weren't expecting\n",
6452 *range_flight.first->second.second->partialBlock;
6460 "invalid compact block/non-matching block transactions");
6463 if (first_in_flight) {
6465 std::vector<CInv> invs;
6473 "Peer %d sent us a compact block but it failed to "
6474 "reconstruct, waiting on first download to complete\n",
6507 std::make_pair(pfrom.
GetId(),
false));
6518 ProcessBlock(config, pfrom, pblock,
true,
6528 "Unexpected headers message received from peer %d\n",
6533 std::vector<CBlockHeader> headers;
6540 strprintf(
"too-many-headers: headers message size = %u",
6544 headers.resize(nCount);
6545 for (
unsigned int n = 0; n < nCount; n++) {
6546 vRecv >> headers[n];
6551 ProcessHeadersMessage(config, pfrom, *peer, std::move(headers),
6557 if (m_headers_presync_should_signal.exchange(
false)) {
6558 HeadersPresyncStats stats;
6560 LOCK(m_headers_presync_mutex);
6562 m_headers_presync_stats.find(m_headers_presync_bestpeer);
6563 if (it != m_headers_presync_stats.end()) {
6569 stats.first, stats.second->first, stats.second->second);
6580 "Unexpected block message received from peer %d\n",
6585 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6589 pblock->GetHash().ToString(), pfrom.
GetId());
6594 pblock->hashPrevBlock))};
6598 "Received mutated block from peer=%d\n", peer->m_id);
6599 Misbehaving(*peer,
"mutated block");
6601 RemoveBlockRequest(pblock->GetHash(), peer->m_id));
6611 const BlockHash hash = pblock->GetHash();
6612 bool min_pow_checked =
false;
6617 forceProcessing = IsBlockRequested(hash);
6618 RemoveBlockRequest(hash, pfrom.
GetId());
6622 mapBlockSource.emplace(hash, std::make_pair(pfrom.
GetId(),
true));
6628 GetAntiDoSWorkThreshold()) {
6629 min_pow_checked =
true;
6632 ProcessBlock(config, pfrom, pblock, forceProcessing, min_pow_checked);
6642 if (pfrom.m_avalanche_pubkey.has_value()) {
6645 "Ignoring avahello from peer %d: already in our node set\n",
6651 vRecv >> delegation;
6658 if (!delegation.
verify(state, pubkey)) {
6659 Misbehaving(*peer,
"invalid-delegation");
6662 pfrom.m_avalanche_pubkey = std::move(pubkey);
6665 sighasher << delegation.
getId();
6673 if (!(*pfrom.m_avalanche_pubkey)
6674 .VerifySchnorr(sighasher.GetHash(),
sig)) {
6675 Misbehaving(*peer,
"invalid-avahello-signature");
6682 if (!AlreadyHaveProof(proofid)) {
6683 const bool preferred = isPreferredDownloadPeer(pfrom);
6684 LOCK(cs_proofrequest);
6685 AddProofAnnouncement(pfrom, proofid,
6686 GetTime<std::chrono::microseconds>(),
6705 WITH_LOCK(peer->m_addr_token_bucket_mutex,
6706 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
6711 peer->m_proof_relay->compactproofs_requested =
true;
6722 const auto now = Now<SteadyMilliseconds>();
6728 last_poll + std::chrono::milliseconds(m_opts.avalanche_cooldown)) {
6730 "Ignoring repeated avapoll from peer %d: cooldown not "
6745 strprintf(
"too-many-ava-poll: poll message size = %u", nCount));
6749 std::vector<avalanche::Vote> votes;
6750 votes.reserve(nCount);
6752 bool fPreconsensus{
false};
6753 bool fStakingPreconsensus{
false};
6758 fStakingPreconsensus =
6762 for (
unsigned int n = 0; n < nCount; n++) {
6770 if (!quorum_established) {
6771 votes.emplace_back(vote, inv.
hash);
6778 if (fPreconsensus) {
6780 GetAvalancheVoteForTx(*m_avalanche,
TxId(inv.
hash));
6792 if (fStakingPreconsensus) {
6799 "poll inv type %d unknown from peer=%d\n",
6804 votes.emplace_back(vote, inv.
hash);
6830 if (!pfrom.m_avalanche_pubkey.has_value() ||
6831 !(*pfrom.m_avalanche_pubkey)
6832 .VerifySchnorr(verifier.GetHash(),
sig)) {
6833 Misbehaving(*peer,
"invalid-ava-response-signature");
6838 auto now = GetTime<std::chrono::seconds>();
6840 std::vector<avalanche::VoteItemUpdate> updates;
6841 bool disconnect{
false};
6844 disconnect, error)) {
6846 Misbehaving(*peer, error);
6864 "Repeated failure to register votes from peer %d: %s\n",
6865 pfrom.
GetId(), error);
6868 Misbehaving(*peer, error);
6881 auto logVoteUpdate = [](
const auto &voteUpdate,
6882 const std::string &voteItemTypeStr,
6883 const auto &voteItemId) {
6884 std::string voteOutcome;
6885 bool alwaysPrint =
false;
6886 switch (voteUpdate.getStatus()) {
6888 voteOutcome =
"invalidated";
6892 voteOutcome =
"rejected";
6895 voteOutcome =
"accepted";
6898 voteOutcome =
"finalized";
6901 alwaysPrint = voteItemTypeStr !=
"tx";
6904 voteOutcome =
"stalled";
6913 alwaysPrint &= (voteItemTypeStr !=
"contender");
6916 LogPrintf(
"Avalanche %s %s %s\n", voteOutcome, voteItemTypeStr,
6917 voteItemId.ToString());
6921 voteItemTypeStr, voteItemId.ToString());
6925 bool shouldActivateBestChain =
false;
6927 bool fPreconsensus{
false};
6928 bool fStakingPreconsensus{
false};
6933 fStakingPreconsensus =
6937 for (
const auto &u : updates) {
6942 if (
auto pitem = std::get_if<const avalanche::ProofRef>(&item)) {
6946 logVoteUpdate(u,
"proof", proofid);
6948 auto rejectionMode =
6950 auto nextCooldownTimePoint = GetTime<std::chrono::seconds>();
6951 switch (u.getStatus()) {
6967 return pm.rejectProof(proofid,
6971 "ERROR: Failed to reject proof: %s\n",
6977 nextCooldownTimePoint += std::chrono::seconds(
6978 m_opts.avalanche_peer_replacement_cooldown);
6984 avalanche::PeerManager::
6985 RegistrationMode::FORCE_ACCEPT);
6988 [&](const avalanche::Peer &peer) {
6989 pm.updateNextPossibleConflictTime(
6991 nextCooldownTimePoint);
6992 if (u.getStatus() ==
6993 avalanche::VoteStatus::
6995 pm.setFinalized(peer.peerid);
7003 "ERROR: Failed to accept proof: %s\n",
7010 auto getBlockFromIndex = [
this](
const CBlockIndex *pindex) {
7013 std::shared_ptr<const CBlock> pblock =
WITH_LOCK(
7014 m_most_recent_block_mutex,
return m_most_recent_block);
7016 if (!pblock || pblock->GetHash() != pindex->
GetBlockHash()) {
7017 std::shared_ptr<CBlock> pblockRead =
7018 std::make_shared<CBlock>();
7021 assert(!
"cannot load block from disk");
7023 pblock = pblockRead;
7028 if (
auto pitem = std::get_if<const CBlockIndex *>(&item)) {
7031 shouldActivateBestChain =
true;
7035 switch (u.getStatus()) {
7040 LogPrintf(
"ERROR: Database error: %s\n",
7049 LogPrintf(
"ERROR: Database error: %s\n",
7054 auto pblock = getBlockFromIndex(pindex);
7070 std::unique_ptr<node::CBlockTemplate> blockTemplate;
7074 chainstate.UnparkBlock(pindex);
7076 const bool newlyFinalized =
7077 !chainstate.IsBlockAvalancheFinalized(pindex) &&
7078 chainstate.AvalancheFinalizeBlock(pindex,
7083 if (fPreconsensus && newlyFinalized) {
7084 auto pblock = getBlockFromIndex(pindex);
7098 std::unordered_set<TxId, SaltedTxIdHasher>
7099 confirmedTxIdsInNonFinalizedBlocks;
7101 block !=
nullptr && block != pindex;
7102 block = block->
pprev) {
7104 getBlockFromIndex(block);
7106 for (
const auto &tx :
7107 currentBlock->vtx) {
7108 confirmedTxIdsInNonFinalizedBlocks
7109 .insert(tx->GetId());
7117 confirmedTxIdsInNonFinalizedBlocks);
7129 config, chainstate, &m_mempool,
7131 blockAssembler.pblocktemplate.reset(
7134 if (blockAssembler.pblocktemplate) {
7135 blockAssembler.addTxs(m_mempool);
7136 blockTemplate = std::move(
7137 blockAssembler.pblocktemplate);
7143 if (blockTemplate) {
7149 for (
const auto &templateEntry :
7163 if (fStakingPreconsensus) {
7165 std::get_if<const avalanche::StakeContenderId>(&item)) {
7167 logVoteUpdate(u,
"contender", contenderId);
7169 switch (u.getStatus()) {
7190 if (!fPreconsensus) {
7194 if (
auto pitem = std::get_if<const CTransactionRef>(&item)) {
7198 const TxId &txid = tx->GetId();
7199 const auto status{u.getStatus()};
7204 logVoteUpdate(u,
"tx", txid);
7215 if (m_mempool.
exists(txid)) {
7219 std::vector<CTransactionRef> conflictingTxs =
7225 if (conflictingTxs.size() > 0) {
7236 for (
const auto &conflictingTx :
7239 conflictingTx->GetId());
7258 m_recent_rejects.insert(txid);
7265 std::make_shared<const std::vector<Coin>>(
7281 return conflicting.HaveTx(txid);
7284 std::vector<CTransactionRef>
7285 mempool_conflicting_txs;
7286 for (
const auto &txin : tx->vin) {
7291 mempool_conflicting_txs.push_back(
7292 std::move(conflict));
7301 [&txid, &mempool_conflicting_txs](
7306 if (mempool_conflicting_txs.size() >
7309 mempool_conflicting_txs[0],
7318 auto it = m_mempool.
GetIter(txid);
7319 if (!it.has_value()) {
7322 "Error: finalized tx (%s) is not in the "
7328 std::vector<TxId> finalizedTxIds;
7329 m_mempool.setAvalancheFinalized(
7334 for (
const auto &finalized_txid : finalizedTxIds) {
7339 logVoteUpdate(u,
"tx", finalized_txid);
7347 std::vector<CTransactionRef>
7350 for (
const auto &conflictingTx :
7352 m_recent_rejects.insert(
7353 conflictingTx->GetId());
7355 conflictingTx->GetId());
7381 m_txrequest.ForgetInvId(txid);
7387 for (
auto &it : m_peer_map) {
7388 auto tx_relay = (*it.second).GetTxRelay();
7393 LOCK(tx_relay->m_tx_inventory_mutex);
7400 auto &stalled_by_time =
7401 tx_relay->m_avalanche_stalled_txids
7403 if (stalled_by_time.size() >=
7405 stalled_by_time.erase(
7406 stalled_by_time.begin()->timeAdded);
7409 tx_relay->m_avalanche_stalled_txids.insert(
7420 if (shouldActivateBestChain) {
7423 state,
nullptr, m_avalanche)) {
7438 ReceivedAvalancheProof(pfrom, *peer, proof);
7447 if (peer->m_proof_relay ==
nullptr) {
7451 peer->m_proof_relay->lastSharedProofsUpdate =
7452 GetTime<std::chrono::seconds>();
7454 peer->m_proof_relay->sharedProofs =
7460 peer->m_proof_relay->sharedProofs);
7471 if (peer->m_proof_relay ==
nullptr) {
7476 if (!peer->m_proof_relay->compactproofs_requested) {
7480 peer->m_proof_relay->compactproofs_requested =
false;
7484 vRecv >> compactProofs;
7485 }
catch (std::ios_base::failure &e) {
7487 Misbehaving(*peer,
"avaproofs-bad-indexes");
7493 if (!ReceivedAvalancheProof(pfrom, *peer, prefilledProof.proof)) {
7523 auto shortIdProcessor =
7527 if (shortIdProcessor.hasOutOfBoundIndex()) {
7530 Misbehaving(*peer,
"avaproofs-bad-indexes");
7533 if (!shortIdProcessor.isEvenlyDistributed()) {
7538 std::vector<std::pair<avalanche::ProofId, bool>> remoteProofsStatus;
7545 shortIdProcessor.matchKnownItem(shortid, peer.
proof);
7552 remoteProofsStatus.emplace_back(peer.
getProofId(),
7563 for (
size_t i = 0; i < compactProofs.
size(); i++) {
7564 if (shortIdProcessor.getItem(i) ==
nullptr) {
7581 return pfrom.m_avalanche_pubkey.has_value())) {
7584 for (
const auto &[proofid, present] : remoteProofsStatus) {
7594 if (peer->m_proof_relay ==
nullptr) {
7601 auto requestedIndiceIt = proofreq.
indices.begin();
7602 uint32_t treeIndice = 0;
7603 peer->m_proof_relay->sharedProofs.forEachLeaf([&](
const auto &proof) {
7604 if (requestedIndiceIt == proofreq.
indices.end()) {
7609 if (treeIndice++ == *requestedIndiceIt) {
7612 requestedIndiceIt++;
7618 peer->m_proof_relay->sharedProofs = {};
7631 "Ignoring \"getaddr\" from %s connection. peer=%d\n",
7638 Assume(SetupAddressRelay(pfrom, *peer));
7642 if (peer->m_getaddr_recvd) {
7647 peer->m_getaddr_recvd =
true;
7649 peer->m_addrs_to_send.clear();
7650 std::vector<CAddress> vAddr;
7651 const size_t maxAddrToSend = m_opts.max_addr_to_send;
7659 for (
const CAddress &addr : vAddr) {
7660 PushAddress(*peer, addr);
7666 auto now = GetTime<std::chrono::seconds>();
7676 if (!SetupAddressRelay(pfrom, *peer)) {
7678 "Ignoring getavaaddr message from %s peer=%d\n",
7683 auto availabilityScoreComparator = [](
const CNode *lhs,
7686 double scoreRhs = rhs->getAvailabilityScore();
7688 if (scoreLhs != scoreRhs) {
7689 return scoreLhs > scoreRhs;
7698 std::set<
const CNode *,
decltype(availabilityScoreComparator)> avaNodes(
7699 availabilityScoreComparator);
7706 avaNodes.insert(pnode);
7707 if (avaNodes.size() > m_opts.max_addr_to_send) {
7708 avaNodes.erase(std::prev(avaNodes.end()));
7712 peer->m_addrs_to_send.clear();
7713 for (
const CNode *pnode : avaNodes) {
7714 PushAddress(*peer, pnode->
addr);
7725 "mempool request with bloom filters disabled, "
7726 "disconnect peer=%d\n",
7737 "mempool request with bandwidth limit reached, "
7738 "disconnect peer=%d\n",
7745 if (
auto tx_relay = peer->GetTxRelay()) {
7746 LOCK(tx_relay->m_tx_inventory_mutex);
7747 tx_relay->m_send_mempool =
true;
7777 const auto ping_end = time_received;
7780 bool bPingFinished =
false;
7781 std::string sProblem;
7783 if (nAvail >=
sizeof(nonce)) {
7788 if (peer->m_ping_nonce_sent != 0) {
7789 if (nonce == peer->m_ping_nonce_sent) {
7792 bPingFinished =
true;
7793 const auto ping_time = ping_end - peer->m_ping_start.load();
7794 if (ping_time.count() >= 0) {
7799 sProblem =
"Timing mishap";
7803 sProblem =
"Nonce mismatch";
7807 bPingFinished =
true;
7808 sProblem =
"Nonce zero";
7812 sProblem =
"Unsolicited pong without ping";
7817 bPingFinished =
true;
7818 sProblem =
"Short payload";
7821 if (!(sProblem.empty())) {
7823 "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
7824 pfrom.
GetId(), sProblem, peer->m_ping_nonce_sent, nonce,
7827 if (bPingFinished) {
7828 peer->m_ping_nonce_sent = 0;
7836 "filterload received despite not offering bloom services "
7837 "from peer=%d; disconnecting\n",
7847 Misbehaving(*peer,
"too-large bloom filter");
7848 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7850 LOCK(tx_relay->m_bloom_filter_mutex);
7851 tx_relay->m_bloom_filter.reset(
new CBloomFilter(filter));
7852 tx_relay->m_relay_txs =
true;
7862 "filteradd received despite not offering bloom services "
7863 "from peer=%d; disconnecting\n",
7868 std::vector<uint8_t> vData;
7877 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7878 LOCK(tx_relay->m_bloom_filter_mutex);
7879 if (tx_relay->m_bloom_filter) {
7880 tx_relay->m_bloom_filter->insert(vData);
7888 Misbehaving(*peer,
"bad filteradd message");
7896 "filterclear received despite not offering bloom services "
7897 "from peer=%d; disconnecting\n",
7902 auto tx_relay = peer->GetTxRelay();
7908 LOCK(tx_relay->m_bloom_filter_mutex);
7909 tx_relay->m_bloom_filter =
nullptr;
7910 tx_relay->m_relay_txs =
true;
7919 vRecv >> newFeeFilter;
7921 if (
auto tx_relay = peer->GetTxRelay()) {
7922 tx_relay->m_fee_filter_received = newFeeFilter;
7931 ProcessGetCFilters(pfrom, *peer, vRecv);
7936 ProcessGetCFHeaders(pfrom, *peer, vRecv);
7941 ProcessGetCFCheckPt(pfrom, *peer, vRecv);
7946 std::vector<CInv> vInv;
7952 for (
CInv &inv : vInv) {
7958 m_txrequest.ReceivedResponse(pfrom.
GetId(),
TxId(inv.
hash));
7965 LOCK(cs_proofrequest);
7966 m_proofrequest.ReceivedResponse(
7980bool PeerManagerImpl::MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer) {
7982 LOCK(peer.m_misbehavior_mutex);
7985 if (!peer.m_should_discourage) {
7989 peer.m_should_discourage =
false;
7995 LogPrintf(
"Warning: not punishing noban peer %d!\n", peer.m_id);
8001 LogPrintf(
"Warning: not punishing manually connected peer %d!\n",
8010 "Warning: disconnecting but not discouraging %s peer %d!\n",
8027bool PeerManagerImpl::ProcessMessages(
const Config &config,
CNode *pfrom,
8028 std::atomic<bool> &interruptMsgProc) {
8040 PeerRef peer = GetPeerRef(pfrom->
GetId());
8041 if (peer ==
nullptr) {
8046 LOCK(peer->m_getdata_requests_mutex);
8047 if (!peer->m_getdata_requests.empty()) {
8048 ProcessGetData(config, *pfrom, *peer, interruptMsgProc);
8052 const bool processed_orphan = ProcessOrphanTx(config, *peer);
8058 if (processed_orphan) {
8065 LOCK(peer->m_getdata_requests_mutex);
8066 if (!peer->m_getdata_requests.empty()) {
8083 bool fMoreWork = poll_result->second;
8087 msg.m_recv.size(), msg.m_recv.
data());
8089 if (m_opts.capture_messages) {
8097 if (!msg.m_valid_netmagic) {
8099 "PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n",
8113 if (!msg.m_valid_header) {
8121 if (!msg.m_valid_checksum) {
8133 ProcessMessage(config, *pfrom, msg.
m_type, vRecv, msg.m_time,
8135 if (interruptMsgProc) {
8140 LOCK(peer->m_getdata_requests_mutex);
8141 if (!peer->m_getdata_requests.empty()) {
8150 return orphanage.HaveTxToReconsider(peer->m_id);
8154 }
catch (
const std::exception &e) {
8157 e.what(),
typeid(e).name());
8166void PeerManagerImpl::ConsiderEviction(
CNode &pto, Peer &peer,
8167 std::chrono::seconds time_in_seconds) {
8170 CNodeState &state = *State(pto.
GetId());
8174 state.fSyncStarted) {
8181 if (state.pindexBestKnownBlock !=
nullptr &&
8182 state.pindexBestKnownBlock->nChainWork >=
8184 if (state.m_chain_sync.m_timeout != 0s) {
8185 state.m_chain_sync.m_timeout = 0s;
8186 state.m_chain_sync.m_work_header =
nullptr;
8187 state.m_chain_sync.m_sent_getheaders =
false;
8189 }
else if (state.m_chain_sync.m_timeout == 0s ||
8190 (state.m_chain_sync.m_work_header !=
nullptr &&
8191 state.pindexBestKnownBlock !=
nullptr &&
8192 state.pindexBestKnownBlock->nChainWork >=
8193 state.m_chain_sync.m_work_header->nChainWork)) {
8199 state.m_chain_sync.m_work_header = m_chainman.
ActiveChain().
Tip();
8200 state.m_chain_sync.m_sent_getheaders =
false;
8201 }
else if (state.m_chain_sync.m_timeout > 0s &&
8202 time_in_seconds > state.m_chain_sync.m_timeout) {
8207 if (state.m_chain_sync.m_sent_getheaders) {
8210 "Disconnecting outbound peer %d for old chain, best known "
8213 state.pindexBestKnownBlock !=
nullptr
8214 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
8218 assert(state.m_chain_sync.m_work_header);
8223 MaybeSendGetHeaders(
8224 pto,
GetLocator(state.m_chain_sync.m_work_header->pprev),
8228 "sending getheaders to outbound peer=%d to verify chain "
8229 "work (current best known block:%s, benchmark blockhash: "
8232 state.pindexBestKnownBlock !=
nullptr
8233 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
8235 state.m_chain_sync.m_work_header->GetBlockHash()
8237 state.m_chain_sync.m_sent_getheaders =
true;
8244 state.m_chain_sync.m_timeout =
8251void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now) {
8260 std::pair<NodeId, std::chrono::seconds> youngest_peer{-1, 0},
8261 next_youngest_peer{-1, 0};
8267 if (pnode->
GetId() > youngest_peer.first) {
8268 next_youngest_peer = youngest_peer;
8269 youngest_peer.first = pnode->GetId();
8270 youngest_peer.second = pnode->m_last_block_time;
8274 NodeId to_disconnect = youngest_peer.first;
8275 if (youngest_peer.second > next_youngest_peer.second) {
8278 to_disconnect = next_youngest_peer.first;
8290 CNodeState *node_state = State(pnode->
GetId());
8291 if (node_state ==
nullptr ||
8293 node_state->vBlocksInFlight.empty())) {
8296 "disconnecting extra block-relay-only peer=%d "
8297 "(last block received at time %d)\n",
8304 "keeping block-relay-only peer=%d chosen for eviction "
8305 "(connect time: %d, blocks_in_flight: %d)\n",
8307 node_state->vBlocksInFlight.size());
8323 int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
8334 CNodeState *state = State(pnode->
GetId());
8335 if (state ==
nullptr) {
8340 if (state->m_chain_sync.m_protect) {
8343 if (state->m_last_block_announcement < oldest_block_announcement ||
8344 (state->m_last_block_announcement == oldest_block_announcement &&
8345 pnode->
GetId() > worst_peer)) {
8346 worst_peer = pnode->
GetId();
8347 oldest_block_announcement = state->m_last_block_announcement;
8351 if (worst_peer == -1) {
8355 bool disconnected = m_connman.
ForNode(
8363 CNodeState &state = *State(pnode->
GetId());
8365 state.vBlocksInFlight.empty()) {
8367 "disconnecting extra outbound peer=%d (last block "
8368 "announcement received at time %d)\n",
8369 pnode->
GetId(), oldest_block_announcement);
8374 "keeping outbound peer=%d chosen for eviction "
8375 "(connect time: %d, blocks_in_flight: %d)\n",
8377 state.vBlocksInFlight.size());
8392void PeerManagerImpl::CheckForStaleTipAndEvictPeers() {
8395 auto now{GetTime<std::chrono::seconds>()};
8397 EvictExtraOutboundPeers(now);
8399 if (now > m_stale_tip_check_time) {
8405 LogPrintf(
"Potential stale tip detected, will try using extra "
8406 "outbound peer (last tip update: %d seconds ago)\n",
8415 if (!m_initial_sync_finished && CanDirectFetch()) {
8417 m_initial_sync_finished =
true;
8421void PeerManagerImpl::MaybeSendPing(
CNode &node_to, Peer &peer,
8422 std::chrono::microseconds now) {
8424 node_to, std::chrono::duration_cast<std::chrono::seconds>(now)) &&
8425 peer.m_ping_nonce_sent &&
8437 bool pingSend =
false;
8439 if (peer.m_ping_queued) {
8444 if (peer.m_ping_nonce_sent == 0 &&
8454 }
while (nonce == 0);
8455 peer.m_ping_queued =
false;
8456 peer.m_ping_start = now;
8458 peer.m_ping_nonce_sent = nonce;
8464 peer.m_ping_nonce_sent = 0;
8470void PeerManagerImpl::MaybeSendAddr(
CNode &
node, Peer &peer,
8471 std::chrono::microseconds current_time) {
8473 if (!peer.m_addr_relay_enabled) {
8477 LOCK(peer.m_addr_send_times_mutex);
8479 peer.m_next_local_addr_send < current_time) {
8486 if (peer.m_next_local_addr_send != 0us) {
8487 peer.m_addr_known->reset();
8490 CAddress local_addr{*local_service, peer.m_our_services,
8491 Now<NodeSeconds>()};
8492 PushAddress(peer, local_addr);
8494 peer.m_next_local_addr_send =
8500 if (current_time <= peer.m_next_addr_send) {
8504 peer.m_next_addr_send =
8507 const size_t max_addr_to_send = m_opts.max_addr_to_send;
8508 if (!
Assume(peer.m_addrs_to_send.size() <= max_addr_to_send)) {
8511 peer.m_addrs_to_send.resize(max_addr_to_send);
8516 auto addr_already_known =
8519 bool ret = peer.m_addr_known->contains(addr.
GetKey());
8521 peer.m_addr_known->insert(addr.
GetKey());
8525 peer.m_addrs_to_send.erase(std::remove_if(peer.m_addrs_to_send.begin(),
8526 peer.m_addrs_to_send.end(),
8527 addr_already_known),
8528 peer.m_addrs_to_send.end());
8531 if (peer.m_addrs_to_send.empty()) {
8535 const char *msg_type;
8537 if (peer.m_wants_addrv2) {
8546 .
Make(make_flags, msg_type, peer.m_addrs_to_send));
8547 peer.m_addrs_to_send.clear();
8550 if (peer.m_addrs_to_send.capacity() > 40) {
8551 peer.m_addrs_to_send.shrink_to_fit();
8555void PeerManagerImpl::MaybeSendSendHeaders(
CNode &
node, Peer &peer) {
8560 if (!peer.m_sent_sendheaders &&
8563 CNodeState &state = *State(
node.GetId());
8564 if (state.pindexBestKnownBlock !=
nullptr &&
8565 state.pindexBestKnownBlock->nChainWork >
8573 peer.m_sent_sendheaders =
true;
8578void PeerManagerImpl::MaybeSendFeefilter(
8579 CNode &pto, Peer &peer, std::chrono::microseconds current_time) {
8580 if (m_opts.ignore_incoming_txs) {
8604 static const Amount MAX_FILTER{m_fee_filter_rounder.round(
MAX_MONEY)};
8605 if (peer.m_fee_filter_sent == MAX_FILTER) {
8608 peer.m_next_send_feefilter = 0us;
8611 if (current_time > peer.m_next_send_feefilter) {
8612 Amount filterToSend = m_fee_filter_rounder.round(currentFilter);
8616 if (filterToSend != peer.m_fee_filter_sent) {
8620 peer.m_fee_filter_sent = filterToSend;
8622 peer.m_next_send_feefilter =
8630 peer.m_next_send_feefilter &&
8631 (currentFilter < 3 * peer.m_fee_filter_sent / 4 ||
8632 currentFilter > 4 * peer.m_fee_filter_sent / 3)) {
8633 peer.m_next_send_feefilter =
8641class CompareInvMempoolOrder {
8645 explicit CompareInvMempoolOrder(
CTxMemPool *_mempool) : mp(_mempool) {}
8647 bool operator()(std::set<TxId>::iterator a, std::set<TxId>::iterator b) {
8657bool PeerManagerImpl::RejectIncomingTxs(
const CNode &peer)
const {
8666 if (m_opts.ignore_incoming_txs &&
8673bool PeerManagerImpl::SetupAddressRelay(
const CNode &
node, Peer &peer) {
8677 if (
node.IsBlockOnlyConn()) {
8681 if (!peer.m_addr_relay_enabled.exchange(
true)) {
8685 peer.m_addr_known = std::make_unique<CRollingBloomFilter>(5000, 0.001);
8691bool PeerManagerImpl::SendMessages(
const Config &config,
CNode *pto) {
8694 PeerRef peer = GetPeerRef(pto->
GetId());
8703 if (MaybeDiscourageAndDisconnect(*pto, *peer)) {
8716 const auto current_time{GetTime<std::chrono::microseconds>()};
8721 "addrfetch connection timeout; disconnecting peer=%d\n",
8727 MaybeSendPing(*pto, *peer, current_time);
8734 bool sync_blocks_and_headers_from_peer =
false;
8736 MaybeSendAddr(*pto, *peer, current_time);
8738 MaybeSendSendHeaders(*pto, *peer);
8743 CNodeState &state = *State(pto->
GetId());
8746 if (m_chainman.m_best_header ==
nullptr) {
8753 if (state.fPreferredDownload) {
8754 sync_blocks_and_headers_from_peer =
true;
8765 if (m_num_preferred_download_peers == 0 ||
8766 mapBlocksInFlight.empty()) {
8767 sync_blocks_and_headers_from_peer =
true;
8771 if (!state.fSyncStarted && CanServeBlocks(*peer) &&
8775 if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) ||
8777 const CBlockIndex *pindexStart = m_chainman.m_best_header;
8786 if (pindexStart->
pprev) {
8787 pindexStart = pindexStart->
pprev;
8789 if (MaybeSendGetHeaders(*pto,
GetLocator(pindexStart), *peer)) {
8792 "initial getheaders (%d) to peer=%d (startheight:%d)\n",
8794 peer->m_starting_height);
8796 state.fSyncStarted =
true;
8797 peer->m_headers_sync_timeout =
8802 std::chrono::microseconds{
8804 Ticks<std::chrono::seconds>(
8806 m_chainman.m_best_header->Time()) /
8823 LOCK(peer->m_block_inv_mutex);
8824 std::vector<CBlock> vHeaders;
8826 ((!peer->m_prefers_headers &&
8827 (!state.m_requested_hb_cmpctblocks ||
8828 peer->m_blocks_for_headers_relay.size() > 1)) ||
8829 peer->m_blocks_for_headers_relay.size() >
8834 ProcessBlockAvailability(pto->
GetId());
8836 if (!fRevertToInv) {
8837 bool fFoundStartingHeader =
false;
8841 for (
const BlockHash &hash : peer->m_blocks_for_headers_relay) {
8847 fRevertToInv =
true;
8850 if (pBestIndex !=
nullptr && pindex->
pprev != pBestIndex) {
8861 fRevertToInv =
true;
8864 pBestIndex = pindex;
8865 if (fFoundStartingHeader) {
8868 }
else if (PeerHasHeader(&state, pindex)) {
8871 }
else if (pindex->
pprev ==
nullptr ||
8872 PeerHasHeader(&state, pindex->
pprev)) {
8875 fFoundStartingHeader =
true;
8880 fRevertToInv =
true;
8885 if (!fRevertToInv && !vHeaders.empty()) {
8886 if (vHeaders.size() == 1 && state.m_requested_hb_cmpctblocks) {
8891 "%s sending header-and-ids %s to peer=%d\n",
8892 __func__, vHeaders.front().GetHash().ToString(),
8895 std::optional<CSerializedNetMsg> cached_cmpctblock_msg;
8897 LOCK(m_most_recent_block_mutex);
8898 if (m_most_recent_block_hash ==
8900 cached_cmpctblock_msg =
8902 *m_most_recent_compact_block);
8905 if (cached_cmpctblock_msg.has_value()) {
8907 pto, std::move(cached_cmpctblock_msg.value()));
8911 block, *pBestIndex)};
8918 state.pindexBestHeaderSent = pBestIndex;
8919 }
else if (peer->m_prefers_headers) {
8920 if (vHeaders.size() > 1) {
8922 "%s: %u headers, range (%s, %s), to peer=%d\n",
8923 __func__, vHeaders.size(),
8924 vHeaders.front().GetHash().ToString(),
8925 vHeaders.back().GetHash().ToString(),
8929 "%s: sending header %s to peer=%d\n", __func__,
8930 vHeaders.front().GetHash().ToString(),
8935 state.pindexBestHeaderSent = pBestIndex;
8937 fRevertToInv =
true;
8944 if (!peer->m_blocks_for_headers_relay.empty()) {
8946 peer->m_blocks_for_headers_relay.back();
8957 "Announcing block %s not on main chain (tip=%s)\n",
8966 if (!PeerHasHeader(&state, pindex)) {
8967 peer->m_blocks_for_inv_relay.push_back(hashToAnnounce);
8969 "%s: sending inv peer=%d hash=%s\n", __func__,
8974 peer->m_blocks_for_headers_relay.clear();
8981 std::vector<CInv> vInv;
8982 auto addInvAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
8983 vInv.emplace_back(type, hash);
8995 LOCK(peer->m_block_inv_mutex);
8997 vInv.reserve(std::max<size_t>(peer->m_blocks_for_inv_relay.size(),
9003 for (
const BlockHash &hash : peer->m_blocks_for_inv_relay) {
9006 peer->m_blocks_for_inv_relay.clear();
9009 auto computeNextInvSendTime =
9010 [&](std::chrono::microseconds &next)
9014 if (next < current_time) {
9015 fSendTrickle =
true;
9017 next = NextInvToInbounds(
9022 next = current_time;
9026 return fSendTrickle;
9030 if (peer->m_proof_relay !=
nullptr) {
9031 LOCK(peer->m_proof_relay->m_proof_inventory_mutex);
9033 if (computeNextInvSendTime(
9034 peer->m_proof_relay->m_next_inv_send_time)) {
9036 peer->m_proof_relay->m_proof_inventory_to_send.begin();
9038 peer->m_proof_relay->m_proof_inventory_to_send.end()) {
9041 it = peer->m_proof_relay->m_proof_inventory_to_send.erase(
9044 if (peer->m_proof_relay->m_proof_inventory_known_filter
9045 .contains(proofid)) {
9049 peer->m_proof_relay->m_proof_inventory_known_filter.insert(
9052 peer->m_proof_relay->m_recently_announced_proofs.insert(
9058 if (
auto tx_relay = peer->GetTxRelay()) {
9059 LOCK(tx_relay->m_tx_inventory_mutex);
9061 const bool fSendTrickle =
9062 computeNextInvSendTime(tx_relay->m_next_inv_send_time);
9067 LOCK(tx_relay->m_bloom_filter_mutex);
9068 if (!tx_relay->m_relay_txs) {
9069 tx_relay->m_tx_inventory_to_send.clear();
9074 if (fSendTrickle && tx_relay->m_send_mempool) {
9075 auto vtxinfo = m_mempool.
infoAll();
9076 tx_relay->m_send_mempool =
false;
9078 tx_relay->m_fee_filter_received.load()};
9080 LOCK(tx_relay->m_bloom_filter_mutex);
9082 for (
const auto &txinfo : vtxinfo) {
9083 const TxId &txid = txinfo.tx->GetId();
9084 tx_relay->m_tx_inventory_to_send.erase(txid);
9087 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
9090 if (tx_relay->m_bloom_filter &&
9091 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
9095 tx_relay->m_tx_inventory_known_filter.insert(txid);
9098 addInvAndMaybeFlush(
MSG_TX, txid);
9100 tx_relay->m_last_mempool_req =
9101 std::chrono::duration_cast<std::chrono::seconds>(
9108 std::vector<std::set<TxId>::iterator> vInvTx;
9109 vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size());
9110 for (std::set<TxId>::iterator it =
9111 tx_relay->m_tx_inventory_to_send.begin();
9112 it != tx_relay->m_tx_inventory_to_send.end(); it++) {
9113 vInvTx.push_back(it);
9116 tx_relay->m_fee_filter_received.load()};
9121 CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool);
9122 std::make_heap(vInvTx.begin(), vInvTx.end(),
9123 compareInvMempoolOrder);
9127 unsigned int nRelayedTransactions = 0;
9128 LOCK(tx_relay->m_bloom_filter_mutex);
9129 while (!vInvTx.empty() &&
9134 std::pop_heap(vInvTx.begin(), vInvTx.end(),
9135 compareInvMempoolOrder);
9136 std::set<TxId>::iterator it = vInvTx.back();
9138 const TxId txid = *it;
9140 tx_relay->m_tx_inventory_to_send.erase(it);
9142 if (tx_relay->m_tx_inventory_known_filter.contains(txid) &&
9143 tx_relay->m_avalanche_stalled_txids.count(txid) == 0) {
9147 auto txinfo = m_mempool.
info(txid);
9153 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
9156 if (tx_relay->m_bloom_filter &&
9157 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
9162 tx_relay->m_recently_announced_invs.insert(txid);
9163 addInvAndMaybeFlush(
MSG_TX, txid);
9164 nRelayedTransactions++;
9165 tx_relay->m_tx_inventory_known_filter.insert(txid);
9166 tx_relay->m_avalanche_stalled_txids.erase(txid);
9172 if (!vInv.empty()) {
9179 CNodeState &state = *State(pto->
GetId());
9182 auto stalling_timeout = m_block_stalling_timeout.load();
9183 if (state.m_stalling_since.count() &&
9184 state.m_stalling_since < current_time - stalling_timeout) {
9189 LogPrintf(
"Peer=%d is stalling block download, disconnecting\n",
9194 const auto new_timeout =
9196 if (stalling_timeout != new_timeout &&
9197 m_block_stalling_timeout.compare_exchange_strong(
9198 stalling_timeout, new_timeout)) {
9201 "Increased stalling timeout temporarily to %d seconds\n",
9213 if (state.vBlocksInFlight.size() > 0) {
9214 QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
9215 int nOtherPeersWithValidatedDownloads =
9216 m_peers_downloading_from - 1;
9218 state.m_downloading_since +
9219 std::chrono::seconds{consensusParams.nPowTargetSpacing} *
9222 nOtherPeersWithValidatedDownloads)) {
9223 LogPrintf(
"Timeout downloading block %s from peer=%d, "
9225 queuedBlock.pindex->GetBlockHash().ToString(),
9233 if (state.fSyncStarted &&
9234 peer->m_headers_sync_timeout < std::chrono::microseconds::max()) {
9237 if (current_time > peer->m_headers_sync_timeout &&
9238 nSyncStarted == 1 &&
9239 (m_num_preferred_download_peers -
9240 state.fPreferredDownload >=
9249 LogPrintf(
"Timeout downloading headers from peer=%d, "
9255 LogPrintf(
"Timeout downloading headers from noban "
9256 "peer=%d, not disconnecting\n",
9262 state.fSyncStarted =
false;
9264 peer->m_headers_sync_timeout = 0us;
9270 peer->m_headers_sync_timeout = std::chrono::microseconds::max();
9276 ConsiderEviction(*pto, *peer, GetTime<std::chrono::seconds>());
9279 std::vector<CInv> vGetData;
9287 CNodeState &state = *State(pto->
GetId());
9289 if (CanServeBlocks(*peer) &&
9290 ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) ||
9293 std::vector<const CBlockIndex *> vToDownload;
9295 auto get_inflight_budget = [&state]() {
9298 static_cast<int>(state.vBlocksInFlight.size()));
9304 FindNextBlocksToDownload(*peer, get_inflight_budget(), vToDownload,
9307 !IsLimitedPeer(*peer)) {
9313 m_chainman.GetSnapshotBaseBlock());
9315 TryDownloadingHistoricalBlocks(
9316 *peer, get_inflight_budget(), vToDownload, from_tip,
9317 Assert(m_chainman.GetSnapshotBaseBlock()));
9321 BlockRequested(config, pto->
GetId(), *pindex);
9326 if (state.vBlocksInFlight.empty() && staller != -1) {
9327 if (State(staller)->m_stalling_since == 0us) {
9328 State(staller)->m_stalling_since = current_time;
9335 auto addGetDataAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
9336 CInv inv(type, hash);
9339 vGetData.push_back(std::move(inv));
9351 LOCK(cs_proofrequest);
9352 std::vector<std::pair<NodeId, avalanche::ProofId>> expired;
9354 m_proofrequest.GetRequestable(pto->
GetId(), current_time, &expired);
9355 for (
const auto &entry : expired) {
9357 "timeout of inflight proof %s from peer=%d\n",
9358 entry.second.ToString(), entry.first);
9360 for (
const auto &proofid : requestable) {
9361 if (!AlreadyHaveProof(proofid)) {
9363 m_proofrequest.RequestedData(
9364 pto->
GetId(), proofid,
9371 m_proofrequest.ForgetInvId(proofid);
9381 std::vector<std::pair<NodeId, TxId>> expired;
9383 m_txrequest.GetRequestable(pto->
GetId(), current_time, &expired);
9384 for (
const auto &entry : expired) {
9386 entry.second.ToString(), entry.first);
9388 for (
const TxId &txid : requestable) {
9392 if (!AlreadyHaveTx(txid,
false)) {
9393 addGetDataAndMaybeFlush(
MSG_TX, txid);
9394 m_txrequest.RequestedData(
9401 m_txrequest.ForgetInvId(txid);
9405 if (!vGetData.empty()) {
9411 MaybeSendFeefilter(*pto, *peer, current_time);
9415bool PeerManagerImpl::ReceivedAvalancheProof(
CNode &
node, Peer &peer,
9417 assert(proof !=
nullptr);
9421 AddKnownProof(peer, proofid);
9433 return node.m_avalanche_pubkey.has_value());
9434 auto saveProofIfStaker = [
this, isStaker](
const CNode &
node,
9436 const NodeId nodeid) ->
bool {
9448 LOCK(cs_proofrequest);
9449 m_proofrequest.ReceivedResponse(nodeid, proofid);
9451 if (AlreadyHaveProof(proofid)) {
9452 m_proofrequest.ForgetInvId(proofid);
9453 saveProofIfStaker(
node, proofid, nodeid);
9463 return pm.registerProof(proof, state);
9465 WITH_LOCK(cs_proofrequest, m_proofrequest.ForgetInvId(proofid));
9466 RelayProof(proofid);
9468 node.m_last_proof_time = GetTime<std::chrono::seconds>();
9471 nodeid, proofid.ToString());
9493 "Not polling the avalanche proof (%s): peer=%d, proofid %s\n",
9494 state.
IsValid() ?
"not-worth-polling"
9496 nodeid, proofid.ToString());
9499 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.
int64_t GetBlockProofEquivalentTime(const CBlockIndex &to, const CBlockIndex &from, const CBlockIndex &tip, const Consensus::Params ¶ms)
Return the time it would take to redo the work difference between from and to, assuming the current h...
const CBlockIndex * LastCommonAncestor(const CBlockIndex *pa, const CBlockIndex *pb)
Find the last common ancestor two blocks have.
#define Assert(val)
Identity function.
#define Assume(val)
Assume is the identity function.
Stochastic address manager.
void Connected(const CService &addr, NodeSeconds time=Now< NodeSeconds >())
We have successfully connected to this peer.
void Good(const CService &addr, bool test_before_evict=true, NodeSeconds time=Now< NodeSeconds >())
Mark an entry as accessible, possibly moving it from "new" to "tried".
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 HaveNumChainTxs() const
Check whether this block and all previous blocks back to the genesis block or an assumeutxo snapshot ...
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
FlatFilePos GetBlockPos() const EXCLUSIVE_LOCKS_REQUIRED(
BloomFilter is a probabilistic filter which SPV clients provide so that we can filter the transaction...
bool IsWithinSizeConstraints() const
True if the size is <= MAX_BLOOM_FILTER_SIZE and the number of hash functions is <= MAX_HASH_FUNCS (c...
An in-memory indexed chain of blocks.
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
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...
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 CBlock & GenesisBlock() const
const Consensus::Params & GetConsensus() const
CCoinsView that adds a memory cache for transactions to another CCoinsView.
CCoinsView that brings transactions from a mempool into view.
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)
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
Fee rate in satoshis per kilobyte: Amount / kB.
Amount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
Inv(ventory) message data.
bool IsMsgCmpctBlk() const
std::string ToString() const
bool IsMsgStakeContender() const
bool IsMsgFilteredBlk() const
void TransactionInvalidated(const CTransactionRef &tx, std::shared_ptr< const std::vector< Coin > > spent_coins)
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.
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.
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
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.
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
std::optional< std::pair< CNetMessage, bool > > PollMessage() EXCLUSIVE_LOCKS_REQUIRED(!m_msg_process_queue_mutex)
Poll the next message from the processing queue of this connection.
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
How much faulty messages did this node accumulate.
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< int > m_avalanche_message_fault_score
This score is incremented for every new faulty message received when m_avalanche_message_fault_counte...
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
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.
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 removeConflicts(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(cs)
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
bool setAvalancheFinalized(const CTxMemPoolEntryRef &tx, const Consensus::Params ¶ms, const CBlockIndex &active_chain_tip, std::vector< TxId > &finalizedTxIds) EXCLUSIVE_LOCKS_REQUIRED(bool isAvalancheFinalizedPreConsensus(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
std::vector< TxMempoolInfo > infoAll() const
CTransactionRef GetConflictTx(const COutPoint &prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Get the transaction in the pool that spends the same prevout.
bool exists(const TxId &txid) const
std::set< TxId > GetUnbroadcastTxs() const
Returns transactions in unbroadcast set.
auto withOrphanage(Callable &&func) const EXCLUSIVE_LOCKS_REQUIRED(!cs_orphanage)
const CFeeRate m_min_relay_feerate
auto withConflicting(Callable &&func) const EXCLUSIVE_LOCKS_REQUIRED(!cs_conflicting)
void removeForFinalizedBlock(const std::unordered_set< TxId, SaltedTxIdHasher > &confirmedTxIdsInNonFinalizedBlocks) 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 BlockConnected(ChainstateRole role, const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex)
Notifies listeners of a block being connected.
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 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...
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex *GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(Chainstate ActiveChainstate)() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
const CBlockIndex * GetBackgroundSyncTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
The tip of the background sync chain.
MempoolAcceptResult ProcessTransaction(const CTransactionRef &tx, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Try to add a transaction to the memory pool.
bool IsInitialBlockDownload() const
Check whether we are doing an initial block download (synchronizing from disk or network)
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.
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
bool BackgroundSyncInProgress() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
The state of a background sync (for net processing)
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.
const arith_uint256 & MinimumChainWork() const
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
void MaybeRebalanceCaches() EXCLUSIVE_LOCKS_REQUIRED(void ReportHeadersPresync(const arith_uint256 &work, int64_t height, int64_t timestamp)
Check to see if caches are out of balance and if so, call ResizeCoinsCaches() as needed.
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
virtual uint64_t GetMaxBlockSize() const =0
void ignore(size_t num_ignore)
uint64_t rand64() noexcept
Generate a random 64-bit integer.
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)
static bool HasFlag(NetPermissionFlags flags, NetPermissionFlags f)
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 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 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 bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) const =0
Get statistics from node state.
virtual void UnitTestMisbehaving(const NodeId peer_id)=0
Public for unit testing.
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.
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
A Span is an object that can refer to a contiguous sequence of objects.
int EraseTx(const TxId &txid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Erase a tx by txid.
void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Erase all txs 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.
bool AddTx(const CTransactionRef &tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Add a new transaction to the pool.
unsigned int LimitTxs(unsigned int max_txs, FastRandomContext &rng) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Limit the txs to the given maximum.
void EraseForBlock(const CBlock &block) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Erase all txs included in or invalidated by a new block.
std::vector< CTransactionRef > GetConflictTxs(const CTransactionRef &tx) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
void AddChildrenToWorkSet(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Add any tx that list a particular tx as a parent into the from peer's work set.
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.
std::string GetRejectReason() const
std::string ToString() const
256-bit unsigned big integer.
const std::vector< PrefilledProof > & getPrefilledProofs() const
uint64_t getShortID(const ProofId &proofid) const
const std::vector< uint64_t > & getShortIDs() const
ProofId getProofId() const
bool verify(DelegationState &state, CPubKey &auth) const
const DelegationId & getId() const
const LimitedProofId & getLimitedProofId() const
bool shouldRequestMoreNodes()
Returns true if we encountered a lack of node since the last call.
bool exists(const ProofId &proofid) const
Return true if the (valid) proof exists, but only for non-dangling proofs.
bool forPeer(const ProofId &proofid, Callable &&func) const
bool addNode(NodeId nodeid, const ProofId &proofid)
Node API.
void removeUnbroadcastProof(const ProofId &proofid)
const ProofRadixTree & getShareableProofsSnapshot() const
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
auto getUnbroadcastProofs() const
bool isInConflictingPool(const ProofId &proofid) const
void sendResponse(CNode *pfrom, Response response) const
bool addToReconcile(const AnyVoteItem &item) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
bool isStakingPreconsensusActivated(const CBlockIndex *pprev) const
int64_t getAvaproofsNodeCounter() const
bool sendHello(CNode *pfrom) EXCLUSIVE_LOCKS_REQUIRED(!cs_delayedAvahelloNodeIds)
Send a avahello message.
void setRecentlyFinalized(const uint256 &itemId) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
bool isQuorumEstablished() LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
void cleanupStakingRewards(const int minHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards
ProofRef getLocalProof() const
void acceptStakeContender(const StakeContenderId &contenderId) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
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...
int getStakeContenderStatus(const StakeContenderId &contenderId) const EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Track votes on stake contenders.
void sendDelayedAvahello() EXCLUSIVE_LOCKS_REQUIRED(!cs_delayedAvahelloNodeIds)
void finalizeStakeContender(const StakeContenderId &contenderId) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
bool isPreconsensusActivated(const CBlockIndex *pprev) const
auto withPeerManager(Callable &&func) const EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
bool registerVotes(NodeId nodeid, const Response &response, std::vector< VoteItemUpdate > &updates, bool &disconnect, std::string &error) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
void rejectStakeContender(const StakeContenderId &contenderId) 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
Generate a new block, without valid proof-of-work.
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 ReadRawBlockFromDisk(std::vector< uint8_t > &block, const FlatFilePos &pos) const
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_PACKAGE_RECONSIDERABLE
fails some policy, but might be acceptable if submitted in a (different) package
@ 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 a finalized tx, i.e.
@ TX_NOT_STANDARD
otherwise didn't meet our local policy rules
@ TX_AVALANCHE_RECONSIDERABLE
fails some policy, but might be reconsidered by avalanche voting
@ 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
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.
ChainstateRole
This enum describes the various roles a specific Chainstate instance can take.
std::array< uint8_t, CPubKey::SCHNORR_SIZE > SchnorrSig
a Schnorr signature
#define LogPrintLevel(category, level,...)
#define LogPrint(category,...)
#define LogDebug(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 StakeContenderId, const CTransactionRef > AnyVoteItem
RCUPtr< const Proof > ProofRef
Implement std::hash so RCUPtr can be used as a key for maps or sets.
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 constexpr size_t MAX_AVALANCHE_STALLED_TXIDS_PER_PEER
Maximum number of stalled avalanche txids to store per peer.
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 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 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.
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 unsigned int MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK
Maximum number of outstanding CMPCTBLOCK requests for the same block.
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)
static constexpr NodeId NO_NODE
Special NodeId that represent no node.
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_AVA_STAKE_CONTENDER
@ 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.
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 &, V)=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 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
StakeContenderIds are unique for each block to ensure that the peer polling for their acceptance has ...
#define AssertLockNotHeld(cs)
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
#define EXCLUSIVE_LOCKS_REQUIRED(...)
#define LOCKS_EXCLUDED(...)
#define NO_THREAD_SAFETY_ANALYSIS
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
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)
#define TRACE6(context, event, a, b, c, d, e, f)
@ AVALANCHE
Removed by avalanche vote.
std::string SanitizeString(std::string_view str, int rule)
Remove unsafe chars.
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.
bool IsBlockMutated(const CBlock &block)
Check if a block has been mutated (with respect to its merkle root).
std::vector< Coin > GetSpentCoins(const CTransactionRef &ptx, const CCoinsViewCache &coins_view)
Get the coins spent by ptx from the coins_view.
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...
CMainSignals & GetMainSignals()
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.