54#include <boost/multi_index/hashed_index.hpp>
55#include <boost/multi_index/member.hpp>
56#include <boost/multi_index/ordered_index.hpp>
57#include <boost/multi_index_container.hpp>
114 "Max protocol message length must be greater than largest "
115 "possible INV message");
172 std::chrono::seconds(2),
173 std::chrono::seconds(2),
174 std::chrono::seconds(60),
181 std::chrono::seconds(2),
182 std::chrono::seconds(2),
183 std::chrono::seconds(60),
216 "MAX_BLOCKTXN_DEPTH too high");
275 std::chrono::seconds{1},
276 "INVENTORY_RELAY_MAX too low");
327 std::unique_ptr<PartiallyDownloadedBlock> partialBlock;
332 std::chrono::seconds timeAdded;
334 StalledTxId(
TxId txid_, std::chrono::seconds timeAdded_)
335 : txid(txid_), timeAdded(timeAdded_){};
341using StalledTxIdSet = boost::multi_index_container<
343 boost::multi_index::indexed_by<
345 boost::multi_index::hashed_unique<
346 boost::multi_index::tag<by_txid>,
347 boost::multi_index::member<StalledTxId, TxId, &StalledTxId::txid>,
350 boost::multi_index::ordered_non_unique<
351 boost::multi_index::tag<by_time>,
352 boost::multi_index::member<StalledTxId, std::chrono::seconds,
353 &StalledTxId::timeAdded>>>>;
390 std::atomic<ServiceFlags> m_their_services{
NODE_NONE};
393 Mutex m_misbehavior_mutex;
398 bool m_should_discourage
GUARDED_BY(m_misbehavior_mutex){
false};
401 Mutex m_block_inv_mutex;
407 std::vector<BlockHash> m_blocks_for_inv_relay
GUARDED_BY(m_block_inv_mutex);
413 std::vector<BlockHash>
414 m_blocks_for_headers_relay
GUARDED_BY(m_block_inv_mutex);
425 std::atomic<int> m_starting_height{-1};
428 std::atomic<uint64_t> m_ping_nonce_sent{0};
430 std::atomic<std::chrono::microseconds> m_ping_start{0us};
432 std::atomic<bool> m_ping_queued{
false};
442 std::chrono::microseconds m_next_send_feefilter
455 bool m_relay_txs
GUARDED_BY(m_bloom_filter_mutex){
false};
460 std::unique_ptr<CBloomFilter>
476 GUARDED_BY(m_tx_inventory_mutex){50000, 0.000001};
482 std::set<TxId> m_tx_inventory_to_send
GUARDED_BY(m_tx_inventory_mutex);
488 bool m_send_mempool
GUARDED_BY(m_tx_inventory_mutex){
false};
490 std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
495 std::chrono::microseconds
496 m_next_inv_send_time
GUARDED_BY(m_tx_inventory_mutex){0};
502 std::atomic<Amount> m_fee_filter_received{
Amount::zero()};
508 m_avalanche_stalled_txids
GUARDED_BY(m_tx_inventory_mutex);
516 LOCK(m_tx_relay_mutex);
518 m_tx_relay = std::make_unique<Peer::TxRelay>();
519 return m_tx_relay.get();
523 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
525 const TxRelay *GetTxRelay() const
527 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
532 std::set<avalanche::ProofId>
533 m_proof_inventory_to_send
GUARDED_BY(m_proof_inventory_mutex);
536 GUARDED_BY(m_proof_inventory_mutex){10000, 0.000001};
543 std::chrono::microseconds m_next_inv_send_time{0};
547 std::atomic<std::chrono::seconds> lastSharedProofsUpdate{0s};
548 std::atomic<bool> compactproofs_requested{
false};
555 const std::unique_ptr<ProofRelay> m_proof_relay;
560 std::vector<CAddress>
572 std::unique_ptr<CRollingBloomFilter>
590 std::atomic_bool m_addr_relay_enabled{
false};
594 mutable Mutex m_addr_send_times_mutex;
596 std::chrono::microseconds
597 m_next_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
599 std::chrono::microseconds
600 m_next_local_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
605 std::atomic_bool m_wants_addrv2{
false};
609 mutable Mutex m_addr_token_bucket_mutex;
614 double m_addr_token_bucket
GUARDED_BY(m_addr_token_bucket_mutex){1.0};
616 std::chrono::microseconds
618 GetTime<std::chrono::microseconds>()};
620 std::atomic<uint64_t> m_addr_rate_limited{0};
625 std::atomic<uint64_t> m_addr_processed{0};
631 bool m_inv_triggered_getheaders_before_sync
635 Mutex m_getdata_requests_mutex;
637 std::deque<CInv> m_getdata_requests
GUARDED_BY(m_getdata_requests_mutex);
644 Mutex m_headers_sync_mutex;
649 std::unique_ptr<HeadersSyncState>
654 std::atomic<bool> m_sent_sendheaders{
false};
657 std::chrono::microseconds m_headers_sync_timeout
668 : m_id(id), m_our_services{our_services},
669 m_proof_relay(fRelayProofs ?
std::make_unique<ProofRelay>()
673 mutable Mutex m_tx_relay_mutex;
676 std::unique_ptr<TxRelay> m_tx_relay
GUARDED_BY(m_tx_relay_mutex);
679using PeerRef = std::shared_ptr<Peer>;
697 bool fSyncStarted{
false};
700 std::chrono::microseconds m_stalling_since{0us};
701 std::list<QueuedBlock> vBlocksInFlight;
704 std::chrono::microseconds m_downloading_since{0us};
706 bool fPreferredDownload{
false};
711 bool m_requested_hb_cmpctblocks{
false};
713 bool m_provides_cmpctblocks{
false};
741 struct ChainSyncTimeoutState {
744 std::chrono::seconds m_timeout{0s};
748 bool m_sent_getheaders{
false};
751 bool m_protect{
false};
754 ChainSyncTimeoutState m_chain_sync;
757 int64_t m_last_block_announcement{0};
760 const bool m_is_inbound;
762 CNodeState(
bool is_inbound) : m_is_inbound(is_inbound) {}
773 const std::shared_ptr<const CBlock> &pblock,
781 bool fInitialDownload)
override
787 const std::shared_ptr<const CBlock> &pblock)
override
796 !m_headers_presync_mutex);
798 std::atomic<bool> &interrupt)
override
800 !m_recent_confirmed_transactions_mutex,
801 !m_most_recent_block_mutex, !cs_proofrequest,
802 !m_headers_presync_mutex, g_msgproc_mutex);
805 !m_recent_confirmed_transactions_mutex,
806 !m_most_recent_block_mutex, !cs_proofrequest,
812 std::optional<std::string>
819 void RelayTransaction(const
TxId &txid) override
821 void RelayProof(const
avalanche::ProofId &proofid) override
823 void SetBestHeight(
int height)
override { m_best_height = height; };
826 Misbehaving(*
Assert(GetPeerRef(peer_id)),
"");
830 const std::chrono::microseconds time_received,
831 const std::atomic<bool> &interruptMsgProc)
override
833 !m_recent_confirmed_transactions_mutex,
834 !m_most_recent_block_mutex, !cs_proofrequest,
835 !m_headers_presync_mutex, g_msgproc_mutex);
837 int64_t time_in_seconds)
override;
844 void ConsiderEviction(
CNode &pto, Peer &peer,
845 std::chrono::seconds time_in_seconds)
852 void EvictExtraOutboundPeers(std::chrono::seconds now)
859 void ReattemptInitialBroadcast(
CScheduler &scheduler)
865 void UpdateAvalancheStatistics()
const;
870 void AvalanchePeriodicNetworking(
CScheduler &scheduler)
const;
888 void Misbehaving(Peer &peer,
const std::string &message);
900 void MaybePunishNodeForBlock(
NodeId nodeid,
902 bool via_compact_block,
903 const std::string &message =
"")
911 const
std::
string &message = "")
923 bool MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer);
941 bool maybe_add_extra_compact_tx)
944 struct PackageToValidate {
946 const std::vector<NodeId> m_senders;
951 : m_txns{parent, child}, m_senders{parent_sender, child_sender} {}
954 Assume(m_txns.size() == 2);
956 "parent %s (sender=%d) + child %s (sender=%d)",
957 m_txns.front()->GetId().ToString(), m_senders.front(),
958 m_txns.back()->GetId().ToString(), m_senders.back());
967 void ProcessPackageResult(
const PackageToValidate &package_to_validate,
977 std::optional<PackageToValidate> Find1P1CPackage(
const CTransactionRef &ptx,
1004 bool ProcessOrphanTx(
const Config &config, Peer &peer)
1017 void ProcessHeadersMessage(
const Config &config,
CNode &pfrom, Peer &peer,
1018 std::vector<CBlockHeader> &&headers,
1019 bool via_compact_block)
1029 bool CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
1039 void HandleUnconnectingHeaders(
CNode &pfrom, Peer &peer,
1040 const std::vector<CBlockHeader> &headers)
1044 CheckHeadersAreContinuous(
const std::vector<CBlockHeader> &headers)
const;
1064 bool IsContinuationOfLowWorkHeadersSync(Peer &peer,
CNode &pfrom,
1065 std::vector<CBlockHeader> &headers)
1067 !m_headers_presync_mutex, g_msgproc_mutex);
1081 bool TryLowWorkHeadersSync(Peer &peer,
CNode &pfrom,
1083 std::vector<CBlockHeader> &headers)
1085 !m_headers_presync_mutex, g_msgproc_mutex);
1091 bool IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header)
1105 void HeadersDirectFetchBlocks(
const Config &config,
CNode &pfrom,
1108 void UpdatePeerStateForReceivedHeaders(
CNode &pfrom, Peer &peer,
1110 bool received_new_header,
1111 bool may_have_more_headers)
1114 void SendBlockTransactions(
CNode &pfrom, Peer &peer,
const CBlock &block,
1123 std::chrono::microseconds current_time)
1133 std::chrono::microseconds current_time,
bool preferred)
1137 void PushNodeVersion(
const Config &config,
CNode &pnode,
const Peer &peer);
1145 void MaybeSendPing(
CNode &node_to, Peer &peer,
1146 std::chrono::microseconds now);
1149 void MaybeSendAddr(
CNode &
node, Peer &peer,
1150 std::chrono::microseconds current_time)
1157 void MaybeSendSendHeaders(
CNode &
node, Peer &peer)
1161 void MaybeSendFeefilter(
CNode &
node, Peer &peer,
1162 std::chrono::microseconds current_time)
1174 void RelayAddress(
NodeId originator,
const CAddress &addr,
bool fReachable)
1195 Mutex cs_proofrequest;
1200 std::atomic<int> m_best_height{-1};
1205 const Options m_opts;
1207 bool RejectIncomingTxs(
const CNode &peer)
const;
1219 mutable Mutex m_peer_mutex;
1226 std::map<NodeId, PeerRef> m_peer_map
GUARDED_BY(m_peer_mutex);
1235 const CNodeState *State(
NodeId pnode)
const
1240 std::atomic<std::chrono::microseconds> m_next_inv_to_inbounds{0us};
1247 m_last_block_inv_triggering_headers_sync
GUARDED_BY(g_msgproc_mutex){};
1255 std::map<BlockHash, std::pair<NodeId, bool>>
1265 std::atomic<std::chrono::seconds> m_block_stalling_timeout{
1279 bool AlreadyHaveTx(
const TxId &txid,
bool include_reconsiderable)
1281 !m_recent_confirmed_transactions_mutex);
1345 mutable Mutex m_recent_confirmed_transactions_mutex;
1347 GUARDED_BY(m_recent_confirmed_transactions_mutex){24'000, 0.000'001};
1356 std::chrono::microseconds
1357 NextInvToInbounds(std::chrono::microseconds now,
1358 std::chrono::seconds average_interval)
1363 mutable Mutex m_most_recent_block_mutex;
1364 std::shared_ptr<const CBlock>
1365 m_most_recent_block
GUARDED_BY(m_most_recent_block_mutex);
1366 std::shared_ptr<const CBlockHeaderAndShortTxIDs>
1367 m_most_recent_compact_block
GUARDED_BY(m_most_recent_block_mutex);
1369 std::unique_ptr<const std::map<TxId, CTransactionRef>>
1370 m_most_recent_block_txs
GUARDED_BY(m_most_recent_block_mutex);
1375 Mutex m_headers_presync_mutex;
1386 using HeadersPresyncStats =
1387 std::pair<arith_uint256, std::optional<std::pair<int64_t, uint32_t>>>;
1389 std::map<NodeId, HeadersPresyncStats>
1390 m_headers_presync_stats
GUARDED_BY(m_headers_presync_mutex){};
1394 std::atomic_bool m_headers_presync_should_signal{
false};
1402 bool IsBlockRequested(
const BlockHash &hash)
1406 bool IsBlockRequestedFromOutbound(
const BlockHash &hash)
1417 void RemoveBlockRequest(
const BlockHash &hash,
1418 std::optional<NodeId> from_peer)
1427 bool BlockRequested(
const Config &config,
NodeId nodeid,
1429 std::list<QueuedBlock>::iterator **pit =
nullptr)
1438 void FindNextBlocksToDownload(const Peer &peer,
unsigned int count,
1444 void TryDownloadingHistoricalBlocks(
1445 const Peer &peer,
unsigned int count,
1479 const Peer &peer, CNodeState *state,
1481 int nWindowEnd, const
CChain *activeChain =
nullptr,
1482 NodeId *nodeStaller =
nullptr)
1492 std::atomic<
std::chrono::seconds> m_last_tip_update{0s};
1499 const std::chrono::seconds mempool_req,
1500 const std::chrono::seconds now)
1505 void ProcessGetData(
const Config &config,
CNode &pfrom, Peer &peer,
1506 const std::atomic<bool> &interruptMsgProc)
1508 peer.m_getdata_requests_mutex,
1514 const std::shared_ptr<const CBlock> &block,
1515 bool force_processing,
bool min_pow_checked);
1523 void MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid)
1542 std::vector<std::pair<TxHash, CTransactionRef>>
1543 vExtraTxnForCompact
GUARDED_BY(g_msgproc_mutex);
1545 size_t vExtraTxnForCompactIt
GUARDED_BY(g_msgproc_mutex) = 0;
1550 void ProcessBlockAvailability(
NodeId nodeid)
1565 bool BlockRequestAllowed(const
CBlockIndex *pindex)
1567 bool AlreadyHaveBlock(const
BlockHash &block_hash)
1569 bool AlreadyHaveProof(const
avalanche::ProofId &proofid);
1570 void ProcessGetBlockData(const
Config &config,
CNode &pfrom, Peer &peer,
1593 bool PrepareBlockFilterRequest(
CNode &
node, Peer &peer,
1595 uint32_t start_height,
1597 uint32_t max_height_diff,
1638 uint32_t GetAvalancheVoteForBlock(const
BlockHash &hash) const
1649 const
TxId &
id) const
1651 !m_recent_confirmed_transactions_mutex);
1660 bool SetupAddressRelay(const
CNode &
node, Peer &peer)
1663 void AddAddressKnown(Peer &peer, const
CAddress &addr)
1665 void PushAddress(Peer &peer, const
CAddress &addr)
1673 bool ReceivedAvalancheProof(
CNode &
node, Peer &peer,
1679 const
std::chrono::seconds now)
1682 bool isPreferredDownloadPeer(const
CNode &pfrom);
1685const CNodeState *PeerManagerImpl::State(
NodeId pnode) const
1687 std::map<NodeId, CNodeState>::const_iterator it = m_node_states.find(pnode);
1688 if (it == m_node_states.end()) {
1695CNodeState *PeerManagerImpl::State(
NodeId pnode)
1697 return const_cast<CNodeState *
>(std::as_const(*this).State(pnode));
1705static bool IsAddrCompatible(
const Peer &peer,
const CAddress &addr) {
1709void PeerManagerImpl::AddAddressKnown(Peer &peer,
const CAddress &addr) {
1710 assert(peer.m_addr_known);
1711 peer.m_addr_known->insert(addr.
GetKey());
1714void PeerManagerImpl::PushAddress(Peer &peer,
const CAddress &addr) {
1718 assert(peer.m_addr_known);
1719 if (addr.
IsValid() && !peer.m_addr_known->contains(addr.
GetKey()) &&
1720 IsAddrCompatible(peer, addr)) {
1721 if (peer.m_addrs_to_send.size() >= m_opts.max_addr_to_send) {
1722 peer.m_addrs_to_send[m_rng.randrange(peer.m_addrs_to_send.size())] =
1725 peer.m_addrs_to_send.push_back(addr);
1730static void AddKnownTx(Peer &peer,
const TxId &txid) {
1731 auto tx_relay = peer.GetTxRelay();
1736 LOCK(tx_relay->m_tx_inventory_mutex);
1737 tx_relay->m_tx_inventory_known_filter.insert(txid);
1741 if (peer.m_proof_relay !=
nullptr) {
1742 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
1743 peer.m_proof_relay->m_proof_inventory_known_filter.insert(proofid);
1747bool PeerManagerImpl::isPreferredDownloadPeer(
const CNode &pfrom) {
1749 const CNodeState *state = State(pfrom.
GetId());
1750 return state && state->fPreferredDownload;
1753static bool CanServeBlocks(
const Peer &peer) {
1761static bool IsLimitedPeer(
const Peer &peer) {
1766std::chrono::microseconds
1767PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
1768 std::chrono::seconds average_interval) {
1769 if (m_next_inv_to_inbounds.load() < now) {
1774 m_next_inv_to_inbounds =
1775 now + m_rng.rand_exp_duration(average_interval);
1777 return m_next_inv_to_inbounds;
1780bool PeerManagerImpl::IsBlockRequested(
const BlockHash &hash) {
1781 return mapBlocksInFlight.count(hash);
1784bool PeerManagerImpl::IsBlockRequestedFromOutbound(
const BlockHash &hash) {
1785 for (
auto range = mapBlocksInFlight.equal_range(hash);
1786 range.first != range.second; range.first++) {
1787 auto [nodeid, block_it] = range.first->second;
1788 CNodeState &nodestate = *
Assert(State(nodeid));
1789 if (!nodestate.m_is_inbound) {
1797void PeerManagerImpl::RemoveBlockRequest(
const BlockHash &hash,
1798 std::optional<NodeId> from_peer) {
1799 auto range = mapBlocksInFlight.equal_range(hash);
1800 if (range.first == range.second) {
1808 while (range.first != range.second) {
1809 auto [node_id, list_it] = range.first->second;
1811 if (from_peer && *from_peer != node_id) {
1816 CNodeState &state = *
Assert(State(node_id));
1818 if (state.vBlocksInFlight.begin() == list_it) {
1821 state.m_downloading_since =
1822 std::max(state.m_downloading_since,
1823 GetTime<std::chrono::microseconds>());
1825 state.vBlocksInFlight.erase(list_it);
1827 if (state.vBlocksInFlight.empty()) {
1829 m_peers_downloading_from--;
1831 state.m_stalling_since = 0us;
1833 range.first = mapBlocksInFlight.erase(range.first);
1837bool PeerManagerImpl::BlockRequested(
const Config &config,
NodeId nodeid,
1839 std::list<QueuedBlock>::iterator **pit) {
1842 CNodeState *state = State(nodeid);
1843 assert(state !=
nullptr);
1848 for (
auto range = mapBlocksInFlight.equal_range(hash);
1849 range.first != range.second; range.first++) {
1850 if (range.first->second.first == nodeid) {
1852 *pit = &range.first->second.second;
1859 RemoveBlockRequest(hash, nodeid);
1861 std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(
1862 state->vBlocksInFlight.end(),
1863 {&block, std::unique_ptr<PartiallyDownloadedBlock>(
1864 pit ? new PartiallyDownloadedBlock(config, &m_mempool)
1866 if (state->vBlocksInFlight.size() == 1) {
1868 state->m_downloading_since = GetTime<std::chrono::microseconds>();
1869 m_peers_downloading_from++;
1872 auto itInFlight = mapBlocksInFlight.insert(
1873 std::make_pair(hash, std::make_pair(nodeid, it)));
1876 *pit = &itInFlight->second.second;
1882void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid) {
1888 if (m_opts.ignore_incoming_txs) {
1892 CNodeState *nodestate = State(nodeid);
1897 if (!nodestate->m_provides_cmpctblocks) {
1900 int num_outbound_hb_peers = 0;
1901 for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin();
1902 it != lNodesAnnouncingHeaderAndIDs.end(); it++) {
1903 if (*it == nodeid) {
1904 lNodesAnnouncingHeaderAndIDs.erase(it);
1905 lNodesAnnouncingHeaderAndIDs.push_back(nodeid);
1908 CNodeState *state = State(*it);
1909 if (state !=
nullptr && !state->m_is_inbound) {
1910 ++num_outbound_hb_peers;
1913 if (nodestate->m_is_inbound) {
1916 if (lNodesAnnouncingHeaderAndIDs.size() >= 3 &&
1917 num_outbound_hb_peers == 1) {
1918 CNodeState *remove_node =
1919 State(lNodesAnnouncingHeaderAndIDs.front());
1920 if (remove_node !=
nullptr && !remove_node->m_is_inbound) {
1923 std::swap(lNodesAnnouncingHeaderAndIDs.front(),
1924 *std::next(lNodesAnnouncingHeaderAndIDs.begin()));
1931 if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
1935 lNodesAnnouncingHeaderAndIDs.front(), [
this](
CNode *pnodeStop) {
1936 m_connman.PushMessage(
1937 pnodeStop, CNetMsgMaker(pnodeStop->GetCommonVersion())
1938 .Make(NetMsgType::SENDCMPCT,
1940 CMPCTBLOCKS_VERSION));
1943 pnodeStop->m_bip152_highbandwidth_to = false;
1946 lNodesAnnouncingHeaderAndIDs.pop_front();
1955 lNodesAnnouncingHeaderAndIDs.push_back(pfrom->
GetId());
1960bool PeerManagerImpl::TipMayBeStale() {
1963 if (m_last_tip_update.load() == 0s) {
1964 m_last_tip_update = GetTime<std::chrono::seconds>();
1966 return m_last_tip_update.load() <
1967 GetTime<std::chrono::seconds>() -
1970 mapBlocksInFlight.empty();
1973bool PeerManagerImpl::CanDirectFetch() {
1979static bool PeerHasHeader(CNodeState *state,
const CBlockIndex *pindex)
1981 if (state->pindexBestKnownBlock &&
1982 pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) {
1985 if (state->pindexBestHeaderSent &&
1986 pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight)) {
1992void PeerManagerImpl::ProcessBlockAvailability(
NodeId nodeid) {
1993 CNodeState *state = State(nodeid);
1994 assert(state !=
nullptr);
1996 if (!state->hashLastUnknownBlock.IsNull()) {
2000 if (state->pindexBestKnownBlock ==
nullptr ||
2001 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
2002 state->pindexBestKnownBlock = pindex;
2004 state->hashLastUnknownBlock.SetNull();
2009void PeerManagerImpl::UpdateBlockAvailability(
NodeId nodeid,
2011 CNodeState *state = State(nodeid);
2012 assert(state !=
nullptr);
2014 ProcessBlockAvailability(nodeid);
2019 if (state->pindexBestKnownBlock ==
nullptr ||
2020 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
2021 state->pindexBestKnownBlock = pindex;
2026 state->hashLastUnknownBlock = hash;
2032void PeerManagerImpl::FindNextBlocksToDownload(
2033 const Peer &peer,
unsigned int count,
2034 std::vector<const CBlockIndex *> &vBlocks,
NodeId &nodeStaller) {
2039 vBlocks.reserve(vBlocks.size() +
count);
2040 CNodeState *state = State(peer.m_id);
2041 assert(state !=
nullptr);
2044 ProcessBlockAvailability(peer.m_id);
2046 if (state->pindexBestKnownBlock ==
nullptr ||
2047 state->pindexBestKnownBlock->nChainWork <
2049 state->pindexBestKnownBlock->nChainWork <
2059 const CBlockIndex *snap_base{m_chainman.GetSnapshotBaseBlock()};
2060 if (snap_base && state->pindexBestKnownBlock->GetAncestor(
2061 snap_base->nHeight) != snap_base) {
2063 "Not downloading blocks from peer=%d, which doesn't have the "
2064 "snapshot block in its best chain.\n",
2073 if (state->pindexLastCommonBlock ==
nullptr ||
2075 state->pindexLastCommonBlock->nHeight < snap_base->nHeight)) {
2076 state->pindexLastCommonBlock =
2078 .
ActiveChain()[std::min(state->pindexBestKnownBlock->nHeight,
2085 state->pindexLastCommonBlock, state->pindexBestKnownBlock);
2086 if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) {
2090 const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
2098 FindNextBlocks(vBlocks, peer, state, pindexWalk,
count, nWindowEnd,
2102void PeerManagerImpl::TryDownloadingHistoricalBlocks(
2103 const Peer &peer,
unsigned int count,
2104 std::vector<const CBlockIndex *> &vBlocks,
const CBlockIndex *from_tip,
2109 if (vBlocks.size() >=
count) {
2113 vBlocks.reserve(
count);
2114 CNodeState *state =
Assert(State(peer.m_id));
2116 if (state->pindexBestKnownBlock ==
nullptr ||
2117 state->pindexBestKnownBlock->GetAncestor(target_block->
nHeight) !=
2132 FindNextBlocks(vBlocks, peer, state, from_tip,
count,
2137void PeerManagerImpl::FindNextBlocks(std::vector<const CBlockIndex *> &vBlocks,
2138 const Peer &peer, CNodeState *state,
2140 unsigned int count,
int nWindowEnd,
2141 const CChain *activeChain,
2143 std::vector<const CBlockIndex *> vToFetch;
2145 std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
2147 while (pindexWalk->
nHeight < nMaxHeight) {
2152 int nToFetch = std::min(nMaxHeight - pindexWalk->
nHeight,
2153 std::max<int>(
count - vBlocks.size(), 128));
2154 vToFetch.resize(nToFetch);
2155 pindexWalk = state->pindexBestKnownBlock->
GetAncestor(
2156 pindexWalk->
nHeight + nToFetch);
2157 vToFetch[nToFetch - 1] = pindexWalk;
2158 for (
unsigned int i = nToFetch - 1; i > 0; i--) {
2159 vToFetch[i - 1] = vToFetch[i]->
pprev;
2172 if (pindex->nStatus.hasData() ||
2173 (activeChain && activeChain->
Contains(pindex))) {
2175 state->pindexLastCommonBlock = pindex;
2177 }
else if (!IsBlockRequested(pindex->
GetBlockHash())) {
2179 if (pindex->
nHeight > nWindowEnd) {
2181 if (vBlocks.size() == 0 && waitingfor != peer.m_id) {
2185 *nodeStaller = waitingfor;
2190 vBlocks.push_back(pindex);
2191 if (vBlocks.size() ==
count) {
2194 }
else if (waitingfor == -1) {
2206template <
class InvId>
2210 return !
node.HasPermission(
2223template <
class InvId>
2224static std::chrono::microseconds
2228 std::chrono::microseconds current_time,
bool preferred) {
2229 auto delay = std::chrono::microseconds{0};
2241 return current_time + delay;
2244void PeerManagerImpl::PushNodeVersion(
const Config &config,
CNode &pnode,
2246 uint64_t my_services{peer.m_our_services};
2247 const int64_t nTime{
count_seconds(GetTime<std::chrono::seconds>())};
2249 const int nNodeStartingHeight{m_best_height};
2260 const bool tx_relay{!RejectIncomingTxs(pnode)};
2271 userAgent(config), nNodeStartingHeight, tx_relay,
2276 "send version message: version %d, blocks=%d, them=%s, "
2277 "txrelay=%d, peer=%d\n",
2282 "send version message: version %d, blocks=%d, "
2283 "txrelay=%d, peer=%d\n",
2288void PeerManagerImpl::AddTxAnnouncement(
2290 std::chrono::microseconds current_time) {
2298 const bool preferred = isPreferredDownloadPeer(
node);
2300 current_time, preferred);
2302 m_txrequest.ReceivedInv(
node.GetId(), txid, preferred, reqtime);
2305void PeerManagerImpl::AddProofAnnouncement(
2307 std::chrono::microseconds current_time,
bool preferred) {
2318 m_proofrequest.ReceivedInv(
node.GetId(), proofid, preferred, reqtime);
2321void PeerManagerImpl::UpdateLastBlockAnnounceTime(
NodeId node,
2322 int64_t time_in_seconds) {
2324 CNodeState *state = State(
node);
2326 state->m_last_block_announcement = time_in_seconds;
2330void PeerManagerImpl::InitializeNode(
const Config &config,
CNode &
node,
2335 m_node_states.emplace_hint(m_node_states.end(),
2336 std::piecewise_construct,
2337 std::forward_as_tuple(nodeid),
2338 std::forward_as_tuple(
node.IsInboundConn()));
2339 assert(m_txrequest.Count(nodeid) == 0);
2347 PeerRef peer = std::make_shared<Peer>(nodeid, our_services, !!m_avalanche);
2350 m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer);
2352 if (!
node.IsInboundConn()) {
2353 PushNodeVersion(config,
node, *peer);
2357void PeerManagerImpl::ReattemptInitialBroadcast(
CScheduler &scheduler) {
2360 for (
const TxId &txid : unbroadcast_txids) {
2362 if (m_mempool.
exists(txid)) {
2363 RelayTransaction(txid);
2374 auto unbroadcasted_proofids =
2378 auto it = unbroadcasted_proofids.begin();
2379 while (it != unbroadcasted_proofids.end()) {
2382 if (!pm.isBoundToPeer(*it)) {
2383 pm.removeUnbroadcastProof(*it);
2384 it = unbroadcasted_proofids.erase(it);
2391 return unbroadcasted_proofids;
2395 for (
const auto &proofid : unbroadcasted_proofids) {
2396 RelayProof(proofid);
2403 const auto reattemptBroadcastInterval =
2405 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2406 reattemptBroadcastInterval);
2409void PeerManagerImpl::UpdateAvalancheStatistics()
const {
2415void PeerManagerImpl::AvalanchePeriodicNetworking(
CScheduler &scheduler)
const {
2416 const auto now = GetTime<std::chrono::seconds>();
2417 std::vector<NodeId> avanode_ids;
2418 bool fQuorumEstablished;
2419 bool fShouldRequestMoreNodes;
2429 fShouldRequestMoreNodes =
2437 avanode_ids.push_back(pnode->GetId());
2440 PeerRef peer = GetPeerRef(pnode->
GetId());
2441 if (peer ==
nullptr) {
2445 if (peer->m_proof_relay &&
2446 now > (peer->m_proof_relay->lastSharedProofsUpdate.load() +
2448 peer->m_proof_relay->sharedProofs = {};
2452 if (avanode_ids.empty()) {
2460 for (
NodeId avanodeId : avanode_ids) {
2461 const bool sentGetavaaddr =
2464 m_connman.PushMessage(
2465 pavanode, CNetMsgMaker(pavanode->GetCommonVersion())
2466 .Make(NetMsgType::GETAVAADDR));
2467 PeerRef peer = GetPeerRef(avanodeId);
2468 WITH_LOCK(peer->m_addr_token_bucket_mutex,
2469 peer->m_addr_token_bucket +=
2470 m_opts.max_addr_to_send);
2478 if (sentGetavaaddr && fQuorumEstablished && !fShouldRequestMoreNodes) {
2493 avanode_ids.resize(std::min<size_t>(avanode_ids.size(), 3));
2496 for (
NodeId nodeid : avanode_ids) {
2499 PeerRef peer = GetPeerRef(nodeid);
2500 if (peer->m_proof_relay) {
2505 peer->m_proof_relay->compactproofs_requested =
true;
2515 const auto avalanchePeriodicNetworkingInterval =
2517 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2518 avalanchePeriodicNetworkingInterval);
2521void PeerManagerImpl::FinalizeNode(
const Config &config,
const CNode &
node) {
2531 PeerRef peer = RemovePeer(nodeid);
2534 m_peer_map.erase(nodeid);
2536 CNodeState *state = State(nodeid);
2537 assert(state !=
nullptr);
2539 if (state->fSyncStarted) {
2543 for (
const QueuedBlock &entry : state->vBlocksInFlight) {
2545 mapBlocksInFlight.equal_range(entry.pindex->GetBlockHash());
2546 while (range.first != range.second) {
2547 auto [node_id, list_it] = range.first->second;
2548 if (node_id != nodeid) {
2551 range.first = mapBlocksInFlight.erase(range.first);
2558 m_txrequest.DisconnectedPeer(nodeid);
2559 m_num_preferred_download_peers -= state->fPreferredDownload;
2560 m_peers_downloading_from -= (!state->vBlocksInFlight.empty());
2561 assert(m_peers_downloading_from >= 0);
2562 m_outbound_peers_with_protect_from_disconnect -=
2563 state->m_chain_sync.m_protect;
2564 assert(m_outbound_peers_with_protect_from_disconnect >= 0);
2566 m_node_states.erase(nodeid);
2568 if (m_node_states.empty()) {
2570 assert(mapBlocksInFlight.empty());
2571 assert(m_num_preferred_download_peers == 0);
2572 assert(m_peers_downloading_from == 0);
2573 assert(m_outbound_peers_with_protect_from_disconnect == 0);
2574 assert(m_txrequest.Size() == 0);
2576 return orphanage.Size();
2581 if (
node.fSuccessfullyConnected && !
node.IsBlockOnlyConn() &&
2582 !
node.IsInboundConn()) {
2589 LOCK(m_headers_presync_mutex);
2590 m_headers_presync_stats.erase(nodeid);
2593 WITH_LOCK(cs_proofrequest, m_proofrequest.DisconnectedPeer(nodeid));
2598PeerRef PeerManagerImpl::GetPeerRef(
NodeId id)
const {
2600 auto it = m_peer_map.find(
id);
2601 return it != m_peer_map.end() ? it->second :
nullptr;
2604PeerRef PeerManagerImpl::RemovePeer(
NodeId id) {
2607 auto it = m_peer_map.find(
id);
2608 if (it != m_peer_map.end()) {
2609 ret = std::move(it->second);
2610 m_peer_map.erase(it);
2615bool PeerManagerImpl::GetNodeStateStats(
NodeId nodeid,
2619 const CNodeState *state = State(nodeid);
2620 if (state ==
nullptr) {
2624 ? state->pindexBestKnownBlock->nHeight
2627 ? state->pindexLastCommonBlock->nHeight
2629 for (
const QueuedBlock &queue : state->vBlocksInFlight) {
2636 PeerRef peer = GetPeerRef(nodeid);
2637 if (peer ==
nullptr) {
2649 auto ping_wait{0us};
2650 if ((0 != peer->m_ping_nonce_sent) &&
2651 (0 != peer->m_ping_start.load().count())) {
2653 GetTime<std::chrono::microseconds>() - peer->m_ping_start.load();
2656 if (
auto tx_relay = peer->GetTxRelay()) {
2658 return tx_relay->m_relay_txs);
2670 LOCK(peer->m_headers_sync_mutex);
2671 if (peer->m_headers_sync) {
2679void PeerManagerImpl::AddToCompactExtraTransactions(
const CTransactionRef &tx) {
2680 if (m_opts.max_extra_txs <= 0) {
2684 if (!vExtraTxnForCompact.size()) {
2685 vExtraTxnForCompact.resize(m_opts.max_extra_txs);
2688 vExtraTxnForCompact[vExtraTxnForCompactIt] =
2689 std::make_pair(tx->GetHash(), tx);
2690 vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
2693void PeerManagerImpl::Misbehaving(Peer &peer,
const std::string &message) {
2694 LOCK(peer.m_misbehavior_mutex);
2696 const std::string message_prefixed =
2697 message.empty() ?
"" : (
": " + message);
2698 peer.m_should_discourage =
true;
2703void PeerManagerImpl::MaybePunishNodeForBlock(
NodeId nodeid,
2705 bool via_compact_block,
2706 const std::string &message) {
2707 PeerRef peer{GetPeerRef(nodeid)};
2718 if (!via_compact_block) {
2720 Misbehaving(*peer, message);
2727 CNodeState *node_state = State(nodeid);
2728 if (node_state ==
nullptr) {
2735 if (!via_compact_block && !node_state->m_is_inbound) {
2737 Misbehaving(*peer, message);
2747 Misbehaving(*peer, message);
2753 Misbehaving(*peer, message);
2759 if (message !=
"") {
2764void PeerManagerImpl::MaybePunishNodeForTx(
NodeId nodeid,
2766 const std::string &message) {
2767 PeerRef peer{GetPeerRef(nodeid)};
2774 Misbehaving(*peer, message);
2792 if (message !=
"") {
2797bool PeerManagerImpl::BlockRequestAllowed(
const CBlockIndex *pindex) {
2803 (m_chainman.m_best_header !=
nullptr) &&
2804 (m_chainman.m_best_header->GetBlockTime() - pindex->
GetBlockTime() <
2807 *m_chainman.m_best_header, *pindex, *m_chainman.m_best_header,
2811std::optional<std::string>
2812PeerManagerImpl::FetchBlock(
const Config &config,
NodeId peer_id,
2815 return "Loading blocks ...";
2821 CNodeState *state = State(peer_id);
2822 if (state ==
nullptr) {
2823 return "Peer does not exist";
2827 RemoveBlockRequest(block_index.
GetBlockHash(), std::nullopt);
2830 if (!BlockRequested(config, peer_id, block_index)) {
2831 return "Already requested from this peer";
2840 const CNetMsgMaker msgMaker(node->GetCommonVersion());
2841 this->m_connman.PushMessage(
2842 node, msgMaker.Make(NetMsgType::GETDATA, invs));
2845 return "Node not fully connected";
2850 return std::nullopt;
2853std::unique_ptr<PeerManager>
2857 return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman,
2866 : m_rng{opts.deterministic_rng},
2868 m_chainparams(chainman.GetParams()), m_connman(connman),
2869 m_addrman(addrman), m_banman(banman), m_chainman(chainman),
2870 m_mempool(pool), m_avalanche(
avalanche), m_opts{opts} {}
2872void PeerManagerImpl::StartScheduledTasks(
CScheduler &scheduler) {
2879 "peer eviction timer should be less than stale tip check timer");
2882 this->CheckForStaleTipAndEvictPeers();
2888 const auto reattemptBroadcastInterval =
2890 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2891 reattemptBroadcastInterval);
2896 UpdateAvalancheStatistics();
2902 const auto avalanchePeriodicNetworkingInterval =
2904 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2905 avalanchePeriodicNetworkingInterval);
2914void PeerManagerImpl::BlockConnected(
2915 ChainstateRole role,
const std::shared_ptr<const CBlock> &pblock,
2919 m_last_tip_update = GetTime<std::chrono::seconds>();
2923 auto stalling_timeout = m_block_stalling_timeout.load();
2926 const auto new_timeout =
2927 std::max(std::chrono::duration_cast<std::chrono::seconds>(
2928 stalling_timeout * 0.85),
2930 if (m_block_stalling_timeout.compare_exchange_strong(stalling_timeout,
2950 LOCK(m_recent_confirmed_transactions_mutex);
2952 m_recent_confirmed_transactions.insert(ptx->GetId());
2957 for (
const auto &ptx : pblock->vtx) {
2958 m_txrequest.ForgetInvId(ptx->GetId());
2963void PeerManagerImpl::BlockDisconnected(
2964 const std::shared_ptr<const CBlock> &block,
const CBlockIndex *pindex) {
2973 LOCK(m_recent_confirmed_transactions_mutex);
2974 m_recent_confirmed_transactions.reset();
2981void PeerManagerImpl::NewPoWValidBlock(
2982 const CBlockIndex *pindex,
const std::shared_ptr<const CBlock> &pblock) {
2983 std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock =
2984 std::make_shared<const CBlockHeaderAndShortTxIDs>(*pblock);
2989 if (pindex->
nHeight <= m_highest_fast_announce) {
2992 m_highest_fast_announce = pindex->
nHeight;
2995 const std::shared_future<CSerializedNetMsg> lazy_ser{
2996 std::async(std::launch::deferred, [&] {
3001 auto most_recent_block_txs =
3002 std::make_unique<std::map<TxId, CTransactionRef>>();
3003 for (
const auto &tx : pblock->vtx) {
3004 most_recent_block_txs->emplace(tx->GetId(), tx);
3007 LOCK(m_most_recent_block_mutex);
3008 m_most_recent_block_hash = hashBlock;
3009 m_most_recent_block = pblock;
3010 m_most_recent_compact_block = pcmpctblock;
3011 m_most_recent_block_txs = std::move(most_recent_block_txs);
3015 [
this, pindex, &lazy_ser, &hashBlock](
CNode *pnode)
3023 ProcessBlockAvailability(pnode->
GetId());
3024 CNodeState &state = *State(pnode->
GetId());
3028 if (state.m_requested_hb_cmpctblocks &&
3029 !PeerHasHeader(&state, pindex) &&
3030 PeerHasHeader(&state, pindex->
pprev)) {
3032 "%s sending header-and-ids %s to peer=%d\n",
3033 "PeerManager::NewPoWValidBlock",
3034 hashBlock.ToString(), pnode->
GetId());
3037 m_connman.
PushMessage(pnode, ser_cmpctblock.Copy());
3038 state.pindexBestHeaderSent = pindex;
3047void PeerManagerImpl::UpdatedBlockTip(
const CBlockIndex *pindexNew,
3049 bool fInitialDownload) {
3050 SetBestHeight(pindexNew->
nHeight);
3054 if (fInitialDownload) {
3059 std::vector<BlockHash> vHashes;
3061 while (pindexToAnnounce != pindexFork) {
3063 pindexToAnnounce = pindexToAnnounce->
pprev;
3073 for (
auto &it : m_peer_map) {
3074 Peer &peer = *it.second;
3075 LOCK(peer.m_block_inv_mutex);
3077 peer.m_blocks_for_headers_relay.push_back(hash);
3089void PeerManagerImpl::BlockChecked(
const CBlock &block,
3094 std::map<BlockHash, std::pair<NodeId, bool>>::iterator it =
3095 mapBlockSource.find(hash);
3099 if (state.
IsInvalid() && it != mapBlockSource.end() &&
3100 State(it->second.first)) {
3101 MaybePunishNodeForBlock(it->second.first, state,
3102 !it->second.second);
3111 mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
3112 if (it != mapBlockSource.end()) {
3113 MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
3117 if (it != mapBlockSource.end()) {
3118 mapBlockSource.erase(it);
3127bool PeerManagerImpl::AlreadyHaveTx(
const TxId &txid,
3128 bool include_reconsiderable) {
3130 hashRecentRejectsChainTip) {
3135 hashRecentRejectsChainTip =
3137 m_recent_rejects.reset();
3138 m_recent_rejects_package_reconsiderable.reset();
3142 return orphanage.HaveTx(txid);
3148 return conflicting.HaveTx(txid);
3153 if (include_reconsiderable &&
3154 m_recent_rejects_package_reconsiderable.contains(txid)) {
3159 LOCK(m_recent_confirmed_transactions_mutex);
3160 if (m_recent_confirmed_transactions.contains(txid)) {
3165 return m_recent_rejects.contains(txid) || m_mempool.
exists(txid);
3168bool PeerManagerImpl::AlreadyHaveBlock(
const BlockHash &block_hash) {
3173 if (!
Assume(m_avalanche)) {
3178 if (localProof && localProof->getId() == proofid) {
3187void PeerManagerImpl::SendPings() {
3189 for (
auto &it : m_peer_map) {
3190 it.second->m_ping_queued =
true;
3194void PeerManagerImpl::RelayTransaction(
const TxId &txid) {
3196 for (
auto &it : m_peer_map) {
3197 Peer &peer = *it.second;
3198 auto tx_relay = peer.GetTxRelay();
3202 LOCK(tx_relay->m_tx_inventory_mutex);
3208 if (tx_relay->m_next_inv_send_time == 0s) {
3212 if (!tx_relay->m_tx_inventory_known_filter.contains(txid) ||
3213 tx_relay->m_avalanche_stalled_txids.count(txid) > 0) {
3214 tx_relay->m_tx_inventory_to_send.insert(txid);
3221 for (
auto &it : m_peer_map) {
3222 Peer &peer = *it.second;
3224 if (!peer.m_proof_relay) {
3227 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
3228 if (!peer.m_proof_relay->m_proof_inventory_known_filter.contains(
3230 peer.m_proof_relay->m_proof_inventory_to_send.insert(proofid);
3235void PeerManagerImpl::RelayAddress(
NodeId originator,
const CAddress &addr,
3251 const auto current_time{GetTime<std::chrono::seconds>()};
3254 const uint64_t time_addr{
3255 (
static_cast<uint64_t
>(
count_seconds(current_time)) + hash_addr) /
3265 unsigned int nRelayNodes = (fReachable || (hasher.Finalize() & 1)) ? 2 : 1;
3266 std::array<std::pair<uint64_t, Peer *>, 2> best{
3267 {{0,
nullptr}, {0,
nullptr}}};
3268 assert(nRelayNodes <= best.size());
3272 for (
auto &[
id, peer] : m_peer_map) {
3273 if (peer->m_addr_relay_enabled &&
id != originator &&
3274 IsAddrCompatible(*peer, addr)) {
3276 for (
unsigned int i = 0; i < nRelayNodes; i++) {
3277 if (hashKey > best[i].first) {
3278 std::copy(best.begin() + i, best.begin() + nRelayNodes - 1,
3279 best.begin() + i + 1);
3280 best[i] = std::make_pair(hashKey, peer.get());
3287 for (
unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
3288 PushAddress(*best[i].second, addr);
3292void PeerManagerImpl::ProcessGetBlockData(
const Config &config,
CNode &pfrom,
3293 Peer &peer,
const CInv &inv) {
3296 std::shared_ptr<const CBlock> a_recent_block;
3297 std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
3299 LOCK(m_most_recent_block_mutex);
3300 a_recent_block = m_most_recent_block;
3301 a_recent_compact_block = m_most_recent_compact_block;
3304 bool need_activate_chain =
false;
3318 need_activate_chain =
true;
3322 if (need_activate_chain) {
3325 state, a_recent_block, m_avalanche)) {
3334 bool can_direct_fetch{
false};
3342 if (!BlockRequestAllowed(pindex)) {
3344 "%s: ignoring request from peer=%i for old "
3345 "block that isn't in the main chain\n",
3346 __func__, pfrom.
GetId());
3352 (((m_chainman.m_best_header !=
nullptr) &&
3353 (m_chainman.m_best_header->GetBlockTime() -
3361 "historical block serving limit reached, disconnect peer=%d\n",
3374 (tip->nHeight - pindex->
nHeight >
3377 "Ignore block request below NODE_NETWORK_LIMITED "
3378 "threshold, disconnect peer=%d\n",
3388 if (!pindex->nStatus.hasData()) {
3391 can_direct_fetch = CanDirectFetch();
3395 std::shared_ptr<const CBlock> pblock;
3396 auto handle_block_read_error = [&]() {
3398 return m_chainman.
m_blockman.IsBlockPruned(*pindex))) {
3400 "Block was pruned before it could be read, disconnect "
3404 LogError(
"Cannot load block from disk, disconnect peer=%d\n",
3410 if (a_recent_block && a_recent_block->GetHash() == pindex->
GetBlockHash()) {
3411 pblock = a_recent_block;
3415 std::vector<uint8_t> block_data;
3418 handle_block_read_error();
3426 std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
3428 handle_block_read_error();
3431 pblock = pblockRead;
3438 bool sendMerkleBlock =
false;
3440 if (
auto tx_relay = peer.GetTxRelay()) {
3441 LOCK(tx_relay->m_bloom_filter_mutex);
3442 if (tx_relay->m_bloom_filter) {
3443 sendMerkleBlock =
true;
3448 if (sendMerkleBlock) {
3461 typedef std::pair<size_t, uint256> PairType;
3465 *pblock->vtx[pair.first]));
3476 if (can_direct_fetch &&
3478 if (a_recent_compact_block &&
3479 a_recent_compact_block->header.GetHash() ==
3483 *a_recent_compact_block));
3487 msgMaker.Make(nSendFlags,
3500 LOCK(peer.m_block_inv_mutex);
3503 if (hash == peer.m_continuation_block) {
3507 std::vector<CInv> vInv;
3510 peer.m_continuation_block =
BlockHash();
3516PeerManagerImpl::FindTxForGetData(
const Peer &peer,
const TxId &txid,
3517 const std::chrono::seconds mempool_req,
3518 const std::chrono::seconds now) {
3519 auto txinfo = m_mempool.
info(txid);
3524 if ((mempool_req.count() && txinfo.m_time <= mempool_req) ||
3526 return std::move(txinfo.tx);
3535 Assume(peer.GetTxRelay())->m_recently_announced_invs.contains(txid);
3536 if (recent && txinfo.tx) {
3537 return std::move(txinfo.tx);
3542 LOCK(m_most_recent_block_mutex);
3543 if (m_most_recent_block_txs !=
nullptr) {
3544 auto it = m_most_recent_block_txs->find(txid);
3545 if (it != m_most_recent_block_txs->end()) {
3558PeerManagerImpl::FindProofForGetData(
const Peer &peer,
3560 const std::chrono::seconds now) {
3563 bool send_unconditionally =
3589 if (send_unconditionally) {
3594 if (peer.m_proof_relay->m_recently_announced_proofs.contains(proofid)) {
3601void PeerManagerImpl::ProcessGetData(
3603 const std::atomic<bool> &interruptMsgProc) {
3606 auto tx_relay = peer.GetTxRelay();
3608 std::deque<CInv>::iterator it = peer.m_getdata_requests.begin();
3609 std::vector<CInv> vNotFound;
3612 const auto now{GetTime<std::chrono::seconds>()};
3614 const auto mempool_req = tx_relay !=
nullptr
3615 ? tx_relay->m_last_mempool_req.load()
3616 : std::chrono::seconds::min();
3621 while (it != peer.m_getdata_requests.end()) {
3622 if (interruptMsgProc) {
3631 const CInv &inv = *it;
3633 if (it->IsMsgProof()) {
3635 vNotFound.push_back(inv);
3640 auto proof = FindProofForGetData(peer, proofid, now);
3648 vNotFound.push_back(inv);
3655 if (it->IsMsgTx()) {
3656 if (tx_relay ==
nullptr) {
3672 std::vector<TxId> parent_ids_to_add;
3675 auto txiter = m_mempool.
GetIter(tx->GetId());
3677 auto &pentry = *txiter;
3679 (*pentry)->GetMemPoolParentsConst();
3680 parent_ids_to_add.reserve(parents.size());
3681 for (
const auto &parent : parents) {
3682 if (parent.get()->GetTime() >
3684 parent_ids_to_add.push_back(
3685 parent.get()->GetTx().GetId());
3690 for (
const TxId &parent_txid : parent_ids_to_add) {
3693 if (
WITH_LOCK(tx_relay->m_tx_inventory_mutex,
3694 return !tx_relay->m_tx_inventory_known_filter
3695 .contains(parent_txid))) {
3696 tx_relay->m_recently_announced_invs.insert(parent_txid);
3700 vNotFound.push_back(inv);
3713 if (it != peer.m_getdata_requests.end() && !pfrom.
fPauseSend) {
3714 const CInv &inv = *it++;
3716 ProcessGetBlockData(config, pfrom, peer, inv);
3722 peer.m_getdata_requests.erase(peer.m_getdata_requests.begin(), it);
3724 if (!vNotFound.empty()) {
3742void PeerManagerImpl::SendBlockTransactions(
3746 for (
size_t i = 0; i < req.
indices.size(); i++) {
3748 Misbehaving(peer,
"getblocktxn with out-of-bounds tx indices");
3760bool PeerManagerImpl::CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
3765 Misbehaving(peer,
"header with invalid proof of work");
3770 if (!CheckHeadersAreContinuous(headers)) {
3771 Misbehaving(peer,
"non-continuous headers sequence");
3784 near_chaintip_work =
3797void PeerManagerImpl::HandleUnconnectingHeaders(
3798 CNode &pfrom, Peer &peer,
const std::vector<CBlockHeader> &headers) {
3804 if (MaybeSendGetHeaders(pfrom,
GetLocator(best_header), peer)) {
3807 "received header %s: missing prev block %s, sending getheaders "
3808 "(%d) to end (peer=%d)\n",
3810 headers[0].hashPrevBlock.ToString(), best_header->nHeight,
3818 UpdateBlockAvailability(pfrom.
GetId(), headers.back().GetHash()));
3821bool PeerManagerImpl::CheckHeadersAreContinuous(
3822 const std::vector<CBlockHeader> &headers)
const {
3825 if (!hashLastBlock.
IsNull() && header.hashPrevBlock != hashLastBlock) {
3828 hashLastBlock = header.GetHash();
3833bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(
3834 Peer &peer,
CNode &pfrom, std::vector<CBlockHeader> &headers) {
3835 if (peer.m_headers_sync) {
3836 auto result = peer.m_headers_sync->ProcessNextHeaders(
3840 if (result.success) {
3841 peer.m_last_getheaders_timestamp = {};
3843 if (result.request_more) {
3844 auto locator = peer.m_headers_sync->NextHeadersRequestLocator();
3847 Assume(!locator.vHave.empty());
3851 if (!locator.vHave.empty()) {
3854 bool sent_getheaders =
3855 MaybeSendGetHeaders(pfrom, locator, peer);
3858 locator.vHave.front().ToString(), pfrom.
GetId());
3863 peer.m_headers_sync.reset(
nullptr);
3868 LOCK(m_headers_presync_mutex);
3869 m_headers_presync_stats.erase(pfrom.
GetId());
3872 HeadersPresyncStats stats;
3873 stats.first = peer.m_headers_sync->GetPresyncWork();
3874 if (peer.m_headers_sync->GetState() ==
3876 stats.second = {peer.m_headers_sync->GetPresyncHeight(),
3877 peer.m_headers_sync->GetPresyncTime()};
3881 LOCK(m_headers_presync_mutex);
3882 m_headers_presync_stats[pfrom.
GetId()] = stats;
3884 m_headers_presync_stats.find(m_headers_presync_bestpeer);
3885 bool best_updated =
false;
3886 if (best_it == m_headers_presync_stats.end()) {
3891 const HeadersPresyncStats *stat_best{
nullptr};
3892 for (
const auto &[_peer, _stat] : m_headers_presync_stats) {
3893 if (!stat_best || _stat > *stat_best) {
3898 m_headers_presync_bestpeer = peer_best;
3899 best_updated = (peer_best == pfrom.
GetId());
3900 }
else if (best_it->first == pfrom.
GetId() ||
3901 stats > best_it->second) {
3904 m_headers_presync_bestpeer = pfrom.
GetId();
3905 best_updated =
true;
3907 if (best_updated && stats.second.has_value()) {
3910 m_headers_presync_should_signal =
true;
3914 if (result.success) {
3917 headers.swap(result.pow_validated_headers);
3920 return result.success;
3928bool PeerManagerImpl::TryLowWorkHeadersSync(
3930 std::vector<CBlockHeader> &headers) {
3937 arith_uint256 minimum_chain_work = GetAntiDoSWorkThreshold();
3941 if (total_work < minimum_chain_work) {
3955 LOCK(peer.m_headers_sync_mutex);
3956 peer.m_headers_sync.reset(
3958 chain_start_header, minimum_chain_work));
3963 (void)IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
3966 "Ignoring low-work chain (height=%u) from peer=%d\n",
3967 chain_start_header->
nHeight + headers.size(),
3979bool PeerManagerImpl::IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header) {
3980 return header !=
nullptr &&
3981 ((m_chainman.m_best_header !=
nullptr &&
3983 m_chainman.m_best_header->GetAncestor(header->
nHeight)) ||
3987bool PeerManagerImpl::MaybeSendGetHeaders(
CNode &pfrom,
3996 if (current_time - peer.m_last_getheaders_timestamp >
4000 peer.m_last_getheaders_timestamp = current_time;
4012void PeerManagerImpl::HeadersDirectFetchBlocks(
const Config &config,
4018 CNodeState *nodestate = State(pfrom.
GetId());
4022 std::vector<const CBlockIndex *> vToFetch;
4028 if (!pindexWalk->nStatus.hasData() &&
4031 vToFetch.push_back(pindexWalk);
4033 pindexWalk = pindexWalk->
pprev;
4044 std::vector<CInv> vGetData;
4047 if (nodestate->vBlocksInFlight.size() >=
4053 BlockRequested(config, pfrom.
GetId(), *pindex);
4057 if (vGetData.size() > 1) {
4059 "Downloading blocks toward %s (%d) via headers "
4064 if (vGetData.size() > 0) {
4065 if (!m_opts.ignore_incoming_txs &&
4066 nodestate->m_provides_cmpctblocks && vGetData.size() == 1 &&
4067 mapBlocksInFlight.size() == 1 &&
4085void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(
4087 bool received_new_header,
bool may_have_more_headers) {
4090 CNodeState *nodestate = State(pfrom.
GetId());
4098 if (received_new_header &&
4100 nodestate->m_last_block_announcement =
GetTime();
4108 if (nodestate->pindexBestKnownBlock &&
4109 nodestate->pindexBestKnownBlock->nChainWork <
4120 LogPrintf(
"Disconnecting outbound peer %d -- headers "
4121 "chain has insufficient work\n",
4135 nodestate->pindexBestKnownBlock !=
nullptr) {
4136 if (m_outbound_peers_with_protect_from_disconnect <
4138 nodestate->pindexBestKnownBlock->nChainWork >=
4140 !nodestate->m_chain_sync.m_protect) {
4143 nodestate->m_chain_sync.m_protect =
true;
4144 ++m_outbound_peers_with_protect_from_disconnect;
4149void PeerManagerImpl::ProcessHeadersMessage(
const Config &config,
CNode &pfrom,
4151 std::vector<CBlockHeader> &&headers,
4152 bool via_compact_block) {
4153 size_t nCount = headers.size();
4161 LOCK(peer.m_headers_sync_mutex);
4162 if (peer.m_headers_sync) {
4163 peer.m_headers_sync.reset(
nullptr);
4164 LOCK(m_headers_presync_mutex);
4165 m_headers_presync_stats.erase(pfrom.
GetId());
4170 peer.m_last_getheaders_timestamp = {};
4178 if (!CheckHeadersPoW(headers, m_chainparams.
GetConsensus(), peer)) {
4193 bool already_validated_work =
false;
4196 bool have_headers_sync =
false;
4198 LOCK(peer.m_headers_sync_mutex);
4200 already_validated_work =
4201 IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
4213 if (headers.empty()) {
4217 have_headers_sync = !!peer.m_headers_sync;
4223 headers[0].hashPrevBlock))};
4224 bool headers_connect_blockindex{chain_start_header !=
nullptr};
4226 if (!headers_connect_blockindex) {
4230 HandleUnconnectingHeaders(pfrom, peer, headers);
4238 peer.m_last_getheaders_timestamp = {};
4247 last_received_header =
4249 if (IsAncestorOfBestHeaderOrTip(last_received_header)) {
4250 already_validated_work =
true;
4258 already_validated_work =
true;
4264 if (!already_validated_work &&
4265 TryLowWorkHeadersSync(peer, pfrom, chain_start_header, headers)) {
4277 bool received_new_header{last_received_header ==
nullptr};
4282 state, &pindexLast)) {
4284 MaybePunishNodeForBlock(pfrom.
GetId(), state, via_compact_block,
4285 "invalid header received");
4295 if (MaybeSendGetHeaders(pfrom,
GetLocator(pindexLast), peer)) {
4298 "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
4299 pindexLast->
nHeight, pfrom.
GetId(), peer.m_starting_height);
4303 UpdatePeerStateForReceivedHeaders(pfrom, peer, *pindexLast,
4304 received_new_header,
4308 HeadersDirectFetchBlocks(config, pfrom, *pindexLast);
4311void PeerManagerImpl::ProcessInvalidTx(
NodeId nodeid,
4314 bool maybe_add_extra_compact_tx) {
4319 const TxId &txid = ptx->GetId();
4339 m_recent_rejects_package_reconsiderable.insert(txid);
4341 m_recent_rejects.insert(txid);
4343 m_txrequest.ForgetInvId(txid);
4346 AddToCompactExtraTransactions(ptx);
4349 MaybePunishNodeForTx(nodeid, state);
4355 return orphanage.EraseTx(txid);
4369 m_txrequest.ForgetInvId(tx->GetId());
4375 orphanage.
EraseTx(tx->GetId());
4380 "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
4381 nodeid, tx->GetId().ToString(), m_mempool.
size(),
4384 RelayTransaction(tx->GetId());
4387void PeerManagerImpl::ProcessPackageResult(
4388 const PackageToValidate &package_to_validate,
4394 const auto &
package = package_to_validate.m_txns;
4395 const auto &senders = package_to_validate.m_senders;
4398 m_recent_rejects_package_reconsiderable.insert(
GetPackageHash(package));
4402 if (!
Assume(package.size() == 2)) {
4408 auto package_iter = package.rbegin();
4409 auto senders_iter = senders.rbegin();
4410 while (package_iter != package.rend()) {
4411 const auto &tx = *package_iter;
4412 const NodeId nodeid = *senders_iter;
4413 const auto it_result{package_result.
m_tx_results.find(tx->GetId())};
4417 const auto &tx_result = it_result->second;
4418 switch (tx_result.m_result_type) {
4420 ProcessValidTx(nodeid, tx);
4430 ProcessInvalidTx(nodeid, tx, tx_result.m_state,
4447std::optional<PeerManagerImpl::PackageToValidate>
4453 const auto &parent_txid{ptx->GetId()};
4455 Assume(m_recent_rejects_package_reconsiderable.contains(parent_txid));
4461 const auto cpfp_candidates_same_peer{
4467 for (
const auto &child : cpfp_candidates_same_peer) {
4468 Package maybe_cpfp_package{ptx, child};
4469 if (!m_recent_rejects_package_reconsiderable.contains(
4471 return PeerManagerImpl::PackageToValidate{ptx, child, nodeid,
4485 const auto cpfp_candidates_different_peer{
4495 std::vector<size_t> tx_indices(cpfp_candidates_different_peer.size());
4496 std::iota(tx_indices.begin(), tx_indices.end(), 0);
4497 Shuffle(tx_indices.begin(), tx_indices.end(), m_rng);
4499 for (
const auto index : tx_indices) {
4502 const auto [child_tx, child_sender] =
4503 cpfp_candidates_different_peer.at(index);
4504 Package maybe_cpfp_package{ptx, child_tx};
4505 if (!m_recent_rejects_package_reconsiderable.contains(
4507 return PeerManagerImpl::PackageToValidate{ptx, child_tx, nodeid,
4511 return std::nullopt;
4514bool PeerManagerImpl::ProcessOrphanTx(
const Config &config, Peer &peer) {
4520 return orphanage.GetTxToReconsider(peer.m_id);
4525 const TxId &orphanTxId = porphanTx->GetId();
4530 ProcessValidTx(peer.m_id, porphanTx);
4536 " invalid orphan tx %s from peer=%d. %s\n",
4543 ProcessInvalidTx(peer.m_id, porphanTx, state,
4554bool PeerManagerImpl::PrepareBlockFilterRequest(
4556 const BlockHash &stop_hash, uint32_t max_height_diff,
4558 const bool supported_filter_type =
4561 if (!supported_filter_type) {
4563 "peer %d requested unsupported block filter type: %d\n",
4564 node.GetId(),
static_cast<uint8_t
>(filter_type));
4565 node.fDisconnect =
true;
4575 if (!stop_index || !BlockRequestAllowed(stop_index)) {
4578 node.fDisconnect =
true;
4583 uint32_t stop_height = stop_index->
nHeight;
4584 if (start_height > stop_height) {
4587 "peer %d sent invalid getcfilters/getcfheaders with "
4589 "start height %d and stop height %d\n",
4590 node.GetId(), start_height, stop_height);
4591 node.fDisconnect =
true;
4594 if (stop_height - start_height >= max_height_diff) {
4596 "peer %d requested too many cfilters/cfheaders: %d / %d\n",
4597 node.GetId(), stop_height - start_height + 1, max_height_diff);
4598 node.fDisconnect =
true;
4603 if (!filter_index) {
4612void PeerManagerImpl::ProcessGetCFilters(
CNode &
node, Peer &peer,
4614 uint8_t filter_type_ser;
4615 uint32_t start_height;
4618 vRecv >> filter_type_ser >> start_height >> stop_hash;
4625 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4631 std::vector<BlockFilter> filters;
4634 "Failed to find block filter in index: filter_type=%s, "
4635 "start_height=%d, stop_hash=%s\n",
4641 for (
const auto &filter : filters) {
4648void PeerManagerImpl::ProcessGetCFHeaders(
CNode &
node, Peer &peer,
4650 uint8_t filter_type_ser;
4651 uint32_t start_height;
4654 vRecv >> filter_type_ser >> start_height >> stop_hash;
4661 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4668 if (start_height > 0) {
4670 stop_index->
GetAncestor(
static_cast<int>(start_height - 1));
4673 "Failed to find block filter header in index: "
4674 "filter_type=%s, block_hash=%s\n",
4681 std::vector<uint256> filter_hashes;
4685 "Failed to find block filter hashes in index: filter_type=%s, "
4686 "start_height=%d, stop_hash=%s\n",
4695 stop_index->
GetBlockHash(), prev_header, filter_hashes);
4699void PeerManagerImpl::ProcessGetCFCheckPt(
CNode &
node, Peer &peer,
4701 uint8_t filter_type_ser;
4704 vRecv >> filter_type_ser >> stop_hash;
4711 if (!PrepareBlockFilterRequest(
4712 node, peer, filter_type, 0, stop_hash,
4713 std::numeric_limits<uint32_t>::max(),
4714 stop_index, filter_index)) {
4722 for (
int i = headers.size() - 1; i >= 0; i--) {
4728 "Failed to find block filter header in index: "
4729 "filter_type=%s, block_hash=%s\n",
4754PeerManagerImpl::GetAvalancheVoteForBlock(
const BlockHash &hash)
const {
4765 if (pindex->nStatus.isInvalid()) {
4770 if (pindex->nStatus.isOnParkedChain()) {
4778 if (pindex == pindexFork) {
4783 if (pindexFork != pindexTip) {
4788 if (!pindex->nStatus.hasData()) {
4799 const TxId &
id)
const {
4801 if (
WITH_LOCK(m_recent_confirmed_transactions_mutex,
4802 return m_recent_confirmed_transactions.contains(
id))) {
4811 if (m_recent_rejects.contains(
id)) {
4823 if (
auto iter = m_mempool.
GetIter(
id)) {
4824 mempool_tx = (**iter)->GetSharedTx();
4829 return conflicting.HaveTx(id);
4836 return orphanage.HaveTx(id);
4902 const std::shared_ptr<const CBlock> &block,
4903 bool force_processing,
4904 bool min_pow_checked) {
4905 bool new_block{
false};
4907 &new_block, m_avalanche);
4909 node.m_last_block_time = GetTime<std::chrono::seconds>();
4914 RemoveBlockRequest(block->GetHash(), std::nullopt);
4917 mapBlockSource.erase(block->GetHash());
4921void PeerManagerImpl::ProcessMessage(
4922 const Config &config,
CNode &pfrom,
const std::string &msg_type,
4923 CDataStream &vRecv,
const std::chrono::microseconds time_received,
4924 const std::atomic<bool> &interruptMsgProc) {
4930 PeerRef peer = GetPeerRef(pfrom.
GetId());
4931 if (peer ==
nullptr) {
4937 "Avalanche is not initialized, ignoring %s message\n",
4952 uint64_t nNonce = 1;
4955 std::string cleanSubVer;
4956 int starting_height = -1;
4958 uint64_t nExtraEntropy = 1;
4960 vRecv >> nVersion >> Using<CustomUintFormatter<8>>(nServices) >> nTime;
4973 "peer=%d does not offer the expected services "
4974 "(%08x offered, %08x expected); disconnecting\n",
4975 pfrom.
GetId(), nServices,
4985 "peer=%d does not offer the avalanche service; disconnecting\n",
4994 "peer=%d using obsolete version %i; disconnecting\n",
4995 pfrom.
GetId(), nVersion);
5000 if (!vRecv.
empty()) {
5009 if (!vRecv.
empty()) {
5010 std::string strSubVer;
5014 if (!vRecv.
empty()) {
5015 vRecv >> starting_height;
5017 if (!vRecv.
empty()) {
5020 if (!vRecv.
empty()) {
5021 vRecv >> nExtraEntropy;
5025 LogPrintf(
"connected to self at %s, disconnecting\n",
5038 PushNodeVersion(config, pfrom, *peer);
5042 const int greatest_common_version =
5056 peer->m_their_services = nServices;
5060 pfrom.cleanSubVer = cleanSubVer;
5062 peer->m_starting_height = starting_height;
5070 (fRelay || (peer->m_our_services &
NODE_BLOOM))) {
5071 auto *
const tx_relay = peer->SetTxRelay();
5073 LOCK(tx_relay->m_bloom_filter_mutex);
5075 tx_relay->m_relay_txs = fRelay;
5088 CNodeState *state = State(pfrom.
GetId());
5089 state->fPreferredDownload =
5093 m_num_preferred_download_peers += state->fPreferredDownload;
5099 bool send_getaddr{
false};
5101 send_getaddr = SetupAddressRelay(pfrom, *peer);
5113 peer->m_getaddr_sent =
true;
5117 WITH_LOCK(peer->m_addr_token_bucket_mutex,
5118 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
5139 std::string remoteAddr;
5145 "receive version message: [%s] %s: version %d, blocks=%d, "
5146 "us=%s, txrelay=%d, peer=%d%s\n",
5148 peer->m_starting_height, addrMe.
ToString(), fRelay,
5149 pfrom.
GetId(), remoteAddr);
5151 int64_t currentTime =
GetTime();
5152 int64_t nTimeOffset = nTime - currentTime;
5157 Misbehaving(*peer,
"Ignoring invalid timestamp in version message");
5167 "feeler connection completed peer=%d; disconnecting\n",
5176 Misbehaving(*peer,
"non-version message before version handshake");
5186 "ignoring redundant verack message from peer=%d\n",
5193 "New outbound peer connected: version: %d, blocks=%d, "
5195 pfrom.
nVersion.load(), peer->m_starting_height, pfrom.
GetId(),
5217 AddKnownProof(*peer, localProof->getId());
5221 peer->m_proof_relay->m_recently_announced_proofs.insert(
5222 localProof->getId());
5227 if (
auto tx_relay = peer->GetTxRelay()) {
5236 return tx_relay->m_tx_inventory_to_send.empty() &&
5237 tx_relay->m_next_inv_send_time == 0s));
5246 Misbehaving(*peer,
"non-verack message before version handshake");
5251 const auto ser_params{
5260 std::vector<CAddress> vAddr;
5264 if (!SetupAddressRelay(pfrom, *peer)) {
5270 if (vAddr.size() > m_opts.max_addr_to_send) {
5271 Misbehaving(*peer,
strprintf(
"%s message size = %u", msg_type,
5277 std::vector<CAddress> vAddrOk;
5278 const auto current_a_time{Now<NodeSeconds>()};
5281 const auto current_time = GetTime<std::chrono::microseconds>();
5283 LOCK(peer->m_addr_token_bucket_mutex);
5286 const auto time_diff =
5287 std::max(current_time - peer->m_addr_token_timestamp, 0us);
5288 const double increment =
5290 peer->m_addr_token_bucket =
5291 std::min<double>(peer->m_addr_token_bucket + increment,
5295 peer->m_addr_token_timestamp = current_time;
5297 const bool rate_limited =
5299 uint64_t num_proc = 0;
5300 uint64_t num_rate_limit = 0;
5301 Shuffle(vAddr.begin(), vAddr.end(), m_rng);
5303 if (interruptMsgProc) {
5308 LOCK(peer->m_addr_token_bucket_mutex);
5310 if (peer->m_addr_token_bucket < 1.0) {
5316 peer->m_addr_token_bucket -= 1.0;
5329 addr.
nTime > current_a_time + 10min) {
5330 addr.
nTime = current_a_time - 5 * 24h;
5332 AddAddressKnown(*peer, addr);
5341 if (addr.
nTime > current_a_time - 10min && !peer->m_getaddr_sent &&
5344 RelayAddress(pfrom.
GetId(), addr, fReachable);
5348 vAddrOk.push_back(addr);
5351 peer->m_addr_processed += num_proc;
5352 peer->m_addr_rate_limited += num_rate_limit;
5354 "Received addr: %u addresses (%u processed, %u rate-limited) "
5356 vAddr.size(), num_proc, num_rate_limit, pfrom.
GetId());
5358 m_addrman.
Add(vAddrOk, pfrom.
addr, 2h);
5359 if (vAddr.size() < 1000) {
5360 peer->m_getaddr_sent =
false;
5367 "addrfetch connection completed peer=%d; disconnecting\n",
5375 peer->m_wants_addrv2 =
true;
5380 peer->m_prefers_headers =
true;
5385 bool sendcmpct_hb{
false};
5386 uint64_t sendcmpct_version{0};
5387 vRecv >> sendcmpct_hb >> sendcmpct_version;
5394 CNodeState *nodestate = State(pfrom.
GetId());
5395 nodestate->m_provides_cmpctblocks =
true;
5396 nodestate->m_requested_hb_cmpctblocks = sendcmpct_hb;
5405 std::vector<CInv> vInv;
5408 Misbehaving(*peer,
strprintf(
"inv message size = %u", vInv.size()));
5412 const bool reject_tx_invs{RejectIncomingTxs(pfrom)};
5414 const auto current_time{GetTime<std::chrono::microseconds>()};
5415 std::optional<BlockHash> best_block;
5417 auto logInv = [&](
const CInv &inv,
bool fAlreadyHave) {
5419 fAlreadyHave ?
"have" :
"new", pfrom.
GetId());
5422 for (
CInv &inv : vInv) {
5423 if (interruptMsgProc) {
5435 const bool fAlreadyHave = AlreadyHaveBlock(
BlockHash(inv.
hash));
5436 logInv(inv, fAlreadyHave);
5439 UpdateBlockAvailability(pfrom.
GetId(), hash);
5441 !IsBlockRequested(hash)) {
5448 best_block = std::move(hash);
5459 const bool fAlreadyHave = AlreadyHaveProof(proofid);
5460 logInv(inv, fAlreadyHave);
5461 AddKnownProof(*peer, proofid);
5463 if (!fAlreadyHave && m_avalanche &&
5465 const bool preferred = isPreferredDownloadPeer(pfrom);
5467 LOCK(cs_proofrequest);
5468 AddProofAnnouncement(pfrom, proofid, current_time,
5477 const bool fAlreadyHave =
5478 AlreadyHaveTx(txid,
true);
5479 logInv(inv, fAlreadyHave);
5481 AddKnownTx(*peer, txid);
5482 if (reject_tx_invs) {
5484 "transaction (%s) inv sent in violation of "
5485 "protocol, disconnecting peer=%d\n",
5489 }
else if (!fAlreadyHave &&
5491 AddTxAnnouncement(pfrom, txid, current_time);
5498 "Unknown inv type \"%s\" received from peer=%d\n",
5515 if (state.fSyncStarted ||
5516 (!peer->m_inv_triggered_getheaders_before_sync &&
5517 *best_block != m_last_block_inv_triggering_headers_sync)) {
5518 if (MaybeSendGetHeaders(
5519 pfrom,
GetLocator(m_chainman.m_best_header), *peer)) {
5521 m_chainman.m_best_header->nHeight,
5522 best_block->ToString(), pfrom.
GetId());
5524 if (!state.fSyncStarted) {
5525 peer->m_inv_triggered_getheaders_before_sync =
true;
5529 m_last_block_inv_triggering_headers_sync = *best_block;
5538 std::vector<CInv> vInv;
5542 strprintf(
"getdata message size = %u", vInv.size()));
5547 vInv.size(), pfrom.
GetId());
5549 if (vInv.size() > 0) {
5555 LOCK(peer->m_getdata_requests_mutex);
5556 peer->m_getdata_requests.insert(peer->m_getdata_requests.end(),
5557 vInv.begin(), vInv.end());
5558 ProcessGetData(config, pfrom, *peer, interruptMsgProc);
5567 vRecv >> locator >> hashStop;
5571 "getblocks locator size %lld > %d, disconnect peer=%d\n",
5585 std::shared_ptr<const CBlock> a_recent_block;
5587 LOCK(m_most_recent_block_mutex);
5588 a_recent_block = m_most_recent_block;
5592 state, a_recent_block, m_avalanche)) {
5610 (pindex ? pindex->
nHeight : -1),
5613 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5622 const int nPrunedBlocksLikelyToHave =
5626 (!pindex->nStatus.hasData() ||
5628 nPrunedBlocksLikelyToHave)) {
5631 " getblocks stopping, pruned or too old block at %d %s\n",
5636 peer->m_block_inv_mutex,
5637 peer->m_blocks_for_inv_relay.push_back(pindex->
GetBlockHash()));
5638 if (--nLimit <= 0) {
5644 peer->m_continuation_block = pindex->GetBlockHash();
5656 std::shared_ptr<const CBlock> recent_block;
5658 LOCK(m_most_recent_block_mutex);
5659 if (m_most_recent_block_hash == req.
blockhash) {
5660 recent_block = m_most_recent_block;
5665 SendBlockTransactions(pfrom, *peer, *recent_block, req);
5675 if (!pindex || !pindex->nStatus.hasData()) {
5678 "Peer %d sent us a getblocktxn for a block we don't have\n",
5689 if (!block_pos.IsNull()) {
5698 SendBlockTransactions(pfrom, *peer, block, req);
5710 "Peer %d sent us a getblocktxn for a block > %i deep\n",
5715 WITH_LOCK(peer->m_getdata_requests_mutex,
5716 peer->m_getdata_requests.push_back(inv));
5725 vRecv >> locator >> hashStop;
5729 "getheaders locator size %lld > %d, disconnect peer=%d\n",
5738 "Ignoring getheaders from peer=%d while importing/reindexing\n",
5752 if (m_chainman.
ActiveTip() ==
nullptr ||
5757 "Ignoring getheaders from peer=%d because active chain "
5758 "has too little work; sending empty response\n",
5763 std::vector<CBlock>()));
5767 CNodeState *nodestate = State(pfrom.
GetId());
5776 if (!BlockRequestAllowed(pindex)) {
5778 "%s: ignoring request from peer=%i for old block "
5779 "header that isn't in the main chain\n",
5780 __func__, pfrom.
GetId());
5794 std::vector<CBlock> vHeaders;
5797 (pindex ? pindex->
nHeight : -1),
5800 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5802 if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) {
5819 nodestate->pindexBestHeaderSent =
5827 if (RejectIncomingTxs(pfrom)) {
5829 "transaction sent in violation of protocol peer=%d\n",
5845 const CTransaction &tx = *ptx;
5846 const TxId &txid = tx.GetId();
5847 AddKnownTx(*peer, txid);
5852 m_txrequest.ReceivedResponse(pfrom.
GetId(), txid);
5854 if (AlreadyHaveTx(txid,
true)) {
5860 if (!m_mempool.
exists(tx.GetId())) {
5862 "Not relaying non-mempool transaction %s from "
5863 "forcerelay peer=%d\n",
5864 tx.GetId().ToString(), pfrom.
GetId());
5866 LogPrintf(
"Force relaying tx %s from peer=%d\n",
5867 tx.GetId().ToString(), pfrom.
GetId());
5868 RelayTransaction(tx.GetId());
5872 if (m_recent_rejects_package_reconsiderable.contains(txid)) {
5880 "found tx %s in reconsiderable rejects, looking for "
5881 "child in orphanage\n",
5883 if (
auto package_to_validate{
5884 Find1P1CPackage(ptx, pfrom.
GetId())}) {
5887 package_to_validate->m_txns,
5890 "package evaluation for %s: %s (%s)\n",
5891 package_to_validate->ToString(),
5893 ?
"package accepted"
5894 :
"package rejected",
5896 ProcessPackageResult(package_to_validate.value(),
5925 ProcessValidTx(pfrom.
GetId(), ptx);
5931 bool fRejectedParents =
false;
5935 std::vector<TxId> unique_parents;
5936 unique_parents.reserve(tx.vin.size());
5937 for (
const CTxIn &txin : tx.vin) {
5940 unique_parents.push_back(txin.prevout.GetTxId());
5942 std::sort(unique_parents.begin(), unique_parents.end());
5943 unique_parents.erase(
5944 std::unique(unique_parents.begin(), unique_parents.end()),
5945 unique_parents.end());
5953 std::optional<TxId> rejected_parent_reconsiderable;
5954 for (
const TxId &parent_txid : unique_parents) {
5955 if (m_recent_rejects.contains(parent_txid)) {
5956 fRejectedParents =
true;
5960 if (m_recent_rejects_package_reconsiderable.contains(
5962 !m_mempool.
exists(parent_txid)) {
5967 if (rejected_parent_reconsiderable.has_value()) {
5968 fRejectedParents =
true;
5971 rejected_parent_reconsiderable = parent_txid;
5974 if (!fRejectedParents) {
5975 const auto current_time{
5976 GetTime<std::chrono::microseconds>()};
5978 for (
const TxId &parent_txid : unique_parents) {
5980 AddKnownTx(*peer, parent_txid);
5984 if (!AlreadyHaveTx(parent_txid,
5986 AddTxAnnouncement(pfrom, parent_txid, current_time);
5992 if (
unsigned int nEvicted =
5996 if (orphanage.AddTx(ptx,
5998 AddToCompactExtraTransactions(ptx);
6001 m_opts.max_orphan_txs, m_rng);
6004 "orphanage overflow, removed %u tx\n",
6010 m_txrequest.ForgetInvId(tx.GetId());
6014 "not keeping orphan with rejected parents %s\n",
6015 tx.GetId().ToString());
6018 m_recent_rejects.insert(tx.GetId());
6019 m_txrequest.ForgetInvId(tx.GetId());
6023 ProcessInvalidTx(pfrom.
GetId(), ptx, state,
6033 "tx %s failed but reconsiderable, looking for child in "
6036 if (
auto package_to_validate{
6037 Find1P1CPackage(ptx, pfrom.
GetId())}) {
6040 package_to_validate->m_txns,
false)};
6042 "package evaluation for %s: %s (%s)\n",
6043 package_to_validate->ToString(),
6045 ?
"package accepted"
6046 :
"package rejected",
6048 ProcessPackageResult(package_to_validate.value(),
6057 m_txrequest.ForgetInvId(tx.GetId());
6059 unsigned int nEvicted{0};
6066 m_opts.max_conflicting_txs, m_rng);
6071 "conflicting pool overflow, removed %u tx\n",
6084 "Unexpected cmpctblock message received from peer %d\n",
6091 vRecv >> cmpctblock;
6092 }
catch (std::ios_base::failure &e) {
6094 Misbehaving(*peer,
"cmpctblock-bad-indexes");
6098 bool received_new_header =
false;
6111 MaybeSendGetHeaders(
6112 pfrom,
GetLocator(m_chainman.m_best_header), *peer);
6118 GetAntiDoSWorkThreshold()) {
6122 "Ignoring low-work compact block from peer %d\n",
6128 received_new_header =
true;
6138 MaybePunishNodeForBlock(pfrom.
GetId(), state,
6140 "invalid header via cmpctblock");
6145 if (received_new_header) {
6146 LogInfo(
"Saw new cmpctblock header hash=%s peer=%d\n",
6147 blockhash.ToString(), pfrom.
GetId());
6154 bool fProcessBLOCKTXN =
false;
6160 bool fRevertToHeaderProcessing =
false;
6164 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6165 bool fBlockReconstructed =
false;
6173 CNodeState *nodestate = State(pfrom.
GetId());
6177 if (received_new_header &&
6180 nodestate->m_last_block_announcement =
GetTime();
6183 if (pindex->nStatus.hasData()) {
6190 size_t already_in_flight =
6191 std::distance(range_flight.first, range_flight.second);
6192 bool requested_block_from_this_peer{
false};
6196 bool first_in_flight =
6197 already_in_flight == 0 ||
6198 (range_flight.first->second.first == pfrom.
GetId());
6200 while (range_flight.first != range_flight.second) {
6201 if (range_flight.first->second.first == pfrom.
GetId()) {
6202 requested_block_from_this_peer =
true;
6205 range_flight.first++;
6214 if (requested_block_from_this_peer) {
6218 std::vector<CInv> vInv(1);
6228 if (!already_in_flight && !CanDirectFetch()) {
6236 nodestate->vBlocksInFlight.size() <
6238 requested_block_from_this_peer) {
6239 std::list<QueuedBlock>::iterator *queuedBlockIt =
nullptr;
6240 if (!BlockRequested(config, pfrom.
GetId(), *pindex,
6242 if (!(*queuedBlockIt)->partialBlock) {
6244 ->partialBlock.reset(
6251 "we were already syncing!\n");
6257 *(*queuedBlockIt)->partialBlock;
6259 partialBlock.
InitData(cmpctblock, vExtraTxnForCompact);
6265 Misbehaving(*peer,
"invalid compact block");
6268 if (first_in_flight) {
6271 std::vector<CInv> vInv(1);
6285 for (
size_t i = 0; i < cmpctblock.
BlockTxCount(); i++) {
6296 fProcessBLOCKTXN =
true;
6297 }
else if (first_in_flight) {
6306 IsBlockRequestedFromOutbound(blockhash) ||
6331 tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
6336 std::vector<CTransactionRef> dummy;
6337 status = tempBlock.FillBlock(*pblock, dummy);
6339 fBlockReconstructed =
true;
6343 if (requested_block_from_this_peer) {
6347 std::vector<CInv> vInv(1);
6355 fRevertToHeaderProcessing =
true;
6360 if (fProcessBLOCKTXN) {
6362 blockTxnMsg, time_received, interruptMsgProc);
6365 if (fRevertToHeaderProcessing) {
6371 return ProcessHeadersMessage(config, pfrom, *peer,
6376 if (fBlockReconstructed) {
6381 mapBlockSource.emplace(pblock->GetHash(),
6382 std::make_pair(pfrom.
GetId(),
false));
6393 ProcessBlock(config, pfrom, pblock,
true,
6402 RemoveBlockRequest(pblock->GetHash(), std::nullopt);
6412 "Unexpected blocktxn message received from peer %d\n",
6420 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6421 bool fBlockRead =
false;
6425 auto range_flight = mapBlocksInFlight.equal_range(resp.
blockhash);
6426 size_t already_in_flight =
6427 std::distance(range_flight.first, range_flight.second);
6428 bool requested_block_from_this_peer{
false};
6432 bool first_in_flight =
6433 already_in_flight == 0 ||
6434 (range_flight.first->second.first == pfrom.
GetId());
6436 while (range_flight.first != range_flight.second) {
6437 auto [node_id, block_it] = range_flight.first->second;
6438 if (node_id == pfrom.
GetId() && block_it->partialBlock) {
6439 requested_block_from_this_peer =
true;
6442 range_flight.first++;
6445 if (!requested_block_from_this_peer) {
6447 "Peer %d sent us block transactions for block "
6448 "we weren't expecting\n",
6454 *range_flight.first->second.second->partialBlock;
6462 "invalid compact block/non-matching block transactions");
6465 if (first_in_flight) {
6467 std::vector<CInv> invs;
6475 "Peer %d sent us a compact block but it failed to "
6476 "reconstruct, waiting on first download to complete\n",
6509 std::make_pair(pfrom.
GetId(),
false));
6520 ProcessBlock(config, pfrom, pblock,
true,
6530 "Unexpected headers message received from peer %d\n",
6535 std::vector<CBlockHeader> headers;
6542 strprintf(
"too-many-headers: headers message size = %u",
6546 headers.resize(nCount);
6547 for (
unsigned int n = 0; n < nCount; n++) {
6548 vRecv >> headers[n];
6553 ProcessHeadersMessage(config, pfrom, *peer, std::move(headers),
6559 if (m_headers_presync_should_signal.exchange(
false)) {
6560 HeadersPresyncStats stats;
6562 LOCK(m_headers_presync_mutex);
6564 m_headers_presync_stats.find(m_headers_presync_bestpeer);
6565 if (it != m_headers_presync_stats.end()) {
6571 stats.first, stats.second->first, stats.second->second);
6582 "Unexpected block message received from peer %d\n",
6587 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6591 pblock->GetHash().ToString(), pfrom.
GetId());
6596 pblock->hashPrevBlock))};
6600 "Received mutated block from peer=%d\n", peer->m_id);
6601 Misbehaving(*peer,
"mutated block");
6603 RemoveBlockRequest(pblock->GetHash(), peer->m_id));
6613 const BlockHash hash = pblock->GetHash();
6614 bool min_pow_checked =
false;
6619 forceProcessing = IsBlockRequested(hash);
6620 RemoveBlockRequest(hash, pfrom.
GetId());
6624 mapBlockSource.emplace(hash, std::make_pair(pfrom.
GetId(),
true));
6630 GetAntiDoSWorkThreshold()) {
6631 min_pow_checked =
true;
6634 ProcessBlock(config, pfrom, pblock, forceProcessing, min_pow_checked);
6644 if (pfrom.m_avalanche_pubkey.has_value()) {
6647 "Ignoring avahello from peer %d: already in our node set\n",
6653 vRecv >> delegation;
6660 if (!delegation.
verify(state, pubkey)) {
6661 Misbehaving(*peer,
"invalid-delegation");
6664 pfrom.m_avalanche_pubkey = std::move(pubkey);
6667 sighasher << delegation.
getId();
6675 if (!(*pfrom.m_avalanche_pubkey)
6676 .VerifySchnorr(sighasher.GetHash(),
sig)) {
6677 Misbehaving(*peer,
"invalid-avahello-signature");
6684 if (!AlreadyHaveProof(proofid)) {
6685 const bool preferred = isPreferredDownloadPeer(pfrom);
6686 LOCK(cs_proofrequest);
6687 AddProofAnnouncement(pfrom, proofid,
6688 GetTime<std::chrono::microseconds>(),
6707 WITH_LOCK(peer->m_addr_token_bucket_mutex,
6708 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
6713 peer->m_proof_relay->compactproofs_requested =
true;
6724 const auto now = Now<SteadyMilliseconds>();
6730 last_poll + std::chrono::milliseconds(m_opts.avalanche_cooldown)) {
6732 "Ignoring repeated avapoll from peer %d: cooldown not "
6747 strprintf(
"too-many-ava-poll: poll message size = %u", nCount));
6751 std::vector<avalanche::Vote> votes;
6752 votes.reserve(nCount);
6754 bool fPreconsensus{
false};
6755 bool fStakingPreconsensus{
false};
6760 fStakingPreconsensus =
6764 for (
unsigned int n = 0; n < nCount; n++) {
6772 if (!quorum_established) {
6773 votes.emplace_back(vote, inv.
hash);
6780 if (fPreconsensus) {
6782 GetAvalancheVoteForTx(*m_avalanche,
TxId(inv.
hash));
6794 if (fStakingPreconsensus) {
6801 "poll inv type %d unknown from peer=%d\n",
6806 votes.emplace_back(vote, inv.
hash);
6832 if (!pfrom.m_avalanche_pubkey.has_value() ||
6833 !(*pfrom.m_avalanche_pubkey)
6834 .VerifySchnorr(verifier.GetHash(),
sig)) {
6835 Misbehaving(*peer,
"invalid-ava-response-signature");
6840 auto now = GetTime<std::chrono::seconds>();
6842 std::vector<avalanche::VoteItemUpdate> updates;
6843 bool disconnect{
false};
6846 disconnect, error)) {
6848 Misbehaving(*peer, error);
6866 "Repeated failure to register votes from peer %d: %s\n",
6867 pfrom.
GetId(), error);
6870 Misbehaving(*peer, error);
6883 auto logVoteUpdate = [](
const auto &voteUpdate,
6884 const std::string &voteItemTypeStr,
6885 const auto &voteItemId) {
6886 std::string voteOutcome;
6887 bool alwaysPrint =
false;
6888 switch (voteUpdate.getStatus()) {
6890 voteOutcome =
"invalidated";
6894 voteOutcome =
"rejected";
6897 voteOutcome =
"accepted";
6900 voteOutcome =
"finalized";
6903 alwaysPrint = voteItemTypeStr !=
"tx";
6906 voteOutcome =
"stalled";
6915 alwaysPrint &= (voteItemTypeStr !=
"contender");
6918 LogPrintf(
"Avalanche %s %s %s\n", voteOutcome, voteItemTypeStr,
6919 voteItemId.ToString());
6923 voteItemTypeStr, voteItemId.ToString());
6927 bool shouldActivateBestChain =
false;
6929 bool fPreconsensus{
false};
6930 bool fStakingPreconsensus{
false};
6935 fStakingPreconsensus =
6939 for (
const auto &u : updates) {
6944 if (
auto pitem = std::get_if<const avalanche::ProofRef>(&item)) {
6948 logVoteUpdate(u,
"proof", proofid);
6950 auto rejectionMode =
6952 auto nextCooldownTimePoint = GetTime<std::chrono::seconds>();
6953 switch (u.getStatus()) {
6969 return pm.rejectProof(proofid,
6973 "ERROR: Failed to reject proof: %s\n",
6979 nextCooldownTimePoint += std::chrono::seconds(
6980 m_opts.avalanche_peer_replacement_cooldown);
6986 avalanche::PeerManager::
6987 RegistrationMode::FORCE_ACCEPT);
6990 [&](const avalanche::Peer &peer) {
6991 pm.updateNextPossibleConflictTime(
6993 nextCooldownTimePoint);
6994 if (u.getStatus() ==
6995 avalanche::VoteStatus::
6997 pm.setFinalized(peer.peerid);
7005 "ERROR: Failed to accept proof: %s\n",
7012 auto getBlockFromIndex = [
this](
const CBlockIndex *pindex) {
7015 std::shared_ptr<const CBlock> pblock =
WITH_LOCK(
7016 m_most_recent_block_mutex,
return m_most_recent_block);
7018 if (!pblock || pblock->GetHash() != pindex->
GetBlockHash()) {
7019 std::shared_ptr<CBlock> pblockRead =
7020 std::make_shared<CBlock>();
7023 assert(!
"cannot load block from disk");
7025 pblock = pblockRead;
7030 if (
auto pitem = std::get_if<const CBlockIndex *>(&item)) {
7033 shouldActivateBestChain =
true;
7037 switch (u.getStatus()) {
7042 LogPrintf(
"ERROR: Database error: %s\n",
7051 LogPrintf(
"ERROR: Database error: %s\n",
7056 auto pblock = getBlockFromIndex(pindex);
7072 std::unique_ptr<node::CBlockTemplate> blockTemplate;
7076 chainstate.UnparkBlock(pindex);
7078 const bool newlyFinalized =
7079 !chainstate.IsBlockAvalancheFinalized(pindex) &&
7080 chainstate.AvalancheFinalizeBlock(pindex,
7085 if (fPreconsensus && newlyFinalized) {
7086 auto pblock = getBlockFromIndex(pindex);
7100 std::unordered_set<TxId, SaltedTxIdHasher>
7101 confirmedTxIdsInNonFinalizedBlocks;
7103 block !=
nullptr && block != pindex;
7104 block = block->
pprev) {
7106 getBlockFromIndex(block);
7108 for (
const auto &tx :
7109 currentBlock->vtx) {
7110 confirmedTxIdsInNonFinalizedBlocks
7111 .insert(tx->GetId());
7119 confirmedTxIdsInNonFinalizedBlocks);
7131 config, chainstate, &m_mempool,
7133 blockAssembler.pblocktemplate.reset(
7136 if (blockAssembler.pblocktemplate) {
7137 blockAssembler.addTxs(m_mempool);
7138 blockTemplate = std::move(
7139 blockAssembler.pblocktemplate);
7145 if (blockTemplate) {
7151 for (
const auto &templateEntry :
7165 if (fStakingPreconsensus) {
7167 std::get_if<const avalanche::StakeContenderId>(&item)) {
7169 logVoteUpdate(u,
"contender", contenderId);
7171 switch (u.getStatus()) {
7192 if (!fPreconsensus) {
7196 if (
auto pitem = std::get_if<const CTransactionRef>(&item)) {
7200 const TxId &txid = tx->GetId();
7201 const auto status{u.getStatus()};
7206 logVoteUpdate(u,
"tx", txid);
7217 if (m_mempool.
exists(txid)) {
7221 std::vector<CTransactionRef> conflictingTxs =
7227 if (conflictingTxs.size() > 0) {
7238 for (
const auto &conflictingTx :
7241 conflictingTx->GetId());
7260 m_recent_rejects.insert(txid);
7267 std::make_shared<const std::vector<Coin>>(
7283 return conflicting.HaveTx(txid);
7286 std::vector<CTransactionRef>
7287 mempool_conflicting_txs;
7288 for (
const auto &txin : tx->vin) {
7293 mempool_conflicting_txs.push_back(
7294 std::move(conflict));
7303 [&txid, &mempool_conflicting_txs](
7308 if (mempool_conflicting_txs.size() >
7311 mempool_conflicting_txs[0],
7320 auto it = m_mempool.
GetIter(txid);
7321 if (!it.has_value()) {
7324 "Error: finalized tx (%s) is not in the "
7330 std::vector<TxId> finalizedTxIds;
7331 m_mempool.setAvalancheFinalized(
7336 for (
const auto &finalized_txid : finalizedTxIds) {
7341 logVoteUpdate(u,
"tx", finalized_txid);
7349 std::vector<CTransactionRef>
7352 for (
const auto &conflictingTx :
7354 m_recent_rejects.insert(
7355 conflictingTx->GetId());
7357 conflictingTx->GetId());
7383 m_txrequest.ForgetInvId(txid);
7389 for (
auto &it : m_peer_map) {
7390 auto tx_relay = (*it.second).GetTxRelay();
7395 LOCK(tx_relay->m_tx_inventory_mutex);
7402 auto &stalled_by_time =
7403 tx_relay->m_avalanche_stalled_txids
7405 if (stalled_by_time.size() >=
7407 stalled_by_time.erase(
7408 stalled_by_time.begin()->timeAdded);
7411 tx_relay->m_avalanche_stalled_txids.insert(
7422 if (shouldActivateBestChain) {
7425 state,
nullptr, m_avalanche)) {
7440 ReceivedAvalancheProof(pfrom, *peer, proof);
7449 if (peer->m_proof_relay ==
nullptr) {
7453 peer->m_proof_relay->lastSharedProofsUpdate =
7454 GetTime<std::chrono::seconds>();
7456 peer->m_proof_relay->sharedProofs =
7462 peer->m_proof_relay->sharedProofs);
7473 if (peer->m_proof_relay ==
nullptr) {
7478 if (!peer->m_proof_relay->compactproofs_requested) {
7482 peer->m_proof_relay->compactproofs_requested =
false;
7486 vRecv >> compactProofs;
7487 }
catch (std::ios_base::failure &e) {
7489 Misbehaving(*peer,
"avaproofs-bad-indexes");
7495 if (!ReceivedAvalancheProof(pfrom, *peer, prefilledProof.proof)) {
7525 auto shortIdProcessor =
7529 if (shortIdProcessor.hasOutOfBoundIndex()) {
7532 Misbehaving(*peer,
"avaproofs-bad-indexes");
7535 if (!shortIdProcessor.isEvenlyDistributed()) {
7540 std::vector<std::pair<avalanche::ProofId, bool>> remoteProofsStatus;
7547 shortIdProcessor.matchKnownItem(shortid, peer.
proof);
7554 remoteProofsStatus.emplace_back(peer.
getProofId(),
7565 for (
size_t i = 0; i < compactProofs.
size(); i++) {
7566 if (shortIdProcessor.getItem(i) ==
nullptr) {
7583 return pfrom.m_avalanche_pubkey.has_value())) {
7586 for (
const auto &[proofid, present] : remoteProofsStatus) {
7596 if (peer->m_proof_relay ==
nullptr) {
7603 auto requestedIndiceIt = proofreq.
indices.begin();
7604 uint32_t treeIndice = 0;
7605 peer->m_proof_relay->sharedProofs.forEachLeaf([&](
const auto &proof) {
7606 if (requestedIndiceIt == proofreq.
indices.end()) {
7611 if (treeIndice++ == *requestedIndiceIt) {
7614 requestedIndiceIt++;
7620 peer->m_proof_relay->sharedProofs = {};
7633 "Ignoring \"getaddr\" from %s connection. peer=%d\n",
7640 Assume(SetupAddressRelay(pfrom, *peer));
7644 if (peer->m_getaddr_recvd) {
7649 peer->m_getaddr_recvd =
true;
7651 peer->m_addrs_to_send.clear();
7652 std::vector<CAddress> vAddr;
7653 const size_t maxAddrToSend = m_opts.max_addr_to_send;
7661 for (
const CAddress &addr : vAddr) {
7662 PushAddress(*peer, addr);
7668 auto now = GetTime<std::chrono::seconds>();
7678 if (!SetupAddressRelay(pfrom, *peer)) {
7680 "Ignoring getavaaddr message from %s peer=%d\n",
7685 auto availabilityScoreComparator = [](
const CNode *lhs,
7688 double scoreRhs = rhs->getAvailabilityScore();
7690 if (scoreLhs != scoreRhs) {
7691 return scoreLhs > scoreRhs;
7700 std::set<
const CNode *,
decltype(availabilityScoreComparator)> avaNodes(
7701 availabilityScoreComparator);
7708 avaNodes.insert(pnode);
7709 if (avaNodes.size() > m_opts.max_addr_to_send) {
7710 avaNodes.erase(std::prev(avaNodes.end()));
7714 peer->m_addrs_to_send.clear();
7715 for (
const CNode *pnode : avaNodes) {
7716 PushAddress(*peer, pnode->
addr);
7727 "mempool request with bloom filters disabled, "
7728 "disconnect peer=%d\n",
7739 "mempool request with bandwidth limit reached, "
7740 "disconnect peer=%d\n",
7747 if (
auto tx_relay = peer->GetTxRelay()) {
7748 LOCK(tx_relay->m_tx_inventory_mutex);
7749 tx_relay->m_send_mempool =
true;
7779 const auto ping_end = time_received;
7782 bool bPingFinished =
false;
7783 std::string sProblem;
7785 if (nAvail >=
sizeof(nonce)) {
7790 if (peer->m_ping_nonce_sent != 0) {
7791 if (nonce == peer->m_ping_nonce_sent) {
7794 bPingFinished =
true;
7795 const auto ping_time = ping_end - peer->m_ping_start.load();
7796 if (ping_time.count() >= 0) {
7801 sProblem =
"Timing mishap";
7805 sProblem =
"Nonce mismatch";
7809 bPingFinished =
true;
7810 sProblem =
"Nonce zero";
7814 sProblem =
"Unsolicited pong without ping";
7819 bPingFinished =
true;
7820 sProblem =
"Short payload";
7823 if (!(sProblem.empty())) {
7825 "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
7826 pfrom.
GetId(), sProblem, peer->m_ping_nonce_sent, nonce,
7829 if (bPingFinished) {
7830 peer->m_ping_nonce_sent = 0;
7838 "filterload received despite not offering bloom services "
7839 "from peer=%d; disconnecting\n",
7849 Misbehaving(*peer,
"too-large bloom filter");
7850 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7852 LOCK(tx_relay->m_bloom_filter_mutex);
7853 tx_relay->m_bloom_filter.reset(
new CBloomFilter(filter));
7854 tx_relay->m_relay_txs =
true;
7864 "filteradd received despite not offering bloom services "
7865 "from peer=%d; disconnecting\n",
7870 std::vector<uint8_t> vData;
7879 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7880 LOCK(tx_relay->m_bloom_filter_mutex);
7881 if (tx_relay->m_bloom_filter) {
7882 tx_relay->m_bloom_filter->insert(vData);
7890 Misbehaving(*peer,
"bad filteradd message");
7898 "filterclear received despite not offering bloom services "
7899 "from peer=%d; disconnecting\n",
7904 auto tx_relay = peer->GetTxRelay();
7910 LOCK(tx_relay->m_bloom_filter_mutex);
7911 tx_relay->m_bloom_filter =
nullptr;
7912 tx_relay->m_relay_txs =
true;
7921 vRecv >> newFeeFilter;
7923 if (
auto tx_relay = peer->GetTxRelay()) {
7924 tx_relay->m_fee_filter_received = newFeeFilter;
7933 ProcessGetCFilters(pfrom, *peer, vRecv);
7938 ProcessGetCFHeaders(pfrom, *peer, vRecv);
7943 ProcessGetCFCheckPt(pfrom, *peer, vRecv);
7948 std::vector<CInv> vInv;
7954 for (
CInv &inv : vInv) {
7960 m_txrequest.ReceivedResponse(pfrom.
GetId(),
TxId(inv.
hash));
7967 LOCK(cs_proofrequest);
7968 m_proofrequest.ReceivedResponse(
7982bool PeerManagerImpl::MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer) {
7984 LOCK(peer.m_misbehavior_mutex);
7987 if (!peer.m_should_discourage) {
7991 peer.m_should_discourage =
false;
7997 LogPrintf(
"Warning: not punishing noban peer %d!\n", peer.m_id);
8003 LogPrintf(
"Warning: not punishing manually connected peer %d!\n",
8012 "Warning: disconnecting but not discouraging %s peer %d!\n",
8029bool PeerManagerImpl::ProcessMessages(
const Config &config,
CNode *pfrom,
8030 std::atomic<bool> &interruptMsgProc) {
8042 PeerRef peer = GetPeerRef(pfrom->
GetId());
8043 if (peer ==
nullptr) {
8048 LOCK(peer->m_getdata_requests_mutex);
8049 if (!peer->m_getdata_requests.empty()) {
8050 ProcessGetData(config, *pfrom, *peer, interruptMsgProc);
8054 const bool processed_orphan = ProcessOrphanTx(config, *peer);
8060 if (processed_orphan) {
8067 LOCK(peer->m_getdata_requests_mutex);
8068 if (!peer->m_getdata_requests.empty()) {
8085 bool fMoreWork = poll_result->second;
8089 msg.m_recv.size(), msg.m_recv.
data());
8091 if (m_opts.capture_messages) {
8099 if (!msg.m_valid_netmagic) {
8101 "PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n",
8115 if (!msg.m_valid_header) {
8123 if (!msg.m_valid_checksum) {
8135 ProcessMessage(config, *pfrom, msg.
m_type, vRecv, msg.m_time,
8137 if (interruptMsgProc) {
8142 LOCK(peer->m_getdata_requests_mutex);
8143 if (!peer->m_getdata_requests.empty()) {
8152 return orphanage.HaveTxToReconsider(peer->m_id);
8156 }
catch (
const std::exception &e) {
8159 e.what(),
typeid(e).name());
8168void PeerManagerImpl::ConsiderEviction(
CNode &pto, Peer &peer,
8169 std::chrono::seconds time_in_seconds) {
8172 CNodeState &state = *State(pto.
GetId());
8176 state.fSyncStarted) {
8183 if (state.pindexBestKnownBlock !=
nullptr &&
8184 state.pindexBestKnownBlock->nChainWork >=
8186 if (state.m_chain_sync.m_timeout != 0s) {
8187 state.m_chain_sync.m_timeout = 0s;
8188 state.m_chain_sync.m_work_header =
nullptr;
8189 state.m_chain_sync.m_sent_getheaders =
false;
8191 }
else if (state.m_chain_sync.m_timeout == 0s ||
8192 (state.m_chain_sync.m_work_header !=
nullptr &&
8193 state.pindexBestKnownBlock !=
nullptr &&
8194 state.pindexBestKnownBlock->nChainWork >=
8195 state.m_chain_sync.m_work_header->nChainWork)) {
8201 state.m_chain_sync.m_work_header = m_chainman.
ActiveChain().
Tip();
8202 state.m_chain_sync.m_sent_getheaders =
false;
8203 }
else if (state.m_chain_sync.m_timeout > 0s &&
8204 time_in_seconds > state.m_chain_sync.m_timeout) {
8209 if (state.m_chain_sync.m_sent_getheaders) {
8212 "Disconnecting outbound peer %d for old chain, best known "
8215 state.pindexBestKnownBlock !=
nullptr
8216 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
8220 assert(state.m_chain_sync.m_work_header);
8225 MaybeSendGetHeaders(
8226 pto,
GetLocator(state.m_chain_sync.m_work_header->pprev),
8230 "sending getheaders to outbound peer=%d to verify chain "
8231 "work (current best known block:%s, benchmark blockhash: "
8234 state.pindexBestKnownBlock !=
nullptr
8235 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
8237 state.m_chain_sync.m_work_header->GetBlockHash()
8239 state.m_chain_sync.m_sent_getheaders =
true;
8246 state.m_chain_sync.m_timeout =
8253void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now) {
8262 std::pair<NodeId, std::chrono::seconds> youngest_peer{-1, 0},
8263 next_youngest_peer{-1, 0};
8269 if (pnode->
GetId() > youngest_peer.first) {
8270 next_youngest_peer = youngest_peer;
8271 youngest_peer.first = pnode->GetId();
8272 youngest_peer.second = pnode->m_last_block_time;
8276 NodeId to_disconnect = youngest_peer.first;
8277 if (youngest_peer.second > next_youngest_peer.second) {
8280 to_disconnect = next_youngest_peer.first;
8292 CNodeState *node_state = State(pnode->
GetId());
8293 if (node_state ==
nullptr ||
8295 node_state->vBlocksInFlight.empty())) {
8298 "disconnecting extra block-relay-only peer=%d "
8299 "(last block received at time %d)\n",
8306 "keeping block-relay-only peer=%d chosen for eviction "
8307 "(connect time: %d, blocks_in_flight: %d)\n",
8309 node_state->vBlocksInFlight.size());
8325 int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
8336 CNodeState *state = State(pnode->
GetId());
8337 if (state ==
nullptr) {
8342 if (state->m_chain_sync.m_protect) {
8345 if (state->m_last_block_announcement < oldest_block_announcement ||
8346 (state->m_last_block_announcement == oldest_block_announcement &&
8347 pnode->
GetId() > worst_peer)) {
8348 worst_peer = pnode->
GetId();
8349 oldest_block_announcement = state->m_last_block_announcement;
8353 if (worst_peer == -1) {
8357 bool disconnected = m_connman.
ForNode(
8365 CNodeState &state = *State(pnode->
GetId());
8367 state.vBlocksInFlight.empty()) {
8369 "disconnecting extra outbound peer=%d (last block "
8370 "announcement received at time %d)\n",
8371 pnode->
GetId(), oldest_block_announcement);
8376 "keeping outbound peer=%d chosen for eviction "
8377 "(connect time: %d, blocks_in_flight: %d)\n",
8379 state.vBlocksInFlight.size());
8394void PeerManagerImpl::CheckForStaleTipAndEvictPeers() {
8397 auto now{GetTime<std::chrono::seconds>()};
8399 EvictExtraOutboundPeers(now);
8401 if (now > m_stale_tip_check_time) {
8407 LogPrintf(
"Potential stale tip detected, will try using extra "
8408 "outbound peer (last tip update: %d seconds ago)\n",
8417 if (!m_initial_sync_finished && CanDirectFetch()) {
8419 m_initial_sync_finished =
true;
8423void PeerManagerImpl::MaybeSendPing(
CNode &node_to, Peer &peer,
8424 std::chrono::microseconds now) {
8426 node_to, std::chrono::duration_cast<std::chrono::seconds>(now)) &&
8427 peer.m_ping_nonce_sent &&
8439 bool pingSend =
false;
8441 if (peer.m_ping_queued) {
8446 if (peer.m_ping_nonce_sent == 0 &&
8456 }
while (nonce == 0);
8457 peer.m_ping_queued =
false;
8458 peer.m_ping_start = now;
8460 peer.m_ping_nonce_sent = nonce;
8466 peer.m_ping_nonce_sent = 0;
8472void PeerManagerImpl::MaybeSendAddr(
CNode &
node, Peer &peer,
8473 std::chrono::microseconds current_time) {
8475 if (!peer.m_addr_relay_enabled) {
8479 LOCK(peer.m_addr_send_times_mutex);
8481 peer.m_next_local_addr_send < current_time) {
8488 if (peer.m_next_local_addr_send != 0us) {
8489 peer.m_addr_known->reset();
8492 CAddress local_addr{*local_service, peer.m_our_services,
8493 Now<NodeSeconds>()};
8494 PushAddress(peer, local_addr);
8496 peer.m_next_local_addr_send =
8502 if (current_time <= peer.m_next_addr_send) {
8506 peer.m_next_addr_send =
8509 const size_t max_addr_to_send = m_opts.max_addr_to_send;
8510 if (!
Assume(peer.m_addrs_to_send.size() <= max_addr_to_send)) {
8513 peer.m_addrs_to_send.resize(max_addr_to_send);
8518 auto addr_already_known =
8521 bool ret = peer.m_addr_known->contains(addr.
GetKey());
8523 peer.m_addr_known->insert(addr.
GetKey());
8527 peer.m_addrs_to_send.erase(std::remove_if(peer.m_addrs_to_send.begin(),
8528 peer.m_addrs_to_send.end(),
8529 addr_already_known),
8530 peer.m_addrs_to_send.end());
8533 if (peer.m_addrs_to_send.empty()) {
8537 const char *msg_type;
8539 if (peer.m_wants_addrv2) {
8552 peer.m_addrs_to_send)));
8553 peer.m_addrs_to_send.clear();
8556 if (peer.m_addrs_to_send.capacity() > 40) {
8557 peer.m_addrs_to_send.shrink_to_fit();
8561void PeerManagerImpl::MaybeSendSendHeaders(
CNode &
node, Peer &peer) {
8566 if (!peer.m_sent_sendheaders &&
8569 CNodeState &state = *State(
node.GetId());
8570 if (state.pindexBestKnownBlock !=
nullptr &&
8571 state.pindexBestKnownBlock->nChainWork >
8579 peer.m_sent_sendheaders =
true;
8584void PeerManagerImpl::MaybeSendFeefilter(
8585 CNode &pto, Peer &peer, std::chrono::microseconds current_time) {
8586 if (m_opts.ignore_incoming_txs) {
8610 static const Amount MAX_FILTER{m_fee_filter_rounder.round(
MAX_MONEY)};
8611 if (peer.m_fee_filter_sent == MAX_FILTER) {
8614 peer.m_next_send_feefilter = 0us;
8617 if (current_time > peer.m_next_send_feefilter) {
8618 Amount filterToSend = m_fee_filter_rounder.round(currentFilter);
8622 if (filterToSend != peer.m_fee_filter_sent) {
8626 peer.m_fee_filter_sent = filterToSend;
8628 peer.m_next_send_feefilter =
8636 peer.m_next_send_feefilter &&
8637 (currentFilter < 3 * peer.m_fee_filter_sent / 4 ||
8638 currentFilter > 4 * peer.m_fee_filter_sent / 3)) {
8639 peer.m_next_send_feefilter =
8647class CompareInvMempoolOrder {
8651 explicit CompareInvMempoolOrder(
CTxMemPool *_mempool) : mp(_mempool) {}
8653 bool operator()(std::set<TxId>::iterator a, std::set<TxId>::iterator b) {
8663bool PeerManagerImpl::RejectIncomingTxs(
const CNode &peer)
const {
8672 if (m_opts.ignore_incoming_txs &&
8679bool PeerManagerImpl::SetupAddressRelay(
const CNode &
node, Peer &peer) {
8683 if (
node.IsBlockOnlyConn()) {
8687 if (!peer.m_addr_relay_enabled.exchange(
true)) {
8691 peer.m_addr_known = std::make_unique<CRollingBloomFilter>(5000, 0.001);
8697bool PeerManagerImpl::SendMessages(
const Config &config,
CNode *pto) {
8700 PeerRef peer = GetPeerRef(pto->
GetId());
8709 if (MaybeDiscourageAndDisconnect(*pto, *peer)) {
8722 const auto current_time{GetTime<std::chrono::microseconds>()};
8727 "addrfetch connection timeout; disconnecting peer=%d\n",
8733 MaybeSendPing(*pto, *peer, current_time);
8740 bool sync_blocks_and_headers_from_peer =
false;
8742 MaybeSendAddr(*pto, *peer, current_time);
8744 MaybeSendSendHeaders(*pto, *peer);
8749 CNodeState &state = *State(pto->
GetId());
8752 if (m_chainman.m_best_header ==
nullptr) {
8759 if (state.fPreferredDownload) {
8760 sync_blocks_and_headers_from_peer =
true;
8771 if (m_num_preferred_download_peers == 0 ||
8772 mapBlocksInFlight.empty()) {
8773 sync_blocks_and_headers_from_peer =
true;
8777 if (!state.fSyncStarted && CanServeBlocks(*peer) &&
8781 if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) ||
8783 const CBlockIndex *pindexStart = m_chainman.m_best_header;
8792 if (pindexStart->
pprev) {
8793 pindexStart = pindexStart->
pprev;
8795 if (MaybeSendGetHeaders(*pto,
GetLocator(pindexStart), *peer)) {
8798 "initial getheaders (%d) to peer=%d (startheight:%d)\n",
8800 peer->m_starting_height);
8802 state.fSyncStarted =
true;
8803 peer->m_headers_sync_timeout =
8808 std::chrono::microseconds{
8810 Ticks<std::chrono::seconds>(
8812 m_chainman.m_best_header->Time()) /
8829 LOCK(peer->m_block_inv_mutex);
8830 std::vector<CBlock> vHeaders;
8832 ((!peer->m_prefers_headers &&
8833 (!state.m_requested_hb_cmpctblocks ||
8834 peer->m_blocks_for_headers_relay.size() > 1)) ||
8835 peer->m_blocks_for_headers_relay.size() >
8840 ProcessBlockAvailability(pto->
GetId());
8842 if (!fRevertToInv) {
8843 bool fFoundStartingHeader =
false;
8847 for (
const BlockHash &hash : peer->m_blocks_for_headers_relay) {
8853 fRevertToInv =
true;
8856 if (pBestIndex !=
nullptr && pindex->
pprev != pBestIndex) {
8867 fRevertToInv =
true;
8870 pBestIndex = pindex;
8871 if (fFoundStartingHeader) {
8874 }
else if (PeerHasHeader(&state, pindex)) {
8877 }
else if (pindex->
pprev ==
nullptr ||
8878 PeerHasHeader(&state, pindex->
pprev)) {
8881 fFoundStartingHeader =
true;
8886 fRevertToInv =
true;
8891 if (!fRevertToInv && !vHeaders.empty()) {
8892 if (vHeaders.size() == 1 && state.m_requested_hb_cmpctblocks) {
8897 "%s sending header-and-ids %s to peer=%d\n",
8898 __func__, vHeaders.front().GetHash().ToString(),
8901 std::optional<CSerializedNetMsg> cached_cmpctblock_msg;
8903 LOCK(m_most_recent_block_mutex);
8904 if (m_most_recent_block_hash ==
8906 cached_cmpctblock_msg =
8908 *m_most_recent_compact_block);
8911 if (cached_cmpctblock_msg.has_value()) {
8913 pto, std::move(cached_cmpctblock_msg.value()));
8917 block, *pBestIndex)};
8924 state.pindexBestHeaderSent = pBestIndex;
8925 }
else if (peer->m_prefers_headers) {
8926 if (vHeaders.size() > 1) {
8928 "%s: %u headers, range (%s, %s), to peer=%d\n",
8929 __func__, vHeaders.size(),
8930 vHeaders.front().GetHash().ToString(),
8931 vHeaders.back().GetHash().ToString(),
8935 "%s: sending header %s to peer=%d\n", __func__,
8936 vHeaders.front().GetHash().ToString(),
8941 state.pindexBestHeaderSent = pBestIndex;
8943 fRevertToInv =
true;
8950 if (!peer->m_blocks_for_headers_relay.empty()) {
8952 peer->m_blocks_for_headers_relay.back();
8963 "Announcing block %s not on main chain (tip=%s)\n",
8972 if (!PeerHasHeader(&state, pindex)) {
8973 peer->m_blocks_for_inv_relay.push_back(hashToAnnounce);
8975 "%s: sending inv peer=%d hash=%s\n", __func__,
8980 peer->m_blocks_for_headers_relay.clear();
8987 std::vector<CInv> vInv;
8988 auto addInvAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
8989 vInv.emplace_back(type, hash);
9001 LOCK(peer->m_block_inv_mutex);
9003 vInv.reserve(std::max<size_t>(peer->m_blocks_for_inv_relay.size(),
9009 for (
const BlockHash &hash : peer->m_blocks_for_inv_relay) {
9012 peer->m_blocks_for_inv_relay.clear();
9015 auto computeNextInvSendTime =
9016 [&](std::chrono::microseconds &next)
9020 if (next < current_time) {
9021 fSendTrickle =
true;
9023 next = NextInvToInbounds(
9028 next = current_time;
9032 return fSendTrickle;
9036 if (peer->m_proof_relay !=
nullptr) {
9037 LOCK(peer->m_proof_relay->m_proof_inventory_mutex);
9039 if (computeNextInvSendTime(
9040 peer->m_proof_relay->m_next_inv_send_time)) {
9042 peer->m_proof_relay->m_proof_inventory_to_send.begin();
9044 peer->m_proof_relay->m_proof_inventory_to_send.end()) {
9047 it = peer->m_proof_relay->m_proof_inventory_to_send.erase(
9050 if (peer->m_proof_relay->m_proof_inventory_known_filter
9051 .contains(proofid)) {
9055 peer->m_proof_relay->m_proof_inventory_known_filter.insert(
9058 peer->m_proof_relay->m_recently_announced_proofs.insert(
9064 if (
auto tx_relay = peer->GetTxRelay()) {
9065 LOCK(tx_relay->m_tx_inventory_mutex);
9067 const bool fSendTrickle =
9068 computeNextInvSendTime(tx_relay->m_next_inv_send_time);
9073 LOCK(tx_relay->m_bloom_filter_mutex);
9074 if (!tx_relay->m_relay_txs) {
9075 tx_relay->m_tx_inventory_to_send.clear();
9080 if (fSendTrickle && tx_relay->m_send_mempool) {
9081 auto vtxinfo = m_mempool.
infoAll();
9082 tx_relay->m_send_mempool =
false;
9084 tx_relay->m_fee_filter_received.load()};
9086 LOCK(tx_relay->m_bloom_filter_mutex);
9088 for (
const auto &txinfo : vtxinfo) {
9089 const TxId &txid = txinfo.tx->GetId();
9090 tx_relay->m_tx_inventory_to_send.erase(txid);
9093 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
9096 if (tx_relay->m_bloom_filter &&
9097 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
9101 tx_relay->m_tx_inventory_known_filter.insert(txid);
9104 addInvAndMaybeFlush(
MSG_TX, txid);
9106 tx_relay->m_last_mempool_req =
9107 std::chrono::duration_cast<std::chrono::seconds>(
9114 std::vector<std::set<TxId>::iterator> vInvTx;
9115 vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size());
9116 for (std::set<TxId>::iterator it =
9117 tx_relay->m_tx_inventory_to_send.begin();
9118 it != tx_relay->m_tx_inventory_to_send.end(); it++) {
9119 vInvTx.push_back(it);
9122 tx_relay->m_fee_filter_received.load()};
9127 CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool);
9128 std::make_heap(vInvTx.begin(), vInvTx.end(),
9129 compareInvMempoolOrder);
9133 unsigned int nRelayedTransactions = 0;
9134 LOCK(tx_relay->m_bloom_filter_mutex);
9135 while (!vInvTx.empty() &&
9140 std::pop_heap(vInvTx.begin(), vInvTx.end(),
9141 compareInvMempoolOrder);
9142 std::set<TxId>::iterator it = vInvTx.back();
9144 const TxId txid = *it;
9146 tx_relay->m_tx_inventory_to_send.erase(it);
9148 if (tx_relay->m_tx_inventory_known_filter.contains(txid) &&
9149 tx_relay->m_avalanche_stalled_txids.count(txid) == 0) {
9153 auto txinfo = m_mempool.
info(txid);
9159 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
9162 if (tx_relay->m_bloom_filter &&
9163 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
9168 tx_relay->m_recently_announced_invs.insert(txid);
9169 addInvAndMaybeFlush(
MSG_TX, txid);
9170 nRelayedTransactions++;
9171 tx_relay->m_tx_inventory_known_filter.insert(txid);
9172 tx_relay->m_avalanche_stalled_txids.erase(txid);
9178 if (!vInv.empty()) {
9185 CNodeState &state = *State(pto->
GetId());
9188 auto stalling_timeout = m_block_stalling_timeout.load();
9189 if (state.m_stalling_since.count() &&
9190 state.m_stalling_since < current_time - stalling_timeout) {
9195 LogPrintf(
"Peer=%d is stalling block download, disconnecting\n",
9200 const auto new_timeout =
9202 if (stalling_timeout != new_timeout &&
9203 m_block_stalling_timeout.compare_exchange_strong(
9204 stalling_timeout, new_timeout)) {
9207 "Increased stalling timeout temporarily to %d seconds\n",
9219 if (state.vBlocksInFlight.size() > 0) {
9220 QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
9221 int nOtherPeersWithValidatedDownloads =
9222 m_peers_downloading_from - 1;
9224 state.m_downloading_since +
9225 std::chrono::seconds{consensusParams.nPowTargetSpacing} *
9228 nOtherPeersWithValidatedDownloads)) {
9229 LogPrintf(
"Timeout downloading block %s from peer=%d, "
9231 queuedBlock.pindex->GetBlockHash().ToString(),
9239 if (state.fSyncStarted &&
9240 peer->m_headers_sync_timeout < std::chrono::microseconds::max()) {
9243 if (current_time > peer->m_headers_sync_timeout &&
9244 nSyncStarted == 1 &&
9245 (m_num_preferred_download_peers -
9246 state.fPreferredDownload >=
9255 LogPrintf(
"Timeout downloading headers from peer=%d, "
9261 LogPrintf(
"Timeout downloading headers from noban "
9262 "peer=%d, not disconnecting\n",
9268 state.fSyncStarted =
false;
9270 peer->m_headers_sync_timeout = 0us;
9276 peer->m_headers_sync_timeout = std::chrono::microseconds::max();
9282 ConsiderEviction(*pto, *peer, GetTime<std::chrono::seconds>());
9285 std::vector<CInv> vGetData;
9293 CNodeState &state = *State(pto->
GetId());
9295 if (CanServeBlocks(*peer) &&
9296 ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) ||
9299 std::vector<const CBlockIndex *> vToDownload;
9301 auto get_inflight_budget = [&state]() {
9304 static_cast<int>(state.vBlocksInFlight.size()));
9310 FindNextBlocksToDownload(*peer, get_inflight_budget(), vToDownload,
9313 !IsLimitedPeer(*peer)) {
9319 m_chainman.GetSnapshotBaseBlock());
9321 TryDownloadingHistoricalBlocks(
9322 *peer, get_inflight_budget(), vToDownload, from_tip,
9323 Assert(m_chainman.GetSnapshotBaseBlock()));
9327 BlockRequested(config, pto->
GetId(), *pindex);
9332 if (state.vBlocksInFlight.empty() && staller != -1) {
9333 if (State(staller)->m_stalling_since == 0us) {
9334 State(staller)->m_stalling_since = current_time;
9341 auto addGetDataAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
9342 CInv inv(type, hash);
9345 vGetData.push_back(std::move(inv));
9357 LOCK(cs_proofrequest);
9358 std::vector<std::pair<NodeId, avalanche::ProofId>> expired;
9360 m_proofrequest.GetRequestable(pto->
GetId(), current_time, &expired);
9361 for (
const auto &entry : expired) {
9363 "timeout of inflight proof %s from peer=%d\n",
9364 entry.second.ToString(), entry.first);
9366 for (
const auto &proofid : requestable) {
9367 if (!AlreadyHaveProof(proofid)) {
9369 m_proofrequest.RequestedData(
9370 pto->
GetId(), proofid,
9377 m_proofrequest.ForgetInvId(proofid);
9387 std::vector<std::pair<NodeId, TxId>> expired;
9389 m_txrequest.GetRequestable(pto->
GetId(), current_time, &expired);
9390 for (
const auto &entry : expired) {
9392 entry.second.ToString(), entry.first);
9394 for (
const TxId &txid : requestable) {
9398 if (!AlreadyHaveTx(txid,
false)) {
9399 addGetDataAndMaybeFlush(
MSG_TX, txid);
9400 m_txrequest.RequestedData(
9407 m_txrequest.ForgetInvId(txid);
9411 if (!vGetData.empty()) {
9417 MaybeSendFeefilter(*pto, *peer, current_time);
9421bool PeerManagerImpl::ReceivedAvalancheProof(
CNode &
node, Peer &peer,
9423 assert(proof !=
nullptr);
9427 AddKnownProof(peer, proofid);
9439 return node.m_avalanche_pubkey.has_value());
9440 auto saveProofIfStaker = [
this, isStaker](
const CNode &
node,
9442 const NodeId nodeid) ->
bool {
9454 LOCK(cs_proofrequest);
9455 m_proofrequest.ReceivedResponse(nodeid, proofid);
9457 if (AlreadyHaveProof(proofid)) {
9458 m_proofrequest.ForgetInvId(proofid);
9459 saveProofIfStaker(
node, proofid, nodeid);
9469 return pm.registerProof(proof, state);
9471 WITH_LOCK(cs_proofrequest, m_proofrequest.ForgetInvId(proofid));
9472 RelayProof(proofid);
9474 node.m_last_proof_time = GetTime<std::chrono::seconds>();
9477 nodeid, proofid.ToString());
9499 "Not polling the avalanche proof (%s): peer=%d, proofid %s\n",
9500 state.
IsValid() ?
"not-worth-polling"
9502 nodeid, proofid.ToString());
9505 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.
static constexpr SerParams V1_NETWORK
NodeSeconds nTime
Always included in serialization, except in the network format on INIT_PROTO_VERSION.
static constexpr SerParams V2_NETWORK
size_t BlockTxCount() const
std::vector< CTransactionRef > vtx
The block chain is a tree shaped structure starting with the genesis block at the root,...
bool IsValid(enum BlockValidity nUpTo=BlockValidity::TRANSACTIONS) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
CBlockIndex * pprev
pointer to the index of the predecessor of this block
CBlockHeader GetBlockHeader() const
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
bool HaveNumChainTxs() const
Check whether this block and all previous blocks back to the genesis block or an assumeutxo snapshot ...
int64_t GetBlockTime() const
unsigned int nTx
Number of transactions in this block.
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
BlockHash GetBlockHash() const
int nHeight
height of the entry in the chain. The genesis block has height 0
FlatFilePos GetBlockPos() const EXCLUSIVE_LOCKS_REQUIRED(
BloomFilter is a probabilistic filter which SPV clients provide so that we can filter the transaction...
bool IsWithinSizeConstraints() const
True if the size is <= MAX_BLOOM_FILTER_SIZE and the number of hash functions is <= MAX_HASH_FUNCS (c...
An in-memory indexed chain of blocks.
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
CBlockIndex * Next(const CBlockIndex *pindex) const
Find the successor of a block in this chain, or nullptr if the given index is not found or is the tip...
int Height() const
Return the maximal height in the chain.
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
const CBlock & GenesisBlock() const
const Consensus::Params & GetConsensus() const
CCoinsView that adds a memory cache for transactions to another CCoinsView.
CCoinsView that brings transactions from a mempool into view.
void ForEachNode(const NodeFn &func)
bool OutboundTargetReached(bool historicalBlockServingLimit) const
check if the outbound target is reached.
bool ForNode(NodeId id, std::function< bool(CNode *pnode)> func)
bool GetNetworkActive() const
bool GetTryNewOutboundPeer() const
void SetTryNewOutboundPeer(bool flag)
int GetExtraBlockRelayCount() const
void WakeMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc)
void StartExtraBlockRelayPeers()
bool DisconnectNode(const std::string &node)
CSipHasher GetDeterministicRandomizer(uint64_t id) const
Get a unique deterministic randomizer.
int GetExtraFullOutboundCount() const
std::vector< CAddress > GetAddresses(size_t max_addresses, size_t max_pct, std::optional< Network > network) const
Return all or many randomly selected addresses, optionally by network.
bool CheckIncomingNonce(uint64_t nonce)
bool ShouldRunInactivityChecks(const CNode &node, std::chrono::seconds now) const
Return true if we should disconnect the peer for failing an inactivity check.
void PushMessage(CNode *pnode, CSerializedNetMsg &&msg)
bool GetUseAddrmanOutgoing() const
Fee rate in satoshis per kilobyte: Amount / kB.
Amount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
Inv(ventory) message data.
bool IsMsgCmpctBlk() const
std::string ToString() const
bool IsMsgStakeContender() const
bool IsMsgFilteredBlk() const
void TransactionInvalidated(const CTransactionRef &tx, std::shared_ptr< const std::vector< Coin > > spent_coins)
Used to create a Merkle proof (usually from a subset of transactions), which consists of a block head...
std::vector< std::pair< size_t, uint256 > > vMatchedTxn
Public only for unit testing and relay testing (not relayed).
bool IsRelayable() const
Whether this address should be relayed to other peers even if we can't reach it ourselves.
static constexpr SerParams V1
bool IsAddrV1Compatible() const
Check if the current object can be serialized in pre-ADDRv2/BIP155 format.
Transport protocol agnostic message container.
CSerializedNetMsg Make(int nFlags, std::string msg_type, Args &&...args) const
Information about a peer.
Mutex cs_avalanche_pubkey
bool IsFeelerConn() const
const std::chrono::seconds m_connected
Unix epoch time at peer connection.
bool ExpectServicesFromConn() const
std::atomic< int > nVersion
std::atomic_bool m_has_all_wanted_services
Whether this peer provides all services that we want.
bool IsInboundConn() const
bool HasPermission(NetPermissionFlags permission) const
bool IsOutboundOrBlockRelayConn() const
bool IsManualConn() const
std::atomic< int64_t > nTimeOffset
const std::string m_addr_name
std::string ConnectionTypeAsString() const
void SetCommonVersion(int greatest_common_version)
std::atomic< bool > m_bip152_highbandwidth_to
std::atomic_bool m_relays_txs
Whether we should relay transactions to this peer.
std::atomic< bool > m_bip152_highbandwidth_from
void PongReceived(std::chrono::microseconds ping_time)
A ping-pong round trip has completed successfully.
std::atomic_bool fSuccessfullyConnected
bool IsAddrFetchConn() const
uint64_t GetLocalNonce() const
void SetAddrLocal(const CService &addrLocalIn) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_local_mutex)
May not be called more than once.
bool IsBlockOnlyConn() const
int GetCommonVersion() const
bool IsFullOutboundConn() const
uint64_t nRemoteHostNonce
Mutex m_subver_mutex
cleanSubVer is a sanitized string of the user agent byte array we read from the wire.
std::atomic_bool fPauseSend
std::chrono::seconds m_nextGetAvaAddr
uint64_t nRemoteExtraEntropy
std::optional< std::pair< CNetMessage, bool > > PollMessage() EXCLUSIVE_LOCKS_REQUIRED(!m_msg_process_queue_mutex)
Poll the next message from the processing queue of this connection.
uint64_t GetLocalExtraEntropy() const
SteadyMilliseconds m_last_poll
double getAvailabilityScore() const
std::atomic_bool m_bloom_filter_loaded
Whether this peer has loaded a bloom filter.
void updateAvailabilityScore(double decayFactor)
The availability score is calculated using an exponentially weighted average.
std::atomic< std::chrono::seconds > m_avalanche_last_message_fault
const bool m_inbound_onion
Whether this peer is an inbound onion, i.e.
std::atomic< int > m_avalanche_message_fault_counter
How much faulty messages did this node accumulate.
std::atomic< bool > m_avalanche_enabled
std::atomic< std::chrono::seconds > m_last_block_time
UNIX epoch time of the last block received from this peer that we had not yet seen (e....
std::atomic_bool fDisconnect
std::atomic< int > m_avalanche_message_fault_score
This score is incremented for every new faulty message received when m_avalanche_message_fault_counte...
std::atomic< std::chrono::seconds > m_last_tx_time
UNIX epoch time of the last transaction received from this peer that we had not yet seen (e....
void invsVoted(uint32_t count)
The node voted for count invs.
bool IsAvalancheOutboundConnection() const
An encapsulated public key.
RollingBloomFilter is a probabilistic "keep track of most recently inserted" set.
Simple class for background tasks that should be run periodically or once "after a while".
void scheduleEvery(Predicate p, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Repeat p until it return false.
void scheduleFromNow(Function f, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Call f once after the delta has passed.
A combination of a network address (CNetAddr) and a (TCP) port.
std::string ToString() const
std::vector< uint8_t > GetKey() const
uint64_t Finalize() const
Compute the 64-bit SipHash-2-4 of the data written so far.
CSipHasher & Write(uint64_t data)
Hash a 64-bit integer worth of data.
std::set< std::reference_wrapper< const CTxMemPoolEntryRef >, CompareIteratorById > Parents
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
void removeConflicts(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(cs)
void RemoveUnbroadcastTx(const TxId &txid, const bool unchecked=false)
Removes a transaction from the unbroadcast set.
CFeeRate GetMinFee() const
The minimum fee to get into the mempool, which may itself not be enough for larger-sized transactions...
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs)
bool CompareTopologically(const TxId &txida, const TxId &txidb) const
TxMempoolInfo info(const TxId &txid) const
size_t DynamicMemoryUsage() const
bool setAvalancheFinalized(const CTxMemPoolEntryRef &tx, const Consensus::Params ¶ms, const CBlockIndex &active_chain_tip, std::vector< TxId > &finalizedTxIds) EXCLUSIVE_LOCKS_REQUIRED(bool isAvalancheFinalizedPreConsensus(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
std::vector< TxMempoolInfo > infoAll() const
CTransactionRef GetConflictTx(const COutPoint &prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Get the transaction in the pool that spends the same prevout.
bool exists(const TxId &txid) const
std::set< TxId > GetUnbroadcastTxs() const
Returns transactions in unbroadcast set.
auto withOrphanage(Callable &&func) const EXCLUSIVE_LOCKS_REQUIRED(!cs_orphanage)
const CFeeRate m_min_relay_feerate
auto withConflicting(Callable &&func) const EXCLUSIVE_LOCKS_REQUIRED(!cs_conflicting)
void removeForFinalizedBlock(const std::unordered_set< TxId, SaltedTxIdHasher > &confirmedTxIdsInNonFinalizedBlocks) EXCLUSIVE_LOCKS_REQUIRED(cs)
unsigned long size() const
std::optional< txiter > GetIter(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Returns an iterator to the given txid, if found.
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr< const CBlock > &block)
Notifies listeners that a block which builds directly on our current tip has been received and connec...
virtual void BlockConnected(ChainstateRole role, const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex)
Notifies listeners of a block being connected.
virtual void BlockChecked(const CBlock &, const BlockValidationState &)
Notifies listeners of a block validation result.
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
Notifies listeners when the block chain tip advances.
virtual void BlockDisconnected(const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex)
Notifies listeners of a block being disconnected.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex *GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(Chainstate ActiveChainstate)() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
const CBlockIndex * GetBackgroundSyncTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
The tip of the background sync chain.
MempoolAcceptResult ProcessTransaction(const CTransactionRef &tx, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Try to add a transaction to the memory pool.
bool IsInitialBlockDownload() const
Check whether we are doing an initial block download (synchronizing from disk or network)
bool ProcessNewBlock(const std::shared_ptr< const CBlock > &block, bool force_processing, bool min_pow_checked, bool *new_block, avalanche::Processor *const avalanche=nullptr) LOCKS_EXCLUDED(cs_main)
Process an incoming block.
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
bool BackgroundSyncInProgress() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
The state of a background sync (for net processing)
bool ProcessNewBlockHeaders(const std::vector< CBlockHeader > &block, bool min_pow_checked, BlockValidationState &state, const CBlockIndex **ppindex=nullptr, const std::optional< CCheckpointData > &test_checkpoints=std::nullopt) LOCKS_EXCLUDED(cs_main)
Process incoming block headers.
const arith_uint256 & MinimumChainWork() const
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
void MaybeRebalanceCaches() EXCLUSIVE_LOCKS_REQUIRED(void ReportHeadersPresync(const arith_uint256 &work, int64_t height, int64_t timestamp)
Check to see if caches are out of balance and if so, call ResizeCoinsCaches() as needed.
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
virtual uint64_t GetMaxBlockSize() const =0
void ignore(size_t num_ignore)
uint64_t rand64() noexcept
Generate a random 64-bit integer.
Reads data from an underlying stream, while hashing the read data.
A writer stream (for serialization) that computes a 256-bit hash.
size_t Count(NodeId peer) const
Count how many announcements a peer has (REQUESTED, CANDIDATE, and COMPLETED combined).
size_t CountInFlight(NodeId peer) const
Count how many REQUESTED announcements a peer has.
Interface for message handling.
static Mutex g_msgproc_mutex
Mutex for anything that is only accessed via the msg processing thread.
virtual bool ProcessMessages(const Config &config, CNode *pnode, std::atomic< bool > &interrupt) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex)=0
Process protocol messages received from a given node.
virtual bool SendMessages(const Config &config, CNode *pnode) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex)=0
Send queued protocol messages to a given node.
virtual void InitializeNode(const Config &config, CNode &node, ServiceFlags our_services)=0
Initialize a peer (setup state, queue any initial messages)
virtual void FinalizeNode(const Config &config, const CNode &node)=0
Handle removal of a peer (clear state)
static bool HasFlag(NetPermissionFlags flags, NetPermissionFlags f)
ReadStatus InitData(const CBlockHeaderAndShortTxIDs &cmpctblock, const std::vector< std::pair< TxHash, CTransactionRef > > &extra_txn)
bool IsTxAvailable(size_t index) const
ReadStatus FillBlock(CBlock &block, const std::vector< CTransactionRef > &vtx_missing)
virtual std::optional< std::string > FetchBlock(const Config &config, NodeId peer_id, const CBlockIndex &block_index)=0
Attempt to manually fetch block from a given peer.
virtual void SendPings()=0
Send ping message to all peers.
static std::unique_ptr< PeerManager > make(CConnman &connman, AddrMan &addrman, BanMan *banman, ChainstateManager &chainman, CTxMemPool &pool, avalanche::Processor *const avalanche, Options opts)
virtual void ProcessMessage(const Config &config, CNode &pfrom, const std::string &msg_type, CDataStream &vRecv, const std::chrono::microseconds time_received, const std::atomic< bool > &interruptMsgProc) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex)=0
Process a single message from a peer.
virtual void StartScheduledTasks(CScheduler &scheduler)=0
Begin running background tasks, should only be called once.
virtual bool IgnoresIncomingTxs()=0
Whether this node ignores txs received over p2p.
virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) const =0
Get statistics from node state.
virtual void UnitTestMisbehaving(const NodeId peer_id)=0
Public for unit testing.
virtual void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds)=0
This function is used for testing the stale tip eviction logic, see denialofservice_tests....
virtual void CheckForStaleTipAndEvictPeers()=0
Evict extra outbound peers.
static RCUPtr make(Args &&...args)
Construct a new object that is owned by the pointer.
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
A Span is an object that can refer to a contiguous sequence of objects.
int EraseTx(const TxId &txid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Erase a tx by txid.
void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Erase all txs announced by a peer (eg, after that peer disconnects)
std::vector< CTransactionRef > GetChildrenFromSamePeer(const CTransactionRef &parent, NodeId nodeid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get all children that spend from this tx and were received from nodeid.
bool AddTx(const CTransactionRef &tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Add a new transaction to the pool.
unsigned int LimitTxs(unsigned int max_txs, FastRandomContext &rng) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Limit the txs to the given maximum.
void EraseForBlock(const CBlock &block) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Erase all txs included in or invalidated by a new block.
std::vector< CTransactionRef > GetConflictTxs(const CTransactionRef &tx) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
void AddChildrenToWorkSet(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Add any tx that list a particular tx as a parent into the from peer's work set.
std::vector< std::pair< CTransactionRef, NodeId > > GetChildrenFromDifferentPeer(const CTransactionRef &parent, NodeId nodeid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get all children that spend from this tx but were not received from nodeid.
std::string GetRejectReason() const
std::string ToString() const
256-bit unsigned big integer.
const std::vector< PrefilledProof > & getPrefilledProofs() const
uint64_t getShortID(const ProofId &proofid) const
const std::vector< uint64_t > & getShortIDs() const
ProofId getProofId() const
bool verify(DelegationState &state, CPubKey &auth) const
const DelegationId & getId() const
const LimitedProofId & getLimitedProofId() const
bool shouldRequestMoreNodes()
Returns true if we encountered a lack of node since the last call.
bool exists(const ProofId &proofid) const
Return true if the (valid) proof exists, but only for non-dangling proofs.
bool forPeer(const ProofId &proofid, Callable &&func) const
bool addNode(NodeId nodeid, const ProofId &proofid)
Node API.
void removeUnbroadcastProof(const ProofId &proofid)
const ProofRadixTree & getShareableProofsSnapshot() const
bool isBoundToPeer(const ProofId &proofid) const
bool saveRemoteProof(const ProofId &proofid, const NodeId nodeid, const bool present)
void forEachPeer(Callable &&func) const
void setInvalid(const ProofId &proofid)
bool isInvalid(const ProofId &proofid) const
bool isImmature(const ProofId &proofid) const
auto getUnbroadcastProofs() const
bool isInConflictingPool(const ProofId &proofid) const
void sendResponse(CNode *pfrom, Response response) const
bool addToReconcile(const AnyVoteItem &item) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
bool isStakingPreconsensusActivated(const CBlockIndex *pprev) const
int64_t getAvaproofsNodeCounter() const
bool sendHello(CNode *pfrom) EXCLUSIVE_LOCKS_REQUIRED(!cs_delayedAvahelloNodeIds)
Send a avahello message.
void setRecentlyFinalized(const uint256 &itemId) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
bool isQuorumEstablished() LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
void cleanupStakingRewards(const int minHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_stakingRewards
ProofRef getLocalProof() const
void acceptStakeContender(const StakeContenderId &contenderId) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
bool reconcileOrFinalize(const ProofRef &proof) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Wrapper around the addToReconcile for proofs that adds back the finalization flag to the peer if it i...
int getStakeContenderStatus(const StakeContenderId &contenderId) const EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
Track votes on stake contenders.
void sendDelayedAvahello() EXCLUSIVE_LOCKS_REQUIRED(!cs_delayedAvahelloNodeIds)
void finalizeStakeContender(const StakeContenderId &contenderId) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
bool isPreconsensusActivated(const CBlockIndex *pprev) const
auto withPeerManager(Callable &&func) const EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
bool registerVotes(NodeId nodeid, const Response &response, std::vector< VoteItemUpdate > &updates, bool &disconnect, std::string &error) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
void rejectStakeContender(const StakeContenderId &contenderId) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
void avaproofsSent(NodeId nodeid) LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
std::vector< uint32_t > indices
std::string ToString() const
std::string GetHex() const
Generate a new block, without valid proof-of-work.
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool ReadRawBlockFromDisk(std::vector< uint8_t > &block, const FlatFilePos &pos) const
bool LoadingBlocks() const
bool IsPruneMode() const
Whether running in -prune mode.
static const uint256 ZERO
@ BLOCK_CHECKPOINT
the block failed to meet one of our checkpoints
@ BLOCK_HEADER_LOW_WORK
the block header may be on a too-little-work chain
@ BLOCK_INVALID_HEADER
invalid proof of work or time too old
@ BLOCK_CACHED_INVALID
this block was cached as being invalid and we didn't store the reason why
@ BLOCK_CONSENSUS
invalid by consensus rules (excluding any below reasons)
@ BLOCK_MISSING_PREV
We don't have the previous block the checked one is built on.
@ BLOCK_INVALID_PREV
A block this one builds on is invalid.
@ BLOCK_MUTATED
the block's data didn't match the data committed to by the PoW
@ BLOCK_TIME_FUTURE
block timestamp was > 2 hours in the future (or our clock is bad)
@ BLOCK_RESULT_UNSET
initial value. Block has not yet been rejected
@ TX_MISSING_INPUTS
transaction was missing some of its inputs
@ TX_CHILD_BEFORE_PARENT
This tx outputs are already spent in the mempool.
@ TX_MEMPOOL_POLICY
violated mempool's fee/size/descendant/etc limits
@ TX_PACKAGE_RECONSIDERABLE
fails some policy, but might be acceptable if submitted in a (different) package
@ TX_UNKNOWN
transaction was not validated because package failed
@ TX_PREMATURE_SPEND
transaction spends a coinbase too early, or violates locktime/sequence locks
@ TX_DUPLICATE
Tx already in mempool or in the chain.
@ TX_INPUTS_NOT_STANDARD
inputs failed policy rules
@ TX_CONFLICT
Tx conflicts with a finalized tx, i.e.
@ TX_NOT_STANDARD
otherwise didn't meet our local policy rules
@ TX_AVALANCHE_RECONSIDERABLE
fails some policy, but might be reconsidered by avalanche voting
@ TX_NO_MEMPOOL
this node does not have a mempool so can't validate the transaction
@ TX_RESULT_UNSET
initial value. Tx has not yet been rejected
@ TX_CONSENSUS
invalid by consensus rules
static size_t RecursiveDynamicUsage(const CScript &script)
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
ChainstateRole
This enum describes the various roles a specific Chainstate instance can take.
std::array< uint8_t, CPubKey::SCHNORR_SIZE > SchnorrSig
a Schnorr signature
#define LogPrintLevel(category, level,...)
#define LogPrint(category,...)
#define LogDebug(category,...)
const char * FILTERLOAD
The filterload message tells the receiving peer to filter all relayed transactions and requested merk...
const char * CFHEADERS
cfheaders is a response to a getcfheaders request containing a filter header and a vector of filter h...
const char * AVAPROOFSREQ
Request for missing avalanche proofs after an avaproofs message has been processed.
const char * CFILTER
cfilter is a response to a getcfilters request containing a single compact filter.
const char * BLOCK
The block message transmits a single serialized block.
const char * FILTERCLEAR
The filterclear message tells the receiving peer to remove a previously-set bloom filter.
const char * HEADERS
The headers message sends one or more block headers to a node which previously requested certain head...
const char * ADDRV2
The addrv2 message relays connection information for peers on the network just like the addr message,...
const char * SENDHEADERS
Indicates that a node prefers to receive new block announcements via a "headers" message rather than ...
const char * AVAPROOFS
The avaproofs message the proof short ids of all the valid proofs that we know.
const char * PONG
The pong message replies to a ping message, proving to the pinging node that the ponging node is stil...
const char * GETAVAPROOFS
The getavaproofs message requests an avaproofs message that provides the proof short ids of all the v...
const char * SENDCMPCT
Contains a 1-byte bool and 8-byte LE version number.
const char * GETADDR
The getaddr message requests an addr message from the receiving node, preferably one with lots of IP ...
const char * GETCFCHECKPT
getcfcheckpt requests evenly spaced compact filter headers, enabling parallelized download and valida...
const char * NOTFOUND
The notfound message is a reply to a getdata message which requested an object the receiving node doe...
const char * GETAVAADDR
The getavaaddr message requests an addr message from the receiving node, containing IP addresses of t...
const char * CMPCTBLOCK
Contains a CBlockHeaderAndShortTxIDs object - providing a header and list of "short txids".
const char * MEMPOOL
The mempool message requests the TXIDs of transactions that the receiving node has verified as valid ...
const char * GETCFILTERS
getcfilters requests compact filters for a range of blocks.
const char * TX
The tx message transmits a single transaction.
const char * AVAHELLO
Contains a delegation and a signature.
const char * FILTERADD
The filteradd message tells the receiving peer to add a single element to a previously-set bloom filt...
const char * ADDR
The addr (IP address) message relays connection information for peers on the network.
const char * VERSION
The version message provides information about the transmitting node to the receiving node at the beg...
const char * GETBLOCKS
The getblocks message requests an inv message that provides block header hashes starting from a parti...
const char * FEEFILTER
The feefilter message tells the receiving peer not to inv us any txs which do not meet the specified ...
const char * GETHEADERS
The getheaders message requests a headers message that provides block headers starting from a particu...
const char * AVARESPONSE
Contains an avalanche::Response.
const char * GETDATA
The getdata message requests one or more data objects from another node.
const char * VERACK
The verack message acknowledges a previously-received version message, informing the connecting node ...
const char * BLOCKTXN
Contains a BlockTransactions.
const char * GETCFHEADERS
getcfheaders requests a compact filter header and the filter hashes for a range of blocks,...
const char * SENDADDRV2
The sendaddrv2 message signals support for receiving ADDRV2 messages (BIP155).
const char * PING
The ping message is sent periodically to help confirm that the receiving peer is still connected.
const char * AVAPOLL
Contains an avalanche::Poll.
const char * MERKLEBLOCK
The merkleblock message is a reply to a getdata message which requested a block using the inventory t...
const char * AVAPROOF
Contains an avalanche::Proof.
const char * CFCHECKPT
cfcheckpt is a response to a getcfcheckpt request containing a vector of evenly spaced filter headers...
const char * GETBLOCKTXN
Contains a BlockTransactionsRequest Peer should respond with "blocktxn" message.
const char * INV
The inv message (inventory message) transmits one or more inventories of objects known to the transmi...
ShortIdProcessor< PrefilledProof, ShortIdProcessorPrefilledProofAdapter, ProofRefCompare > ProofShortIdProcessor
std::variant< const ProofRef, const CBlockIndex *, const StakeContenderId, const CTransactionRef > AnyVoteItem
RCUPtr< const Proof > ProofRef
Implement std::hash so RCUPtr can be used as a key for maps or sets.
std::optional< CService > GetLocalAddrForPeer(CNode &node)
Returns a local address that we should advertise to this peer.
std::function< void(const CAddress &addr, const std::string &msg_type, Span< const uint8_t > data, bool is_incoming)> CaptureMessage
Defaults to CaptureMessageToFile(), but can be overridden by unit tests.
std::string userAgent(const Config &config)
bool IsReachable(enum Network net)
bool SeenLocal(const CService &addr)
vote for a local address
static const unsigned int MAX_SUBVERSION_LENGTH
Maximum length of the user agent string in version message.
static constexpr std::chrono::minutes TIMEOUT_INTERVAL
Time after which to disconnect, after waiting for a ping response (or inactivity).
@ BypassProofRequestLimits
static constexpr auto HEADERS_RESPONSE_TIME
How long to wait for a peer to respond to a getheaders request.
static constexpr size_t MAX_ADDR_PROCESSING_TOKEN_BUCKET
The soft limit of the address processing token bucket (the regular MAX_ADDR_RATE_PER_SECOND based inc...
static constexpr size_t MAX_AVALANCHE_STALLED_TXIDS_PER_PEER
Maximum number of stalled avalanche txids to store per peer.
static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER
Number of blocks that can be requested at any given time from a single peer.
static constexpr auto BLOCK_STALLING_TIMEOUT_DEFAULT
Default time during which a peer must stall block download progress before being disconnected.
static constexpr auto GETAVAADDR_INTERVAL
Minimum time between 2 successives getavaaddr messages from the same peer.
static constexpr auto AVG_FEEFILTER_BROADCAST_INTERVAL
Verify that INVENTORY_MAX_RECENT_RELAY is enough to cache everything typically relayed before uncondi...
static constexpr unsigned int INVENTORY_BROADCAST_MAX_PER_MB
Maximum number of inventory items to send per transmission.
static constexpr auto EXTRA_PEER_CHECK_INTERVAL
How frequently to check for extra outbound peers and disconnect.
static const unsigned int BLOCK_DOWNLOAD_WINDOW
Size of the "block download window": how far ahead of our current height do we fetch?...
static uint32_t getAvalancheVoteForProof(const avalanche::Processor &avalanche, const avalanche::ProofId &id)
Decide a response for an Avalanche poll about the given proof.
static constexpr int STALE_RELAY_AGE_LIMIT
Age after which a stale block will no longer be served if requested as protection against fingerprint...
static constexpr int HISTORICAL_BLOCK_AGE
Age after which a block is considered historical for purposes of rate limiting block relay.
static constexpr auto ROTATE_ADDR_RELAY_DEST_INTERVAL
Delay between rotating the peers we relay a particular address to.
static constexpr auto MINIMUM_CONNECT_TIME
Minimum time an outbound-peer-eviction candidate must be connected for, in order to evict.
static constexpr auto CHAIN_SYNC_TIMEOUT
Timeout for (unprotected) outbound peers to sync to our chainwork.
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS
Minimum blocks required to signal NODE_NETWORK_LIMITED.
static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL
Average delay between local address broadcasts.
static const int MAX_BLOCKTXN_DEPTH
Maximum depth of blocks we're willing to respond to GETBLOCKTXN requests for.
static constexpr uint64_t CMPCTBLOCKS_VERSION
The compactblocks version we support.
bool IsAvalancheMessageType(const std::string &msg_type)
static constexpr int32_t MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT
Protect at least this many outbound peers from disconnection due to slow/behind headers chain.
static std::chrono::microseconds ComputeRequestTime(const CNode &node, const InvRequestTracker< InvId > &requestTracker, const DataRequestParameters &requestParams, std::chrono::microseconds current_time, bool preferred)
Compute the request time for this announcement, current time plus delays for:
static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL
Average delay between trickled inventory transmissions for inbound peers.
static constexpr DataRequestParameters TX_REQUEST_PARAMS
static constexpr auto MAX_FEEFILTER_CHANGE_DELAY
Maximum feefilter broadcast delay after significant change.
static constexpr uint32_t MAX_GETCFILTERS_SIZE
Maximum number of compact filters that may be requested with one getcfilters.
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_BASE
Headers download timeout.
static const unsigned int MAX_GETDATA_SZ
Limit to avoid sending big packets.
static constexpr double BLOCK_DOWNLOAD_TIMEOUT_BASE
Block download timeout base, expressed in multiples of the block interval (i.e.
static constexpr auto AVALANCHE_AVAPROOFS_TIMEOUT
If no proof was requested from a compact proof message after this timeout expired,...
static constexpr auto STALE_CHECK_INTERVAL
How frequently to check for stale tips.
static constexpr unsigned int INVENTORY_MAX_RECENT_RELAY
The number of most recently announced transactions a peer can request.
static constexpr auto UNCONDITIONAL_RELAY_DELAY
How long a transaction has to be in the mempool before it can unconditionally be relayed.
static constexpr auto AVG_ADDRESS_BROADCAST_INTERVAL
Average delay between peer address broadcasts.
static const unsigned int MAX_LOCATOR_SZ
The maximum number of entries in a locator.
static constexpr double BLOCK_DOWNLOAD_TIMEOUT_PER_PEER
Additional block download timeout per parallel downloading peer (i.e.
static constexpr double MAX_ADDR_RATE_PER_SECOND
The maximum rate of address records we're willing to process on average.
static constexpr auto PING_INTERVAL
Time between pings automatically sent out for latency probing and keepalive.
static const int MAX_CMPCTBLOCK_DEPTH
Maximum depth of blocks we're willing to serve as compact blocks to peers when requested.
static constexpr DataRequestParameters PROOF_REQUEST_PARAMS
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE
Maximum number of headers to announce when relaying blocks with headers message.
static bool TooManyAnnouncements(const CNode &node, const InvRequestTracker< InvId > &requestTracker, const DataRequestParameters &requestParams)
static constexpr uint32_t MAX_GETCFHEADERS_SIZE
Maximum number of cf hashes that may be requested with one getcfheaders.
static constexpr auto BLOCK_STALLING_TIMEOUT_MAX
Maximum timeout for stalling block download.
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER
static constexpr uint64_t RANDOMIZER_ID_ADDRESS_RELAY
SHA256("main address relay")[0:8].
static constexpr size_t MAX_PCT_ADDR_TO_SEND
the maximum percentage of addresses from our addrman to return in response to a getaddr message.
static const unsigned int MAX_INV_SZ
The maximum number of entries in an 'inv' protocol message.
static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND
Maximum rate of inventory items to send per second.
static constexpr size_t MAX_ADDR_TO_SEND
The maximum number of address records permitted in an ADDR message.
static const unsigned int MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK
Maximum number of outstanding CMPCTBLOCK requests for the same block.
static const unsigned int MAX_HEADERS_RESULTS
Number of headers sent in one getheaders result.
bool IsProxy(const CNetAddr &addr)
static constexpr NodeId NO_NODE
Special NodeId that represent no node.
uint256 GetPackageHash(const Package &package)
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
static constexpr Amount DEFAULT_MIN_RELAY_TX_FEE_PER_KB(1000 *SATOSHI)
Default for -minrelaytxfee, minimum relay fee for transactions.
std::shared_ptr< const CTransaction > CTransactionRef
static constexpr size_t AVALANCHE_MAX_ELEMENT_POLL
Maximum item that can be polled at once.
void SetServiceFlagsIBDCache(bool state)
Set the current IBD status in order to figure out the desirable service flags.
ServiceFlags GetDesirableServiceFlags(ServiceFlags services)
Gets the set of service flags which are "desirable" for a given peer.
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH
Maximum length of incoming protocol messages (Currently 2MB).
static bool HasAllDesirableServiceFlags(ServiceFlags services)
A shortcut for (services & GetDesirableServiceFlags(services)) == GetDesirableServiceFlags(services),...
@ MSG_AVA_STAKE_CONTENDER
@ MSG_CMPCT_BLOCK
Defined in BIP152.
ServiceFlags
nServices flags.
static bool MayHaveUsefulAddressDB(ServiceFlags services)
Checks if a peer with the given service flags may be capable of having a robust address-storage DB.
void Shuffle(I first, I last, R &&rng)
More efficient than using std::shuffle on a FastRandomContext.
reverse_range< T > reverse_iterate(T &x)
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE
void Unserialize(Stream &, V)=delete
#define LIMITED_STRING(obj, n)
static auto WithParams(const Params ¶ms, T &&t)
Return a wrapper around t that (de)serializes it with specified parameter params.
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.