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);
1362 mutable Mutex m_most_recent_block_mutex;
1363 std::shared_ptr<const CBlock>
1364 m_most_recent_block
GUARDED_BY(m_most_recent_block_mutex);
1365 std::shared_ptr<const CBlockHeaderAndShortTxIDs>
1366 m_most_recent_compact_block
GUARDED_BY(m_most_recent_block_mutex);
1368 std::unique_ptr<const std::map<TxId, CTransactionRef>>
1369 m_most_recent_block_txs
GUARDED_BY(m_most_recent_block_mutex);
1374 Mutex m_headers_presync_mutex;
1385 using HeadersPresyncStats =
1386 std::pair<arith_uint256, std::optional<std::pair<int64_t, uint32_t>>>;
1388 std::map<NodeId, HeadersPresyncStats>
1389 m_headers_presync_stats
GUARDED_BY(m_headers_presync_mutex){};
1393 std::atomic_bool m_headers_presync_should_signal{
false};
1401 bool IsBlockRequested(
const BlockHash &hash)
1405 bool IsBlockRequestedFromOutbound(
const BlockHash &hash)
1416 void RemoveBlockRequest(
const BlockHash &hash,
1417 std::optional<NodeId> from_peer)
1426 bool BlockRequested(
const Config &config,
NodeId nodeid,
1428 std::list<QueuedBlock>::iterator **pit =
nullptr)
1437 void FindNextBlocksToDownload(const Peer &peer,
unsigned int count,
1443 void TryDownloadingHistoricalBlocks(
1444 const Peer &peer,
unsigned int count,
1478 const Peer &peer, CNodeState *state,
1480 int nWindowEnd, const
CChain *activeChain =
nullptr,
1481 NodeId *nodeStaller =
nullptr)
1491 std::atomic<
std::chrono::seconds> m_last_tip_update{0s};
1498 const std::chrono::seconds mempool_req,
1499 const std::chrono::seconds now)
1504 void ProcessGetData(
const Config &config,
CNode &pfrom, Peer &peer,
1505 const std::atomic<bool> &interruptMsgProc)
1507 peer.m_getdata_requests_mutex,
1513 const std::shared_ptr<const CBlock> &block,
1514 bool force_processing,
bool min_pow_checked);
1522 void MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid)
1541 std::vector<std::pair<TxHash, CTransactionRef>>
1542 vExtraTxnForCompact
GUARDED_BY(g_msgproc_mutex);
1544 size_t vExtraTxnForCompactIt
GUARDED_BY(g_msgproc_mutex) = 0;
1549 void ProcessBlockAvailability(
NodeId nodeid)
1564 bool BlockRequestAllowed(const
CBlockIndex *pindex)
1566 bool AlreadyHaveBlock(const
BlockHash &block_hash)
1568 bool AlreadyHaveProof(const
avalanche::ProofId &proofid);
1569 void ProcessGetBlockData(const
Config &config,
CNode &pfrom, Peer &peer,
1592 bool PrepareBlockFilterRequest(
CNode &
node, Peer &peer,
1594 uint32_t start_height,
1596 uint32_t max_height_diff,
1637 uint32_t GetAvalancheVoteForBlock(const
BlockHash &hash) const
1648 const
TxId &
id) const
1650 !m_recent_confirmed_transactions_mutex);
1659 bool SetupAddressRelay(const
CNode &
node, Peer &peer)
1662 void AddAddressKnown(Peer &peer, const
CAddress &addr)
1664 void PushAddress(Peer &peer, const
CAddress &addr)
1672 bool ReceivedAvalancheProof(
CNode &
node, Peer &peer,
1678 const
std::chrono::seconds now)
1681 bool isPreferredDownloadPeer(const
CNode &pfrom);
1684const CNodeState *PeerManagerImpl::State(
NodeId pnode) const
1686 std::map<NodeId, CNodeState>::const_iterator it = m_node_states.find(pnode);
1687 if (it == m_node_states.end()) {
1694CNodeState *PeerManagerImpl::State(
NodeId pnode)
1696 return const_cast<CNodeState *
>(std::as_const(*this).State(pnode));
1704static bool IsAddrCompatible(
const Peer &peer,
const CAddress &addr) {
1708void PeerManagerImpl::AddAddressKnown(Peer &peer,
const CAddress &addr) {
1709 assert(peer.m_addr_known);
1710 peer.m_addr_known->insert(addr.
GetKey());
1713void PeerManagerImpl::PushAddress(Peer &peer,
const CAddress &addr) {
1717 assert(peer.m_addr_known);
1718 if (addr.
IsValid() && !peer.m_addr_known->contains(addr.
GetKey()) &&
1719 IsAddrCompatible(peer, addr)) {
1720 if (peer.m_addrs_to_send.size() >= m_opts.max_addr_to_send) {
1721 peer.m_addrs_to_send[m_rng.randrange(peer.m_addrs_to_send.size())] =
1724 peer.m_addrs_to_send.push_back(addr);
1729static void AddKnownTx(Peer &peer,
const TxId &txid) {
1730 auto tx_relay = peer.GetTxRelay();
1735 LOCK(tx_relay->m_tx_inventory_mutex);
1736 tx_relay->m_tx_inventory_known_filter.insert(txid);
1740 if (peer.m_proof_relay !=
nullptr) {
1741 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
1742 peer.m_proof_relay->m_proof_inventory_known_filter.insert(proofid);
1746bool PeerManagerImpl::isPreferredDownloadPeer(
const CNode &pfrom) {
1748 const CNodeState *state = State(pfrom.
GetId());
1749 return state && state->fPreferredDownload;
1752static bool CanServeBlocks(
const Peer &peer) {
1760static bool IsLimitedPeer(
const Peer &peer) {
1765std::chrono::microseconds
1766PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
1767 std::chrono::seconds average_interval) {
1768 if (m_next_inv_to_inbounds.load() < now) {
1775 return m_next_inv_to_inbounds;
1778bool PeerManagerImpl::IsBlockRequested(
const BlockHash &hash) {
1779 return mapBlocksInFlight.count(hash);
1782bool PeerManagerImpl::IsBlockRequestedFromOutbound(
const BlockHash &hash) {
1783 for (
auto range = mapBlocksInFlight.equal_range(hash);
1784 range.first != range.second; range.first++) {
1785 auto [nodeid, block_it] = range.first->second;
1786 CNodeState &nodestate = *
Assert(State(nodeid));
1787 if (!nodestate.m_is_inbound) {
1795void PeerManagerImpl::RemoveBlockRequest(
const BlockHash &hash,
1796 std::optional<NodeId> from_peer) {
1797 auto range = mapBlocksInFlight.equal_range(hash);
1798 if (range.first == range.second) {
1806 while (range.first != range.second) {
1807 auto [node_id, list_it] = range.first->second;
1809 if (from_peer && *from_peer != node_id) {
1814 CNodeState &state = *
Assert(State(node_id));
1816 if (state.vBlocksInFlight.begin() == list_it) {
1819 state.m_downloading_since =
1820 std::max(state.m_downloading_since,
1821 GetTime<std::chrono::microseconds>());
1823 state.vBlocksInFlight.erase(list_it);
1825 if (state.vBlocksInFlight.empty()) {
1827 m_peers_downloading_from--;
1829 state.m_stalling_since = 0us;
1831 range.first = mapBlocksInFlight.erase(range.first);
1835bool PeerManagerImpl::BlockRequested(
const Config &config,
NodeId nodeid,
1837 std::list<QueuedBlock>::iterator **pit) {
1840 CNodeState *state = State(nodeid);
1841 assert(state !=
nullptr);
1846 for (
auto range = mapBlocksInFlight.equal_range(hash);
1847 range.first != range.second; range.first++) {
1848 if (range.first->second.first == nodeid) {
1850 *pit = &range.first->second.second;
1857 RemoveBlockRequest(hash, nodeid);
1859 std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(
1860 state->vBlocksInFlight.end(),
1861 {&block, std::unique_ptr<PartiallyDownloadedBlock>(
1862 pit ? new PartiallyDownloadedBlock(config, &m_mempool)
1864 if (state->vBlocksInFlight.size() == 1) {
1866 state->m_downloading_since = GetTime<std::chrono::microseconds>();
1867 m_peers_downloading_from++;
1870 auto itInFlight = mapBlocksInFlight.insert(
1871 std::make_pair(hash, std::make_pair(nodeid, it)));
1874 *pit = &itInFlight->second.second;
1880void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid) {
1886 if (m_opts.ignore_incoming_txs) {
1890 CNodeState *nodestate = State(nodeid);
1895 if (!nodestate->m_provides_cmpctblocks) {
1898 int num_outbound_hb_peers = 0;
1899 for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin();
1900 it != lNodesAnnouncingHeaderAndIDs.end(); it++) {
1901 if (*it == nodeid) {
1902 lNodesAnnouncingHeaderAndIDs.erase(it);
1903 lNodesAnnouncingHeaderAndIDs.push_back(nodeid);
1906 CNodeState *state = State(*it);
1907 if (state !=
nullptr && !state->m_is_inbound) {
1908 ++num_outbound_hb_peers;
1911 if (nodestate->m_is_inbound) {
1914 if (lNodesAnnouncingHeaderAndIDs.size() >= 3 &&
1915 num_outbound_hb_peers == 1) {
1916 CNodeState *remove_node =
1917 State(lNodesAnnouncingHeaderAndIDs.front());
1918 if (remove_node !=
nullptr && !remove_node->m_is_inbound) {
1921 std::swap(lNodesAnnouncingHeaderAndIDs.front(),
1922 *std::next(lNodesAnnouncingHeaderAndIDs.begin()));
1929 if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
1933 lNodesAnnouncingHeaderAndIDs.front(), [
this](
CNode *pnodeStop) {
1934 m_connman.PushMessage(
1935 pnodeStop, CNetMsgMaker(pnodeStop->GetCommonVersion())
1936 .Make(NetMsgType::SENDCMPCT,
1938 CMPCTBLOCKS_VERSION));
1941 pnodeStop->m_bip152_highbandwidth_to = false;
1944 lNodesAnnouncingHeaderAndIDs.pop_front();
1953 lNodesAnnouncingHeaderAndIDs.push_back(pfrom->
GetId());
1958bool PeerManagerImpl::TipMayBeStale() {
1961 if (m_last_tip_update.load() == 0s) {
1962 m_last_tip_update = GetTime<std::chrono::seconds>();
1964 return m_last_tip_update.load() <
1965 GetTime<std::chrono::seconds>() -
1968 mapBlocksInFlight.empty();
1971bool PeerManagerImpl::CanDirectFetch() {
1977static bool PeerHasHeader(CNodeState *state,
const CBlockIndex *pindex)
1979 if (state->pindexBestKnownBlock &&
1980 pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) {
1983 if (state->pindexBestHeaderSent &&
1984 pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight)) {
1990void PeerManagerImpl::ProcessBlockAvailability(
NodeId nodeid) {
1991 CNodeState *state = State(nodeid);
1992 assert(state !=
nullptr);
1994 if (!state->hashLastUnknownBlock.IsNull()) {
1998 if (state->pindexBestKnownBlock ==
nullptr ||
1999 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
2000 state->pindexBestKnownBlock = pindex;
2002 state->hashLastUnknownBlock.SetNull();
2007void PeerManagerImpl::UpdateBlockAvailability(
NodeId nodeid,
2009 CNodeState *state = State(nodeid);
2010 assert(state !=
nullptr);
2012 ProcessBlockAvailability(nodeid);
2017 if (state->pindexBestKnownBlock ==
nullptr ||
2018 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
2019 state->pindexBestKnownBlock = pindex;
2024 state->hashLastUnknownBlock = hash;
2030void PeerManagerImpl::FindNextBlocksToDownload(
2031 const Peer &peer,
unsigned int count,
2032 std::vector<const CBlockIndex *> &vBlocks,
NodeId &nodeStaller) {
2037 vBlocks.reserve(vBlocks.size() +
count);
2038 CNodeState *state = State(peer.m_id);
2039 assert(state !=
nullptr);
2042 ProcessBlockAvailability(peer.m_id);
2044 if (state->pindexBestKnownBlock ==
nullptr ||
2045 state->pindexBestKnownBlock->nChainWork <
2047 state->pindexBestKnownBlock->nChainWork <
2057 const CBlockIndex *snap_base{m_chainman.GetSnapshotBaseBlock()};
2058 if (snap_base && state->pindexBestKnownBlock->GetAncestor(
2059 snap_base->nHeight) != snap_base) {
2061 "Not downloading blocks from peer=%d, which doesn't have the "
2062 "snapshot block in its best chain.\n",
2071 if (state->pindexLastCommonBlock ==
nullptr ||
2073 state->pindexLastCommonBlock->nHeight < snap_base->nHeight)) {
2074 state->pindexLastCommonBlock =
2076 .
ActiveChain()[std::min(state->pindexBestKnownBlock->nHeight,
2083 state->pindexLastCommonBlock, state->pindexBestKnownBlock);
2084 if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) {
2088 const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
2096 FindNextBlocks(vBlocks, peer, state, pindexWalk,
count, nWindowEnd,
2100void PeerManagerImpl::TryDownloadingHistoricalBlocks(
2101 const Peer &peer,
unsigned int count,
2102 std::vector<const CBlockIndex *> &vBlocks,
const CBlockIndex *from_tip,
2107 if (vBlocks.size() >=
count) {
2111 vBlocks.reserve(
count);
2112 CNodeState *state =
Assert(State(peer.m_id));
2114 if (state->pindexBestKnownBlock ==
nullptr ||
2115 state->pindexBestKnownBlock->GetAncestor(target_block->
nHeight) !=
2130 FindNextBlocks(vBlocks, peer, state, from_tip,
count,
2135void PeerManagerImpl::FindNextBlocks(std::vector<const CBlockIndex *> &vBlocks,
2136 const Peer &peer, CNodeState *state,
2138 unsigned int count,
int nWindowEnd,
2139 const CChain *activeChain,
2141 std::vector<const CBlockIndex *> vToFetch;
2143 std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
2145 while (pindexWalk->
nHeight < nMaxHeight) {
2150 int nToFetch = std::min(nMaxHeight - pindexWalk->
nHeight,
2151 std::max<int>(
count - vBlocks.size(), 128));
2152 vToFetch.resize(nToFetch);
2153 pindexWalk = state->pindexBestKnownBlock->
GetAncestor(
2154 pindexWalk->
nHeight + nToFetch);
2155 vToFetch[nToFetch - 1] = pindexWalk;
2156 for (
unsigned int i = nToFetch - 1; i > 0; i--) {
2157 vToFetch[i - 1] = vToFetch[i]->
pprev;
2170 if (pindex->nStatus.hasData() ||
2171 (activeChain && activeChain->
Contains(pindex))) {
2173 state->pindexLastCommonBlock = pindex;
2175 }
else if (!IsBlockRequested(pindex->
GetBlockHash())) {
2177 if (pindex->
nHeight > nWindowEnd) {
2179 if (vBlocks.size() == 0 && waitingfor != peer.m_id) {
2183 *nodeStaller = waitingfor;
2188 vBlocks.push_back(pindex);
2189 if (vBlocks.size() ==
count) {
2192 }
else if (waitingfor == -1) {
2204template <
class InvId>
2208 return !
node.HasPermission(
2221template <
class InvId>
2222static std::chrono::microseconds
2226 std::chrono::microseconds current_time,
bool preferred) {
2227 auto delay = std::chrono::microseconds{0};
2239 return current_time + delay;
2242void PeerManagerImpl::PushNodeVersion(
const Config &config,
CNode &pnode,
2244 uint64_t my_services{peer.m_our_services};
2245 const int64_t nTime{
count_seconds(GetTime<std::chrono::seconds>())};
2247 const int nNodeStartingHeight{m_best_height};
2258 const bool tx_relay{!RejectIncomingTxs(pnode)};
2266 nTime, your_services, addr_you, my_services,
2268 nNodeStartingHeight, tx_relay, extraEntropy));
2272 "send version message: version %d, blocks=%d, them=%s, "
2273 "txrelay=%d, peer=%d\n",
2278 "send version message: version %d, blocks=%d, "
2279 "txrelay=%d, peer=%d\n",
2284void PeerManagerImpl::AddTxAnnouncement(
2286 std::chrono::microseconds current_time) {
2294 const bool preferred = isPreferredDownloadPeer(
node);
2296 current_time, preferred);
2298 m_txrequest.ReceivedInv(
node.GetId(), txid, preferred, reqtime);
2301void PeerManagerImpl::AddProofAnnouncement(
2303 std::chrono::microseconds current_time,
bool preferred) {
2314 m_proofrequest.ReceivedInv(
node.GetId(), proofid, preferred, reqtime);
2317void PeerManagerImpl::UpdateLastBlockAnnounceTime(
NodeId node,
2318 int64_t time_in_seconds) {
2320 CNodeState *state = State(
node);
2322 state->m_last_block_announcement = time_in_seconds;
2326void PeerManagerImpl::InitializeNode(
const Config &config,
CNode &
node,
2331 m_node_states.emplace_hint(m_node_states.end(),
2332 std::piecewise_construct,
2333 std::forward_as_tuple(nodeid),
2334 std::forward_as_tuple(
node.IsInboundConn()));
2335 assert(m_txrequest.Count(nodeid) == 0);
2343 PeerRef peer = std::make_shared<Peer>(nodeid, our_services, !!m_avalanche);
2346 m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer);
2348 if (!
node.IsInboundConn()) {
2349 PushNodeVersion(config,
node, *peer);
2353void PeerManagerImpl::ReattemptInitialBroadcast(
CScheduler &scheduler) {
2356 for (
const TxId &txid : unbroadcast_txids) {
2358 if (m_mempool.
exists(txid)) {
2359 RelayTransaction(txid);
2370 auto unbroadcasted_proofids =
2374 auto it = unbroadcasted_proofids.begin();
2375 while (it != unbroadcasted_proofids.end()) {
2378 if (!pm.isBoundToPeer(*it)) {
2379 pm.removeUnbroadcastProof(*it);
2380 it = unbroadcasted_proofids.erase(it);
2387 return unbroadcasted_proofids;
2391 for (
const auto &proofid : unbroadcasted_proofids) {
2392 RelayProof(proofid);
2399 const auto reattemptBroadcastInterval = 10min +
GetRandMillis(5min);
2400 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2401 reattemptBroadcastInterval);
2404void PeerManagerImpl::UpdateAvalancheStatistics()
const {
2410void PeerManagerImpl::AvalanchePeriodicNetworking(
CScheduler &scheduler)
const {
2411 const auto now = GetTime<std::chrono::seconds>();
2412 std::vector<NodeId> avanode_ids;
2413 bool fQuorumEstablished;
2414 bool fShouldRequestMoreNodes;
2424 fShouldRequestMoreNodes =
2432 avanode_ids.push_back(pnode->GetId());
2435 PeerRef peer = GetPeerRef(pnode->
GetId());
2436 if (peer ==
nullptr) {
2440 if (peer->m_proof_relay &&
2441 now > (peer->m_proof_relay->lastSharedProofsUpdate.load() +
2443 peer->m_proof_relay->sharedProofs = {};
2447 if (avanode_ids.empty()) {
2455 for (
NodeId avanodeId : avanode_ids) {
2456 const bool sentGetavaaddr =
2459 m_connman.PushMessage(
2460 pavanode, CNetMsgMaker(pavanode->GetCommonVersion())
2461 .Make(NetMsgType::GETAVAADDR));
2462 PeerRef peer = GetPeerRef(avanodeId);
2463 WITH_LOCK(peer->m_addr_token_bucket_mutex,
2464 peer->m_addr_token_bucket +=
2465 m_opts.max_addr_to_send);
2473 if (sentGetavaaddr && fQuorumEstablished && !fShouldRequestMoreNodes) {
2488 avanode_ids.resize(std::min<size_t>(avanode_ids.size(), 3));
2491 for (
NodeId nodeid : avanode_ids) {
2494 PeerRef peer = GetPeerRef(nodeid);
2495 if (peer->m_proof_relay) {
2500 peer->m_proof_relay->compactproofs_requested =
true;
2510 const auto avalanchePeriodicNetworkingInterval = 2min +
GetRandMillis(3min);
2511 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2512 avalanchePeriodicNetworkingInterval);
2515void PeerManagerImpl::FinalizeNode(
const Config &config,
const CNode &
node) {
2525 PeerRef peer = RemovePeer(nodeid);
2528 m_peer_map.erase(nodeid);
2530 CNodeState *state = State(nodeid);
2531 assert(state !=
nullptr);
2533 if (state->fSyncStarted) {
2537 for (
const QueuedBlock &entry : state->vBlocksInFlight) {
2539 mapBlocksInFlight.equal_range(entry.pindex->GetBlockHash());
2540 while (range.first != range.second) {
2541 auto [node_id, list_it] = range.first->second;
2542 if (node_id != nodeid) {
2545 range.first = mapBlocksInFlight.erase(range.first);
2552 m_txrequest.DisconnectedPeer(nodeid);
2553 m_num_preferred_download_peers -= state->fPreferredDownload;
2554 m_peers_downloading_from -= (!state->vBlocksInFlight.empty());
2555 assert(m_peers_downloading_from >= 0);
2556 m_outbound_peers_with_protect_from_disconnect -=
2557 state->m_chain_sync.m_protect;
2558 assert(m_outbound_peers_with_protect_from_disconnect >= 0);
2560 m_node_states.erase(nodeid);
2562 if (m_node_states.empty()) {
2564 assert(mapBlocksInFlight.empty());
2565 assert(m_num_preferred_download_peers == 0);
2566 assert(m_peers_downloading_from == 0);
2567 assert(m_outbound_peers_with_protect_from_disconnect == 0);
2568 assert(m_txrequest.Size() == 0);
2570 return orphanage.Size();
2575 if (
node.fSuccessfullyConnected && !
node.IsBlockOnlyConn() &&
2576 !
node.IsInboundConn()) {
2583 LOCK(m_headers_presync_mutex);
2584 m_headers_presync_stats.erase(nodeid);
2587 WITH_LOCK(cs_proofrequest, m_proofrequest.DisconnectedPeer(nodeid));
2592PeerRef PeerManagerImpl::GetPeerRef(
NodeId id)
const {
2594 auto it = m_peer_map.find(
id);
2595 return it != m_peer_map.end() ? it->second :
nullptr;
2598PeerRef PeerManagerImpl::RemovePeer(
NodeId id) {
2601 auto it = m_peer_map.find(
id);
2602 if (it != m_peer_map.end()) {
2603 ret = std::move(it->second);
2604 m_peer_map.erase(it);
2609bool PeerManagerImpl::GetNodeStateStats(
NodeId nodeid,
2613 const CNodeState *state = State(nodeid);
2614 if (state ==
nullptr) {
2618 ? state->pindexBestKnownBlock->nHeight
2621 ? state->pindexLastCommonBlock->nHeight
2623 for (
const QueuedBlock &queue : state->vBlocksInFlight) {
2630 PeerRef peer = GetPeerRef(nodeid);
2631 if (peer ==
nullptr) {
2643 auto ping_wait{0us};
2644 if ((0 != peer->m_ping_nonce_sent) &&
2645 (0 != peer->m_ping_start.load().count())) {
2647 GetTime<std::chrono::microseconds>() - peer->m_ping_start.load();
2650 if (
auto tx_relay = peer->GetTxRelay()) {
2652 return tx_relay->m_relay_txs);
2664 LOCK(peer->m_headers_sync_mutex);
2665 if (peer->m_headers_sync) {
2673void PeerManagerImpl::AddToCompactExtraTransactions(
const CTransactionRef &tx) {
2674 if (m_opts.max_extra_txs <= 0) {
2678 if (!vExtraTxnForCompact.size()) {
2679 vExtraTxnForCompact.resize(m_opts.max_extra_txs);
2682 vExtraTxnForCompact[vExtraTxnForCompactIt] =
2683 std::make_pair(tx->GetHash(), tx);
2684 vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
2687void PeerManagerImpl::Misbehaving(Peer &peer,
const std::string &message) {
2688 LOCK(peer.m_misbehavior_mutex);
2690 const std::string message_prefixed =
2691 message.empty() ?
"" : (
": " + message);
2692 peer.m_should_discourage =
true;
2697void PeerManagerImpl::MaybePunishNodeForBlock(
NodeId nodeid,
2699 bool via_compact_block,
2700 const std::string &message) {
2701 PeerRef peer{GetPeerRef(nodeid)};
2712 if (!via_compact_block) {
2714 Misbehaving(*peer, message);
2721 CNodeState *node_state = State(nodeid);
2722 if (node_state ==
nullptr) {
2729 if (!via_compact_block && !node_state->m_is_inbound) {
2731 Misbehaving(*peer, message);
2741 Misbehaving(*peer, message);
2747 Misbehaving(*peer, message);
2753 if (message !=
"") {
2758void PeerManagerImpl::MaybePunishNodeForTx(
NodeId nodeid,
2760 const std::string &message) {
2761 PeerRef peer{GetPeerRef(nodeid)};
2768 Misbehaving(*peer, message);
2786 if (message !=
"") {
2791bool PeerManagerImpl::BlockRequestAllowed(
const CBlockIndex *pindex) {
2797 (m_chainman.m_best_header !=
nullptr) &&
2798 (m_chainman.m_best_header->GetBlockTime() - pindex->
GetBlockTime() <
2801 *m_chainman.m_best_header, *pindex, *m_chainman.m_best_header,
2805std::optional<std::string>
2806PeerManagerImpl::FetchBlock(
const Config &config,
NodeId peer_id,
2809 return "Loading blocks ...";
2815 CNodeState *state = State(peer_id);
2816 if (state ==
nullptr) {
2817 return "Peer does not exist";
2821 RemoveBlockRequest(block_index.
GetBlockHash(), std::nullopt);
2824 if (!BlockRequested(config, peer_id, block_index)) {
2825 return "Already requested from this peer";
2834 const CNetMsgMaker msgMaker(node->GetCommonVersion());
2835 this->m_connman.PushMessage(
2836 node, msgMaker.Make(NetMsgType::GETDATA, invs));
2839 return "Node not fully connected";
2844 return std::nullopt;
2847std::unique_ptr<PeerManager>
2851 return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman,
2860 : m_rng{opts.deterministic_rng},
2862 m_chainparams(chainman.GetParams()), m_connman(connman),
2863 m_addrman(addrman), m_banman(banman), m_chainman(chainman),
2864 m_mempool(pool), m_avalanche(
avalanche), m_opts{opts} {}
2866void PeerManagerImpl::StartScheduledTasks(
CScheduler &scheduler) {
2873 "peer eviction timer should be less than stale tip check timer");
2876 this->CheckForStaleTipAndEvictPeers();
2882 const auto reattemptBroadcastInterval = 10min +
GetRandMillis(5min);
2883 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2884 reattemptBroadcastInterval);
2889 UpdateAvalancheStatistics();
2895 const auto avalanchePeriodicNetworkingInterval = 2min +
GetRandMillis(3min);
2896 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2897 avalanchePeriodicNetworkingInterval);
2906void PeerManagerImpl::BlockConnected(
2907 ChainstateRole role,
const std::shared_ptr<const CBlock> &pblock,
2911 m_last_tip_update = GetTime<std::chrono::seconds>();
2915 auto stalling_timeout = m_block_stalling_timeout.load();
2918 const auto new_timeout =
2919 std::max(std::chrono::duration_cast<std::chrono::seconds>(
2920 stalling_timeout * 0.85),
2922 if (m_block_stalling_timeout.compare_exchange_strong(stalling_timeout,
2942 LOCK(m_recent_confirmed_transactions_mutex);
2944 m_recent_confirmed_transactions.insert(ptx->GetId());
2949 for (
const auto &ptx : pblock->vtx) {
2950 m_txrequest.ForgetInvId(ptx->GetId());
2955void PeerManagerImpl::BlockDisconnected(
2956 const std::shared_ptr<const CBlock> &block,
const CBlockIndex *pindex) {
2965 LOCK(m_recent_confirmed_transactions_mutex);
2966 m_recent_confirmed_transactions.reset();
2973void PeerManagerImpl::NewPoWValidBlock(
2974 const CBlockIndex *pindex,
const std::shared_ptr<const CBlock> &pblock) {
2975 std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock =
2976 std::make_shared<const CBlockHeaderAndShortTxIDs>(*pblock);
2981 if (pindex->
nHeight <= m_highest_fast_announce) {
2984 m_highest_fast_announce = pindex->
nHeight;
2987 const std::shared_future<CSerializedNetMsg> lazy_ser{
2988 std::async(std::launch::deferred, [&] {
2993 auto most_recent_block_txs =
2994 std::make_unique<std::map<TxId, CTransactionRef>>();
2995 for (
const auto &tx : pblock->vtx) {
2996 most_recent_block_txs->emplace(tx->GetId(), tx);
2999 LOCK(m_most_recent_block_mutex);
3000 m_most_recent_block_hash = hashBlock;
3001 m_most_recent_block = pblock;
3002 m_most_recent_compact_block = pcmpctblock;
3003 m_most_recent_block_txs = std::move(most_recent_block_txs);
3007 [
this, pindex, &lazy_ser, &hashBlock](
CNode *pnode)
3015 ProcessBlockAvailability(pnode->
GetId());
3016 CNodeState &state = *State(pnode->
GetId());
3020 if (state.m_requested_hb_cmpctblocks &&
3021 !PeerHasHeader(&state, pindex) &&
3022 PeerHasHeader(&state, pindex->
pprev)) {
3024 "%s sending header-and-ids %s to peer=%d\n",
3025 "PeerManager::NewPoWValidBlock",
3026 hashBlock.ToString(), pnode->
GetId());
3029 m_connman.
PushMessage(pnode, ser_cmpctblock.Copy());
3030 state.pindexBestHeaderSent = pindex;
3039void PeerManagerImpl::UpdatedBlockTip(
const CBlockIndex *pindexNew,
3041 bool fInitialDownload) {
3042 SetBestHeight(pindexNew->
nHeight);
3046 if (fInitialDownload) {
3051 std::vector<BlockHash> vHashes;
3053 while (pindexToAnnounce != pindexFork) {
3055 pindexToAnnounce = pindexToAnnounce->
pprev;
3065 for (
auto &it : m_peer_map) {
3066 Peer &peer = *it.second;
3067 LOCK(peer.m_block_inv_mutex);
3069 peer.m_blocks_for_headers_relay.push_back(hash);
3081void PeerManagerImpl::BlockChecked(
const CBlock &block,
3086 std::map<BlockHash, std::pair<NodeId, bool>>::iterator it =
3087 mapBlockSource.find(hash);
3091 if (state.
IsInvalid() && it != mapBlockSource.end() &&
3092 State(it->second.first)) {
3093 MaybePunishNodeForBlock(it->second.first, state,
3094 !it->second.second);
3103 mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
3104 if (it != mapBlockSource.end()) {
3105 MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
3109 if (it != mapBlockSource.end()) {
3110 mapBlockSource.erase(it);
3119bool PeerManagerImpl::AlreadyHaveTx(
const TxId &txid,
3120 bool include_reconsiderable) {
3122 hashRecentRejectsChainTip) {
3127 hashRecentRejectsChainTip =
3129 m_recent_rejects.reset();
3130 m_recent_rejects_package_reconsiderable.reset();
3134 return orphanage.HaveTx(txid);
3140 return conflicting.HaveTx(txid);
3145 if (include_reconsiderable &&
3146 m_recent_rejects_package_reconsiderable.contains(txid)) {
3151 LOCK(m_recent_confirmed_transactions_mutex);
3152 if (m_recent_confirmed_transactions.contains(txid)) {
3157 return m_recent_rejects.contains(txid) || m_mempool.
exists(txid);
3160bool PeerManagerImpl::AlreadyHaveBlock(
const BlockHash &block_hash) {
3165 if (!
Assume(m_avalanche)) {
3170 if (localProof && localProof->getId() == proofid) {
3179void PeerManagerImpl::SendPings() {
3181 for (
auto &it : m_peer_map) {
3182 it.second->m_ping_queued =
true;
3186void PeerManagerImpl::RelayTransaction(
const TxId &txid) {
3188 for (
auto &it : m_peer_map) {
3189 Peer &peer = *it.second;
3190 auto tx_relay = peer.GetTxRelay();
3194 LOCK(tx_relay->m_tx_inventory_mutex);
3200 if (tx_relay->m_next_inv_send_time == 0s) {
3204 if (!tx_relay->m_tx_inventory_known_filter.contains(txid) ||
3205 tx_relay->m_avalanche_stalled_txids.count(txid) > 0) {
3206 tx_relay->m_tx_inventory_to_send.insert(txid);
3213 for (
auto &it : m_peer_map) {
3214 Peer &peer = *it.second;
3216 if (!peer.m_proof_relay) {
3219 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
3220 if (!peer.m_proof_relay->m_proof_inventory_known_filter.contains(
3222 peer.m_proof_relay->m_proof_inventory_to_send.insert(proofid);
3227void PeerManagerImpl::RelayAddress(
NodeId originator,
const CAddress &addr,
3243 const auto current_time{GetTime<std::chrono::seconds>()};
3246 const uint64_t time_addr{
3247 (
static_cast<uint64_t
>(
count_seconds(current_time)) + hash_addr) /
3257 unsigned int nRelayNodes = (fReachable || (hasher.Finalize() & 1)) ? 2 : 1;
3258 std::array<std::pair<uint64_t, Peer *>, 2> best{
3259 {{0,
nullptr}, {0,
nullptr}}};
3260 assert(nRelayNodes <= best.size());
3264 for (
auto &[
id, peer] : m_peer_map) {
3265 if (peer->m_addr_relay_enabled &&
id != originator &&
3266 IsAddrCompatible(*peer, addr)) {
3268 for (
unsigned int i = 0; i < nRelayNodes; i++) {
3269 if (hashKey > best[i].first) {
3270 std::copy(best.begin() + i, best.begin() + nRelayNodes - 1,
3271 best.begin() + i + 1);
3272 best[i] = std::make_pair(hashKey, peer.get());
3279 for (
unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
3280 PushAddress(*best[i].second, addr);
3284void PeerManagerImpl::ProcessGetBlockData(
const Config &config,
CNode &pfrom,
3285 Peer &peer,
const CInv &inv) {
3288 std::shared_ptr<const CBlock> a_recent_block;
3289 std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
3291 LOCK(m_most_recent_block_mutex);
3292 a_recent_block = m_most_recent_block;
3293 a_recent_compact_block = m_most_recent_compact_block;
3296 bool need_activate_chain =
false;
3310 need_activate_chain =
true;
3314 if (need_activate_chain) {
3317 state, a_recent_block, m_avalanche)) {
3326 bool can_direct_fetch{
false};
3334 if (!BlockRequestAllowed(pindex)) {
3336 "%s: ignoring request from peer=%i for old "
3337 "block that isn't in the main chain\n",
3338 __func__, pfrom.
GetId());
3344 (((m_chainman.m_best_header !=
nullptr) &&
3345 (m_chainman.m_best_header->GetBlockTime() -
3353 "historical block serving limit reached, disconnect peer=%d\n",
3366 (tip->nHeight - pindex->
nHeight >
3369 "Ignore block request below NODE_NETWORK_LIMITED "
3370 "threshold, disconnect peer=%d\n",
3380 if (!pindex->nStatus.hasData()) {
3383 can_direct_fetch = CanDirectFetch();
3387 std::shared_ptr<const CBlock> pblock;
3388 auto handle_block_read_error = [&]() {
3390 return m_chainman.
m_blockman.IsBlockPruned(*pindex))) {
3392 "Block was pruned before it could be read, disconnect "
3396 LogError(
"Cannot load block from disk, disconnect peer=%d\n",
3402 if (a_recent_block && a_recent_block->GetHash() == pindex->
GetBlockHash()) {
3403 pblock = a_recent_block;
3407 std::vector<uint8_t> block_data;
3410 handle_block_read_error();
3418 std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
3420 handle_block_read_error();
3423 pblock = pblockRead;
3430 bool sendMerkleBlock =
false;
3432 if (
auto tx_relay = peer.GetTxRelay()) {
3433 LOCK(tx_relay->m_bloom_filter_mutex);
3434 if (tx_relay->m_bloom_filter) {
3435 sendMerkleBlock =
true;
3440 if (sendMerkleBlock) {
3453 typedef std::pair<size_t, uint256> PairType;
3457 *pblock->vtx[pair.first]));
3468 if (can_direct_fetch &&
3470 if (a_recent_compact_block &&
3471 a_recent_compact_block->header.GetHash() ==
3475 *a_recent_compact_block));
3479 msgMaker.Make(nSendFlags,
3492 LOCK(peer.m_block_inv_mutex);
3495 if (hash == peer.m_continuation_block) {
3499 std::vector<CInv> vInv;
3502 peer.m_continuation_block =
BlockHash();
3508PeerManagerImpl::FindTxForGetData(
const Peer &peer,
const TxId &txid,
3509 const std::chrono::seconds mempool_req,
3510 const std::chrono::seconds now) {
3511 auto txinfo = m_mempool.
info(txid);
3516 if ((mempool_req.count() && txinfo.m_time <= mempool_req) ||
3518 return std::move(txinfo.tx);
3527 Assume(peer.GetTxRelay())->m_recently_announced_invs.contains(txid);
3528 if (recent && txinfo.tx) {
3529 return std::move(txinfo.tx);
3534 LOCK(m_most_recent_block_mutex);
3535 if (m_most_recent_block_txs !=
nullptr) {
3536 auto it = m_most_recent_block_txs->find(txid);
3537 if (it != m_most_recent_block_txs->end()) {
3550PeerManagerImpl::FindProofForGetData(
const Peer &peer,
3552 const std::chrono::seconds now) {
3555 bool send_unconditionally =
3581 if (send_unconditionally) {
3586 if (peer.m_proof_relay->m_recently_announced_proofs.contains(proofid)) {
3593void PeerManagerImpl::ProcessGetData(
3595 const std::atomic<bool> &interruptMsgProc) {
3598 auto tx_relay = peer.GetTxRelay();
3600 std::deque<CInv>::iterator it = peer.m_getdata_requests.begin();
3601 std::vector<CInv> vNotFound;
3604 const auto now{GetTime<std::chrono::seconds>()};
3606 const auto mempool_req = tx_relay !=
nullptr
3607 ? tx_relay->m_last_mempool_req.load()
3608 : std::chrono::seconds::min();
3613 while (it != peer.m_getdata_requests.end()) {
3614 if (interruptMsgProc) {
3623 const CInv &inv = *it;
3625 if (it->IsMsgProof()) {
3627 vNotFound.push_back(inv);
3632 auto proof = FindProofForGetData(peer, proofid, now);
3640 vNotFound.push_back(inv);
3647 if (it->IsMsgTx()) {
3648 if (tx_relay ==
nullptr) {
3664 std::vector<TxId> parent_ids_to_add;
3667 auto txiter = m_mempool.
GetIter(tx->GetId());
3669 auto &pentry = *txiter;
3671 (*pentry)->GetMemPoolParentsConst();
3672 parent_ids_to_add.reserve(parents.size());
3673 for (
const auto &parent : parents) {
3674 if (parent.get()->GetTime() >
3676 parent_ids_to_add.push_back(
3677 parent.get()->GetTx().GetId());
3682 for (
const TxId &parent_txid : parent_ids_to_add) {
3685 if (
WITH_LOCK(tx_relay->m_tx_inventory_mutex,
3686 return !tx_relay->m_tx_inventory_known_filter
3687 .contains(parent_txid))) {
3688 tx_relay->m_recently_announced_invs.insert(parent_txid);
3692 vNotFound.push_back(inv);
3705 if (it != peer.m_getdata_requests.end() && !pfrom.
fPauseSend) {
3706 const CInv &inv = *it++;
3708 ProcessGetBlockData(config, pfrom, peer, inv);
3714 peer.m_getdata_requests.erase(peer.m_getdata_requests.begin(), it);
3716 if (!vNotFound.empty()) {
3734void PeerManagerImpl::SendBlockTransactions(
3738 for (
size_t i = 0; i < req.
indices.size(); i++) {
3740 Misbehaving(peer,
"getblocktxn with out-of-bounds tx indices");
3752bool PeerManagerImpl::CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
3757 Misbehaving(peer,
"header with invalid proof of work");
3762 if (!CheckHeadersAreContinuous(headers)) {
3763 Misbehaving(peer,
"non-continuous headers sequence");
3776 near_chaintip_work =
3789void PeerManagerImpl::HandleUnconnectingHeaders(
3790 CNode &pfrom, Peer &peer,
const std::vector<CBlockHeader> &headers) {
3796 if (MaybeSendGetHeaders(pfrom,
GetLocator(best_header), peer)) {
3799 "received header %s: missing prev block %s, sending getheaders "
3800 "(%d) to end (peer=%d)\n",
3802 headers[0].hashPrevBlock.ToString(), best_header->nHeight,
3810 UpdateBlockAvailability(pfrom.
GetId(), headers.back().GetHash()));
3813bool PeerManagerImpl::CheckHeadersAreContinuous(
3814 const std::vector<CBlockHeader> &headers)
const {
3817 if (!hashLastBlock.
IsNull() && header.hashPrevBlock != hashLastBlock) {
3820 hashLastBlock = header.GetHash();
3825bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(
3826 Peer &peer,
CNode &pfrom, std::vector<CBlockHeader> &headers) {
3827 if (peer.m_headers_sync) {
3828 auto result = peer.m_headers_sync->ProcessNextHeaders(
3832 if (result.success) {
3833 peer.m_last_getheaders_timestamp = {};
3835 if (result.request_more) {
3836 auto locator = peer.m_headers_sync->NextHeadersRequestLocator();
3839 Assume(!locator.vHave.empty());
3843 if (!locator.vHave.empty()) {
3846 bool sent_getheaders =
3847 MaybeSendGetHeaders(pfrom, locator, peer);
3850 locator.vHave.front().ToString(), pfrom.
GetId());
3855 peer.m_headers_sync.reset(
nullptr);
3860 LOCK(m_headers_presync_mutex);
3861 m_headers_presync_stats.erase(pfrom.
GetId());
3864 HeadersPresyncStats stats;
3865 stats.first = peer.m_headers_sync->GetPresyncWork();
3866 if (peer.m_headers_sync->GetState() ==
3868 stats.second = {peer.m_headers_sync->GetPresyncHeight(),
3869 peer.m_headers_sync->GetPresyncTime()};
3873 LOCK(m_headers_presync_mutex);
3874 m_headers_presync_stats[pfrom.
GetId()] = stats;
3876 m_headers_presync_stats.find(m_headers_presync_bestpeer);
3877 bool best_updated =
false;
3878 if (best_it == m_headers_presync_stats.end()) {
3883 const HeadersPresyncStats *stat_best{
nullptr};
3884 for (
const auto &[_peer, _stat] : m_headers_presync_stats) {
3885 if (!stat_best || _stat > *stat_best) {
3890 m_headers_presync_bestpeer = peer_best;
3891 best_updated = (peer_best == pfrom.
GetId());
3892 }
else if (best_it->first == pfrom.
GetId() ||
3893 stats > best_it->second) {
3896 m_headers_presync_bestpeer = pfrom.
GetId();
3897 best_updated =
true;
3899 if (best_updated && stats.second.has_value()) {
3902 m_headers_presync_should_signal =
true;
3906 if (result.success) {
3909 headers.swap(result.pow_validated_headers);
3912 return result.success;
3920bool PeerManagerImpl::TryLowWorkHeadersSync(
3922 std::vector<CBlockHeader> &headers) {
3929 arith_uint256 minimum_chain_work = GetAntiDoSWorkThreshold();
3933 if (total_work < minimum_chain_work) {
3947 LOCK(peer.m_headers_sync_mutex);
3948 peer.m_headers_sync.reset(
3950 chain_start_header, minimum_chain_work));
3955 (void)IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
3958 "Ignoring low-work chain (height=%u) from peer=%d\n",
3959 chain_start_header->
nHeight + headers.size(),
3971bool PeerManagerImpl::IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header) {
3972 return header !=
nullptr &&
3973 ((m_chainman.m_best_header !=
nullptr &&
3975 m_chainman.m_best_header->GetAncestor(header->
nHeight)) ||
3979bool PeerManagerImpl::MaybeSendGetHeaders(
CNode &pfrom,
3988 if (current_time - peer.m_last_getheaders_timestamp >
3992 peer.m_last_getheaders_timestamp = current_time;
4004void PeerManagerImpl::HeadersDirectFetchBlocks(
const Config &config,
4010 CNodeState *nodestate = State(pfrom.
GetId());
4014 std::vector<const CBlockIndex *> vToFetch;
4020 if (!pindexWalk->nStatus.hasData() &&
4023 vToFetch.push_back(pindexWalk);
4025 pindexWalk = pindexWalk->
pprev;
4036 std::vector<CInv> vGetData;
4039 if (nodestate->vBlocksInFlight.size() >=
4045 BlockRequested(config, pfrom.
GetId(), *pindex);
4049 if (vGetData.size() > 1) {
4051 "Downloading blocks toward %s (%d) via headers "
4056 if (vGetData.size() > 0) {
4057 if (!m_opts.ignore_incoming_txs &&
4058 nodestate->m_provides_cmpctblocks && vGetData.size() == 1 &&
4059 mapBlocksInFlight.size() == 1 &&
4077void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(
4079 bool received_new_header,
bool may_have_more_headers) {
4082 CNodeState *nodestate = State(pfrom.
GetId());
4090 if (received_new_header &&
4092 nodestate->m_last_block_announcement =
GetTime();
4100 if (nodestate->pindexBestKnownBlock &&
4101 nodestate->pindexBestKnownBlock->nChainWork <
4112 LogPrintf(
"Disconnecting outbound peer %d -- headers "
4113 "chain has insufficient work\n",
4127 nodestate->pindexBestKnownBlock !=
nullptr) {
4128 if (m_outbound_peers_with_protect_from_disconnect <
4130 nodestate->pindexBestKnownBlock->nChainWork >=
4132 !nodestate->m_chain_sync.m_protect) {
4135 nodestate->m_chain_sync.m_protect =
true;
4136 ++m_outbound_peers_with_protect_from_disconnect;
4141void PeerManagerImpl::ProcessHeadersMessage(
const Config &config,
CNode &pfrom,
4143 std::vector<CBlockHeader> &&headers,
4144 bool via_compact_block) {
4145 size_t nCount = headers.size();
4153 LOCK(peer.m_headers_sync_mutex);
4154 if (peer.m_headers_sync) {
4155 peer.m_headers_sync.reset(
nullptr);
4156 LOCK(m_headers_presync_mutex);
4157 m_headers_presync_stats.erase(pfrom.
GetId());
4162 peer.m_last_getheaders_timestamp = {};
4170 if (!CheckHeadersPoW(headers, m_chainparams.
GetConsensus(), peer)) {
4185 bool already_validated_work =
false;
4188 bool have_headers_sync =
false;
4190 LOCK(peer.m_headers_sync_mutex);
4192 already_validated_work =
4193 IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
4205 if (headers.empty()) {
4209 have_headers_sync = !!peer.m_headers_sync;
4215 headers[0].hashPrevBlock))};
4216 bool headers_connect_blockindex{chain_start_header !=
nullptr};
4218 if (!headers_connect_blockindex) {
4222 HandleUnconnectingHeaders(pfrom, peer, headers);
4230 peer.m_last_getheaders_timestamp = {};
4239 last_received_header =
4241 if (IsAncestorOfBestHeaderOrTip(last_received_header)) {
4242 already_validated_work =
true;
4250 already_validated_work =
true;
4256 if (!already_validated_work &&
4257 TryLowWorkHeadersSync(peer, pfrom, chain_start_header, headers)) {
4269 bool received_new_header{last_received_header ==
nullptr};
4274 state, &pindexLast)) {
4276 MaybePunishNodeForBlock(pfrom.
GetId(), state, via_compact_block,
4277 "invalid header received");
4287 if (MaybeSendGetHeaders(pfrom,
GetLocator(pindexLast), peer)) {
4290 "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
4291 pindexLast->
nHeight, pfrom.
GetId(), peer.m_starting_height);
4295 UpdatePeerStateForReceivedHeaders(pfrom, peer, *pindexLast,
4296 received_new_header,
4300 HeadersDirectFetchBlocks(config, pfrom, *pindexLast);
4303void PeerManagerImpl::ProcessInvalidTx(
NodeId nodeid,
4306 bool maybe_add_extra_compact_tx) {
4311 const TxId &txid = ptx->GetId();
4331 m_recent_rejects_package_reconsiderable.insert(txid);
4333 m_recent_rejects.insert(txid);
4335 m_txrequest.ForgetInvId(txid);
4338 AddToCompactExtraTransactions(ptx);
4341 MaybePunishNodeForTx(nodeid, state);
4347 return orphanage.EraseTx(txid);
4361 m_txrequest.ForgetInvId(tx->GetId());
4367 orphanage.
EraseTx(tx->GetId());
4372 "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
4373 nodeid, tx->GetId().ToString(), m_mempool.
size(),
4376 RelayTransaction(tx->GetId());
4379void PeerManagerImpl::ProcessPackageResult(
4380 const PackageToValidate &package_to_validate,
4386 const auto &
package = package_to_validate.m_txns;
4387 const auto &senders = package_to_validate.m_senders;
4390 m_recent_rejects_package_reconsiderable.insert(
GetPackageHash(package));
4394 if (!
Assume(package.size() == 2)) {
4400 auto package_iter = package.rbegin();
4401 auto senders_iter = senders.rbegin();
4402 while (package_iter != package.rend()) {
4403 const auto &tx = *package_iter;
4404 const NodeId nodeid = *senders_iter;
4405 const auto it_result{package_result.
m_tx_results.find(tx->GetId())};
4409 const auto &tx_result = it_result->second;
4410 switch (tx_result.m_result_type) {
4412 ProcessValidTx(nodeid, tx);
4422 ProcessInvalidTx(nodeid, tx, tx_result.m_state,
4439std::optional<PeerManagerImpl::PackageToValidate>
4445 const auto &parent_txid{ptx->GetId()};
4447 Assume(m_recent_rejects_package_reconsiderable.contains(parent_txid));
4453 const auto cpfp_candidates_same_peer{
4459 for (
const auto &child : cpfp_candidates_same_peer) {
4460 Package maybe_cpfp_package{ptx, child};
4461 if (!m_recent_rejects_package_reconsiderable.contains(
4463 return PeerManagerImpl::PackageToValidate{ptx, child, nodeid,
4477 const auto cpfp_candidates_different_peer{
4487 std::vector<size_t> tx_indices(cpfp_candidates_different_peer.size());
4488 std::iota(tx_indices.begin(), tx_indices.end(), 0);
4489 Shuffle(tx_indices.begin(), tx_indices.end(), m_rng);
4491 for (
const auto index : tx_indices) {
4494 const auto [child_tx, child_sender] =
4495 cpfp_candidates_different_peer.at(index);
4496 Package maybe_cpfp_package{ptx, child_tx};
4497 if (!m_recent_rejects_package_reconsiderable.contains(
4499 return PeerManagerImpl::PackageToValidate{ptx, child_tx, nodeid,
4503 return std::nullopt;
4506bool PeerManagerImpl::ProcessOrphanTx(
const Config &config, Peer &peer) {
4512 return orphanage.GetTxToReconsider(peer.m_id);
4517 const TxId &orphanTxId = porphanTx->GetId();
4522 ProcessValidTx(peer.m_id, porphanTx);
4528 " invalid orphan tx %s from peer=%d. %s\n",
4535 ProcessInvalidTx(peer.m_id, porphanTx, state,
4546bool PeerManagerImpl::PrepareBlockFilterRequest(
4548 const BlockHash &stop_hash, uint32_t max_height_diff,
4550 const bool supported_filter_type =
4553 if (!supported_filter_type) {
4555 "peer %d requested unsupported block filter type: %d\n",
4556 node.GetId(),
static_cast<uint8_t
>(filter_type));
4557 node.fDisconnect =
true;
4567 if (!stop_index || !BlockRequestAllowed(stop_index)) {
4570 node.fDisconnect =
true;
4575 uint32_t stop_height = stop_index->
nHeight;
4576 if (start_height > stop_height) {
4579 "peer %d sent invalid getcfilters/getcfheaders with "
4581 "start height %d and stop height %d\n",
4582 node.GetId(), start_height, stop_height);
4583 node.fDisconnect =
true;
4586 if (stop_height - start_height >= max_height_diff) {
4588 "peer %d requested too many cfilters/cfheaders: %d / %d\n",
4589 node.GetId(), stop_height - start_height + 1, max_height_diff);
4590 node.fDisconnect =
true;
4595 if (!filter_index) {
4604void PeerManagerImpl::ProcessGetCFilters(
CNode &
node, Peer &peer,
4606 uint8_t filter_type_ser;
4607 uint32_t start_height;
4610 vRecv >> filter_type_ser >> start_height >> stop_hash;
4617 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4623 std::vector<BlockFilter> filters;
4626 "Failed to find block filter in index: filter_type=%s, "
4627 "start_height=%d, stop_hash=%s\n",
4633 for (
const auto &filter : filters) {
4640void PeerManagerImpl::ProcessGetCFHeaders(
CNode &
node, Peer &peer,
4642 uint8_t filter_type_ser;
4643 uint32_t start_height;
4646 vRecv >> filter_type_ser >> start_height >> stop_hash;
4653 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4660 if (start_height > 0) {
4662 stop_index->
GetAncestor(
static_cast<int>(start_height - 1));
4665 "Failed to find block filter header in index: "
4666 "filter_type=%s, block_hash=%s\n",
4673 std::vector<uint256> filter_hashes;
4677 "Failed to find block filter hashes in index: filter_type=%s, "
4678 "start_height=%d, stop_hash=%s\n",
4687 stop_index->
GetBlockHash(), prev_header, filter_hashes);
4691void PeerManagerImpl::ProcessGetCFCheckPt(
CNode &
node, Peer &peer,
4693 uint8_t filter_type_ser;
4696 vRecv >> filter_type_ser >> stop_hash;
4703 if (!PrepareBlockFilterRequest(
4704 node, peer, filter_type, 0, stop_hash,
4705 std::numeric_limits<uint32_t>::max(),
4706 stop_index, filter_index)) {
4714 for (
int i = headers.size() - 1; i >= 0; i--) {
4720 "Failed to find block filter header in index: "
4721 "filter_type=%s, block_hash=%s\n",
4746PeerManagerImpl::GetAvalancheVoteForBlock(
const BlockHash &hash)
const {
4757 if (pindex->nStatus.isInvalid()) {
4762 if (pindex->nStatus.isOnParkedChain()) {
4770 if (pindex == pindexFork) {
4775 if (pindexFork != pindexTip) {
4780 if (!pindex->nStatus.hasData()) {
4791 const TxId &
id)
const {
4793 if (
WITH_LOCK(m_recent_confirmed_transactions_mutex,
4794 return m_recent_confirmed_transactions.contains(
id))) {
4803 if (m_recent_rejects.contains(
id)) {
4815 if (
auto iter = m_mempool.
GetIter(
id)) {
4816 mempool_tx = (**iter)->GetSharedTx();
4821 return conflicting.HaveTx(id);
4828 return orphanage.HaveTx(id);
4894 const std::shared_ptr<const CBlock> &block,
4895 bool force_processing,
4896 bool min_pow_checked) {
4897 bool new_block{
false};
4899 &new_block, m_avalanche);
4901 node.m_last_block_time = GetTime<std::chrono::seconds>();
4906 RemoveBlockRequest(block->GetHash(), std::nullopt);
4909 mapBlockSource.erase(block->GetHash());
4913void PeerManagerImpl::ProcessMessage(
4914 const Config &config,
CNode &pfrom,
const std::string &msg_type,
4915 CDataStream &vRecv,
const std::chrono::microseconds time_received,
4916 const std::atomic<bool> &interruptMsgProc) {
4922 PeerRef peer = GetPeerRef(pfrom.
GetId());
4923 if (peer ==
nullptr) {
4929 "Avalanche is not initialized, ignoring %s message\n",
4944 uint64_t nNonce = 1;
4947 std::string cleanSubVer;
4948 int starting_height = -1;
4950 uint64_t nExtraEntropy = 1;
4952 vRecv >> nVersion >> Using<CustomUintFormatter<8>>(nServices) >> nTime;
4965 "peer=%d does not offer the expected services "
4966 "(%08x offered, %08x expected); disconnecting\n",
4967 pfrom.
GetId(), nServices,
4977 "peer=%d does not offer the avalanche service; disconnecting\n",
4986 "peer=%d using obsolete version %i; disconnecting\n",
4987 pfrom.
GetId(), nVersion);
4992 if (!vRecv.
empty()) {
5001 if (!vRecv.
empty()) {
5002 std::string strSubVer;
5006 if (!vRecv.
empty()) {
5007 vRecv >> starting_height;
5009 if (!vRecv.
empty()) {
5012 if (!vRecv.
empty()) {
5013 vRecv >> nExtraEntropy;
5017 LogPrintf(
"connected to self at %s, disconnecting\n",
5030 PushNodeVersion(config, pfrom, *peer);
5034 const int greatest_common_version =
5048 peer->m_their_services = nServices;
5052 pfrom.cleanSubVer = cleanSubVer;
5054 peer->m_starting_height = starting_height;
5062 (fRelay || (peer->m_our_services &
NODE_BLOOM))) {
5063 auto *
const tx_relay = peer->SetTxRelay();
5065 LOCK(tx_relay->m_bloom_filter_mutex);
5067 tx_relay->m_relay_txs = fRelay;
5080 CNodeState *state = State(pfrom.
GetId());
5081 state->fPreferredDownload =
5085 m_num_preferred_download_peers += state->fPreferredDownload;
5091 bool send_getaddr{
false};
5093 send_getaddr = SetupAddressRelay(pfrom, *peer);
5105 peer->m_getaddr_sent =
true;
5109 WITH_LOCK(peer->m_addr_token_bucket_mutex,
5110 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
5131 std::string remoteAddr;
5137 "receive version message: [%s] %s: version %d, blocks=%d, "
5138 "us=%s, txrelay=%d, peer=%d%s\n",
5140 peer->m_starting_height, addrMe.ToString(), fRelay,
5141 pfrom.
GetId(), remoteAddr);
5143 int64_t currentTime =
GetTime();
5144 int64_t nTimeOffset = nTime - currentTime;
5149 Misbehaving(*peer,
"Ignoring invalid timestamp in version message");
5159 "feeler connection completed peer=%d; disconnecting\n",
5168 Misbehaving(*peer,
"non-version message before version handshake");
5178 "ignoring redundant verack message from peer=%d\n",
5185 "New outbound peer connected: version: %d, blocks=%d, "
5187 pfrom.
nVersion.load(), peer->m_starting_height, pfrom.
GetId(),
5209 AddKnownProof(*peer, localProof->getId());
5213 peer->m_proof_relay->m_recently_announced_proofs.insert(
5214 localProof->getId());
5219 if (
auto tx_relay = peer->GetTxRelay()) {
5228 return tx_relay->m_tx_inventory_to_send.empty() &&
5229 tx_relay->m_next_inv_send_time == 0s));
5238 Misbehaving(*peer,
"non-verack message before version handshake");
5252 std::vector<CAddress> vAddr;
5256 if (!SetupAddressRelay(pfrom, *peer)) {
5262 if (vAddr.size() > m_opts.max_addr_to_send) {
5263 Misbehaving(*peer,
strprintf(
"%s message size = %u", msg_type,
5269 std::vector<CAddress> vAddrOk;
5270 const auto current_a_time{Now<NodeSeconds>()};
5273 const auto current_time = GetTime<std::chrono::microseconds>();
5275 LOCK(peer->m_addr_token_bucket_mutex);
5278 const auto time_diff =
5279 std::max(current_time - peer->m_addr_token_timestamp, 0us);
5280 const double increment =
5282 peer->m_addr_token_bucket =
5283 std::min<double>(peer->m_addr_token_bucket + increment,
5287 peer->m_addr_token_timestamp = current_time;
5289 const bool rate_limited =
5291 uint64_t num_proc = 0;
5292 uint64_t num_rate_limit = 0;
5293 Shuffle(vAddr.begin(), vAddr.end(), m_rng);
5295 if (interruptMsgProc) {
5300 LOCK(peer->m_addr_token_bucket_mutex);
5302 if (peer->m_addr_token_bucket < 1.0) {
5308 peer->m_addr_token_bucket -= 1.0;
5321 addr.
nTime > current_a_time + 10min) {
5322 addr.
nTime = current_a_time - 5 * 24h;
5324 AddAddressKnown(*peer, addr);
5333 if (addr.
nTime > current_a_time - 10min && !peer->m_getaddr_sent &&
5336 RelayAddress(pfrom.
GetId(), addr, fReachable);
5340 vAddrOk.push_back(addr);
5343 peer->m_addr_processed += num_proc;
5344 peer->m_addr_rate_limited += num_rate_limit;
5346 "Received addr: %u addresses (%u processed, %u rate-limited) "
5348 vAddr.size(), num_proc, num_rate_limit, pfrom.
GetId());
5350 m_addrman.
Add(vAddrOk, pfrom.
addr, 2h);
5351 if (vAddr.size() < 1000) {
5352 peer->m_getaddr_sent =
false;
5359 "addrfetch connection completed peer=%d; disconnecting\n",
5367 peer->m_wants_addrv2 =
true;
5372 peer->m_prefers_headers =
true;
5377 bool sendcmpct_hb{
false};
5378 uint64_t sendcmpct_version{0};
5379 vRecv >> sendcmpct_hb >> sendcmpct_version;
5386 CNodeState *nodestate = State(pfrom.
GetId());
5387 nodestate->m_provides_cmpctblocks =
true;
5388 nodestate->m_requested_hb_cmpctblocks = sendcmpct_hb;
5397 std::vector<CInv> vInv;
5400 Misbehaving(*peer,
strprintf(
"inv message size = %u", vInv.size()));
5404 const bool reject_tx_invs{RejectIncomingTxs(pfrom)};
5406 const auto current_time{GetTime<std::chrono::microseconds>()};
5407 std::optional<BlockHash> best_block;
5409 auto logInv = [&](
const CInv &inv,
bool fAlreadyHave) {
5411 fAlreadyHave ?
"have" :
"new", pfrom.
GetId());
5414 for (
CInv &inv : vInv) {
5415 if (interruptMsgProc) {
5427 const bool fAlreadyHave = AlreadyHaveBlock(
BlockHash(inv.
hash));
5428 logInv(inv, fAlreadyHave);
5431 UpdateBlockAvailability(pfrom.
GetId(), hash);
5433 !IsBlockRequested(hash)) {
5440 best_block = std::move(hash);
5451 const bool fAlreadyHave = AlreadyHaveProof(proofid);
5452 logInv(inv, fAlreadyHave);
5453 AddKnownProof(*peer, proofid);
5455 if (!fAlreadyHave && m_avalanche &&
5457 const bool preferred = isPreferredDownloadPeer(pfrom);
5459 LOCK(cs_proofrequest);
5460 AddProofAnnouncement(pfrom, proofid, current_time,
5469 const bool fAlreadyHave =
5470 AlreadyHaveTx(txid,
true);
5471 logInv(inv, fAlreadyHave);
5473 AddKnownTx(*peer, txid);
5474 if (reject_tx_invs) {
5476 "transaction (%s) inv sent in violation of "
5477 "protocol, disconnecting peer=%d\n",
5481 }
else if (!fAlreadyHave &&
5483 AddTxAnnouncement(pfrom, txid, current_time);
5490 "Unknown inv type \"%s\" received from peer=%d\n",
5507 if (state.fSyncStarted ||
5508 (!peer->m_inv_triggered_getheaders_before_sync &&
5509 *best_block != m_last_block_inv_triggering_headers_sync)) {
5510 if (MaybeSendGetHeaders(
5511 pfrom,
GetLocator(m_chainman.m_best_header), *peer)) {
5513 m_chainman.m_best_header->nHeight,
5514 best_block->ToString(), pfrom.
GetId());
5516 if (!state.fSyncStarted) {
5517 peer->m_inv_triggered_getheaders_before_sync =
true;
5521 m_last_block_inv_triggering_headers_sync = *best_block;
5530 std::vector<CInv> vInv;
5534 strprintf(
"getdata message size = %u", vInv.size()));
5539 vInv.size(), pfrom.
GetId());
5541 if (vInv.size() > 0) {
5547 LOCK(peer->m_getdata_requests_mutex);
5548 peer->m_getdata_requests.insert(peer->m_getdata_requests.end(),
5549 vInv.begin(), vInv.end());
5550 ProcessGetData(config, pfrom, *peer, interruptMsgProc);
5559 vRecv >> locator >> hashStop;
5563 "getblocks locator size %lld > %d, disconnect peer=%d\n",
5577 std::shared_ptr<const CBlock> a_recent_block;
5579 LOCK(m_most_recent_block_mutex);
5580 a_recent_block = m_most_recent_block;
5584 state, a_recent_block, m_avalanche)) {
5602 (pindex ? pindex->
nHeight : -1),
5605 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5614 const int nPrunedBlocksLikelyToHave =
5618 (!pindex->nStatus.hasData() ||
5620 nPrunedBlocksLikelyToHave)) {
5623 " getblocks stopping, pruned or too old block at %d %s\n",
5628 peer->m_block_inv_mutex,
5629 peer->m_blocks_for_inv_relay.push_back(pindex->
GetBlockHash()));
5630 if (--nLimit <= 0) {
5636 peer->m_continuation_block = pindex->GetBlockHash();
5648 std::shared_ptr<const CBlock> recent_block;
5650 LOCK(m_most_recent_block_mutex);
5651 if (m_most_recent_block_hash == req.
blockhash) {
5652 recent_block = m_most_recent_block;
5657 SendBlockTransactions(pfrom, *peer, *recent_block, req);
5667 if (!pindex || !pindex->nStatus.hasData()) {
5670 "Peer %d sent us a getblocktxn for a block we don't have\n",
5681 if (!block_pos.IsNull()) {
5690 SendBlockTransactions(pfrom, *peer, block, req);
5702 "Peer %d sent us a getblocktxn for a block > %i deep\n",
5707 WITH_LOCK(peer->m_getdata_requests_mutex,
5708 peer->m_getdata_requests.push_back(inv));
5717 vRecv >> locator >> hashStop;
5721 "getheaders locator size %lld > %d, disconnect peer=%d\n",
5730 "Ignoring getheaders from peer=%d while importing/reindexing\n",
5744 if (m_chainman.
ActiveTip() ==
nullptr ||
5749 "Ignoring getheaders from peer=%d because active chain "
5750 "has too little work; sending empty response\n",
5755 std::vector<CBlock>()));
5759 CNodeState *nodestate = State(pfrom.
GetId());
5768 if (!BlockRequestAllowed(pindex)) {
5770 "%s: ignoring request from peer=%i for old block "
5771 "header that isn't in the main chain\n",
5772 __func__, pfrom.
GetId());
5786 std::vector<CBlock> vHeaders;
5789 (pindex ? pindex->
nHeight : -1),
5792 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5794 if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) {
5811 nodestate->pindexBestHeaderSent =
5819 if (RejectIncomingTxs(pfrom)) {
5821 "transaction sent in violation of protocol peer=%d\n",
5837 const CTransaction &tx = *ptx;
5838 const TxId &txid = tx.GetId();
5839 AddKnownTx(*peer, txid);
5844 m_txrequest.ReceivedResponse(pfrom.
GetId(), txid);
5846 if (AlreadyHaveTx(txid,
true)) {
5852 if (!m_mempool.
exists(tx.GetId())) {
5854 "Not relaying non-mempool transaction %s from "
5855 "forcerelay peer=%d\n",
5856 tx.GetId().ToString(), pfrom.
GetId());
5858 LogPrintf(
"Force relaying tx %s from peer=%d\n",
5859 tx.GetId().ToString(), pfrom.
GetId());
5860 RelayTransaction(tx.GetId());
5864 if (m_recent_rejects_package_reconsiderable.contains(txid)) {
5872 "found tx %s in reconsiderable rejects, looking for "
5873 "child in orphanage\n",
5875 if (
auto package_to_validate{
5876 Find1P1CPackage(ptx, pfrom.
GetId())}) {
5879 package_to_validate->m_txns,
5882 "package evaluation for %s: %s (%s)\n",
5883 package_to_validate->ToString(),
5885 ?
"package accepted"
5886 :
"package rejected",
5888 ProcessPackageResult(package_to_validate.value(),
5917 ProcessValidTx(pfrom.
GetId(), ptx);
5923 bool fRejectedParents =
false;
5927 std::vector<TxId> unique_parents;
5928 unique_parents.reserve(tx.vin.size());
5929 for (
const CTxIn &txin : tx.vin) {
5932 unique_parents.push_back(txin.prevout.GetTxId());
5934 std::sort(unique_parents.begin(), unique_parents.end());
5935 unique_parents.erase(
5936 std::unique(unique_parents.begin(), unique_parents.end()),
5937 unique_parents.end());
5945 std::optional<TxId> rejected_parent_reconsiderable;
5946 for (
const TxId &parent_txid : unique_parents) {
5947 if (m_recent_rejects.contains(parent_txid)) {
5948 fRejectedParents =
true;
5952 if (m_recent_rejects_package_reconsiderable.contains(
5954 !m_mempool.
exists(parent_txid)) {
5959 if (rejected_parent_reconsiderable.has_value()) {
5960 fRejectedParents =
true;
5963 rejected_parent_reconsiderable = parent_txid;
5966 if (!fRejectedParents) {
5967 const auto current_time{
5968 GetTime<std::chrono::microseconds>()};
5970 for (
const TxId &parent_txid : unique_parents) {
5972 AddKnownTx(*peer, parent_txid);
5976 if (!AlreadyHaveTx(parent_txid,
5978 AddTxAnnouncement(pfrom, parent_txid, current_time);
5984 if (
unsigned int nEvicted =
5988 if (orphanage.AddTx(ptx,
5990 AddToCompactExtraTransactions(ptx);
5993 m_opts.max_orphan_txs, m_rng);
5996 "orphanage overflow, removed %u tx\n",
6002 m_txrequest.ForgetInvId(tx.GetId());
6006 "not keeping orphan with rejected parents %s\n",
6007 tx.GetId().ToString());
6010 m_recent_rejects.insert(tx.GetId());
6011 m_txrequest.ForgetInvId(tx.GetId());
6015 ProcessInvalidTx(pfrom.
GetId(), ptx, state,
6025 "tx %s failed but reconsiderable, looking for child in "
6028 if (
auto package_to_validate{
6029 Find1P1CPackage(ptx, pfrom.
GetId())}) {
6032 package_to_validate->m_txns,
false)};
6034 "package evaluation for %s: %s (%s)\n",
6035 package_to_validate->ToString(),
6037 ?
"package accepted"
6038 :
"package rejected",
6040 ProcessPackageResult(package_to_validate.value(),
6049 m_txrequest.ForgetInvId(tx.GetId());
6051 unsigned int nEvicted{0};
6058 m_opts.max_conflicting_txs, m_rng);
6063 "conflicting pool overflow, removed %u tx\n",
6076 "Unexpected cmpctblock message received from peer %d\n",
6083 vRecv >> cmpctblock;
6084 }
catch (std::ios_base::failure &e) {
6086 Misbehaving(*peer,
"cmpctblock-bad-indexes");
6090 bool received_new_header =
false;
6103 MaybeSendGetHeaders(
6104 pfrom,
GetLocator(m_chainman.m_best_header), *peer);
6110 GetAntiDoSWorkThreshold()) {
6114 "Ignoring low-work compact block from peer %d\n",
6120 received_new_header =
true;
6130 MaybePunishNodeForBlock(pfrom.
GetId(), state,
6132 "invalid header via cmpctblock");
6137 if (received_new_header) {
6138 LogInfo(
"Saw new cmpctblock header hash=%s peer=%d\n",
6139 blockhash.ToString(), pfrom.
GetId());
6146 bool fProcessBLOCKTXN =
false;
6152 bool fRevertToHeaderProcessing =
false;
6156 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6157 bool fBlockReconstructed =
false;
6165 CNodeState *nodestate = State(pfrom.
GetId());
6169 if (received_new_header &&
6172 nodestate->m_last_block_announcement =
GetTime();
6175 if (pindex->nStatus.hasData()) {
6182 size_t already_in_flight =
6183 std::distance(range_flight.first, range_flight.second);
6184 bool requested_block_from_this_peer{
false};
6188 bool first_in_flight =
6189 already_in_flight == 0 ||
6190 (range_flight.first->second.first == pfrom.
GetId());
6192 while (range_flight.first != range_flight.second) {
6193 if (range_flight.first->second.first == pfrom.
GetId()) {
6194 requested_block_from_this_peer =
true;
6197 range_flight.first++;
6206 if (requested_block_from_this_peer) {
6210 std::vector<CInv> vInv(1);
6220 if (!already_in_flight && !CanDirectFetch()) {
6228 nodestate->vBlocksInFlight.size() <
6230 requested_block_from_this_peer) {
6231 std::list<QueuedBlock>::iterator *queuedBlockIt =
nullptr;
6232 if (!BlockRequested(config, pfrom.
GetId(), *pindex,
6234 if (!(*queuedBlockIt)->partialBlock) {
6236 ->partialBlock.reset(
6243 "we were already syncing!\n");
6249 *(*queuedBlockIt)->partialBlock;
6251 partialBlock.
InitData(cmpctblock, vExtraTxnForCompact);
6257 Misbehaving(*peer,
"invalid compact block");
6260 if (first_in_flight) {
6263 std::vector<CInv> vInv(1);
6277 for (
size_t i = 0; i < cmpctblock.
BlockTxCount(); i++) {
6288 fProcessBLOCKTXN =
true;
6289 }
else if (first_in_flight) {
6298 IsBlockRequestedFromOutbound(blockhash) ||
6323 tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
6328 std::vector<CTransactionRef> dummy;
6329 status = tempBlock.FillBlock(*pblock, dummy);
6331 fBlockReconstructed =
true;
6335 if (requested_block_from_this_peer) {
6339 std::vector<CInv> vInv(1);
6347 fRevertToHeaderProcessing =
true;
6352 if (fProcessBLOCKTXN) {
6354 blockTxnMsg, time_received, interruptMsgProc);
6357 if (fRevertToHeaderProcessing) {
6363 return ProcessHeadersMessage(config, pfrom, *peer,
6368 if (fBlockReconstructed) {
6373 mapBlockSource.emplace(pblock->GetHash(),
6374 std::make_pair(pfrom.
GetId(),
false));
6385 ProcessBlock(config, pfrom, pblock,
true,
6394 RemoveBlockRequest(pblock->GetHash(), std::nullopt);
6404 "Unexpected blocktxn message received from peer %d\n",
6412 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6413 bool fBlockRead =
false;
6417 auto range_flight = mapBlocksInFlight.equal_range(resp.
blockhash);
6418 size_t already_in_flight =
6419 std::distance(range_flight.first, range_flight.second);
6420 bool requested_block_from_this_peer{
false};
6424 bool first_in_flight =
6425 already_in_flight == 0 ||
6426 (range_flight.first->second.first == pfrom.
GetId());
6428 while (range_flight.first != range_flight.second) {
6429 auto [node_id, block_it] = range_flight.first->second;
6430 if (node_id == pfrom.
GetId() && block_it->partialBlock) {
6431 requested_block_from_this_peer =
true;
6434 range_flight.first++;
6437 if (!requested_block_from_this_peer) {
6439 "Peer %d sent us block transactions for block "
6440 "we weren't expecting\n",
6446 *range_flight.first->second.second->partialBlock;
6454 "invalid compact block/non-matching block transactions");
6457 if (first_in_flight) {
6459 std::vector<CInv> invs;
6467 "Peer %d sent us a compact block but it failed to "
6468 "reconstruct, waiting on first download to complete\n",
6501 std::make_pair(pfrom.
GetId(),
false));
6512 ProcessBlock(config, pfrom, pblock,
true,
6522 "Unexpected headers message received from peer %d\n",
6527 std::vector<CBlockHeader> headers;
6534 strprintf(
"too-many-headers: headers message size = %u",
6538 headers.resize(nCount);
6539 for (
unsigned int n = 0; n < nCount; n++) {
6540 vRecv >> headers[n];
6545 ProcessHeadersMessage(config, pfrom, *peer, std::move(headers),
6551 if (m_headers_presync_should_signal.exchange(
false)) {
6552 HeadersPresyncStats stats;
6554 LOCK(m_headers_presync_mutex);
6556 m_headers_presync_stats.find(m_headers_presync_bestpeer);
6557 if (it != m_headers_presync_stats.end()) {
6563 stats.first, stats.second->first, stats.second->second);
6574 "Unexpected block message received from peer %d\n",
6579 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6583 pblock->GetHash().ToString(), pfrom.
GetId());
6588 pblock->hashPrevBlock))};
6592 "Received mutated block from peer=%d\n", peer->m_id);
6593 Misbehaving(*peer,
"mutated block");
6595 RemoveBlockRequest(pblock->GetHash(), peer->m_id));
6605 const BlockHash hash = pblock->GetHash();
6606 bool min_pow_checked =
false;
6611 forceProcessing = IsBlockRequested(hash);
6612 RemoveBlockRequest(hash, pfrom.
GetId());
6616 mapBlockSource.emplace(hash, std::make_pair(pfrom.
GetId(),
true));
6622 GetAntiDoSWorkThreshold()) {
6623 min_pow_checked =
true;
6626 ProcessBlock(config, pfrom, pblock, forceProcessing, min_pow_checked);
6636 if (pfrom.m_avalanche_pubkey.has_value()) {
6639 "Ignoring avahello from peer %d: already in our node set\n",
6645 vRecv >> delegation;
6652 if (!delegation.
verify(state, pubkey)) {
6653 Misbehaving(*peer,
"invalid-delegation");
6656 pfrom.m_avalanche_pubkey = std::move(pubkey);
6659 sighasher << delegation.
getId();
6667 if (!(*pfrom.m_avalanche_pubkey)
6668 .VerifySchnorr(sighasher.GetHash(),
sig)) {
6669 Misbehaving(*peer,
"invalid-avahello-signature");
6676 if (!AlreadyHaveProof(proofid)) {
6677 const bool preferred = isPreferredDownloadPeer(pfrom);
6678 LOCK(cs_proofrequest);
6679 AddProofAnnouncement(pfrom, proofid,
6680 GetTime<std::chrono::microseconds>(),
6699 WITH_LOCK(peer->m_addr_token_bucket_mutex,
6700 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
6705 peer->m_proof_relay->compactproofs_requested =
true;
6716 const auto now = Now<SteadyMilliseconds>();
6722 last_poll + std::chrono::milliseconds(m_opts.avalanche_cooldown)) {
6724 "Ignoring repeated avapoll from peer %d: cooldown not "
6739 strprintf(
"too-many-ava-poll: poll message size = %u", nCount));
6743 std::vector<avalanche::Vote> votes;
6744 votes.reserve(nCount);
6746 bool fPreconsensus{
false};
6747 bool fStakingPreconsensus{
false};
6752 fStakingPreconsensus =
6756 for (
unsigned int n = 0; n < nCount; n++) {
6764 if (!quorum_established) {
6765 votes.emplace_back(vote, inv.
hash);
6772 if (fPreconsensus) {
6774 GetAvalancheVoteForTx(*m_avalanche,
TxId(inv.
hash));
6786 if (fStakingPreconsensus) {
6793 "poll inv type %d unknown from peer=%d\n",
6798 votes.emplace_back(vote, inv.
hash);
6824 if (!pfrom.m_avalanche_pubkey.has_value() ||
6825 !(*pfrom.m_avalanche_pubkey)
6826 .VerifySchnorr(verifier.GetHash(),
sig)) {
6827 Misbehaving(*peer,
"invalid-ava-response-signature");
6832 auto now = GetTime<std::chrono::seconds>();
6834 std::vector<avalanche::VoteItemUpdate> updates;
6835 bool disconnect{
false};
6838 disconnect, error)) {
6840 Misbehaving(*peer, error);
6858 "Repeated failure to register votes from peer %d: %s\n",
6859 pfrom.
GetId(), error);
6862 Misbehaving(*peer, error);
6875 auto logVoteUpdate = [](
const auto &voteUpdate,
6876 const std::string &voteItemTypeStr,
6877 const auto &voteItemId) {
6878 std::string voteOutcome;
6879 bool alwaysPrint =
false;
6880 switch (voteUpdate.getStatus()) {
6882 voteOutcome =
"invalidated";
6886 voteOutcome =
"rejected";
6889 voteOutcome =
"accepted";
6892 voteOutcome =
"finalized";
6895 alwaysPrint = voteItemTypeStr !=
"tx";
6898 voteOutcome =
"stalled";
6907 alwaysPrint &= (voteItemTypeStr !=
"contender");
6910 LogPrintf(
"Avalanche %s %s %s\n", voteOutcome, voteItemTypeStr,
6911 voteItemId.ToString());
6915 voteItemTypeStr, voteItemId.ToString());
6919 bool shouldActivateBestChain =
false;
6921 bool fPreconsensus{
false};
6922 bool fStakingPreconsensus{
false};
6927 fStakingPreconsensus =
6931 for (
const auto &u : updates) {
6936 if (
auto pitem = std::get_if<const avalanche::ProofRef>(&item)) {
6940 logVoteUpdate(u,
"proof", proofid);
6942 auto rejectionMode =
6944 auto nextCooldownTimePoint = GetTime<std::chrono::seconds>();
6945 switch (u.getStatus()) {
6961 return pm.rejectProof(proofid,
6965 "ERROR: Failed to reject proof: %s\n",
6971 nextCooldownTimePoint += std::chrono::seconds(
6972 m_opts.avalanche_peer_replacement_cooldown);
6978 avalanche::PeerManager::
6979 RegistrationMode::FORCE_ACCEPT);
6982 [&](const avalanche::Peer &peer) {
6983 pm.updateNextPossibleConflictTime(
6985 nextCooldownTimePoint);
6986 if (u.getStatus() ==
6987 avalanche::VoteStatus::
6989 pm.setFinalized(peer.peerid);
6997 "ERROR: Failed to accept proof: %s\n",
7004 auto getBlockFromIndex = [
this](
const CBlockIndex *pindex) {
7007 std::shared_ptr<const CBlock> pblock =
WITH_LOCK(
7008 m_most_recent_block_mutex,
return m_most_recent_block);
7010 if (!pblock || pblock->GetHash() != pindex->
GetBlockHash()) {
7011 std::shared_ptr<CBlock> pblockRead =
7012 std::make_shared<CBlock>();
7015 assert(!
"cannot load block from disk");
7017 pblock = pblockRead;
7022 if (
auto pitem = std::get_if<const CBlockIndex *>(&item)) {
7025 shouldActivateBestChain =
true;
7029 switch (u.getStatus()) {
7034 LogPrintf(
"ERROR: Database error: %s\n",
7043 LogPrintf(
"ERROR: Database error: %s\n",
7048 auto pblock = getBlockFromIndex(pindex);
7064 std::unique_ptr<node::CBlockTemplate> blockTemplate;
7068 chainstate.UnparkBlock(pindex);
7070 const bool newlyFinalized =
7071 !chainstate.IsBlockAvalancheFinalized(pindex) &&
7072 chainstate.AvalancheFinalizeBlock(pindex,
7077 if (fPreconsensus && newlyFinalized) {
7078 auto pblock = getBlockFromIndex(pindex);
7092 std::unordered_set<TxId, SaltedTxIdHasher>
7093 confirmedTxIdsInNonFinalizedBlocks;
7095 block !=
nullptr && block != pindex;
7096 block = block->
pprev) {
7098 getBlockFromIndex(block);
7100 for (
const auto &tx :
7101 currentBlock->vtx) {
7102 confirmedTxIdsInNonFinalizedBlocks
7103 .insert(tx->GetId());
7111 confirmedTxIdsInNonFinalizedBlocks);
7123 config, chainstate, &m_mempool,
7125 blockAssembler.pblocktemplate.reset(
7128 if (blockAssembler.pblocktemplate) {
7129 blockAssembler.addTxs(m_mempool);
7130 blockTemplate = std::move(
7131 blockAssembler.pblocktemplate);
7137 if (blockTemplate) {
7143 for (
const auto &templateEntry :
7157 if (fStakingPreconsensus) {
7159 std::get_if<const avalanche::StakeContenderId>(&item)) {
7161 logVoteUpdate(u,
"contender", contenderId);
7163 switch (u.getStatus()) {
7184 if (!fPreconsensus) {
7188 if (
auto pitem = std::get_if<const CTransactionRef>(&item)) {
7192 const TxId &txid = tx->GetId();
7193 const auto status{u.getStatus()};
7198 logVoteUpdate(u,
"tx", txid);
7209 if (m_mempool.
exists(txid)) {
7213 std::vector<CTransactionRef> conflictingTxs =
7219 if (conflictingTxs.size() > 0) {
7230 for (
const auto &conflictingTx :
7233 conflictingTx->GetId());
7252 m_recent_rejects.insert(txid);
7259 std::make_shared<const std::vector<Coin>>(
7275 return conflicting.HaveTx(txid);
7278 std::vector<CTransactionRef>
7279 mempool_conflicting_txs;
7280 for (
const auto &txin : tx->vin) {
7285 mempool_conflicting_txs.push_back(
7286 std::move(conflict));
7295 [&txid, &mempool_conflicting_txs](
7300 if (mempool_conflicting_txs.size() >
7303 mempool_conflicting_txs[0],
7312 auto it = m_mempool.
GetIter(txid);
7313 if (!it.has_value()) {
7316 "Error: finalized tx (%s) is not in the "
7322 std::vector<TxId> finalizedTxIds;
7323 m_mempool.setAvalancheFinalized(
7328 for (
const auto &finalized_txid : finalizedTxIds) {
7333 logVoteUpdate(u,
"tx", finalized_txid);
7341 std::vector<CTransactionRef>
7344 for (
const auto &conflictingTx :
7346 m_recent_rejects.insert(
7347 conflictingTx->GetId());
7349 conflictingTx->GetId());
7375 m_txrequest.ForgetInvId(txid);
7381 for (
auto &it : m_peer_map) {
7382 auto tx_relay = (*it.second).GetTxRelay();
7387 LOCK(tx_relay->m_tx_inventory_mutex);
7394 auto &stalled_by_time =
7395 tx_relay->m_avalanche_stalled_txids
7397 if (stalled_by_time.size() >=
7399 stalled_by_time.erase(
7400 stalled_by_time.begin()->timeAdded);
7403 tx_relay->m_avalanche_stalled_txids.insert(
7414 if (shouldActivateBestChain) {
7417 state,
nullptr, m_avalanche)) {
7432 ReceivedAvalancheProof(pfrom, *peer, proof);
7441 if (peer->m_proof_relay ==
nullptr) {
7445 peer->m_proof_relay->lastSharedProofsUpdate =
7446 GetTime<std::chrono::seconds>();
7448 peer->m_proof_relay->sharedProofs =
7454 peer->m_proof_relay->sharedProofs);
7465 if (peer->m_proof_relay ==
nullptr) {
7470 if (!peer->m_proof_relay->compactproofs_requested) {
7474 peer->m_proof_relay->compactproofs_requested =
false;
7478 vRecv >> compactProofs;
7479 }
catch (std::ios_base::failure &e) {
7481 Misbehaving(*peer,
"avaproofs-bad-indexes");
7487 if (!ReceivedAvalancheProof(pfrom, *peer, prefilledProof.proof)) {
7517 auto shortIdProcessor =
7521 if (shortIdProcessor.hasOutOfBoundIndex()) {
7524 Misbehaving(*peer,
"avaproofs-bad-indexes");
7527 if (!shortIdProcessor.isEvenlyDistributed()) {
7532 std::vector<std::pair<avalanche::ProofId, bool>> remoteProofsStatus;
7539 shortIdProcessor.matchKnownItem(shortid, peer.
proof);
7546 remoteProofsStatus.emplace_back(peer.
getProofId(),
7557 for (
size_t i = 0; i < compactProofs.
size(); i++) {
7558 if (shortIdProcessor.getItem(i) ==
nullptr) {
7575 return pfrom.m_avalanche_pubkey.has_value())) {
7578 for (
const auto &[proofid, present] : remoteProofsStatus) {
7588 if (peer->m_proof_relay ==
nullptr) {
7595 auto requestedIndiceIt = proofreq.
indices.begin();
7596 uint32_t treeIndice = 0;
7597 peer->m_proof_relay->sharedProofs.forEachLeaf([&](
const auto &proof) {
7598 if (requestedIndiceIt == proofreq.
indices.end()) {
7603 if (treeIndice++ == *requestedIndiceIt) {
7606 requestedIndiceIt++;
7612 peer->m_proof_relay->sharedProofs = {};
7625 "Ignoring \"getaddr\" from %s connection. peer=%d\n",
7632 Assume(SetupAddressRelay(pfrom, *peer));
7636 if (peer->m_getaddr_recvd) {
7641 peer->m_getaddr_recvd =
true;
7643 peer->m_addrs_to_send.clear();
7644 std::vector<CAddress> vAddr;
7645 const size_t maxAddrToSend = m_opts.max_addr_to_send;
7653 for (
const CAddress &addr : vAddr) {
7654 PushAddress(*peer, addr);
7660 auto now = GetTime<std::chrono::seconds>();
7670 if (!SetupAddressRelay(pfrom, *peer)) {
7672 "Ignoring getavaaddr message from %s peer=%d\n",
7677 auto availabilityScoreComparator = [](
const CNode *lhs,
7680 double scoreRhs = rhs->getAvailabilityScore();
7682 if (scoreLhs != scoreRhs) {
7683 return scoreLhs > scoreRhs;
7692 std::set<
const CNode *,
decltype(availabilityScoreComparator)> avaNodes(
7693 availabilityScoreComparator);
7700 avaNodes.insert(pnode);
7701 if (avaNodes.size() > m_opts.max_addr_to_send) {
7702 avaNodes.erase(std::prev(avaNodes.end()));
7706 peer->m_addrs_to_send.clear();
7707 for (
const CNode *pnode : avaNodes) {
7708 PushAddress(*peer, pnode->
addr);
7719 "mempool request with bloom filters disabled, "
7720 "disconnect peer=%d\n",
7731 "mempool request with bandwidth limit reached, "
7732 "disconnect peer=%d\n",
7739 if (
auto tx_relay = peer->GetTxRelay()) {
7740 LOCK(tx_relay->m_tx_inventory_mutex);
7741 tx_relay->m_send_mempool =
true;
7771 const auto ping_end = time_received;
7774 bool bPingFinished =
false;
7775 std::string sProblem;
7777 if (nAvail >=
sizeof(nonce)) {
7782 if (peer->m_ping_nonce_sent != 0) {
7783 if (nonce == peer->m_ping_nonce_sent) {
7786 bPingFinished =
true;
7787 const auto ping_time = ping_end - peer->m_ping_start.load();
7788 if (ping_time.count() >= 0) {
7793 sProblem =
"Timing mishap";
7797 sProblem =
"Nonce mismatch";
7801 bPingFinished =
true;
7802 sProblem =
"Nonce zero";
7806 sProblem =
"Unsolicited pong without ping";
7811 bPingFinished =
true;
7812 sProblem =
"Short payload";
7815 if (!(sProblem.empty())) {
7817 "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
7818 pfrom.
GetId(), sProblem, peer->m_ping_nonce_sent, nonce,
7821 if (bPingFinished) {
7822 peer->m_ping_nonce_sent = 0;
7830 "filterload received despite not offering bloom services "
7831 "from peer=%d; disconnecting\n",
7841 Misbehaving(*peer,
"too-large bloom filter");
7842 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7844 LOCK(tx_relay->m_bloom_filter_mutex);
7845 tx_relay->m_bloom_filter.reset(
new CBloomFilter(filter));
7846 tx_relay->m_relay_txs =
true;
7856 "filteradd received despite not offering bloom services "
7857 "from peer=%d; disconnecting\n",
7862 std::vector<uint8_t> vData;
7871 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7872 LOCK(tx_relay->m_bloom_filter_mutex);
7873 if (tx_relay->m_bloom_filter) {
7874 tx_relay->m_bloom_filter->insert(vData);
7882 Misbehaving(*peer,
"bad filteradd message");
7890 "filterclear received despite not offering bloom services "
7891 "from peer=%d; disconnecting\n",
7896 auto tx_relay = peer->GetTxRelay();
7902 LOCK(tx_relay->m_bloom_filter_mutex);
7903 tx_relay->m_bloom_filter =
nullptr;
7904 tx_relay->m_relay_txs =
true;
7913 vRecv >> newFeeFilter;
7915 if (
auto tx_relay = peer->GetTxRelay()) {
7916 tx_relay->m_fee_filter_received = newFeeFilter;
7925 ProcessGetCFilters(pfrom, *peer, vRecv);
7930 ProcessGetCFHeaders(pfrom, *peer, vRecv);
7935 ProcessGetCFCheckPt(pfrom, *peer, vRecv);
7940 std::vector<CInv> vInv;
7946 for (
CInv &inv : vInv) {
7952 m_txrequest.ReceivedResponse(pfrom.
GetId(),
TxId(inv.
hash));
7959 LOCK(cs_proofrequest);
7960 m_proofrequest.ReceivedResponse(
7974bool PeerManagerImpl::MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer) {
7976 LOCK(peer.m_misbehavior_mutex);
7979 if (!peer.m_should_discourage) {
7983 peer.m_should_discourage =
false;
7989 LogPrintf(
"Warning: not punishing noban peer %d!\n", peer.m_id);
7995 LogPrintf(
"Warning: not punishing manually connected peer %d!\n",
8004 "Warning: disconnecting but not discouraging %s peer %d!\n",
8021bool PeerManagerImpl::ProcessMessages(
const Config &config,
CNode *pfrom,
8022 std::atomic<bool> &interruptMsgProc) {
8034 PeerRef peer = GetPeerRef(pfrom->
GetId());
8035 if (peer ==
nullptr) {
8040 LOCK(peer->m_getdata_requests_mutex);
8041 if (!peer->m_getdata_requests.empty()) {
8042 ProcessGetData(config, *pfrom, *peer, interruptMsgProc);
8046 const bool processed_orphan = ProcessOrphanTx(config, *peer);
8052 if (processed_orphan) {
8059 LOCK(peer->m_getdata_requests_mutex);
8060 if (!peer->m_getdata_requests.empty()) {
8077 bool fMoreWork = poll_result->second;
8081 msg.m_recv.size(), msg.m_recv.
data());
8083 if (m_opts.capture_messages) {
8091 if (!msg.m_valid_netmagic) {
8093 "PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n",
8107 if (!msg.m_valid_header) {
8115 if (!msg.m_valid_checksum) {
8127 ProcessMessage(config, *pfrom, msg.
m_type, vRecv, msg.m_time,
8129 if (interruptMsgProc) {
8134 LOCK(peer->m_getdata_requests_mutex);
8135 if (!peer->m_getdata_requests.empty()) {
8144 return orphanage.HaveTxToReconsider(peer->m_id);
8148 }
catch (
const std::exception &e) {
8151 e.what(),
typeid(e).name());
8160void PeerManagerImpl::ConsiderEviction(
CNode &pto, Peer &peer,
8161 std::chrono::seconds time_in_seconds) {
8164 CNodeState &state = *State(pto.
GetId());
8168 state.fSyncStarted) {
8175 if (state.pindexBestKnownBlock !=
nullptr &&
8176 state.pindexBestKnownBlock->nChainWork >=
8178 if (state.m_chain_sync.m_timeout != 0s) {
8179 state.m_chain_sync.m_timeout = 0s;
8180 state.m_chain_sync.m_work_header =
nullptr;
8181 state.m_chain_sync.m_sent_getheaders =
false;
8183 }
else if (state.m_chain_sync.m_timeout == 0s ||
8184 (state.m_chain_sync.m_work_header !=
nullptr &&
8185 state.pindexBestKnownBlock !=
nullptr &&
8186 state.pindexBestKnownBlock->nChainWork >=
8187 state.m_chain_sync.m_work_header->nChainWork)) {
8193 state.m_chain_sync.m_work_header = m_chainman.
ActiveChain().
Tip();
8194 state.m_chain_sync.m_sent_getheaders =
false;
8195 }
else if (state.m_chain_sync.m_timeout > 0s &&
8196 time_in_seconds > state.m_chain_sync.m_timeout) {
8201 if (state.m_chain_sync.m_sent_getheaders) {
8204 "Disconnecting outbound peer %d for old chain, best known "
8207 state.pindexBestKnownBlock !=
nullptr
8208 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
8212 assert(state.m_chain_sync.m_work_header);
8217 MaybeSendGetHeaders(
8218 pto,
GetLocator(state.m_chain_sync.m_work_header->pprev),
8222 "sending getheaders to outbound peer=%d to verify chain "
8223 "work (current best known block:%s, benchmark blockhash: "
8226 state.pindexBestKnownBlock !=
nullptr
8227 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
8229 state.m_chain_sync.m_work_header->GetBlockHash()
8231 state.m_chain_sync.m_sent_getheaders =
true;
8238 state.m_chain_sync.m_timeout =
8245void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now) {
8254 std::pair<NodeId, std::chrono::seconds> youngest_peer{-1, 0},
8255 next_youngest_peer{-1, 0};
8261 if (pnode->
GetId() > youngest_peer.first) {
8262 next_youngest_peer = youngest_peer;
8263 youngest_peer.first = pnode->GetId();
8264 youngest_peer.second = pnode->m_last_block_time;
8268 NodeId to_disconnect = youngest_peer.first;
8269 if (youngest_peer.second > next_youngest_peer.second) {
8272 to_disconnect = next_youngest_peer.first;
8284 CNodeState *node_state = State(pnode->
GetId());
8285 if (node_state ==
nullptr ||
8287 node_state->vBlocksInFlight.empty())) {
8290 "disconnecting extra block-relay-only peer=%d "
8291 "(last block received at time %d)\n",
8298 "keeping block-relay-only peer=%d chosen for eviction "
8299 "(connect time: %d, blocks_in_flight: %d)\n",
8301 node_state->vBlocksInFlight.size());
8317 int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
8328 CNodeState *state = State(pnode->
GetId());
8329 if (state ==
nullptr) {
8334 if (state->m_chain_sync.m_protect) {
8337 if (state->m_last_block_announcement < oldest_block_announcement ||
8338 (state->m_last_block_announcement == oldest_block_announcement &&
8339 pnode->
GetId() > worst_peer)) {
8340 worst_peer = pnode->
GetId();
8341 oldest_block_announcement = state->m_last_block_announcement;
8345 if (worst_peer == -1) {
8349 bool disconnected = m_connman.
ForNode(
8357 CNodeState &state = *State(pnode->
GetId());
8359 state.vBlocksInFlight.empty()) {
8361 "disconnecting extra outbound peer=%d (last block "
8362 "announcement received at time %d)\n",
8363 pnode->
GetId(), oldest_block_announcement);
8368 "keeping outbound peer=%d chosen for eviction "
8369 "(connect time: %d, blocks_in_flight: %d)\n",
8371 state.vBlocksInFlight.size());
8386void PeerManagerImpl::CheckForStaleTipAndEvictPeers() {
8389 auto now{GetTime<std::chrono::seconds>()};
8391 EvictExtraOutboundPeers(now);
8393 if (now > m_stale_tip_check_time) {
8399 LogPrintf(
"Potential stale tip detected, will try using extra "
8400 "outbound peer (last tip update: %d seconds ago)\n",
8409 if (!m_initial_sync_finished && CanDirectFetch()) {
8411 m_initial_sync_finished =
true;
8415void PeerManagerImpl::MaybeSendPing(
CNode &node_to, Peer &peer,
8416 std::chrono::microseconds now) {
8418 node_to, std::chrono::duration_cast<std::chrono::seconds>(now)) &&
8419 peer.m_ping_nonce_sent &&
8431 bool pingSend =
false;
8433 if (peer.m_ping_queued) {
8438 if (peer.m_ping_nonce_sent == 0 &&
8447 nonce = GetRand<uint64_t>();
8448 }
while (nonce == 0);
8449 peer.m_ping_queued =
false;
8450 peer.m_ping_start = now;
8452 peer.m_ping_nonce_sent = nonce;
8458 peer.m_ping_nonce_sent = 0;
8464void PeerManagerImpl::MaybeSendAddr(
CNode &
node, Peer &peer,
8465 std::chrono::microseconds current_time) {
8467 if (!peer.m_addr_relay_enabled) {
8471 LOCK(peer.m_addr_send_times_mutex);
8473 peer.m_next_local_addr_send < current_time) {
8480 if (peer.m_next_local_addr_send != 0us) {
8481 peer.m_addr_known->reset();
8484 CAddress local_addr{*local_service, peer.m_our_services,
8485 Now<NodeSeconds>()};
8486 PushAddress(peer, local_addr);
8493 if (current_time <= peer.m_next_addr_send) {
8497 peer.m_next_addr_send =
8500 const size_t max_addr_to_send = m_opts.max_addr_to_send;
8501 if (!
Assume(peer.m_addrs_to_send.size() <= max_addr_to_send)) {
8504 peer.m_addrs_to_send.resize(max_addr_to_send);
8509 auto addr_already_known =
8512 bool ret = peer.m_addr_known->contains(addr.
GetKey());
8514 peer.m_addr_known->insert(addr.
GetKey());
8518 peer.m_addrs_to_send.erase(std::remove_if(peer.m_addrs_to_send.begin(),
8519 peer.m_addrs_to_send.end(),
8520 addr_already_known),
8521 peer.m_addrs_to_send.end());
8524 if (peer.m_addrs_to_send.empty()) {
8528 const char *msg_type;
8530 if (peer.m_wants_addrv2) {
8539 .
Make(make_flags, msg_type, peer.m_addrs_to_send));
8540 peer.m_addrs_to_send.clear();
8543 if (peer.m_addrs_to_send.capacity() > 40) {
8544 peer.m_addrs_to_send.shrink_to_fit();
8548void PeerManagerImpl::MaybeSendSendHeaders(
CNode &
node, Peer &peer) {
8553 if (!peer.m_sent_sendheaders &&
8556 CNodeState &state = *State(
node.GetId());
8557 if (state.pindexBestKnownBlock !=
nullptr &&
8558 state.pindexBestKnownBlock->nChainWork >
8566 peer.m_sent_sendheaders =
true;
8571void PeerManagerImpl::MaybeSendFeefilter(
8572 CNode &pto, Peer &peer, std::chrono::microseconds current_time) {
8573 if (m_opts.ignore_incoming_txs) {
8597 static const Amount MAX_FILTER{m_fee_filter_rounder.round(
MAX_MONEY)};
8598 if (peer.m_fee_filter_sent == MAX_FILTER) {
8601 peer.m_next_send_feefilter = 0us;
8604 if (current_time > peer.m_next_send_feefilter) {
8605 Amount filterToSend = m_fee_filter_rounder.round(currentFilter);
8609 if (filterToSend != peer.m_fee_filter_sent) {
8613 peer.m_fee_filter_sent = filterToSend;
8615 peer.m_next_send_feefilter =
8622 peer.m_next_send_feefilter &&
8623 (currentFilter < 3 * peer.m_fee_filter_sent / 4 ||
8624 currentFilter > 4 * peer.m_fee_filter_sent / 3)) {
8625 peer.m_next_send_feefilter =
8626 current_time + GetRandomDuration<std::chrono::microseconds>(
8632class CompareInvMempoolOrder {
8636 explicit CompareInvMempoolOrder(
CTxMemPool *_mempool) : mp(_mempool) {}
8638 bool operator()(std::set<TxId>::iterator a, std::set<TxId>::iterator b) {
8648bool PeerManagerImpl::RejectIncomingTxs(
const CNode &peer)
const {
8657 if (m_opts.ignore_incoming_txs &&
8664bool PeerManagerImpl::SetupAddressRelay(
const CNode &
node, Peer &peer) {
8668 if (
node.IsBlockOnlyConn()) {
8672 if (!peer.m_addr_relay_enabled.exchange(
true)) {
8676 peer.m_addr_known = std::make_unique<CRollingBloomFilter>(5000, 0.001);
8682bool PeerManagerImpl::SendMessages(
const Config &config,
CNode *pto) {
8685 PeerRef peer = GetPeerRef(pto->
GetId());
8694 if (MaybeDiscourageAndDisconnect(*pto, *peer)) {
8707 const auto current_time{GetTime<std::chrono::microseconds>()};
8712 "addrfetch connection timeout; disconnecting peer=%d\n",
8718 MaybeSendPing(*pto, *peer, current_time);
8725 bool sync_blocks_and_headers_from_peer =
false;
8727 MaybeSendAddr(*pto, *peer, current_time);
8729 MaybeSendSendHeaders(*pto, *peer);
8734 CNodeState &state = *State(pto->
GetId());
8737 if (m_chainman.m_best_header ==
nullptr) {
8744 if (state.fPreferredDownload) {
8745 sync_blocks_and_headers_from_peer =
true;
8756 if (m_num_preferred_download_peers == 0 ||
8757 mapBlocksInFlight.empty()) {
8758 sync_blocks_and_headers_from_peer =
true;
8762 if (!state.fSyncStarted && CanServeBlocks(*peer) &&
8766 if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) ||
8768 const CBlockIndex *pindexStart = m_chainman.m_best_header;
8777 if (pindexStart->
pprev) {
8778 pindexStart = pindexStart->
pprev;
8780 if (MaybeSendGetHeaders(*pto,
GetLocator(pindexStart), *peer)) {
8783 "initial getheaders (%d) to peer=%d (startheight:%d)\n",
8785 peer->m_starting_height);
8787 state.fSyncStarted =
true;
8788 peer->m_headers_sync_timeout =
8793 std::chrono::microseconds{
8795 Ticks<std::chrono::seconds>(
8797 m_chainman.m_best_header->Time()) /
8814 LOCK(peer->m_block_inv_mutex);
8815 std::vector<CBlock> vHeaders;
8817 ((!peer->m_prefers_headers &&
8818 (!state.m_requested_hb_cmpctblocks ||
8819 peer->m_blocks_for_headers_relay.size() > 1)) ||
8820 peer->m_blocks_for_headers_relay.size() >
8825 ProcessBlockAvailability(pto->
GetId());
8827 if (!fRevertToInv) {
8828 bool fFoundStartingHeader =
false;
8832 for (
const BlockHash &hash : peer->m_blocks_for_headers_relay) {
8838 fRevertToInv =
true;
8841 if (pBestIndex !=
nullptr && pindex->
pprev != pBestIndex) {
8852 fRevertToInv =
true;
8855 pBestIndex = pindex;
8856 if (fFoundStartingHeader) {
8859 }
else if (PeerHasHeader(&state, pindex)) {
8862 }
else if (pindex->
pprev ==
nullptr ||
8863 PeerHasHeader(&state, pindex->
pprev)) {
8866 fFoundStartingHeader =
true;
8871 fRevertToInv =
true;
8876 if (!fRevertToInv && !vHeaders.empty()) {
8877 if (vHeaders.size() == 1 && state.m_requested_hb_cmpctblocks) {
8882 "%s sending header-and-ids %s to peer=%d\n",
8883 __func__, vHeaders.front().GetHash().ToString(),
8886 std::optional<CSerializedNetMsg> cached_cmpctblock_msg;
8888 LOCK(m_most_recent_block_mutex);
8889 if (m_most_recent_block_hash ==
8891 cached_cmpctblock_msg =
8893 *m_most_recent_compact_block);
8896 if (cached_cmpctblock_msg.has_value()) {
8898 pto, std::move(cached_cmpctblock_msg.value()));
8902 block, *pBestIndex)};
8909 state.pindexBestHeaderSent = pBestIndex;
8910 }
else if (peer->m_prefers_headers) {
8911 if (vHeaders.size() > 1) {
8913 "%s: %u headers, range (%s, %s), to peer=%d\n",
8914 __func__, vHeaders.size(),
8915 vHeaders.front().GetHash().ToString(),
8916 vHeaders.back().GetHash().ToString(),
8920 "%s: sending header %s to peer=%d\n", __func__,
8921 vHeaders.front().GetHash().ToString(),
8926 state.pindexBestHeaderSent = pBestIndex;
8928 fRevertToInv =
true;
8935 if (!peer->m_blocks_for_headers_relay.empty()) {
8937 peer->m_blocks_for_headers_relay.back();
8948 "Announcing block %s not on main chain (tip=%s)\n",
8957 if (!PeerHasHeader(&state, pindex)) {
8958 peer->m_blocks_for_inv_relay.push_back(hashToAnnounce);
8960 "%s: sending inv peer=%d hash=%s\n", __func__,
8965 peer->m_blocks_for_headers_relay.clear();
8972 std::vector<CInv> vInv;
8973 auto addInvAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
8974 vInv.emplace_back(type, hash);
8986 LOCK(peer->m_block_inv_mutex);
8988 vInv.reserve(std::max<size_t>(peer->m_blocks_for_inv_relay.size(),
8994 for (
const BlockHash &hash : peer->m_blocks_for_inv_relay) {
8997 peer->m_blocks_for_inv_relay.clear();
9000 auto computeNextInvSendTime =
9001 [&](std::chrono::microseconds &next) ->
bool {
9004 if (next < current_time) {
9005 fSendTrickle =
true;
9007 next = NextInvToInbounds(
9012 next = current_time;
9016 return fSendTrickle;
9020 if (peer->m_proof_relay !=
nullptr) {
9021 LOCK(peer->m_proof_relay->m_proof_inventory_mutex);
9023 if (computeNextInvSendTime(
9024 peer->m_proof_relay->m_next_inv_send_time)) {
9026 peer->m_proof_relay->m_proof_inventory_to_send.begin();
9028 peer->m_proof_relay->m_proof_inventory_to_send.end()) {
9031 it = peer->m_proof_relay->m_proof_inventory_to_send.erase(
9034 if (peer->m_proof_relay->m_proof_inventory_known_filter
9035 .contains(proofid)) {
9039 peer->m_proof_relay->m_proof_inventory_known_filter.insert(
9042 peer->m_proof_relay->m_recently_announced_proofs.insert(
9048 if (
auto tx_relay = peer->GetTxRelay()) {
9049 LOCK(tx_relay->m_tx_inventory_mutex);
9051 const bool fSendTrickle =
9052 computeNextInvSendTime(tx_relay->m_next_inv_send_time);
9057 LOCK(tx_relay->m_bloom_filter_mutex);
9058 if (!tx_relay->m_relay_txs) {
9059 tx_relay->m_tx_inventory_to_send.clear();
9064 if (fSendTrickle && tx_relay->m_send_mempool) {
9065 auto vtxinfo = m_mempool.
infoAll();
9066 tx_relay->m_send_mempool =
false;
9068 tx_relay->m_fee_filter_received.load()};
9070 LOCK(tx_relay->m_bloom_filter_mutex);
9072 for (
const auto &txinfo : vtxinfo) {
9073 const TxId &txid = txinfo.tx->GetId();
9074 tx_relay->m_tx_inventory_to_send.erase(txid);
9077 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
9080 if (tx_relay->m_bloom_filter &&
9081 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
9085 tx_relay->m_tx_inventory_known_filter.insert(txid);
9088 addInvAndMaybeFlush(
MSG_TX, txid);
9090 tx_relay->m_last_mempool_req =
9091 std::chrono::duration_cast<std::chrono::seconds>(
9098 std::vector<std::set<TxId>::iterator> vInvTx;
9099 vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size());
9100 for (std::set<TxId>::iterator it =
9101 tx_relay->m_tx_inventory_to_send.begin();
9102 it != tx_relay->m_tx_inventory_to_send.end(); it++) {
9103 vInvTx.push_back(it);
9106 tx_relay->m_fee_filter_received.load()};
9111 CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool);
9112 std::make_heap(vInvTx.begin(), vInvTx.end(),
9113 compareInvMempoolOrder);
9117 unsigned int nRelayedTransactions = 0;
9118 LOCK(tx_relay->m_bloom_filter_mutex);
9119 while (!vInvTx.empty() &&
9124 std::pop_heap(vInvTx.begin(), vInvTx.end(),
9125 compareInvMempoolOrder);
9126 std::set<TxId>::iterator it = vInvTx.back();
9128 const TxId txid = *it;
9130 tx_relay->m_tx_inventory_to_send.erase(it);
9132 if (tx_relay->m_tx_inventory_known_filter.contains(txid) &&
9133 tx_relay->m_avalanche_stalled_txids.count(txid) == 0) {
9137 auto txinfo = m_mempool.
info(txid);
9143 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
9146 if (tx_relay->m_bloom_filter &&
9147 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
9152 tx_relay->m_recently_announced_invs.insert(txid);
9153 addInvAndMaybeFlush(
MSG_TX, txid);
9154 nRelayedTransactions++;
9155 tx_relay->m_tx_inventory_known_filter.insert(txid);
9156 tx_relay->m_avalanche_stalled_txids.erase(txid);
9162 if (!vInv.empty()) {
9169 CNodeState &state = *State(pto->
GetId());
9172 auto stalling_timeout = m_block_stalling_timeout.load();
9173 if (state.m_stalling_since.count() &&
9174 state.m_stalling_since < current_time - stalling_timeout) {
9179 LogPrintf(
"Peer=%d is stalling block download, disconnecting\n",
9184 const auto new_timeout =
9186 if (stalling_timeout != new_timeout &&
9187 m_block_stalling_timeout.compare_exchange_strong(
9188 stalling_timeout, new_timeout)) {
9191 "Increased stalling timeout temporarily to %d seconds\n",
9203 if (state.vBlocksInFlight.size() > 0) {
9204 QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
9205 int nOtherPeersWithValidatedDownloads =
9206 m_peers_downloading_from - 1;
9208 state.m_downloading_since +
9209 std::chrono::seconds{consensusParams.nPowTargetSpacing} *
9212 nOtherPeersWithValidatedDownloads)) {
9213 LogPrintf(
"Timeout downloading block %s from peer=%d, "
9215 queuedBlock.pindex->GetBlockHash().ToString(),
9223 if (state.fSyncStarted &&
9224 peer->m_headers_sync_timeout < std::chrono::microseconds::max()) {
9227 if (current_time > peer->m_headers_sync_timeout &&
9228 nSyncStarted == 1 &&
9229 (m_num_preferred_download_peers -
9230 state.fPreferredDownload >=
9239 LogPrintf(
"Timeout downloading headers from peer=%d, "
9245 LogPrintf(
"Timeout downloading headers from noban "
9246 "peer=%d, not disconnecting\n",
9252 state.fSyncStarted =
false;
9254 peer->m_headers_sync_timeout = 0us;
9260 peer->m_headers_sync_timeout = std::chrono::microseconds::max();
9266 ConsiderEviction(*pto, *peer, GetTime<std::chrono::seconds>());
9269 std::vector<CInv> vGetData;
9277 CNodeState &state = *State(pto->
GetId());
9279 if (CanServeBlocks(*peer) &&
9280 ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) ||
9283 std::vector<const CBlockIndex *> vToDownload;
9285 auto get_inflight_budget = [&state]() {
9288 static_cast<int>(state.vBlocksInFlight.size()));
9294 FindNextBlocksToDownload(*peer, get_inflight_budget(), vToDownload,
9297 !IsLimitedPeer(*peer)) {
9303 m_chainman.GetSnapshotBaseBlock());
9305 TryDownloadingHistoricalBlocks(
9306 *peer, get_inflight_budget(), vToDownload, from_tip,
9307 Assert(m_chainman.GetSnapshotBaseBlock()));
9311 BlockRequested(config, pto->
GetId(), *pindex);
9316 if (state.vBlocksInFlight.empty() && staller != -1) {
9317 if (State(staller)->m_stalling_since == 0us) {
9318 State(staller)->m_stalling_since = current_time;
9325 auto addGetDataAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
9326 CInv inv(type, hash);
9329 vGetData.push_back(std::move(inv));
9341 LOCK(cs_proofrequest);
9342 std::vector<std::pair<NodeId, avalanche::ProofId>> expired;
9344 m_proofrequest.GetRequestable(pto->
GetId(), current_time, &expired);
9345 for (
const auto &entry : expired) {
9347 "timeout of inflight proof %s from peer=%d\n",
9348 entry.second.ToString(), entry.first);
9350 for (
const auto &proofid : requestable) {
9351 if (!AlreadyHaveProof(proofid)) {
9353 m_proofrequest.RequestedData(
9354 pto->
GetId(), proofid,
9361 m_proofrequest.ForgetInvId(proofid);
9371 std::vector<std::pair<NodeId, TxId>> expired;
9373 m_txrequest.GetRequestable(pto->
GetId(), current_time, &expired);
9374 for (
const auto &entry : expired) {
9376 entry.second.ToString(), entry.first);
9378 for (
const TxId &txid : requestable) {
9382 if (!AlreadyHaveTx(txid,
false)) {
9383 addGetDataAndMaybeFlush(
MSG_TX, txid);
9384 m_txrequest.RequestedData(
9391 m_txrequest.ForgetInvId(txid);
9395 if (!vGetData.empty()) {
9401 MaybeSendFeefilter(*pto, *peer, current_time);
9405bool PeerManagerImpl::ReceivedAvalancheProof(
CNode &
node, Peer &peer,
9407 assert(proof !=
nullptr);
9411 AddKnownProof(peer, proofid);
9423 return node.m_avalanche_pubkey.has_value());
9424 auto saveProofIfStaker = [
this, isStaker](
const CNode &
node,
9426 const NodeId nodeid) ->
bool {
9438 LOCK(cs_proofrequest);
9439 m_proofrequest.ReceivedResponse(nodeid, proofid);
9441 if (AlreadyHaveProof(proofid)) {
9442 m_proofrequest.ForgetInvId(proofid);
9443 saveProofIfStaker(
node, proofid, nodeid);
9453 return pm.registerProof(proof, state);
9455 WITH_LOCK(cs_proofrequest, m_proofrequest.ForgetInvId(proofid));
9456 RelayProof(proofid);
9458 node.m_last_proof_time = GetTime<std::chrono::seconds>();
9461 nodeid, proofid.ToString());
9483 "Not polling the avalanche proof (%s): peer=%d, proofid %s\n",
9484 state.
IsValid() ?
"not-worth-polling"
9486 nodeid, proofid.ToString());
9489 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.
Reads data from an underlying stream, while hashing the read data.
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
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.
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.
std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval)
Return a timestamp in the future sampled from an exponential distribution (https://en....
constexpr auto GetRandMillis
void Shuffle(I first, I last, R &&rng)
More efficient than using std::shuffle on a FastRandomContext.
reverse_range< T > reverse_iterate(T &x)
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE
void Unserialize(Stream &, 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.