55#include <boost/multi_index/hashed_index.hpp>
56#include <boost/multi_index/member.hpp>
57#include <boost/multi_index/ordered_index.hpp>
58#include <boost/multi_index_container.hpp>
70#include <unordered_set>
119 "Max protocol message length must be greater than largest "
120 "possible INV message");
193 std::chrono::seconds(2),
194 std::chrono::seconds(2),
195 std::chrono::seconds(60),
202 std::chrono::seconds(2),
203 std::chrono::seconds(2),
204 std::chrono::seconds(60),
237 "MAX_BLOCKTXN_DEPTH too high");
296 std::chrono::seconds{1},
297 "INVENTORY_RELAY_MAX too low");
348 std::unique_ptr<PartiallyDownloadedBlock> partialBlock;
353 std::chrono::seconds timeAdded;
355 StalledTxId(
TxId txid_, std::chrono::seconds timeAdded_)
356 : txid(txid_), timeAdded(timeAdded_) {};
362using StalledTxIdSet = boost::multi_index_container<
364 boost::multi_index::indexed_by<
366 boost::multi_index::hashed_unique<
367 boost::multi_index::tag<by_txid>,
368 boost::multi_index::member<StalledTxId, TxId, &StalledTxId::txid>,
371 boost::multi_index::ordered_non_unique<
372 boost::multi_index::tag<by_time>,
373 boost::multi_index::member<StalledTxId, std::chrono::seconds,
374 &StalledTxId::timeAdded>>>>;
411 std::atomic<ServiceFlags> m_their_services{
NODE_NONE};
414 Mutex m_misbehavior_mutex;
419 bool m_should_discourage
GUARDED_BY(m_misbehavior_mutex){
false};
422 Mutex m_block_inv_mutex;
428 std::vector<BlockHash> m_blocks_for_inv_relay
GUARDED_BY(m_block_inv_mutex);
434 std::vector<BlockHash>
435 m_blocks_for_headers_relay
GUARDED_BY(m_block_inv_mutex);
446 std::atomic<int> m_starting_height{-1};
449 std::atomic<uint64_t> m_ping_nonce_sent{0};
451 std::atomic<std::chrono::microseconds> m_ping_start{0us};
453 std::atomic<bool> m_ping_queued{
false};
463 std::chrono::microseconds m_next_send_feefilter
476 bool m_relay_txs
GUARDED_BY(m_bloom_filter_mutex){
false};
481 std::unique_ptr<CBloomFilter>
497 GUARDED_BY(m_tx_inventory_mutex){50000, 0.000001};
503 std::set<TxId> m_tx_inventory_to_send
GUARDED_BY(m_tx_inventory_mutex);
509 bool m_send_mempool
GUARDED_BY(m_tx_inventory_mutex){
false};
511 std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
516 std::chrono::microseconds
517 m_next_inv_send_time
GUARDED_BY(m_tx_inventory_mutex){0};
523 std::atomic<Amount> m_fee_filter_received{
Amount::zero()};
529 m_avalanche_stalled_txids
GUARDED_BY(m_tx_inventory_mutex);
537 LOCK(m_tx_relay_mutex);
539 m_tx_relay = std::make_unique<Peer::TxRelay>();
540 return m_tx_relay.get();
544 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
546 const TxRelay *GetTxRelay() const
548 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
553 std::set<avalanche::ProofId>
554 m_proof_inventory_to_send
GUARDED_BY(m_proof_inventory_mutex);
557 GUARDED_BY(m_proof_inventory_mutex){10000, 0.000001};
564 std::chrono::microseconds m_next_inv_send_time{0};
568 std::atomic<std::chrono::seconds> lastSharedProofsUpdate{0s};
569 std::atomic<bool> compactproofs_requested{
false};
576 const std::unique_ptr<ProofRelay> m_proof_relay;
595 std::vector<std::chrono::seconds> m_invalid_avaproof_times
601 std::vector<CAddress>
613 std::unique_ptr<CRollingBloomFilter>
631 std::atomic_bool m_addr_relay_enabled{
false};
635 mutable Mutex m_addr_send_times_mutex;
637 std::chrono::microseconds
638 m_next_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
640 std::chrono::microseconds
641 m_next_local_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
646 std::atomic_bool m_wants_addrv2{
false};
650 mutable Mutex m_addr_token_bucket_mutex;
655 double m_addr_token_bucket
GUARDED_BY(m_addr_token_bucket_mutex){1.0};
657 std::chrono::microseconds
659 GetTime<std::chrono::microseconds>()};
661 std::atomic<uint64_t> m_addr_rate_limited{0};
666 std::atomic<uint64_t> m_addr_processed{0};
672 bool m_inv_triggered_getheaders_before_sync
676 Mutex m_getdata_requests_mutex;
678 std::deque<CInv> m_getdata_requests
GUARDED_BY(m_getdata_requests_mutex);
685 Mutex m_headers_sync_mutex;
690 std::unique_ptr<HeadersSyncState>
695 std::atomic<bool> m_sent_sendheaders{
false};
698 std::chrono::microseconds m_headers_sync_timeout
709 : m_id(id), m_our_services{our_services},
710 m_proof_relay(fRelayProofs ?
std::make_unique<ProofRelay>()
716 mutable Mutex m_tx_relay_mutex;
719 std::unique_ptr<TxRelay> m_tx_relay
GUARDED_BY(m_tx_relay_mutex);
722using PeerRef = std::shared_ptr<Peer>;
740 bool fSyncStarted{
false};
743 std::chrono::microseconds m_stalling_since{0us};
744 std::list<QueuedBlock> vBlocksInFlight;
747 std::chrono::microseconds m_downloading_since{0us};
749 bool fPreferredDownload{
false};
754 bool m_requested_hb_cmpctblocks{
false};
756 bool m_provides_cmpctblocks{
false};
784 struct ChainSyncTimeoutState {
787 std::chrono::seconds m_timeout{0s};
791 bool m_sent_getheaders{
false};
794 bool m_protect{
false};
797 ChainSyncTimeoutState m_chain_sync;
800 int64_t m_last_block_announcement{0};
803 const bool m_is_inbound;
805 CNodeState(
bool is_inbound) : m_is_inbound(is_inbound) {}
816 const std::shared_ptr<const CBlock> &pblock,
824 bool fInitialDownload)
override
830 const std::shared_ptr<const CBlock> &pblock)
override
839 !m_headers_presync_mutex);
841 std::atomic<bool> &interrupt)
override
843 !m_recent_confirmed_transactions_mutex,
844 !m_most_recent_block_mutex, !cs_proofrequest,
845 !m_headers_presync_mutex, g_msgproc_mutex);
848 !m_recent_confirmed_transactions_mutex,
849 !m_most_recent_block_mutex, !cs_proofrequest,
855 std::optional<std::string>
862 void RelayTransaction(const
TxId &txid) override
864 void RelayProof(const
avalanche::ProofId &proofid) override
866 void SetBestHeight(
int height)
override { m_best_height = height; };
869 Misbehaving(*
Assert(GetPeerRef(peer_id)),
"");
872 const std::string &msg_type,
DataStream &vRecv,
873 const std::chrono::microseconds time_received,
874 const std::atomic<bool> &interruptMsgProc)
override
876 !m_recent_confirmed_transactions_mutex,
877 !m_most_recent_block_mutex, !cs_proofrequest,
878 !m_headers_presync_mutex, g_msgproc_mutex);
880 int64_t time_in_seconds)
override;
887 void ConsiderEviction(
CNode &pto, Peer &peer,
888 std::chrono::seconds time_in_seconds)
895 void EvictExtraOutboundPeers(std::chrono::seconds now)
902 void ReattemptInitialBroadcast(
CScheduler &scheduler)
908 void UpdateAvalancheStatistics()
const;
913 void AvalanchePeriodicNetworking(
CScheduler &scheduler)
const;
931 void Misbehaving(Peer &peer,
const std::string &message);
943 void MaybePunishNodeForBlock(
NodeId nodeid,
945 bool via_compact_block,
946 const std::string &message =
"")
954 const
std::
string &message = "")
966 bool MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer);
984 bool maybe_add_extra_compact_tx)
987 struct PackageToValidate {
989 const std::vector<NodeId> m_senders;
994 : m_txns{parent, child}, m_senders{parent_sender, child_sender} {}
997 Assume(m_txns.size() == 2);
999 "parent %s (sender=%d) + child %s (sender=%d)",
1000 m_txns.front()->GetId().ToString(), m_senders.front(),
1001 m_txns.back()->GetId().ToString(), m_senders.back());
1010 void ProcessPackageResult(
const PackageToValidate &package_to_validate,
1020 std::optional<PackageToValidate> Find1P1CPackage(
const CTransactionRef &ptx,
1047 bool ProcessOrphanTx(
const Config &config, Peer &peer)
1060 void ProcessHeadersMessage(
const Config &config,
CNode &pfrom, Peer &peer,
1061 std::vector<CBlockHeader> &&headers,
1062 bool via_compact_block)
1072 bool CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
1082 void HandleUnconnectingHeaders(
CNode &pfrom, Peer &peer,
1083 const std::vector<CBlockHeader> &headers)
1087 CheckHeadersAreContinuous(
const std::vector<CBlockHeader> &headers)
const;
1107 bool IsContinuationOfLowWorkHeadersSync(Peer &peer,
CNode &pfrom,
1108 std::vector<CBlockHeader> &headers)
1110 !m_headers_presync_mutex, g_msgproc_mutex);
1124 bool TryLowWorkHeadersSync(Peer &peer,
CNode &pfrom,
1126 std::vector<CBlockHeader> &headers)
1128 !m_headers_presync_mutex, g_msgproc_mutex);
1134 bool IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header)
1148 void HeadersDirectFetchBlocks(
const Config &config,
CNode &pfrom,
1151 void UpdatePeerStateForReceivedHeaders(
CNode &pfrom, Peer &peer,
1153 bool received_new_header,
1154 bool may_have_more_headers)
1157 void SendBlockTransactions(
CNode &pfrom, Peer &peer,
const CBlock &block,
1166 std::chrono::microseconds current_time)
1176 std::chrono::microseconds current_time,
bool preferred)
1181 m_connman.PushMessage(&
node, std::move(
msg));
1183 template <
typename... Args>
1184 void MakeAndPushMessage(
CNode &
node, std::string msg_type,
1185 Args &&...args)
const {
1187 std::forward<Args>(args)...));
1191 void PushNodeVersion(
const Config &config,
CNode &pnode,
const Peer &peer);
1199 void MaybeSendPing(
CNode &node_to, Peer &peer,
1200 std::chrono::microseconds now);
1203 void MaybeSendAddr(
CNode &
node, Peer &peer,
1204 std::chrono::microseconds current_time)
1211 void MaybeSendSendHeaders(
CNode &
node, Peer &peer)
1215 void MaybeSendFeefilter(
CNode &
node, Peer &peer,
1216 std::chrono::microseconds current_time)
1228 void RelayAddress(
NodeId originator,
const CAddress &addr,
bool fReachable)
1249 Mutex cs_proofrequest;
1254 std::atomic<int> m_best_height{-1};
1259 const Options m_opts;
1261 bool RejectIncomingTxs(
const CNode &peer)
const;
1273 mutable Mutex m_peer_mutex;
1280 std::map<NodeId, PeerRef> m_peer_map
GUARDED_BY(m_peer_mutex);
1289 const CNodeState *State(
NodeId pnode)
const
1294 std::atomic<std::chrono::microseconds> m_next_inv_to_inbounds{0us};
1301 m_last_block_inv_triggering_headers_sync
GUARDED_BY(g_msgproc_mutex){};
1309 std::map<BlockHash, std::pair<NodeId, bool>>
1319 std::atomic<std::chrono::seconds> m_block_stalling_timeout{
1333 bool AlreadyHaveTx(
const TxId &txid,
bool include_reconsiderable)
1335 !m_recent_confirmed_transactions_mutex);
1398 mutable Mutex m_recent_confirmed_transactions_mutex;
1400 GUARDED_BY(m_recent_confirmed_transactions_mutex){24'000, 0.000'001};
1409 std::chrono::microseconds
1410 NextInvToInbounds(std::chrono::microseconds now,
1411 std::chrono::seconds average_interval)
1416 mutable Mutex m_most_recent_block_mutex;
1417 std::shared_ptr<const CBlock>
1418 m_most_recent_block
GUARDED_BY(m_most_recent_block_mutex);
1419 std::shared_ptr<const CBlockHeaderAndShortTxIDs>
1420 m_most_recent_compact_block
GUARDED_BY(m_most_recent_block_mutex);
1422 std::unique_ptr<const std::map<TxId, CTransactionRef>>
1423 m_most_recent_block_txs
GUARDED_BY(m_most_recent_block_mutex);
1428 Mutex m_headers_presync_mutex;
1439 using HeadersPresyncStats =
1440 std::pair<arith_uint256, std::optional<std::pair<int64_t, uint32_t>>>;
1442 std::map<NodeId, HeadersPresyncStats>
1443 m_headers_presync_stats
GUARDED_BY(m_headers_presync_mutex){};
1447 std::atomic_bool m_headers_presync_should_signal{
false};
1455 bool IsBlockRequested(
const BlockHash &hash)
1459 bool IsBlockRequestedFromOutbound(
const BlockHash &hash)
1470 void RemoveBlockRequest(
const BlockHash &hash,
1471 std::optional<NodeId> from_peer)
1480 bool BlockRequested(
const Config &config,
NodeId nodeid,
1482 std::list<QueuedBlock>::iterator **pit =
nullptr)
1491 void FindNextBlocksToDownload(const Peer &peer,
unsigned int count,
1497 void TryDownloadingHistoricalBlocks(
1498 const Peer &peer,
unsigned int count,
1532 const Peer &peer, CNodeState *state,
1534 int nWindowEnd, const
CChain *activeChain =
nullptr,
1535 NodeId *nodeStaller =
nullptr)
1545 std::atomic<
std::chrono::seconds> m_last_tip_update{0s};
1552 const std::chrono::seconds mempool_req,
1553 const std::chrono::seconds now)
1558 void ProcessGetData(
const Config &config,
CNode &pfrom, Peer &peer,
1559 const std::atomic<bool> &interruptMsgProc)
1561 peer.m_getdata_requests_mutex,
1567 const std::shared_ptr<const CBlock> &block,
1568 bool force_processing,
bool min_pow_checked);
1576 void MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid)
1595 std::vector<CTransactionRef>
1596 vExtraTxnForCompact
GUARDED_BY(g_msgproc_mutex);
1598 size_t vExtraTxnForCompactIt
GUARDED_BY(g_msgproc_mutex) = 0;
1603 void ProcessBlockAvailability(
NodeId nodeid)
1618 bool BlockRequestAllowed(const
CBlockIndex *pindex)
1620 bool AlreadyHaveBlock(const
BlockHash &block_hash)
1622 bool AlreadyHaveProof(const
avalanche::ProofId &proofid);
1623 void ProcessGetBlockData(const
Config &config,
CNode &pfrom, Peer &peer,
1646 bool PrepareBlockFilterRequest(
CNode &
node, Peer &peer,
1648 uint32_t start_height,
1650 uint32_t max_height_diff,
1692 uint32_t GetAvalancheVoteForBlock(const
BlockHash &hash) const
1703 const
TxId &
id) const
1705 !m_recent_confirmed_transactions_mutex);
1714 bool SetupAddressRelay(const
CNode &
node, Peer &peer)
1717 void AddAddressKnown(Peer &peer, const
CAddress &addr)
1719 void PushAddress(Peer &peer, const
CAddress &addr)
1727 bool ReceivedAvalancheProof(
CNode &
node, Peer &peer,
1734 const
std::chrono::seconds now)
1737 bool isPreferredDownloadPeer(const
CNode &pfrom);
1740const CNodeState *PeerManagerImpl::State(
NodeId pnode) const
1742 std::map<NodeId, CNodeState>::const_iterator it = m_node_states.find(pnode);
1743 if (it == m_node_states.end()) {
1750CNodeState *PeerManagerImpl::State(
NodeId pnode)
1752 return const_cast<CNodeState *
>(std::as_const(*this).State(pnode));
1760static bool IsAddrCompatible(
const Peer &peer,
const CAddress &addr) {
1764void PeerManagerImpl::AddAddressKnown(Peer &peer,
const CAddress &addr) {
1765 assert(peer.m_addr_known);
1766 peer.m_addr_known->insert(addr.
GetKey());
1769void PeerManagerImpl::PushAddress(Peer &peer,
const CAddress &addr) {
1773 assert(peer.m_addr_known);
1774 if (addr.
IsValid() && !peer.m_addr_known->contains(addr.
GetKey()) &&
1775 IsAddrCompatible(peer, addr)) {
1776 if (peer.m_addrs_to_send.size() >= m_opts.max_addr_to_send) {
1777 peer.m_addrs_to_send[m_rng.randrange(peer.m_addrs_to_send.size())] =
1780 peer.m_addrs_to_send.push_back(addr);
1785static void AddKnownTx(Peer &peer,
const TxId &txid) {
1786 auto tx_relay = peer.GetTxRelay();
1791 LOCK(tx_relay->m_tx_inventory_mutex);
1792 tx_relay->m_tx_inventory_known_filter.insert(txid);
1796 if (peer.m_proof_relay !=
nullptr) {
1797 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
1798 peer.m_proof_relay->m_proof_inventory_known_filter.insert(proofid);
1802bool PeerManagerImpl::isPreferredDownloadPeer(
const CNode &pfrom) {
1804 const CNodeState *state = State(pfrom.
GetId());
1805 return state && state->fPreferredDownload;
1808static bool CanServeBlocks(
const Peer &peer) {
1816static bool IsLimitedPeer(
const Peer &peer) {
1821std::chrono::microseconds
1822PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
1823 std::chrono::seconds average_interval) {
1824 if (m_next_inv_to_inbounds.load() < now) {
1829 m_next_inv_to_inbounds =
1830 now + m_rng.rand_exp_duration(average_interval);
1832 return m_next_inv_to_inbounds;
1835bool PeerManagerImpl::IsBlockRequested(
const BlockHash &hash) {
1836 return mapBlocksInFlight.count(hash);
1839bool PeerManagerImpl::IsBlockRequestedFromOutbound(
const BlockHash &hash) {
1840 for (
auto range = mapBlocksInFlight.equal_range(hash);
1841 range.first != range.second; range.first++) {
1842 auto [nodeid, block_it] = range.first->second;
1843 CNodeState &nodestate = *
Assert(State(nodeid));
1844 if (!nodestate.m_is_inbound) {
1852void PeerManagerImpl::RemoveBlockRequest(
const BlockHash &hash,
1853 std::optional<NodeId> from_peer) {
1854 auto range = mapBlocksInFlight.equal_range(hash);
1855 if (range.first == range.second) {
1863 while (range.first != range.second) {
1864 auto [node_id, list_it] = range.first->second;
1866 if (from_peer && *from_peer != node_id) {
1871 CNodeState &state = *
Assert(State(node_id));
1873 if (state.vBlocksInFlight.begin() == list_it) {
1876 state.m_downloading_since =
1877 std::max(state.m_downloading_since,
1878 GetTime<std::chrono::microseconds>());
1880 state.vBlocksInFlight.erase(list_it);
1882 if (state.vBlocksInFlight.empty()) {
1884 m_peers_downloading_from--;
1886 state.m_stalling_since = 0us;
1888 range.first = mapBlocksInFlight.erase(range.first);
1892bool PeerManagerImpl::BlockRequested(
const Config &config,
NodeId nodeid,
1894 std::list<QueuedBlock>::iterator **pit) {
1897 CNodeState *state = State(nodeid);
1898 assert(state !=
nullptr);
1903 for (
auto range = mapBlocksInFlight.equal_range(hash);
1904 range.first != range.second; range.first++) {
1905 if (range.first->second.first == nodeid) {
1907 *pit = &range.first->second.second;
1914 RemoveBlockRequest(hash, nodeid);
1916 std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(
1917 state->vBlocksInFlight.end(),
1918 {&block, std::unique_ptr<PartiallyDownloadedBlock>(
1919 pit ? new PartiallyDownloadedBlock(config, &m_mempool)
1921 if (state->vBlocksInFlight.size() == 1) {
1923 state->m_downloading_since = GetTime<std::chrono::microseconds>();
1924 m_peers_downloading_from++;
1927 auto itInFlight = mapBlocksInFlight.insert(
1928 std::make_pair(hash, std::make_pair(nodeid, it)));
1931 *pit = &itInFlight->second.second;
1937void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid) {
1943 if (m_opts.ignore_incoming_txs) {
1947 CNodeState *nodestate = State(nodeid);
1952 if (!nodestate->m_provides_cmpctblocks) {
1955 int num_outbound_hb_peers = 0;
1956 for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin();
1957 it != lNodesAnnouncingHeaderAndIDs.end(); it++) {
1958 if (*it == nodeid) {
1959 lNodesAnnouncingHeaderAndIDs.erase(it);
1960 lNodesAnnouncingHeaderAndIDs.push_back(nodeid);
1963 CNodeState *state = State(*it);
1964 if (state !=
nullptr && !state->m_is_inbound) {
1965 ++num_outbound_hb_peers;
1968 if (nodestate->m_is_inbound) {
1971 if (lNodesAnnouncingHeaderAndIDs.size() >= 3 &&
1972 num_outbound_hb_peers == 1) {
1973 CNodeState *remove_node =
1974 State(lNodesAnnouncingHeaderAndIDs.front());
1975 if (remove_node !=
nullptr && !remove_node->m_is_inbound) {
1978 std::swap(lNodesAnnouncingHeaderAndIDs.front(),
1979 *std::next(lNodesAnnouncingHeaderAndIDs.begin()));
1986 if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
1990 lNodesAnnouncingHeaderAndIDs.front(), [
this](
CNode *pnodeStop) {
1991 MakeAndPushMessage(*pnodeStop, NetMsgType::SENDCMPCT,
1993 CMPCTBLOCKS_VERSION);
1996 pnodeStop->m_bip152_highbandwidth_to = false;
1999 lNodesAnnouncingHeaderAndIDs.pop_front();
2006 lNodesAnnouncingHeaderAndIDs.push_back(pfrom->
GetId());
2011bool PeerManagerImpl::TipMayBeStale() {
2014 if (m_last_tip_update.load() == 0s) {
2015 m_last_tip_update = GetTime<std::chrono::seconds>();
2017 return m_last_tip_update.load() <
2018 GetTime<std::chrono::seconds>() -
2021 mapBlocksInFlight.empty();
2024bool PeerManagerImpl::CanDirectFetch() {
2030static bool PeerHasHeader(CNodeState *state,
const CBlockIndex *pindex)
2032 if (state->pindexBestKnownBlock &&
2033 pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) {
2036 if (state->pindexBestHeaderSent &&
2037 pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight)) {
2043void PeerManagerImpl::ProcessBlockAvailability(
NodeId nodeid) {
2044 CNodeState *state = State(nodeid);
2045 assert(state !=
nullptr);
2047 if (!state->hashLastUnknownBlock.IsNull()) {
2051 if (state->pindexBestKnownBlock ==
nullptr ||
2052 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
2053 state->pindexBestKnownBlock = pindex;
2055 state->hashLastUnknownBlock.SetNull();
2060void PeerManagerImpl::UpdateBlockAvailability(
NodeId nodeid,
2062 CNodeState *state = State(nodeid);
2063 assert(state !=
nullptr);
2065 ProcessBlockAvailability(nodeid);
2070 if (state->pindexBestKnownBlock ==
nullptr ||
2071 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
2072 state->pindexBestKnownBlock = pindex;
2077 state->hashLastUnknownBlock = hash;
2083void PeerManagerImpl::FindNextBlocksToDownload(
2084 const Peer &peer,
unsigned int count,
2085 std::vector<const CBlockIndex *> &vBlocks,
NodeId &nodeStaller) {
2090 vBlocks.reserve(vBlocks.size() +
count);
2091 CNodeState *state = State(peer.m_id);
2092 assert(state !=
nullptr);
2095 ProcessBlockAvailability(peer.m_id);
2097 if (state->pindexBestKnownBlock ==
nullptr ||
2098 state->pindexBestKnownBlock->nChainWork <
2100 state->pindexBestKnownBlock->nChainWork <
2110 const CBlockIndex *snap_base{m_chainman.GetSnapshotBaseBlock()};
2111 if (snap_base && state->pindexBestKnownBlock->GetAncestor(
2112 snap_base->nHeight) != snap_base) {
2114 "Not downloading blocks from peer=%d, which doesn't have the "
2115 "snapshot block in its best chain.\n",
2124 if (state->pindexLastCommonBlock ==
nullptr ||
2126 state->pindexLastCommonBlock->nHeight < snap_base->nHeight)) {
2127 state->pindexLastCommonBlock =
2129 .
ActiveChain()[std::min(state->pindexBestKnownBlock->nHeight,
2136 state->pindexLastCommonBlock, state->pindexBestKnownBlock);
2137 if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) {
2141 const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
2149 FindNextBlocks(vBlocks, peer, state, pindexWalk,
count, nWindowEnd,
2153void PeerManagerImpl::TryDownloadingHistoricalBlocks(
2154 const Peer &peer,
unsigned int count,
2155 std::vector<const CBlockIndex *> &vBlocks,
const CBlockIndex *from_tip,
2160 if (vBlocks.size() >=
count) {
2164 vBlocks.reserve(
count);
2165 CNodeState *state =
Assert(State(peer.m_id));
2167 if (state->pindexBestKnownBlock ==
nullptr ||
2168 state->pindexBestKnownBlock->GetAncestor(target_block->
nHeight) !=
2183 FindNextBlocks(vBlocks, peer, state, from_tip,
count,
2188void PeerManagerImpl::FindNextBlocks(std::vector<const CBlockIndex *> &vBlocks,
2189 const Peer &peer, CNodeState *state,
2191 unsigned int count,
int nWindowEnd,
2192 const CChain *activeChain,
2194 std::vector<const CBlockIndex *> vToFetch;
2196 std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
2198 while (pindexWalk->
nHeight < nMaxHeight) {
2203 int nToFetch = std::min(nMaxHeight - pindexWalk->
nHeight,
2204 std::max<int>(
count - vBlocks.size(), 128));
2205 vToFetch.resize(nToFetch);
2206 pindexWalk = state->pindexBestKnownBlock->
GetAncestor(
2207 pindexWalk->
nHeight + nToFetch);
2208 vToFetch[nToFetch - 1] = pindexWalk;
2209 for (
unsigned int i = nToFetch - 1; i > 0; i--) {
2210 vToFetch[i - 1] = vToFetch[i]->
pprev;
2223 if (pindex->nStatus.hasData() ||
2224 (activeChain && activeChain->
Contains(pindex))) {
2226 state->pindexLastCommonBlock = pindex;
2228 }
else if (!IsBlockRequested(pindex->
GetBlockHash())) {
2230 if (pindex->
nHeight > nWindowEnd) {
2232 if (vBlocks.size() == 0 && waitingfor != peer.m_id) {
2236 *nodeStaller = waitingfor;
2241 vBlocks.push_back(pindex);
2242 if (vBlocks.size() ==
count) {
2245 }
else if (waitingfor == -1) {
2257template <
class InvId>
2261 return !
node.HasPermission(
2274template <
class InvId>
2275static std::chrono::microseconds
2279 std::chrono::microseconds current_time,
bool preferred) {
2280 auto delay = std::chrono::microseconds{0};
2292 return current_time + delay;
2295void PeerManagerImpl::PushNodeVersion(
const Config &config,
CNode &pnode,
2297 uint64_t my_services{peer.m_our_services};
2298 const int64_t nTime{
count_seconds(GetTime<std::chrono::seconds>())};
2300 const int nNodeStartingHeight{m_best_height};
2311 const bool tx_relay{!RejectIncomingTxs(pnode)};
2320 nNodeStartingHeight, tx_relay, extraEntropy);
2324 "send version message: version %d, blocks=%d, them=%s, "
2325 "txrelay=%d, peer=%d\n",
2330 "send version message: version %d, blocks=%d, "
2331 "txrelay=%d, peer=%d\n",
2336void PeerManagerImpl::AddTxAnnouncement(
2338 std::chrono::microseconds current_time) {
2346 const bool preferred = isPreferredDownloadPeer(
node);
2348 current_time, preferred);
2350 m_txrequest.ReceivedInv(
node.GetId(), txid, preferred, reqtime);
2353void PeerManagerImpl::AddProofAnnouncement(
2355 std::chrono::microseconds current_time,
bool preferred) {
2366 m_proofrequest.ReceivedInv(
node.GetId(), proofid, preferred, reqtime);
2369void PeerManagerImpl::UpdateLastBlockAnnounceTime(
NodeId node,
2370 int64_t time_in_seconds) {
2372 CNodeState *state = State(
node);
2374 state->m_last_block_announcement = time_in_seconds;
2378void PeerManagerImpl::InitializeNode(
const Config &config,
CNode &
node,
2383 m_node_states.emplace_hint(m_node_states.end(),
2384 std::piecewise_construct,
2385 std::forward_as_tuple(nodeid),
2386 std::forward_as_tuple(
node.IsInboundConn()));
2387 assert(m_txrequest.Count(nodeid) == 0);
2395 PeerRef peer = std::make_shared<Peer>(nodeid, our_services, !!m_avalanche);
2398 m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer);
2400 if (!
node.IsInboundConn()) {
2401 PushNodeVersion(config,
node, *peer);
2405void PeerManagerImpl::ReattemptInitialBroadcast(
CScheduler &scheduler) {
2408 for (
const TxId &txid : unbroadcast_txids) {
2410 if (m_mempool.
exists(txid)) {
2411 RelayTransaction(txid);
2422 auto unbroadcasted_proofids =
2426 auto it = unbroadcasted_proofids.begin();
2427 while (it != unbroadcasted_proofids.end()) {
2430 if (!pm.isBoundToPeer(*it)) {
2431 pm.removeUnbroadcastProof(*it);
2432 it = unbroadcasted_proofids.erase(it);
2439 return unbroadcasted_proofids;
2443 for (
const auto &proofid : unbroadcasted_proofids) {
2444 RelayProof(proofid);
2451 const auto reattemptBroadcastInterval =
2453 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2454 reattemptBroadcastInterval);
2457void PeerManagerImpl::UpdateAvalancheStatistics()
const {
2463void PeerManagerImpl::AvalanchePeriodicNetworking(
CScheduler &scheduler)
const {
2464 const auto now = GetTime<std::chrono::seconds>();
2465 std::vector<NodeId> avanode_ids;
2466 bool fQuorumEstablished;
2467 bool fShouldRequestMoreNodes;
2477 fShouldRequestMoreNodes =
2485 avanode_ids.push_back(pnode->GetId());
2488 PeerRef peer = GetPeerRef(pnode->
GetId());
2489 if (peer ==
nullptr) {
2493 if (peer->m_proof_relay &&
2494 now > (peer->m_proof_relay->lastSharedProofsUpdate.load() +
2496 peer->m_proof_relay->sharedProofs = {};
2500 if (avanode_ids.empty()) {
2508 for (
NodeId avanodeId : avanode_ids) {
2509 const bool sentGetavaaddr =
2512 MakeAndPushMessage(*pavanode, NetMsgType::GETAVAADDR);
2513 PeerRef peer = GetPeerRef(avanodeId);
2514 WITH_LOCK(peer->m_addr_token_bucket_mutex,
2515 peer->m_addr_token_bucket +=
2516 m_opts.max_addr_to_send);
2524 if (sentGetavaaddr && fQuorumEstablished && !fShouldRequestMoreNodes) {
2539 avanode_ids.resize(std::min<size_t>(avanode_ids.size(), 3));
2542 for (
NodeId nodeid : avanode_ids) {
2545 PeerRef peer = GetPeerRef(nodeid);
2546 if (peer->m_proof_relay) {
2548 peer->m_proof_relay->compactproofs_requested =
true;
2558 const auto avalanchePeriodicNetworkingInterval =
2560 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2561 avalanchePeriodicNetworkingInterval);
2564void PeerManagerImpl::FinalizeNode(
const Config &config,
const CNode &
node) {
2574 PeerRef peer = RemovePeer(nodeid);
2577 m_peer_map.erase(nodeid);
2579 CNodeState *state = State(nodeid);
2580 assert(state !=
nullptr);
2582 if (state->fSyncStarted) {
2586 for (
const QueuedBlock &entry : state->vBlocksInFlight) {
2588 mapBlocksInFlight.equal_range(entry.pindex->GetBlockHash());
2589 while (range.first != range.second) {
2590 auto [node_id, list_it] = range.first->second;
2591 if (node_id != nodeid) {
2594 range.first = mapBlocksInFlight.erase(range.first);
2601 m_txrequest.DisconnectedPeer(nodeid);
2602 m_num_preferred_download_peers -= state->fPreferredDownload;
2603 m_peers_downloading_from -= (!state->vBlocksInFlight.empty());
2604 assert(m_peers_downloading_from >= 0);
2605 m_outbound_peers_with_protect_from_disconnect -=
2606 state->m_chain_sync.m_protect;
2607 assert(m_outbound_peers_with_protect_from_disconnect >= 0);
2609 m_node_states.erase(nodeid);
2611 if (m_node_states.empty()) {
2613 assert(mapBlocksInFlight.empty());
2614 assert(m_num_preferred_download_peers == 0);
2615 assert(m_peers_downloading_from == 0);
2616 assert(m_outbound_peers_with_protect_from_disconnect == 0);
2617 assert(m_txrequest.Size() == 0);
2619 return orphanage.Size();
2624 if (
node.fSuccessfullyConnected && !
node.IsBlockOnlyConn() &&
2625 !
node.IsInboundConn()) {
2632 LOCK(m_headers_presync_mutex);
2633 m_headers_presync_stats.erase(nodeid);
2636 WITH_LOCK(cs_proofrequest, m_proofrequest.DisconnectedPeer(nodeid));
2641PeerRef PeerManagerImpl::GetPeerRef(
NodeId id)
const {
2643 auto it = m_peer_map.find(
id);
2644 return it != m_peer_map.end() ? it->second :
nullptr;
2647PeerRef PeerManagerImpl::RemovePeer(
NodeId id) {
2650 auto it = m_peer_map.find(
id);
2651 if (it != m_peer_map.end()) {
2652 ret = std::move(it->second);
2653 m_peer_map.erase(it);
2658bool PeerManagerImpl::GetNodeStateStats(
NodeId nodeid,
2662 const CNodeState *state = State(nodeid);
2663 if (state ==
nullptr) {
2667 ? state->pindexBestKnownBlock->nHeight
2670 ? state->pindexLastCommonBlock->nHeight
2672 for (
const QueuedBlock &queue : state->vBlocksInFlight) {
2679 PeerRef peer = GetPeerRef(nodeid);
2680 if (peer ==
nullptr) {
2692 auto ping_wait{0us};
2693 if ((0 != peer->m_ping_nonce_sent) &&
2694 (0 != peer->m_ping_start.load().count())) {
2696 GetTime<std::chrono::microseconds>() - peer->m_ping_start.load();
2699 if (
auto tx_relay = peer->GetTxRelay()) {
2701 return tx_relay->m_relay_txs);
2713 LOCK(peer->m_headers_sync_mutex);
2714 if (peer->m_headers_sync) {
2722void PeerManagerImpl::AddToCompactExtraTransactions(
const CTransactionRef &tx) {
2723 if (m_opts.max_extra_txs <= 0) {
2727 if (!vExtraTxnForCompact.size()) {
2728 vExtraTxnForCompact.resize(m_opts.max_extra_txs);
2731 vExtraTxnForCompact[vExtraTxnForCompactIt] = tx;
2732 vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
2735void PeerManagerImpl::Misbehaving(Peer &peer,
const std::string &message) {
2736 LOCK(peer.m_misbehavior_mutex);
2738 const std::string message_prefixed =
2739 message.empty() ?
"" : (
": " + message);
2740 peer.m_should_discourage =
true;
2745void PeerManagerImpl::MaybePunishNodeForBlock(
NodeId nodeid,
2747 bool via_compact_block,
2748 const std::string &message) {
2749 PeerRef peer{GetPeerRef(nodeid)};
2760 if (!via_compact_block) {
2762 Misbehaving(*peer, message);
2769 CNodeState *node_state = State(nodeid);
2770 if (node_state ==
nullptr) {
2777 if (!via_compact_block && !node_state->m_is_inbound) {
2779 Misbehaving(*peer, message);
2789 Misbehaving(*peer, message);
2795 Misbehaving(*peer, message);
2801 if (message !=
"") {
2806void PeerManagerImpl::MaybePunishNodeForTx(
NodeId nodeid,
2808 const std::string &message) {
2809 PeerRef peer{GetPeerRef(nodeid)};
2816 Misbehaving(*peer, message);
2834 if (message !=
"") {
2839bool PeerManagerImpl::BlockRequestAllowed(
const CBlockIndex *pindex) {
2845 (m_chainman.m_best_header !=
nullptr) &&
2846 (m_chainman.m_best_header->GetBlockTime() - pindex->
GetBlockTime() <
2849 *m_chainman.m_best_header, *pindex, *m_chainman.m_best_header,
2853std::optional<std::string>
2854PeerManagerImpl::FetchBlock(
const Config &config,
NodeId peer_id,
2857 return "Loading blocks ...";
2863 CNodeState *state = State(peer_id);
2864 if (state ==
nullptr) {
2865 return "Peer does not exist";
2869 RemoveBlockRequest(block_index.
GetBlockHash(), std::nullopt);
2874 if (!BlockRequested(config, peer_id, block_index)) {
2875 return "Already requested from this peer";
2884 this->MakeAndPushMessage(*node, NetMsgType::GETDATA, invs);
2887 return "Node not fully connected";
2892 return std::nullopt;
2895std::unique_ptr<PeerManager>
2899 return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman,
2908 : m_rng{opts.deterministic_rng},
2910 m_chainparams(chainman.GetParams()), m_connman(connman),
2911 m_addrman(addrman), m_banman(banman), m_chainman(chainman),
2912 m_mempool(pool), m_avalanche(
avalanche), m_opts{opts} {}
2914void PeerManagerImpl::StartScheduledTasks(
CScheduler &scheduler) {
2921 "peer eviction timer should be less than stale tip check timer");
2924 this->CheckForStaleTipAndEvictPeers();
2930 const auto reattemptBroadcastInterval =
2932 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2933 reattemptBroadcastInterval);
2938 UpdateAvalancheStatistics();
2944 const auto avalanchePeriodicNetworkingInterval =
2946 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2947 avalanchePeriodicNetworkingInterval);
2956void PeerManagerImpl::BlockConnected(
2957 ChainstateRole role,
const std::shared_ptr<const CBlock> &pblock,
2961 m_last_tip_update = GetTime<std::chrono::seconds>();
2965 auto stalling_timeout = m_block_stalling_timeout.load();
2968 const auto new_timeout =
2969 std::max(std::chrono::duration_cast<std::chrono::seconds>(
2970 stalling_timeout * 0.85),
2972 if (m_block_stalling_timeout.compare_exchange_strong(stalling_timeout,
2992 LOCK(m_recent_confirmed_transactions_mutex);
2994 m_recent_confirmed_transactions.insert(ptx->GetId());
2999 for (
const auto &ptx : pblock->vtx) {
3000 m_txrequest.ForgetInvId(ptx->GetId());
3005void PeerManagerImpl::BlockDisconnected(
3006 const std::shared_ptr<const CBlock> &block,
const CBlockIndex *pindex) {
3015 LOCK(m_recent_confirmed_transactions_mutex);
3016 m_recent_confirmed_transactions.reset();
3023void PeerManagerImpl::NewPoWValidBlock(
3024 const CBlockIndex *pindex,
const std::shared_ptr<const CBlock> &pblock) {
3025 std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock =
3026 std::make_shared<const CBlockHeaderAndShortTxIDs>(
3031 if (pindex->
nHeight <= m_highest_fast_announce) {
3034 m_highest_fast_announce = pindex->
nHeight;
3037 const std::shared_future<CSerializedNetMsg> lazy_ser{
3038 std::async(std::launch::deferred, [&] {
3043 auto most_recent_block_txs =
3044 std::make_unique<std::map<TxId, CTransactionRef>>();
3045 for (
const auto &tx : pblock->vtx) {
3046 most_recent_block_txs->emplace(tx->GetId(), tx);
3049 LOCK(m_most_recent_block_mutex);
3050 m_most_recent_block_hash = hashBlock;
3051 m_most_recent_block = pblock;
3052 m_most_recent_compact_block = pcmpctblock;
3053 m_most_recent_block_txs = std::move(most_recent_block_txs);
3057 [
this, pindex, &lazy_ser, &hashBlock](
CNode *pnode)
3065 ProcessBlockAvailability(pnode->
GetId());
3066 CNodeState &state = *State(pnode->
GetId());
3070 if (state.m_requested_hb_cmpctblocks &&
3071 !PeerHasHeader(&state, pindex) &&
3072 PeerHasHeader(&state, pindex->
pprev)) {
3074 "%s sending header-and-ids %s to peer=%d\n",
3075 "PeerManager::NewPoWValidBlock",
3076 hashBlock.ToString(), pnode->
GetId());
3079 PushMessage(*pnode, ser_cmpctblock.Copy());
3080 state.pindexBestHeaderSent = pindex;
3089void PeerManagerImpl::UpdatedBlockTip(
const CBlockIndex *pindexNew,
3091 bool fInitialDownload) {
3092 SetBestHeight(pindexNew->
nHeight);
3096 if (fInitialDownload) {
3101 std::vector<BlockHash> vHashes;
3103 while (pindexToAnnounce != pindexFork) {
3105 pindexToAnnounce = pindexToAnnounce->
pprev;
3115 for (
auto &it : m_peer_map) {
3116 Peer &peer = *it.second;
3117 LOCK(peer.m_block_inv_mutex);
3119 peer.m_blocks_for_headers_relay.push_back(hash);
3131void PeerManagerImpl::BlockChecked(
const CBlock &block,
3136 std::map<BlockHash, std::pair<NodeId, bool>>::iterator it =
3137 mapBlockSource.find(hash);
3141 if (state.
IsInvalid() && it != mapBlockSource.end() &&
3142 State(it->second.first)) {
3143 MaybePunishNodeForBlock(it->second.first, state,
3144 !it->second.second);
3153 mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
3154 if (it != mapBlockSource.end()) {
3155 MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
3159 if (it != mapBlockSource.end()) {
3160 mapBlockSource.erase(it);
3169bool PeerManagerImpl::AlreadyHaveTx(
const TxId &txid,
3170 bool include_reconsiderable) {
3172 hashRecentRejectsChainTip) {
3177 hashRecentRejectsChainTip =
3179 m_recent_rejects.reset();
3180 m_recent_rejects_package_reconsiderable.reset();
3184 return orphanage.HaveTx(txid);
3190 return conflicting.HaveTx(txid);
3195 if (include_reconsiderable &&
3196 m_recent_rejects_package_reconsiderable.contains(txid)) {
3201 LOCK(m_recent_confirmed_transactions_mutex);
3202 if (m_recent_confirmed_transactions.contains(txid)) {
3207 return m_recent_rejects.contains(txid) || m_mempool.
exists(txid);
3210bool PeerManagerImpl::AlreadyHaveBlock(
const BlockHash &block_hash) {
3215 if (!
Assume(m_avalanche)) {
3220 if (localProof && localProof->getId() == proofid) {
3229void PeerManagerImpl::SendPings() {
3231 for (
auto &it : m_peer_map) {
3232 it.second->m_ping_queued =
true;
3236void PeerManagerImpl::RelayTransaction(
const TxId &txid) {
3238 for (
auto &it : m_peer_map) {
3239 Peer &peer = *it.second;
3240 auto tx_relay = peer.GetTxRelay();
3244 LOCK(tx_relay->m_tx_inventory_mutex);
3250 if (tx_relay->m_next_inv_send_time == 0s) {
3254 if (!tx_relay->m_tx_inventory_known_filter.contains(txid) ||
3255 tx_relay->m_avalanche_stalled_txids.count(txid) > 0) {
3256 tx_relay->m_tx_inventory_to_send.insert(txid);
3263 for (
auto &it : m_peer_map) {
3264 Peer &peer = *it.second;
3266 if (!peer.m_proof_relay) {
3269 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
3270 if (!peer.m_proof_relay->m_proof_inventory_known_filter.contains(
3272 peer.m_proof_relay->m_proof_inventory_to_send.insert(proofid);
3277void PeerManagerImpl::RelayAddress(
NodeId originator,
const CAddress &addr,
3293 const auto current_time{GetTime<std::chrono::seconds>()};
3296 const uint64_t time_addr{
3297 (
static_cast<uint64_t
>(
count_seconds(current_time)) + hash_addr) /
3307 unsigned int nRelayNodes = (fReachable || (hasher.Finalize() & 1)) ? 2 : 1;
3308 std::array<std::pair<uint64_t, Peer *>, 2> best{
3309 {{0,
nullptr}, {0,
nullptr}}};
3310 assert(nRelayNodes <= best.size());
3314 for (
auto &[
id, peer] : m_peer_map) {
3315 if (peer->m_addr_relay_enabled &&
id != originator &&
3316 IsAddrCompatible(*peer, addr)) {
3318 for (
unsigned int i = 0; i < nRelayNodes; i++) {
3319 if (hashKey > best[i].first) {
3320 std::copy(best.begin() + i, best.begin() + nRelayNodes - 1,
3321 best.begin() + i + 1);
3322 best[i] = std::make_pair(hashKey, peer.get());
3329 for (
unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
3330 PushAddress(*best[i].second, addr);
3334void PeerManagerImpl::ProcessGetBlockData(
const Config &config,
CNode &pfrom,
3335 Peer &peer,
const CInv &inv) {
3338 std::shared_ptr<const CBlock> a_recent_block;
3339 std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
3341 LOCK(m_most_recent_block_mutex);
3342 a_recent_block = m_most_recent_block;
3343 a_recent_compact_block = m_most_recent_compact_block;
3346 bool need_activate_chain =
false;
3360 need_activate_chain =
true;
3364 if (need_activate_chain) {
3367 state, a_recent_block, m_avalanche)) {
3375 bool can_direct_fetch{
false};
3383 if (!BlockRequestAllowed(pindex)) {
3385 "%s: ignoring request from peer=%i for old "
3386 "block that isn't in the main chain\n",
3387 __func__, pfrom.
GetId());
3393 (((m_chainman.m_best_header !=
nullptr) &&
3394 (m_chainman.m_best_header->GetBlockTime() -
3402 "historical block serving limit reached, disconnect peer=%d\n",
3415 (tip->nHeight - pindex->
nHeight >
3418 "Ignore block request below NODE_NETWORK_LIMITED "
3419 "threshold, disconnect peer=%d\n",
3429 if (!pindex->nStatus.hasData()) {
3432 can_direct_fetch = CanDirectFetch();
3436 std::shared_ptr<const CBlock> pblock;
3437 auto handle_block_read_error = [&]() {
3439 return m_chainman.
m_blockman.IsBlockPruned(*pindex))) {
3441 "Block was pruned before it could be read, disconnect "
3445 LogError(
"Cannot load block from disk, disconnect peer=%d\n",
3451 if (a_recent_block && a_recent_block->GetHash() == pindex->
GetBlockHash()) {
3452 pblock = a_recent_block;
3457 std::vector<uint8_t> block_data;
3459 handle_block_read_error();
3466 std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
3468 handle_block_read_error();
3471 pblock = pblockRead;
3477 bool sendMerkleBlock =
false;
3479 if (
auto tx_relay = peer.GetTxRelay()) {
3480 LOCK(tx_relay->m_bloom_filter_mutex);
3481 if (tx_relay->m_bloom_filter) {
3482 sendMerkleBlock =
true;
3487 if (sendMerkleBlock) {
3498 typedef std::pair<size_t, uint256> PairType;
3501 *pblock->vtx[pair.first]);
3511 if (can_direct_fetch &&
3513 if (a_recent_compact_block &&
3514 a_recent_compact_block->header.GetHash() ==
3517 *a_recent_compact_block);
3531 LOCK(peer.m_block_inv_mutex);
3534 if (hash == peer.m_continuation_block) {
3538 std::vector<CInv> vInv;
3541 peer.m_continuation_block =
BlockHash();
3547PeerManagerImpl::FindTxForGetData(
const Peer &peer,
const TxId &txid,
3548 const std::chrono::seconds mempool_req,
3549 const std::chrono::seconds now) {
3550 auto txinfo = m_mempool.
info(txid);
3555 if ((mempool_req.count() && txinfo.m_time <= mempool_req) ||
3557 return std::move(txinfo.tx);
3566 Assume(peer.GetTxRelay())->m_recently_announced_invs.contains(txid);
3567 if (recent && txinfo.tx) {
3568 return std::move(txinfo.tx);
3573 LOCK(m_most_recent_block_mutex);
3574 if (m_most_recent_block_txs !=
nullptr) {
3575 auto it = m_most_recent_block_txs->find(txid);
3576 if (it != m_most_recent_block_txs->end()) {
3589PeerManagerImpl::FindProofForGetData(
const Peer &peer,
3591 const std::chrono::seconds now) {
3594 bool send_unconditionally =
3620 if (send_unconditionally) {
3625 if (peer.m_proof_relay->m_recently_announced_proofs.contains(proofid)) {
3632void PeerManagerImpl::ProcessGetData(
3634 const std::atomic<bool> &interruptMsgProc) {
3637 auto tx_relay = peer.GetTxRelay();
3639 std::deque<CInv>::iterator it = peer.m_getdata_requests.begin();
3640 std::vector<CInv> vNotFound;
3642 const auto now{GetTime<std::chrono::seconds>()};
3644 const auto mempool_req = tx_relay !=
nullptr
3645 ? tx_relay->m_last_mempool_req.load()
3646 : std::chrono::seconds::min();
3651 while (it != peer.m_getdata_requests.end() &&
3652 (it->IsMsgProof() || it->IsMsgTx())) {
3653 if (interruptMsgProc) {
3662 const CInv &inv = *it++;
3666 vNotFound.push_back(inv);
3670 auto proof = FindProofForGetData(peer, proofid, now);
3677 vNotFound.push_back(inv);
3684 if (tx_relay ==
nullptr) {
3698 std::vector<TxId> parent_ids_to_add;
3701 auto tx_iter = m_mempool.
GetIter(tx->GetId());
3703 auto &pentry = *tx_iter;
3705 (*pentry)->GetMemPoolParentsConst();
3706 parent_ids_to_add.reserve(parents.size());
3707 for (
const auto &parent : parents) {
3708 if (parent.get()->GetTime() >
3710 parent_ids_to_add.push_back(
3711 parent.get()->GetTx().GetId());
3716 for (
const TxId &parent_txid : parent_ids_to_add) {
3719 if (
WITH_LOCK(tx_relay->m_tx_inventory_mutex,
3720 return !tx_relay->m_tx_inventory_known_filter
3721 .contains(parent_txid))) {
3722 tx_relay->m_recently_announced_invs.insert(parent_txid);
3726 vNotFound.push_back(inv);
3738 if (it != peer.m_getdata_requests.end() && !pfrom.
fPauseSend) {
3739 const CInv &inv = *it++;
3741 ProcessGetBlockData(config, pfrom, peer, inv);
3747 peer.m_getdata_requests.erase(peer.m_getdata_requests.begin(), it);
3749 if (!vNotFound.empty()) {
3766void PeerManagerImpl::SendBlockTransactions(
3770 for (
size_t i = 0; i < req.
indices.size(); i++) {
3772 Misbehaving(peer,
"getblocktxn with out-of-bounds tx indices");
3781bool PeerManagerImpl::CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
3786 Misbehaving(peer,
"header with invalid proof of work");
3791 if (!CheckHeadersAreContinuous(headers)) {
3792 Misbehaving(peer,
"non-continuous headers sequence");
3805 near_chaintip_work =
3818void PeerManagerImpl::HandleUnconnectingHeaders(
3819 CNode &pfrom, Peer &peer,
const std::vector<CBlockHeader> &headers) {
3823 if (MaybeSendGetHeaders(pfrom,
GetLocator(best_header), peer)) {
3826 "received header %s: missing prev block %s, sending getheaders "
3827 "(%d) to end (peer=%d)\n",
3829 headers[0].hashPrevBlock.ToString(), best_header->nHeight,
3837 UpdateBlockAvailability(pfrom.
GetId(), headers.back().GetHash()));
3840bool PeerManagerImpl::CheckHeadersAreContinuous(
3841 const std::vector<CBlockHeader> &headers)
const {
3844 if (!hashLastBlock.
IsNull() && header.hashPrevBlock != hashLastBlock) {
3847 hashLastBlock = header.GetHash();
3852bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(
3853 Peer &peer,
CNode &pfrom, std::vector<CBlockHeader> &headers) {
3854 if (peer.m_headers_sync) {
3855 auto result = peer.m_headers_sync->ProcessNextHeaders(
3859 if (result.success) {
3860 peer.m_last_getheaders_timestamp = {};
3862 if (result.request_more) {
3863 auto locator = peer.m_headers_sync->NextHeadersRequestLocator();
3866 Assume(!locator.vHave.empty());
3870 if (!locator.vHave.empty()) {
3873 bool sent_getheaders =
3874 MaybeSendGetHeaders(pfrom, locator, peer);
3877 locator.vHave.front().ToString(), pfrom.
GetId());
3882 peer.m_headers_sync.reset(
nullptr);
3887 LOCK(m_headers_presync_mutex);
3888 m_headers_presync_stats.erase(pfrom.
GetId());
3891 HeadersPresyncStats stats;
3892 stats.first = peer.m_headers_sync->GetPresyncWork();
3893 if (peer.m_headers_sync->GetState() ==
3895 stats.second = {peer.m_headers_sync->GetPresyncHeight(),
3896 peer.m_headers_sync->GetPresyncTime()};
3900 LOCK(m_headers_presync_mutex);
3901 m_headers_presync_stats[pfrom.
GetId()] = stats;
3903 m_headers_presync_stats.find(m_headers_presync_bestpeer);
3904 bool best_updated =
false;
3905 if (best_it == m_headers_presync_stats.end()) {
3910 const HeadersPresyncStats *stat_best{
nullptr};
3911 for (
const auto &[_peer, _stat] : m_headers_presync_stats) {
3912 if (!stat_best || _stat > *stat_best) {
3917 m_headers_presync_bestpeer = peer_best;
3918 best_updated = (peer_best == pfrom.
GetId());
3919 }
else if (best_it->first == pfrom.
GetId() ||
3920 stats > best_it->second) {
3923 m_headers_presync_bestpeer = pfrom.
GetId();
3924 best_updated =
true;
3926 if (best_updated && stats.second.has_value()) {
3929 m_headers_presync_should_signal =
true;
3933 if (result.success) {
3936 headers.swap(result.pow_validated_headers);
3939 return result.success;
3947bool PeerManagerImpl::TryLowWorkHeadersSync(
3949 std::vector<CBlockHeader> &headers) {
3956 arith_uint256 minimum_chain_work = GetAntiDoSWorkThreshold();
3960 if (total_work < minimum_chain_work) {
3974 LOCK(peer.m_headers_sync_mutex);
3975 peer.m_headers_sync.reset(
3977 chain_start_header, minimum_chain_work));
3982 (void)IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
3985 "Ignoring low-work chain (height=%u) from peer=%d\n",
3986 chain_start_header->
nHeight + headers.size(),
3998bool PeerManagerImpl::IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header) {
3999 return header !=
nullptr &&
4000 ((m_chainman.m_best_header !=
nullptr &&
4002 m_chainman.m_best_header->GetAncestor(header->
nHeight)) ||
4006bool PeerManagerImpl::MaybeSendGetHeaders(
CNode &pfrom,
4013 if (current_time - peer.m_last_getheaders_timestamp >
4016 peer.m_last_getheaders_timestamp = current_time;
4028void PeerManagerImpl::HeadersDirectFetchBlocks(
const Config &config,
4032 CNodeState *nodestate = State(pfrom.
GetId());
4036 std::vector<const CBlockIndex *> vToFetch;
4042 if (!pindexWalk->nStatus.hasData() &&
4045 vToFetch.push_back(pindexWalk);
4047 pindexWalk = pindexWalk->
pprev;
4058 std::vector<CInv> vGetData;
4061 if (nodestate->vBlocksInFlight.size() >=
4067 BlockRequested(config, pfrom.
GetId(), *pindex);
4071 if (vGetData.size() > 1) {
4073 "Downloading blocks toward %s (%d) via headers "
4078 if (vGetData.size() > 0) {
4079 if (!m_opts.ignore_incoming_txs &&
4080 nodestate->m_provides_cmpctblocks && vGetData.size() == 1 &&
4081 mapBlocksInFlight.size() == 1 &&
4098void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(
4100 bool received_new_header,
bool may_have_more_headers) {
4103 CNodeState *nodestate = State(pfrom.
GetId());
4111 if (received_new_header &&
4113 nodestate->m_last_block_announcement =
GetTime();
4121 if (nodestate->pindexBestKnownBlock &&
4122 nodestate->pindexBestKnownBlock->nChainWork <
4133 LogPrintf(
"Disconnecting outbound peer %d -- headers "
4134 "chain has insufficient work\n",
4148 nodestate->pindexBestKnownBlock !=
nullptr) {
4149 if (m_outbound_peers_with_protect_from_disconnect <
4151 nodestate->pindexBestKnownBlock->nChainWork >=
4153 !nodestate->m_chain_sync.m_protect) {
4156 nodestate->m_chain_sync.m_protect =
true;
4157 ++m_outbound_peers_with_protect_from_disconnect;
4162void PeerManagerImpl::ProcessHeadersMessage(
const Config &config,
CNode &pfrom,
4164 std::vector<CBlockHeader> &&headers,
4165 bool via_compact_block) {
4166 size_t nCount = headers.size();
4174 LOCK(peer.m_headers_sync_mutex);
4175 if (peer.m_headers_sync) {
4176 peer.m_headers_sync.reset(
nullptr);
4177 LOCK(m_headers_presync_mutex);
4178 m_headers_presync_stats.erase(pfrom.
GetId());
4183 peer.m_last_getheaders_timestamp = {};
4191 if (!CheckHeadersPoW(headers, m_chainparams.
GetConsensus(), peer)) {
4206 bool already_validated_work =
false;
4209 bool have_headers_sync =
false;
4211 LOCK(peer.m_headers_sync_mutex);
4213 already_validated_work =
4214 IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
4226 if (headers.empty()) {
4230 have_headers_sync = !!peer.m_headers_sync;
4236 headers[0].hashPrevBlock))};
4237 bool headers_connect_blockindex{chain_start_header !=
nullptr};
4239 if (!headers_connect_blockindex) {
4243 HandleUnconnectingHeaders(pfrom, peer, headers);
4251 peer.m_last_getheaders_timestamp = {};
4260 last_received_header =
4262 if (IsAncestorOfBestHeaderOrTip(last_received_header)) {
4263 already_validated_work =
true;
4271 already_validated_work =
true;
4277 if (!already_validated_work &&
4278 TryLowWorkHeadersSync(peer, pfrom, chain_start_header, headers)) {
4290 bool received_new_header{last_received_header ==
nullptr};
4295 state, &pindexLast)) {
4297 MaybePunishNodeForBlock(pfrom.
GetId(), state, via_compact_block,
4298 "invalid header received");
4304 LogError(
"headers message processed but no pindexLast\n");
4313 if (MaybeSendGetHeaders(pfrom,
GetLocator(pindexLast), peer)) {
4316 "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
4317 pindexLast->
nHeight, pfrom.
GetId(), peer.m_starting_height);
4321 UpdatePeerStateForReceivedHeaders(pfrom, peer, *pindexLast,
4322 received_new_header,
4326 HeadersDirectFetchBlocks(config, pfrom, *pindexLast);
4329void PeerManagerImpl::ProcessInvalidTx(
NodeId nodeid,
4332 bool maybe_add_extra_compact_tx) {
4337 const TxId &txid = ptx->GetId();
4357 m_recent_rejects_package_reconsiderable.insert(txid);
4359 m_recent_rejects.insert(txid);
4361 m_txrequest.ForgetInvId(txid);
4364 AddToCompactExtraTransactions(ptx);
4367 MaybePunishNodeForTx(nodeid, state);
4373 return orphanage.EraseTx(txid);
4387 m_txrequest.ForgetInvId(tx->GetId());
4393 orphanage.
EraseTx(tx->GetId());
4398 "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
4399 nodeid, tx->GetId().ToString(), m_mempool.
size(),
4402 RelayTransaction(tx->GetId());
4405void PeerManagerImpl::ProcessPackageResult(
4406 const PackageToValidate &package_to_validate,
4412 const auto &
package = package_to_validate.m_txns;
4413 const auto &senders = package_to_validate.m_senders;
4416 m_recent_rejects_package_reconsiderable.insert(
GetPackageHash(package));
4420 if (!
Assume(package.size() == 2)) {
4426 auto package_iter = package.rbegin();
4427 auto senders_iter = senders.rbegin();
4428 while (package_iter != package.rend()) {
4429 const auto &tx = *package_iter;
4430 const NodeId nodeid = *senders_iter;
4431 const auto it_result{package_result.
m_tx_results.find(tx->GetId())};
4435 const auto &tx_result = it_result->second;
4436 switch (tx_result.m_result_type) {
4438 ProcessValidTx(nodeid, tx);
4448 ProcessInvalidTx(nodeid, tx, tx_result.m_state,
4465std::optional<PeerManagerImpl::PackageToValidate>
4471 const auto &parent_txid{ptx->GetId()};
4473 Assume(m_recent_rejects_package_reconsiderable.contains(parent_txid));
4479 const auto cpfp_candidates_same_peer{
4485 for (
const auto &child : cpfp_candidates_same_peer) {
4486 Package maybe_cpfp_package{ptx, child};
4487 if (!m_recent_rejects_package_reconsiderable.contains(
4489 return PeerManagerImpl::PackageToValidate{ptx, child, nodeid,
4503 const auto cpfp_candidates_different_peer{
4513 std::vector<size_t> tx_indices(cpfp_candidates_different_peer.size());
4514 std::iota(tx_indices.begin(), tx_indices.end(), 0);
4515 Shuffle(tx_indices.begin(), tx_indices.end(), m_rng);
4517 for (
const auto index : tx_indices) {
4520 const auto [child_tx, child_sender] =
4521 cpfp_candidates_different_peer.at(index);
4522 Package maybe_cpfp_package{ptx, child_tx};
4523 if (!m_recent_rejects_package_reconsiderable.contains(
4525 return PeerManagerImpl::PackageToValidate{ptx, child_tx, nodeid,
4529 return std::nullopt;
4532bool PeerManagerImpl::ProcessOrphanTx(
const Config &config, Peer &peer) {
4538 return orphanage.GetTxToReconsider(peer.m_id);
4543 const TxId &orphanTxId = porphanTx->GetId();
4548 ProcessValidTx(peer.m_id, porphanTx);
4554 " invalid orphan tx %s from peer=%d. %s\n",
4561 ProcessInvalidTx(peer.m_id, porphanTx, state,
4572bool PeerManagerImpl::PrepareBlockFilterRequest(
4574 const BlockHash &stop_hash, uint32_t max_height_diff,
4576 const bool supported_filter_type =
4579 if (!supported_filter_type) {
4581 "peer %d requested unsupported block filter type: %d\n",
4582 node.GetId(),
static_cast<uint8_t
>(filter_type));
4583 node.fDisconnect =
true;
4593 if (!stop_index || !BlockRequestAllowed(stop_index)) {
4596 node.fDisconnect =
true;
4601 uint32_t stop_height = stop_index->
nHeight;
4602 if (start_height > stop_height) {
4605 "peer %d sent invalid getcfilters/getcfheaders with "
4607 "start height %d and stop height %d\n",
4608 node.GetId(), start_height, stop_height);
4609 node.fDisconnect =
true;
4612 if (stop_height - start_height >= max_height_diff) {
4614 "peer %d requested too many cfilters/cfheaders: %d / %d\n",
4615 node.GetId(), stop_height - start_height + 1, max_height_diff);
4616 node.fDisconnect =
true;
4621 if (!filter_index) {
4630void PeerManagerImpl::ProcessGetCFilters(
CNode &
node, Peer &peer,
4632 uint8_t filter_type_ser;
4633 uint32_t start_height;
4636 vRecv >> filter_type_ser >> start_height >> stop_hash;
4643 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4649 std::vector<BlockFilter> filters;
4652 "Failed to find block filter in index: filter_type=%s, "
4653 "start_height=%d, stop_hash=%s\n",
4659 for (
const auto &filter : filters) {
4664void PeerManagerImpl::ProcessGetCFHeaders(
CNode &
node, Peer &peer,
4666 uint8_t filter_type_ser;
4667 uint32_t start_height;
4670 vRecv >> filter_type_ser >> start_height >> stop_hash;
4677 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4684 if (start_height > 0) {
4686 stop_index->
GetAncestor(
static_cast<int>(start_height - 1));
4689 "Failed to find block filter header in index: "
4690 "filter_type=%s, block_hash=%s\n",
4697 std::vector<uint256> filter_hashes;
4701 "Failed to find block filter hashes in index: filter_type=%s, "
4702 "start_height=%d, stop_hash=%s\n",
4709 stop_index->
GetBlockHash(), prev_header, filter_hashes);
4712void PeerManagerImpl::ProcessGetCFCheckPt(
CNode &
node, Peer &peer,
4714 uint8_t filter_type_ser;
4717 vRecv >> filter_type_ser >> stop_hash;
4724 if (!PrepareBlockFilterRequest(
4725 node, peer, filter_type, 0, stop_hash,
4726 std::numeric_limits<uint32_t>::max(),
4727 stop_index, filter_index)) {
4735 for (
int i = headers.size() - 1; i >= 0; i--) {
4741 "Failed to find block filter header in index: "
4742 "filter_type=%s, block_hash=%s\n",
4765PeerManagerImpl::GetAvalancheVoteForBlock(
const BlockHash &hash)
const {
4776 if (pindex->nStatus.isInvalid()) {
4781 if (pindex->nStatus.isOnParkedChain()) {
4789 if (pindex == pindexFork) {
4794 if (pindexFork != pindexTip) {
4799 if (!pindex->nStatus.hasData()) {
4810 const TxId &
id)
const {
4812 if (
WITH_LOCK(m_recent_confirmed_transactions_mutex,
4813 return m_recent_confirmed_transactions.contains(
id))) {
4822 if (m_recent_rejects.contains(
id)) {
4834 if (
auto iter = m_mempool.
GetIter(
id)) {
4835 mempool_tx = (**iter)->GetSharedTx();
4840 return conflicting.HaveTx(id);
4847 return orphanage.HaveTx(id);
4913 const std::shared_ptr<const CBlock> &block,
4914 bool force_processing,
4915 bool min_pow_checked) {
4916 bool new_block{
false};
4918 &new_block, m_avalanche);
4920 node.m_last_block_time = GetTime<std::chrono::seconds>();
4925 RemoveBlockRequest(block->GetHash(), std::nullopt);
4928 mapBlockSource.erase(block->GetHash());
4932void PeerManagerImpl::ProcessMessage(
4933 const Config &config,
CNode &pfrom,
const std::string &msg_type,
4934 DataStream &vRecv,
const std::chrono::microseconds time_received,
4935 const std::atomic<bool> &interruptMsgProc) {
4941 PeerRef peer = GetPeerRef(pfrom.
GetId());
4942 if (peer ==
nullptr) {
4948 "Avalanche is not initialized, ignoring %s message\n",
4963 uint64_t nNonce = 1;
4966 std::string cleanSubVer;
4967 int starting_height = -1;
4969 uint64_t nExtraEntropy = 1;
4971 vRecv >> nVersion >> Using<CustomUintFormatter<8>>(nServices) >> nTime;
4984 "peer=%d does not offer the expected services "
4985 "(%08x offered, %08x expected); disconnecting\n",
4986 pfrom.
GetId(), nServices,
4996 "peer=%d does not offer the avalanche service; disconnecting\n",
5005 "peer=%d using obsolete version %i; disconnecting\n",
5006 pfrom.
GetId(), nVersion);
5011 if (!vRecv.
empty()) {
5020 if (!vRecv.
empty()) {
5021 std::string strSubVer;
5025 if (!vRecv.
empty()) {
5026 vRecv >> starting_height;
5028 if (!vRecv.
empty()) {
5031 if (!vRecv.
empty()) {
5032 vRecv >> nExtraEntropy;
5036 LogPrintf(
"connected to self at %s, disconnecting\n",
5049 PushNodeVersion(config, pfrom, *peer);
5053 const int greatest_common_version =
5065 peer->m_their_services = nServices;
5069 pfrom.cleanSubVer = cleanSubVer;
5071 peer->m_starting_height = starting_height;
5079 (fRelay || (peer->m_our_services &
NODE_BLOOM))) {
5080 auto *
const tx_relay = peer->SetTxRelay();
5082 LOCK(tx_relay->m_bloom_filter_mutex);
5084 tx_relay->m_relay_txs = fRelay;
5097 CNodeState *state = State(pfrom.
GetId());
5098 state->fPreferredDownload =
5102 m_num_preferred_download_peers += state->fPreferredDownload;
5108 bool send_getaddr{
false};
5110 send_getaddr = SetupAddressRelay(pfrom, *peer);
5121 peer->m_getaddr_sent =
true;
5125 WITH_LOCK(peer->m_addr_token_bucket_mutex,
5126 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
5147 std::string remoteAddr;
5153 "receive version message: [%s] %s: version %d, blocks=%d, "
5154 "us=%s, txrelay=%d, peer=%d%s\n",
5157 pfrom.
GetId(), remoteAddr);
5159 int64_t currentTime =
GetTime();
5160 int64_t nTimeOffset = nTime - currentTime;
5165 Misbehaving(*peer,
"Ignoring invalid timestamp in version message");
5175 "feeler connection completed peer=%d; disconnecting\n",
5184 Misbehaving(*peer,
"non-version message before version handshake");
5191 "ignoring redundant verack message from peer=%d\n",
5197 LogPrintf(
"New outbound peer connected: version: %d, blocks=%d, "
5199 pfrom.
nVersion.load(), peer->m_starting_height,
5222 AddKnownProof(*peer, localProof->getId());
5226 peer->m_proof_relay->m_recently_announced_proofs.insert(
5227 localProof->getId());
5232 if (
auto tx_relay = peer->GetTxRelay()) {
5241 return tx_relay->m_tx_inventory_to_send.empty() &&
5242 tx_relay->m_next_inv_send_time == 0s));
5251 Misbehaving(*peer,
"non-verack message before version handshake");
5256 const auto ser_params{
5265 std::vector<CAddress> vAddr;
5269 if (!SetupAddressRelay(pfrom, *peer)) {
5275 if (vAddr.size() > m_opts.max_addr_to_send) {
5276 Misbehaving(*peer,
strprintf(
"%s message size = %u", msg_type,
5282 std::vector<CAddress> vAddrOk;
5283 const auto current_a_time{Now<NodeSeconds>()};
5286 const auto current_time = GetTime<std::chrono::microseconds>();
5288 LOCK(peer->m_addr_token_bucket_mutex);
5291 const auto time_diff =
5292 std::max(current_time - peer->m_addr_token_timestamp, 0us);
5293 const double increment =
5295 peer->m_addr_token_bucket =
5296 std::min<double>(peer->m_addr_token_bucket + increment,
5300 peer->m_addr_token_timestamp = current_time;
5302 const bool rate_limited =
5304 uint64_t num_proc = 0;
5305 uint64_t num_rate_limit = 0;
5306 Shuffle(vAddr.begin(), vAddr.end(), m_rng);
5308 if (interruptMsgProc) {
5313 LOCK(peer->m_addr_token_bucket_mutex);
5315 if (peer->m_addr_token_bucket < 1.0) {
5321 peer->m_addr_token_bucket -= 1.0;
5334 addr.
nTime > current_a_time + 10min) {
5335 addr.
nTime = current_a_time - 5 * 24h;
5337 AddAddressKnown(*peer, addr);
5346 if (addr.
nTime > current_a_time - 10min && !peer->m_getaddr_sent &&
5349 RelayAddress(pfrom.
GetId(), addr, fReachable);
5353 vAddrOk.push_back(addr);
5356 peer->m_addr_processed += num_proc;
5357 peer->m_addr_rate_limited += num_rate_limit;
5359 "Received addr: %u addresses (%u processed, %u rate-limited) "
5361 vAddr.size(), num_proc, num_rate_limit, pfrom.
GetId());
5363 m_addrman.
Add(vAddrOk, pfrom.
addr, 2h);
5364 if (vAddr.size() < 1000) {
5365 peer->m_getaddr_sent =
false;
5372 "addrfetch connection completed peer=%d; disconnecting\n",
5380 peer->m_wants_addrv2 =
true;
5385 peer->m_prefers_headers =
true;
5390 bool sendcmpct_hb{
false};
5391 uint64_t sendcmpct_version{0};
5392 vRecv >> sendcmpct_hb >> sendcmpct_version;
5399 CNodeState *nodestate = State(pfrom.
GetId());
5400 nodestate->m_provides_cmpctblocks =
true;
5401 nodestate->m_requested_hb_cmpctblocks = sendcmpct_hb;
5410 std::vector<CInv> vInv;
5413 Misbehaving(*peer,
strprintf(
"inv message size = %u", vInv.size()));
5417 const bool reject_tx_invs{RejectIncomingTxs(pfrom)};
5419 const auto current_time{GetTime<std::chrono::microseconds>()};
5420 std::optional<BlockHash> best_block;
5422 auto logInv = [&](
const CInv &inv,
bool fAlreadyHave) {
5424 fAlreadyHave ?
"have" :
"new", pfrom.
GetId());
5427 for (
CInv &inv : vInv) {
5428 if (interruptMsgProc) {
5440 const bool fAlreadyHave = AlreadyHaveBlock(
BlockHash(inv.
hash));
5441 logInv(inv, fAlreadyHave);
5444 UpdateBlockAvailability(pfrom.
GetId(), hash);
5446 !IsBlockRequested(hash)) {
5453 best_block = std::move(hash);
5464 const bool fAlreadyHave = AlreadyHaveProof(proofid);
5465 logInv(inv, fAlreadyHave);
5466 AddKnownProof(*peer, proofid);
5468 if (!fAlreadyHave && m_avalanche &&
5470 const bool preferred = isPreferredDownloadPeer(pfrom);
5472 LOCK(cs_proofrequest);
5473 AddProofAnnouncement(pfrom, proofid, current_time,
5482 const bool fAlreadyHave =
5483 AlreadyHaveTx(txid,
true);
5484 logInv(inv, fAlreadyHave);
5486 AddKnownTx(*peer, txid);
5487 if (reject_tx_invs) {
5489 "transaction (%s) inv sent in violation of "
5490 "protocol, disconnecting peer=%d\n",
5494 }
else if (!fAlreadyHave &&
5496 AddTxAnnouncement(pfrom, txid, current_time);
5503 "Unknown inv type \"%s\" received from peer=%d\n",
5520 if (state.fSyncStarted ||
5521 (!peer->m_inv_triggered_getheaders_before_sync &&
5522 *best_block != m_last_block_inv_triggering_headers_sync)) {
5523 if (MaybeSendGetHeaders(
5524 pfrom,
GetLocator(m_chainman.m_best_header), *peer)) {
5526 m_chainman.m_best_header->nHeight,
5527 best_block->ToString(), pfrom.
GetId());
5529 if (!state.fSyncStarted) {
5530 peer->m_inv_triggered_getheaders_before_sync =
true;
5534 m_last_block_inv_triggering_headers_sync = *best_block;
5543 std::vector<CInv> vInv;
5547 strprintf(
"getdata message size = %u", vInv.size()));
5552 vInv.size(), pfrom.
GetId());
5554 if (vInv.size() > 0) {
5560 LOCK(peer->m_getdata_requests_mutex);
5561 peer->m_getdata_requests.insert(peer->m_getdata_requests.end(),
5562 vInv.begin(), vInv.end());
5563 ProcessGetData(config, pfrom, *peer, interruptMsgProc);
5572 vRecv >> locator >> hashStop;
5576 "getblocks locator size %lld > %d, disconnect peer=%d\n",
5590 std::shared_ptr<const CBlock> a_recent_block;
5592 LOCK(m_most_recent_block_mutex);
5593 a_recent_block = m_most_recent_block;
5597 state, a_recent_block, m_avalanche)) {
5615 (pindex ? pindex->
nHeight : -1),
5618 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5627 const int nPrunedBlocksLikelyToHave =
5631 (!pindex->nStatus.hasData() ||
5633 nPrunedBlocksLikelyToHave)) {
5636 " getblocks stopping, pruned or too old block at %d %s\n",
5641 peer->m_block_inv_mutex,
5642 peer->m_blocks_for_inv_relay.push_back(pindex->
GetBlockHash()));
5643 if (--nLimit <= 0) {
5649 peer->m_continuation_block = pindex->GetBlockHash();
5661 std::shared_ptr<const CBlock> recent_block;
5663 LOCK(m_most_recent_block_mutex);
5664 if (m_most_recent_block_hash == req.
blockhash) {
5665 recent_block = m_most_recent_block;
5670 SendBlockTransactions(pfrom, *peer, *recent_block, req);
5680 if (!pindex || !pindex->nStatus.hasData()) {
5683 "Peer %d sent us a getblocktxn for a block we don't have\n",
5694 if (!block_pos.IsNull()) {
5701 LogError(
"getblocktxn: block read failed for block %s\n",
5707 SendBlockTransactions(pfrom, *peer, block, req);
5719 "Peer %d sent us a getblocktxn for a block > %i deep\n",
5724 WITH_LOCK(peer->m_getdata_requests_mutex,
5725 peer->m_getdata_requests.push_back(inv));
5734 vRecv >> locator >> hashStop;
5738 "getheaders locator size %lld > %d, disconnect peer=%d\n",
5747 "Ignoring getheaders from peer=%d while importing/reindexing\n",
5761 if (m_chainman.
ActiveTip() ==
nullptr ||
5766 "Ignoring getheaders from peer=%d because active chain "
5767 "has too little work; sending empty response\n",
5772 std::vector<CBlock>());
5776 CNodeState *nodestate = State(pfrom.
GetId());
5785 if (!BlockRequestAllowed(pindex)) {
5787 "%s: ignoring request from peer=%i for old block "
5788 "header that isn't in the main chain\n",
5789 __func__, pfrom.
GetId());
5803 std::vector<CBlock> vHeaders;
5806 (pindex ? pindex->
nHeight : -1),
5809 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5811 if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) {
5828 nodestate->pindexBestHeaderSent =
5835 if (RejectIncomingTxs(pfrom)) {
5837 "transaction sent in violation of protocol peer=%d\n",
5853 const CTransaction &tx = *ptx;
5854 const TxId &txid = tx.GetId();
5855 AddKnownTx(*peer, txid);
5860 m_txrequest.ReceivedResponse(pfrom.
GetId(), txid);
5862 if (AlreadyHaveTx(txid,
true)) {
5868 if (!m_mempool.
exists(tx.GetId())) {
5870 "Not relaying non-mempool transaction %s from "
5871 "forcerelay peer=%d\n",
5872 tx.GetId().ToString(), pfrom.
GetId());
5874 LogPrintf(
"Force relaying tx %s from peer=%d\n",
5875 tx.GetId().ToString(), pfrom.
GetId());
5876 RelayTransaction(tx.GetId());
5880 if (m_recent_rejects_package_reconsiderable.contains(txid)) {
5888 "found tx %s in reconsiderable rejects, looking for "
5889 "child in orphanage\n",
5891 if (
auto package_to_validate{
5892 Find1P1CPackage(ptx, pfrom.
GetId())}) {
5895 package_to_validate->m_txns,
5898 "package evaluation for %s: %s (%s)\n",
5899 package_to_validate->ToString(),
5901 ?
"package accepted"
5902 :
"package rejected",
5904 ProcessPackageResult(package_to_validate.value(),
5933 ProcessValidTx(pfrom.
GetId(), ptx);
5939 bool fRejectedParents =
false;
5943 std::vector<TxId> unique_parents;
5944 unique_parents.reserve(tx.vin.size());
5945 for (
const CTxIn &txin : tx.vin) {
5948 unique_parents.push_back(txin.prevout.GetTxId());
5950 std::sort(unique_parents.begin(), unique_parents.end());
5951 unique_parents.erase(
5952 std::unique(unique_parents.begin(), unique_parents.end()),
5953 unique_parents.end());
5961 std::optional<TxId> rejected_parent_reconsiderable;
5962 for (
const TxId &parent_txid : unique_parents) {
5963 if (m_recent_rejects.contains(parent_txid)) {
5964 fRejectedParents =
true;
5968 if (m_recent_rejects_package_reconsiderable.contains(
5970 !m_mempool.
exists(parent_txid)) {
5975 if (rejected_parent_reconsiderable.has_value()) {
5976 fRejectedParents =
true;
5979 rejected_parent_reconsiderable = parent_txid;
5982 if (!fRejectedParents) {
5983 const auto current_time{
5984 GetTime<std::chrono::microseconds>()};
5986 for (
const TxId &parent_txid : unique_parents) {
5988 AddKnownTx(*peer, parent_txid);
5992 if (!AlreadyHaveTx(parent_txid,
5994 AddTxAnnouncement(pfrom, parent_txid, current_time);
6000 if (
unsigned int nEvicted =
6004 if (orphanage.AddTx(ptx,
6006 AddToCompactExtraTransactions(ptx);
6009 m_opts.max_orphan_txs, m_rng);
6012 "orphanage overflow, removed %u tx\n",
6018 m_txrequest.ForgetInvId(tx.GetId());
6022 "not keeping orphan with rejected parents %s\n",
6023 tx.GetId().ToString());
6026 m_recent_rejects.insert(tx.GetId());
6027 m_txrequest.ForgetInvId(tx.GetId());
6031 ProcessInvalidTx(pfrom.
GetId(), ptx, state,
6041 "tx %s failed but reconsiderable, looking for child in "
6044 if (
auto package_to_validate{
6045 Find1P1CPackage(ptx, pfrom.
GetId())}) {
6048 package_to_validate->m_txns,
false)};
6050 "package evaluation for %s: %s (%s)\n",
6051 package_to_validate->ToString(),
6053 ?
"package accepted"
6054 :
"package rejected",
6056 ProcessPackageResult(package_to_validate.value(),
6065 m_txrequest.ForgetInvId(tx.GetId());
6067 unsigned int nEvicted{0};
6074 m_opts.max_conflicting_txs, m_rng);
6079 "conflicting pool overflow, removed %u tx\n",
6092 "Unexpected cmpctblock message received from peer %d\n",
6099 vRecv >> cmpctblock;
6100 }
catch (std::ios_base::failure &e) {
6102 Misbehaving(*peer,
"cmpctblock-bad-indexes");
6106 bool received_new_header =
false;
6119 MaybeSendGetHeaders(
6120 pfrom,
GetLocator(m_chainman.m_best_header), *peer);
6126 GetAntiDoSWorkThreshold()) {
6130 "Ignoring low-work compact block from peer %d\n",
6136 received_new_header =
true;
6146 MaybePunishNodeForBlock(pfrom.
GetId(), state,
6148 "invalid header via cmpctblock");
6153 if (received_new_header) {
6154 LogInfo(
"Saw new cmpctblock header hash=%s peer=%d\n",
6155 blockhash.ToString(), pfrom.
GetId());
6162 bool fProcessBLOCKTXN =
false;
6168 bool fRevertToHeaderProcessing =
false;
6172 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6173 bool fBlockReconstructed =
false;
6181 "cmpctblock: header accepted but no pindex for block %s\n",
6182 blockhash.ToString());
6189 CNodeState *nodestate = State(pfrom.
GetId());
6193 if (received_new_header &&
6196 nodestate->m_last_block_announcement =
GetTime();
6199 if (pindex->nStatus.hasData()) {
6206 size_t already_in_flight =
6207 std::distance(range_flight.first, range_flight.second);
6208 bool requested_block_from_this_peer{
false};
6212 bool first_in_flight =
6213 already_in_flight == 0 ||
6214 (range_flight.first->second.first == pfrom.
GetId());
6216 while (range_flight.first != range_flight.second) {
6217 if (range_flight.first->second.first == pfrom.
GetId()) {
6218 requested_block_from_this_peer =
true;
6221 range_flight.first++;
6230 if (requested_block_from_this_peer) {
6234 std::vector<CInv> vInv(1);
6243 if (!already_in_flight && !CanDirectFetch()) {
6251 nodestate->vBlocksInFlight.size() <
6253 requested_block_from_this_peer) {
6254 std::list<QueuedBlock>::iterator *queuedBlockIt =
nullptr;
6255 if (!BlockRequested(config, pfrom.
GetId(), *pindex,
6257 if (!(*queuedBlockIt)->partialBlock) {
6259 ->partialBlock.reset(
6266 "we were already syncing!\n");
6272 *(*queuedBlockIt)->partialBlock;
6274 partialBlock.
InitData(cmpctblock, vExtraTxnForCompact);
6280 Misbehaving(*peer,
"invalid compact block");
6283 if (first_in_flight) {
6286 std::vector<CInv> vInv(1);
6299 for (
size_t i = 0; i < cmpctblock.
BlockTxCount(); i++) {
6310 fProcessBLOCKTXN =
true;
6311 }
else if (first_in_flight) {
6318 IsBlockRequestedFromOutbound(blockhash) ||
6341 tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
6346 std::vector<CTransactionRef> dummy;
6347 status = tempBlock.FillBlock(*pblock, dummy);
6349 fBlockReconstructed =
true;
6353 if (requested_block_from_this_peer) {
6357 std::vector<CInv> vInv(1);
6364 fRevertToHeaderProcessing =
true;
6369 if (fProcessBLOCKTXN) {
6371 blockTxnMsg, time_received, interruptMsgProc);
6374 if (fRevertToHeaderProcessing) {
6380 return ProcessHeadersMessage(config, pfrom, *peer,
6385 if (fBlockReconstructed) {
6390 mapBlockSource.emplace(pblock->GetHash(),
6391 std::make_pair(pfrom.
GetId(),
false));
6402 ProcessBlock(config, pfrom, pblock,
true,
6411 RemoveBlockRequest(pblock->GetHash(), std::nullopt);
6421 "Unexpected blocktxn message received from peer %d\n",
6429 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6430 bool fBlockRead =
false;
6434 auto range_flight = mapBlocksInFlight.equal_range(resp.
blockhash);
6435 size_t already_in_flight =
6436 std::distance(range_flight.first, range_flight.second);
6437 bool requested_block_from_this_peer{
false};
6441 bool first_in_flight =
6442 already_in_flight == 0 ||
6443 (range_flight.first->second.first == pfrom.
GetId());
6445 while (range_flight.first != range_flight.second) {
6446 auto [node_id, block_it] = range_flight.first->second;
6447 if (node_id == pfrom.
GetId() && block_it->partialBlock) {
6448 requested_block_from_this_peer =
true;
6451 range_flight.first++;
6454 if (!requested_block_from_this_peer) {
6456 "Peer %d sent us block transactions for block "
6457 "we weren't expecting\n",
6463 *range_flight.first->second.second->partialBlock;
6471 "invalid compact block/non-matching block transactions");
6474 if (first_in_flight) {
6476 std::vector<CInv> invs;
6483 "Peer %d sent us a compact block but it failed to "
6484 "reconstruct, waiting on first download to complete\n",
6517 std::make_pair(pfrom.
GetId(),
false));
6528 ProcessBlock(config, pfrom, pblock,
true,
6538 "Unexpected headers message received from peer %d\n",
6543 std::vector<CBlockHeader> headers;
6550 strprintf(
"too-many-headers: headers message size = %u",
6554 headers.resize(nCount);
6555 for (
unsigned int n = 0; n < nCount; n++) {
6556 vRecv >> headers[n];
6561 ProcessHeadersMessage(config, pfrom, *peer, std::move(headers),
6567 if (m_headers_presync_should_signal.exchange(
false)) {
6568 HeadersPresyncStats stats;
6570 LOCK(m_headers_presync_mutex);
6572 m_headers_presync_stats.find(m_headers_presync_bestpeer);
6573 if (it != m_headers_presync_stats.end()) {
6579 stats.first, stats.second->first, stats.second->second);
6590 "Unexpected block message received from peer %d\n",
6595 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6599 pblock->GetHash().ToString(), pfrom.
GetId());
6604 pblock->hashPrevBlock))};
6608 "Received mutated block from peer=%d\n", peer->m_id);
6609 Misbehaving(*peer,
"mutated block");
6611 RemoveBlockRequest(pblock->GetHash(), peer->m_id));
6621 const BlockHash hash = pblock->GetHash();
6622 bool min_pow_checked =
false;
6627 forceProcessing = IsBlockRequested(hash);
6628 RemoveBlockRequest(hash, pfrom.
GetId());
6632 mapBlockSource.emplace(hash, std::make_pair(pfrom.
GetId(),
true));
6637 {pblock->GetBlockHeader()}) >=
6638 GetAntiDoSWorkThreshold()) {
6639 min_pow_checked =
true;
6642 ProcessBlock(config, pfrom, pblock, forceProcessing, min_pow_checked);
6652 if (pfrom.m_avalanche_pubkey.has_value()) {
6655 "Ignoring avahello from peer %d: already in our node set\n",
6661 vRecv >> delegation;
6668 if (!delegation.
verify(state, pubkey)) {
6669 Misbehaving(*peer,
"invalid-delegation");
6672 pfrom.m_avalanche_pubkey = std::move(pubkey);
6675 sighasher << delegation.
getId();
6683 if (!(*pfrom.m_avalanche_pubkey)
6684 .VerifySchnorr(sighasher.GetHash(),
sig)) {
6685 Misbehaving(*peer,
"invalid-avahello-signature");
6692 if (!AlreadyHaveProof(proofid)) {
6693 const bool preferred = isPreferredDownloadPeer(pfrom);
6694 LOCK(cs_proofrequest);
6695 AddProofAnnouncement(pfrom, proofid,
6696 GetTime<std::chrono::microseconds>(),
6704 vRecv >> max_elements;
6708 Misbehaving(*peer,
"avahello-max-elements-too-low");
6713 max_elements = std::min(
6719 return pm.
addNode(pfrom.
GetId(), proofid, max_elements);
6730 WITH_LOCK(peer->m_addr_token_bucket_mutex,
6731 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
6735 peer->m_proof_relay->compactproofs_requested =
true;
6746 const auto now = Now<SteadyMilliseconds>();
6752 last_poll + std::chrono::milliseconds(m_opts.avalanche_cooldown)) {
6754 "Ignoring repeated avapoll from peer %d: cooldown not "
6769 strprintf(
"too-many-ava-poll: poll message size = %u", nCount));
6773 std::vector<avalanche::Vote> votes;
6774 votes.reserve(nCount);
6776 bool fPreconsensus{
false};
6777 bool fStakingPreconsensus{
false};
6782 fStakingPreconsensus =
6786 for (
unsigned int n = 0; n < nCount; n++) {
6794 if (!quorum_established) {
6795 votes.emplace_back(vote, inv.
hash);
6802 if (fPreconsensus) {
6804 GetAvalancheVoteForTx(*m_avalanche,
TxId(inv.
hash));
6816 if (fStakingPreconsensus) {
6823 "poll inv type %d unknown from peer=%d\n",
6828 votes.emplace_back(vote, inv.
hash);
6854 if (!pfrom.m_avalanche_pubkey.has_value() ||
6855 !(*pfrom.m_avalanche_pubkey)
6856 .VerifySchnorr(verifier.GetHash(),
sig)) {
6857 Misbehaving(*peer,
"invalid-ava-response-signature");
6862 auto now = GetTime<std::chrono::seconds>();
6864 std::vector<avalanche::VoteItemUpdate> updates;
6865 bool disconnect{
false};
6868 disconnect, error)) {
6870 Misbehaving(*peer, error);
6888 "Repeated failure to register votes from peer %d: %s\n",
6889 pfrom.
GetId(), error);
6892 Misbehaving(*peer, error);
6905 auto logVoteUpdate = [](
const auto &voteUpdate,
6906 const std::string &voteItemTypeStr,
6907 const auto &voteItemId) {
6908 std::string voteOutcome;
6909 bool alwaysPrint =
false;
6910 switch (voteUpdate.getStatus()) {
6912 voteOutcome =
"invalidated";
6916 voteOutcome =
"rejected";
6919 voteOutcome =
"accepted";
6922 voteOutcome =
"finalized";
6925 alwaysPrint = voteItemTypeStr !=
"tx";
6928 voteOutcome =
"stalled";
6937 alwaysPrint &= (voteItemTypeStr !=
"contender");
6940 LogPrintf(
"Avalanche %s %s %s\n", voteOutcome, voteItemTypeStr,
6941 voteItemId.ToString());
6945 voteItemTypeStr, voteItemId.ToString());
6949 bool shouldActivateBestChain =
false;
6951 bool fPreconsensus{
false};
6952 bool fStakingPreconsensus{
false};
6957 fStakingPreconsensus =
6961 for (
const auto &u : updates) {
6966 if (
auto pitem = std::get_if<const avalanche::ProofRef>(&item)) {
6970 logVoteUpdate(u,
"proof", proofid);
6972 auto rejectionMode =
6974 auto nextCooldownTimePoint = GetTime<std::chrono::seconds>();
6975 switch (u.getStatus()) {
6991 return pm.rejectProof(proofid,
6995 "ERROR: Failed to reject proof: %s\n",
7001 nextCooldownTimePoint += std::chrono::seconds(
7002 m_opts.avalanche_peer_replacement_cooldown);
7008 avalanche::PeerManager::
7009 RegistrationMode::FORCE_ACCEPT);
7012 [&](const avalanche::Peer &peer) {
7013 pm.updateNextPossibleConflictTime(
7015 nextCooldownTimePoint);
7016 if (u.getStatus() ==
7017 avalanche::VoteStatus::
7019 pm.setFinalized(peer.peerid);
7027 "ERROR: Failed to accept proof: %s\n",
7034 auto getBlockFromIndex = [
this](
const CBlockIndex *pindex)
7035 -> std::shared_ptr<const CBlock> {
7038 std::shared_ptr<const CBlock> pblock =
WITH_LOCK(
7039 m_most_recent_block_mutex,
return m_most_recent_block);
7041 if (!pblock || pblock->GetHash() != pindex->
GetBlockHash()) {
7042 std::shared_ptr<CBlock> pblockRead =
7043 std::make_shared<CBlock>();
7046 LogError(
"getBlockFromIndex: cannot load block from "
7051 pblock = pblockRead;
7056 if (
auto pitem = std::get_if<const CBlockIndex *>(&item)) {
7059 shouldActivateBestChain =
true;
7063 switch (u.getStatus()) {
7068 LogPrintf(
"ERROR: Database error: %s\n",
7077 LogPrintf(
"ERROR: Database error: %s\n",
7082 auto pblock = getBlockFromIndex(pindex);
7084 LogError(
"avaresponse: failed to get invalidated "
7085 "block from index\n");
7104 std::unique_ptr<node::CBlockTemplate> blockTemplate;
7108 chainstate.UnparkBlock(pindex);
7110 const bool newlyFinalized =
7111 !chainstate.IsBlockAvalancheFinalized(pindex) &&
7112 chainstate.AvalancheFinalizeBlock(pindex,
7117 if (fPreconsensus && newlyFinalized) {
7127 std::unordered_set<TxId, SaltedTxIdHasher>
7128 confirmedTxIdsInNonFinalizedBlocks;
7129 bool missing_block =
false;
7131 block !=
nullptr && block != pindex;
7132 block = block->pprev) {
7134 getBlockFromIndex(block);
7135 if (!currentBlock) {
7137 "avaresponse: failed to get "
7138 "finalized block descendant from "
7141 missing_block =
true;
7144 for (
const auto &tx : currentBlock->vtx) {
7145 confirmedTxIdsInNonFinalizedBlocks
7146 .insert(tx->GetId());
7150 if (missing_block) {
7162 confirmedTxIdsInNonFinalizedBlocks);
7174 config, chainstate, &m_mempool,
7176 blockAssembler.pblocktemplate.reset(
7179 if (blockAssembler.pblocktemplate) {
7180 blockAssembler.addTxs(m_mempool);
7181 blockTemplate = std::move(
7182 blockAssembler.pblocktemplate);
7187 if (blockTemplate) {
7192 for (
const auto &templateEntry :
7206 if (fStakingPreconsensus) {
7208 std::get_if<const avalanche::StakeContenderId>(&item)) {
7210 logVoteUpdate(u,
"contender", contenderId);
7212 switch (u.getStatus()) {
7233 if (!fPreconsensus) {
7237 if (
auto pitem = std::get_if<const CTransactionRef>(&item)) {
7241 const TxId &txid = tx->GetId();
7242 const auto status{u.getStatus()};
7247 logVoteUpdate(u,
"tx", txid);
7259 std::shared_ptr<const std::vector<Coin>> spentCoins;
7271 _spentCoins.has_value()
7272 ? std::make_shared<const std::vector<Coin>>(
7273 std::move(*_spentCoins))
7277 if (m_mempool.
exists(txid)) {
7281 std::vector<CTransactionRef> conflictingTxs =
7287 if (conflictingTxs.size() > 0) {
7295 "Attempting to pull a now invalid "
7296 "conflicting tx %s to mempool\n",
7297 conflictingTxs[0]->GetId().
ToString());
7304 for (
const auto &conflictingTx :
7307 conflictingTx->GetId());
7326 m_recent_rejects.insert(txid);
7328 AddToCompactExtraTransactions(tx);
7345 return conflicting.HaveTx(txid);
7348 std::vector<CTransactionRef>
7349 mempool_conflicting_txs;
7350 for (
const auto &txin : tx->vin) {
7355 mempool_conflicting_txs.push_back(
7356 std::move(conflict));
7363 LogError(
"accepted tx %s failed mempool "
7371 [&txid, &mempool_conflicting_txs](
7376 if (mempool_conflicting_txs.size() >
7379 mempool_conflicting_txs[0],
7388 auto it = m_mempool.
GetIter(txid);
7389 if (!it.has_value()) {
7392 "Error: finalized tx (%s) is not in the "
7398 std::vector<TxId> finalizedTxIds;
7399 m_mempool.setAvalancheFinalized(
7404 for (
const auto &finalized_txid : finalizedTxIds) {
7409 logVoteUpdate(u,
"tx", finalized_txid);
7417 std::vector<CTransactionRef>
7420 for (
const auto &conflictingTx :
7422 m_recent_rejects.insert(
7423 conflictingTx->GetId());
7425 conflictingTx->GetId());
7451 m_txrequest.ForgetInvId(txid);
7457 for (
auto &it : m_peer_map) {
7458 auto tx_relay = (*it.second).GetTxRelay();
7463 LOCK(tx_relay->m_tx_inventory_mutex);
7470 auto &stalled_by_time =
7471 tx_relay->m_avalanche_stalled_txids
7473 if (stalled_by_time.size() >=
7475 stalled_by_time.erase(
7476 stalled_by_time.begin()->timeAdded);
7479 tx_relay->m_avalanche_stalled_txids.insert(
7484 AddToCompactExtraTransactions(tx);
7492 if (shouldActivateBestChain) {
7495 state,
nullptr, m_avalanche)) {
7510 ReceivedAvalancheProof(pfrom, *peer, proof);
7519 if (peer->m_proof_relay ==
nullptr) {
7523 auto now = GetTime<std::chrono::seconds>();
7524 if (now < peer->m_next_getavaproofs) {
7533 peer->m_proof_relay->lastSharedProofsUpdate = now;
7535 peer->m_proof_relay->sharedProofs =
7541 peer->m_proof_relay->sharedProofs);
7551 if (peer->m_proof_relay ==
nullptr) {
7556 if (!peer->m_proof_relay->compactproofs_requested) {
7560 peer->m_proof_relay->compactproofs_requested =
false;
7564 vRecv >> compactProofs;
7565 }
catch (std::ios_base::failure &e) {
7567 Misbehaving(*peer,
"avaproofs-bad-indexes");
7573 if (!ReceivedAvalancheProof(pfrom, *peer, prefilledProof.proof)) {
7603 auto shortIdProcessor =
7607 if (shortIdProcessor.hasOutOfBoundIndex()) {
7610 Misbehaving(*peer,
"avaproofs-bad-indexes");
7613 if (!shortIdProcessor.isEvenlyDistributed()) {
7618 std::vector<std::pair<avalanche::ProofId, bool>> remoteProofsStatus;
7622 uint64_t shortid = compactProofs.
getShortID(proofid);
7624 int added = shortIdProcessor.matchKnownItem(shortid, proof);
7636 remoteProofsStatus.emplace_back(proofid, added > 0);
7641 matchKnownProof(peer.
proof);
7650 matchKnownProof(proof);
7655 for (
size_t i = 0; i < compactProofs.
size(); i++) {
7656 if (shortIdProcessor.getItem(i) ==
nullptr) {
7672 return pfrom.m_avalanche_pubkey.has_value())) {
7677 for (
const auto &[proofid, present] : remoteProofsStatus) {
7687 if (peer->m_proof_relay ==
nullptr) {
7694 auto requestedIndiceIt = proofreq.
indices.begin();
7695 uint32_t treeIndice = 0;
7696 peer->m_proof_relay->sharedProofs.forEachLeaf([&](
const auto &proof) {
7697 if (requestedIndiceIt == proofreq.
indices.end()) {
7702 if (treeIndice++ == *requestedIndiceIt) {
7704 requestedIndiceIt++;
7710 peer->m_proof_relay->sharedProofs = {};
7723 "Ignoring \"getaddr\" from %s connection. peer=%d\n",
7730 Assume(SetupAddressRelay(pfrom, *peer));
7734 if (peer->m_getaddr_recvd) {
7739 peer->m_getaddr_recvd =
true;
7741 peer->m_addrs_to_send.clear();
7742 std::vector<CAddress> vAddr;
7743 const size_t maxAddrToSend = m_opts.max_addr_to_send;
7751 for (
const CAddress &addr : vAddr) {
7752 PushAddress(*peer, addr);
7758 auto now = GetTime<std::chrono::seconds>();
7759 if (now < peer->m_next_getavaaddr) {
7768 if (!SetupAddressRelay(pfrom, *peer)) {
7770 "Ignoring getavaaddr message from %s peer=%d\n",
7775 using AvaNodeInfo = std::tuple<CAddress, NodeId, double>;
7776 auto availabilityScoreComparator = [](
const AvaNodeInfo &lhs,
7777 const AvaNodeInfo &rhs) {
7778 double scoreLhs = std::get<double>(lhs);
7779 double scoreRhs = std::get<double>(rhs);
7781 if (scoreLhs != scoreRhs) {
7782 return scoreLhs > scoreRhs;
7785 return std::get<NodeId>(lhs) < std::get<NodeId>(rhs);
7791 std::set<AvaNodeInfo,
decltype(availabilityScoreComparator)> avaNodes(
7792 availabilityScoreComparator);
7799 avaNodes.insert(AvaNodeInfo{pnode->
addr, pnode->
GetId(), score});
7800 if (avaNodes.size() > m_opts.max_addr_to_send) {
7801 avaNodes.erase(std::prev(avaNodes.end()));
7805 peer->m_addrs_to_send.clear();
7806 for (
const auto &nodeInfo : avaNodes) {
7807 PushAddress(*peer, std::get<CAddress>(nodeInfo));
7818 "mempool request with bloom filters disabled, "
7819 "disconnect peer=%d\n",
7830 "mempool request with bandwidth limit reached, "
7831 "disconnect peer=%d\n",
7838 if (
auto tx_relay = peer->GetTxRelay()) {
7839 LOCK(tx_relay->m_tx_inventory_mutex);
7840 tx_relay->m_send_mempool =
true;
7869 const auto ping_end = time_received;
7872 bool bPingFinished =
false;
7873 std::string sProblem;
7875 if (nAvail >=
sizeof(nonce)) {
7880 if (peer->m_ping_nonce_sent != 0) {
7881 if (nonce == peer->m_ping_nonce_sent) {
7884 bPingFinished =
true;
7885 const auto ping_time = ping_end - peer->m_ping_start.load();
7886 if (ping_time.count() >= 0) {
7891 sProblem =
"Timing mishap";
7895 sProblem =
"Nonce mismatch";
7899 bPingFinished =
true;
7900 sProblem =
"Nonce zero";
7904 sProblem =
"Unsolicited pong without ping";
7909 bPingFinished =
true;
7910 sProblem =
"Short payload";
7913 if (!(sProblem.empty())) {
7915 "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
7916 pfrom.
GetId(), sProblem, peer->m_ping_nonce_sent, nonce,
7919 if (bPingFinished) {
7920 peer->m_ping_nonce_sent = 0;
7928 "filterload received despite not offering bloom services "
7929 "from peer=%d; disconnecting\n",
7939 Misbehaving(*peer,
"too-large bloom filter");
7940 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7942 LOCK(tx_relay->m_bloom_filter_mutex);
7943 tx_relay->m_bloom_filter.reset(
new CBloomFilter(filter));
7944 tx_relay->m_relay_txs =
true;
7954 "filteradd received despite not offering bloom services "
7955 "from peer=%d; disconnecting\n",
7960 std::vector<uint8_t> vData;
7969 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7970 LOCK(tx_relay->m_bloom_filter_mutex);
7971 if (tx_relay->m_bloom_filter) {
7972 tx_relay->m_bloom_filter->insert(vData);
7980 Misbehaving(*peer,
"bad filteradd message");
7988 "filterclear received despite not offering bloom services "
7989 "from peer=%d; disconnecting\n",
7994 auto tx_relay = peer->GetTxRelay();
8000 LOCK(tx_relay->m_bloom_filter_mutex);
8001 tx_relay->m_bloom_filter =
nullptr;
8002 tx_relay->m_relay_txs =
true;
8011 vRecv >> newFeeFilter;
8013 if (
auto tx_relay = peer->GetTxRelay()) {
8014 tx_relay->m_fee_filter_received = newFeeFilter;
8023 ProcessGetCFilters(pfrom, *peer, vRecv);
8028 ProcessGetCFHeaders(pfrom, *peer, vRecv);
8033 ProcessGetCFCheckPt(pfrom, *peer, vRecv);
8038 std::vector<CInv> vInv;
8044 for (
CInv &inv : vInv) {
8050 m_txrequest.ReceivedResponse(pfrom.
GetId(),
TxId(inv.
hash));
8057 LOCK(cs_proofrequest);
8058 m_proofrequest.ReceivedResponse(
8072bool PeerManagerImpl::MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer) {
8074 LOCK(peer.m_misbehavior_mutex);
8077 if (!peer.m_should_discourage) {
8081 peer.m_should_discourage =
false;
8087 LogPrintf(
"Warning: not punishing noban peer %d!\n", peer.m_id);
8093 LogPrintf(
"Warning: not punishing manually connected peer %d!\n",
8102 "Warning: disconnecting but not discouraging %s peer %d!\n",
8119bool PeerManagerImpl::ProcessMessages(
const Config &config,
CNode *pfrom,
8120 std::atomic<bool> &interruptMsgProc) {
8123 PeerRef peer = GetPeerRef(pfrom->
GetId());
8124 if (peer ==
nullptr) {
8129 LOCK(peer->m_getdata_requests_mutex);
8130 if (!peer->m_getdata_requests.empty()) {
8131 ProcessGetData(config, *pfrom, *peer, interruptMsgProc);
8135 const bool processed_orphan = ProcessOrphanTx(config, *peer);
8141 if (processed_orphan) {
8148 LOCK(peer->m_getdata_requests_mutex);
8149 if (!peer->m_getdata_requests.empty()) {
8166 bool fMoreWork = poll_result->second;
8170 msg.m_recv.size(),
msg.m_recv.data());
8172 if (m_opts.capture_messages) {
8178 ProcessMessage(config, *pfrom,
msg.m_type,
msg.m_recv,
msg.m_time,
8180 if (interruptMsgProc) {
8185 LOCK(peer->m_getdata_requests_mutex);
8186 if (!peer->m_getdata_requests.empty()) {
8195 return orphanage.HaveTxToReconsider(peer->m_id);
8199 }
catch (
const std::exception &e) {
8202 e.what(),
typeid(e).name());
8211void PeerManagerImpl::ConsiderEviction(
CNode &pto, Peer &peer,
8212 std::chrono::seconds time_in_seconds) {
8215 CNodeState &state = *State(pto.
GetId());
8218 state.fSyncStarted) {
8225 if (state.pindexBestKnownBlock !=
nullptr &&
8226 state.pindexBestKnownBlock->nChainWork >=
8228 if (state.m_chain_sync.m_timeout != 0s) {
8229 state.m_chain_sync.m_timeout = 0s;
8230 state.m_chain_sync.m_work_header =
nullptr;
8231 state.m_chain_sync.m_sent_getheaders =
false;
8233 }
else if (state.m_chain_sync.m_timeout == 0s ||
8234 (state.m_chain_sync.m_work_header !=
nullptr &&
8235 state.pindexBestKnownBlock !=
nullptr &&
8236 state.pindexBestKnownBlock->nChainWork >=
8237 state.m_chain_sync.m_work_header->nChainWork)) {
8243 state.m_chain_sync.m_work_header = m_chainman.
ActiveChain().
Tip();
8244 state.m_chain_sync.m_sent_getheaders =
false;
8245 }
else if (state.m_chain_sync.m_timeout > 0s &&
8246 time_in_seconds > state.m_chain_sync.m_timeout) {
8251 if (state.m_chain_sync.m_sent_getheaders) {
8254 "Disconnecting outbound peer %d for old chain, best known "
8257 state.pindexBestKnownBlock !=
nullptr
8258 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
8262 assert(state.m_chain_sync.m_work_header);
8267 MaybeSendGetHeaders(
8268 pto,
GetLocator(state.m_chain_sync.m_work_header->pprev),
8272 "sending getheaders to outbound peer=%d to verify chain "
8273 "work (current best known block:%s, benchmark blockhash: "
8276 state.pindexBestKnownBlock !=
nullptr
8277 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
8279 state.m_chain_sync.m_work_header->GetBlockHash()
8281 state.m_chain_sync.m_sent_getheaders =
true;
8288 state.m_chain_sync.m_timeout =
8295void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now) {
8304 std::pair<NodeId, std::chrono::seconds> youngest_peer{-1, 0},
8305 next_youngest_peer{-1, 0};
8311 if (pnode->
GetId() > youngest_peer.first) {
8312 next_youngest_peer = youngest_peer;
8313 youngest_peer.first = pnode->GetId();
8314 youngest_peer.second = pnode->m_last_block_time;
8318 NodeId to_disconnect = youngest_peer.first;
8319 if (youngest_peer.second > next_youngest_peer.second) {
8322 to_disconnect = next_youngest_peer.first;
8334 CNodeState *node_state = State(pnode->
GetId());
8335 if (node_state ==
nullptr ||
8337 node_state->vBlocksInFlight.empty())) {
8340 "disconnecting extra block-relay-only peer=%d "
8341 "(last block received at time %d)\n",
8348 "keeping block-relay-only peer=%d chosen for eviction "
8349 "(connect time: %d, blocks_in_flight: %d)\n",
8351 node_state->vBlocksInFlight.size());
8367 int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
8378 CNodeState *state = State(pnode->
GetId());
8379 if (state ==
nullptr) {
8384 if (state->m_chain_sync.m_protect) {
8387 if (state->m_last_block_announcement < oldest_block_announcement ||
8388 (state->m_last_block_announcement == oldest_block_announcement &&
8389 pnode->
GetId() > worst_peer)) {
8390 worst_peer = pnode->
GetId();
8391 oldest_block_announcement = state->m_last_block_announcement;
8395 if (worst_peer == -1) {
8399 bool disconnected = m_connman.
ForNode(
8407 CNodeState &state = *State(pnode->
GetId());
8409 state.vBlocksInFlight.empty()) {
8411 "disconnecting extra outbound peer=%d (last block "
8412 "announcement received at time %d)\n",
8413 pnode->
GetId(), oldest_block_announcement);
8418 "keeping outbound peer=%d chosen for eviction "
8419 "(connect time: %d, blocks_in_flight: %d)\n",
8421 state.vBlocksInFlight.size());
8436void PeerManagerImpl::CheckForStaleTipAndEvictPeers() {
8439 auto now{GetTime<std::chrono::seconds>()};
8441 EvictExtraOutboundPeers(now);
8443 if (now > m_stale_tip_check_time) {
8449 LogPrintf(
"Potential stale tip detected, will try using extra "
8450 "outbound peer (last tip update: %d seconds ago)\n",
8459 if (!m_initial_sync_finished && CanDirectFetch()) {
8461 m_initial_sync_finished =
true;
8465void PeerManagerImpl::MaybeSendPing(
CNode &node_to, Peer &peer,
8466 std::chrono::microseconds now) {
8468 node_to, std::chrono::duration_cast<std::chrono::seconds>(now)) &&
8469 peer.m_ping_nonce_sent &&
8480 bool pingSend =
false;
8482 if (peer.m_ping_queued) {
8487 if (peer.m_ping_nonce_sent == 0 &&
8497 }
while (nonce == 0);
8498 peer.m_ping_queued =
false;
8499 peer.m_ping_start = now;
8501 peer.m_ping_nonce_sent = nonce;
8506 peer.m_ping_nonce_sent = 0;
8512void PeerManagerImpl::MaybeSendAddr(
CNode &
node, Peer &peer,
8513 std::chrono::microseconds current_time) {
8515 if (!peer.m_addr_relay_enabled) {
8519 LOCK(peer.m_addr_send_times_mutex);
8521 peer.m_next_local_addr_send < current_time) {
8528 if (peer.m_next_local_addr_send != 0us) {
8529 peer.m_addr_known->reset();
8532 CAddress local_addr{*local_service, peer.m_our_services,
8533 Now<NodeSeconds>()};
8534 PushAddress(peer, local_addr);
8536 peer.m_next_local_addr_send =
8542 if (current_time <= peer.m_next_addr_send) {
8546 peer.m_next_addr_send =
8549 const size_t max_addr_to_send = m_opts.max_addr_to_send;
8550 if (!
Assume(peer.m_addrs_to_send.size() <= max_addr_to_send)) {
8553 peer.m_addrs_to_send.resize(max_addr_to_send);
8558 auto addr_already_known =
8561 bool ret = peer.m_addr_known->contains(addr.
GetKey());
8563 peer.m_addr_known->insert(addr.
GetKey());
8567 peer.m_addrs_to_send.erase(std::remove_if(peer.m_addrs_to_send.begin(),
8568 peer.m_addrs_to_send.end(),
8569 addr_already_known),
8570 peer.m_addrs_to_send.end());
8573 if (peer.m_addrs_to_send.empty()) {
8577 const char *msg_type;
8579 if (peer.m_wants_addrv2) {
8589 peer.m_addrs_to_send));
8590 peer.m_addrs_to_send.clear();
8593 if (peer.m_addrs_to_send.capacity() > 40) {
8594 peer.m_addrs_to_send.shrink_to_fit();
8598void PeerManagerImpl::MaybeSendSendHeaders(
CNode &
node, Peer &peer) {
8603 if (!peer.m_sent_sendheaders &&
8606 CNodeState &state = *State(
node.GetId());
8607 if (state.pindexBestKnownBlock !=
nullptr &&
8608 state.pindexBestKnownBlock->nChainWork >
8615 peer.m_sent_sendheaders =
true;
8620void PeerManagerImpl::MaybeSendFeefilter(
8621 CNode &pto, Peer &peer, std::chrono::microseconds current_time) {
8622 if (m_opts.ignore_incoming_txs) {
8646 static const Amount MAX_FILTER{m_fee_filter_rounder.round(
MAX_MONEY)};
8647 if (peer.m_fee_filter_sent == MAX_FILTER) {
8650 peer.m_next_send_feefilter = 0us;
8653 if (current_time > peer.m_next_send_feefilter) {
8654 Amount filterToSend = m_fee_filter_rounder.round(currentFilter);
8656 filterToSend = std::max(
8658 if (filterToSend != peer.m_fee_filter_sent) {
8660 peer.m_fee_filter_sent = filterToSend;
8662 peer.m_next_send_feefilter =
8670 peer.m_next_send_feefilter &&
8671 (currentFilter < 3 * peer.m_fee_filter_sent / 4 ||
8672 currentFilter > 4 * peer.m_fee_filter_sent / 3)) {
8673 peer.m_next_send_feefilter =
8681class CompareInvMempoolOrder {
8685 explicit CompareInvMempoolOrder(
CTxMemPool *_mempool) : mp(_mempool) {}
8687 bool operator()(std::set<TxId>::iterator a, std::set<TxId>::iterator b) {
8697bool PeerManagerImpl::RejectIncomingTxs(
const CNode &peer)
const {
8706 if (m_opts.ignore_incoming_txs &&
8713bool PeerManagerImpl::SetupAddressRelay(
const CNode &
node, Peer &peer) {
8717 if (
node.IsBlockOnlyConn()) {
8721 if (!peer.m_addr_relay_enabled.exchange(
true)) {
8725 peer.m_addr_known = std::make_unique<CRollingBloomFilter>(5000, 0.001);
8731bool PeerManagerImpl::SendMessages(
const Config &config,
CNode *pto) {
8734 PeerRef peer = GetPeerRef(pto->
GetId());
8743 if (MaybeDiscourageAndDisconnect(*pto, *peer)) {
8752 const auto current_time{GetTime<std::chrono::microseconds>()};
8757 "addrfetch connection timeout; disconnecting peer=%d\n",
8763 MaybeSendPing(*pto, *peer, current_time);
8770 bool sync_blocks_and_headers_from_peer =
false;
8772 MaybeSendAddr(*pto, *peer, current_time);
8774 MaybeSendSendHeaders(*pto, *peer);
8779 CNodeState &state = *State(pto->
GetId());
8782 if (m_chainman.m_best_header ==
nullptr) {
8789 if (state.fPreferredDownload) {
8790 sync_blocks_and_headers_from_peer =
true;
8801 if (m_num_preferred_download_peers == 0 ||
8802 mapBlocksInFlight.empty()) {
8803 sync_blocks_and_headers_from_peer =
true;
8807 if (!state.fSyncStarted && CanServeBlocks(*peer) &&
8811 if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) ||
8813 const CBlockIndex *pindexStart = m_chainman.m_best_header;
8822 if (pindexStart->
pprev) {
8823 pindexStart = pindexStart->
pprev;
8825 if (MaybeSendGetHeaders(*pto,
GetLocator(pindexStart), *peer)) {
8828 "initial getheaders (%d) to peer=%d (startheight:%d)\n",
8830 peer->m_starting_height);
8832 state.fSyncStarted =
true;
8833 peer->m_headers_sync_timeout =
8838 std::chrono::microseconds{
8840 Ticks<std::chrono::seconds>(
8842 m_chainman.m_best_header->Time()) /
8859 LOCK(peer->m_block_inv_mutex);
8860 std::vector<CBlock> vHeaders;
8862 ((!peer->m_prefers_headers &&
8863 (!state.m_requested_hb_cmpctblocks ||
8864 peer->m_blocks_for_headers_relay.size() > 1)) ||
8865 peer->m_blocks_for_headers_relay.size() >
8870 ProcessBlockAvailability(pto->
GetId());
8872 if (!fRevertToInv) {
8873 bool fFoundStartingHeader =
false;
8877 for (
const BlockHash &hash : peer->m_blocks_for_headers_relay) {
8883 fRevertToInv =
true;
8886 if (pBestIndex !=
nullptr && pindex->
pprev != pBestIndex) {
8897 fRevertToInv =
true;
8900 pBestIndex = pindex;
8901 if (fFoundStartingHeader) {
8904 }
else if (PeerHasHeader(&state, pindex)) {
8907 }
else if (pindex->
pprev ==
nullptr ||
8908 PeerHasHeader(&state, pindex->
pprev)) {
8911 fFoundStartingHeader =
true;
8916 fRevertToInv =
true;
8921 if (!fRevertToInv && !vHeaders.empty()) {
8922 if (vHeaders.size() == 1 && state.m_requested_hb_cmpctblocks) {
8927 "%s sending header-and-ids %s to peer=%d\n",
8928 __func__, vHeaders.front().GetHash().ToString(),
8931 std::optional<CSerializedNetMsg> cached_cmpctblock_msg;
8933 LOCK(m_most_recent_block_mutex);
8934 if (m_most_recent_block_hash ==
8936 cached_cmpctblock_msg =
8938 *m_most_recent_compact_block);
8941 if (cached_cmpctblock_msg.has_value()) {
8943 std::move(cached_cmpctblock_msg.value()));
8947 block, *pBestIndex)};
8954 state.pindexBestHeaderSent = pBestIndex;
8955 }
else if (peer->m_prefers_headers) {
8956 if (vHeaders.size() > 1) {
8958 "%s: %u headers, range (%s, %s), to peer=%d\n",
8959 __func__, vHeaders.size(),
8960 vHeaders.front().GetHash().ToString(),
8961 vHeaders.back().GetHash().ToString(),
8965 "%s: sending header %s to peer=%d\n", __func__,
8966 vHeaders.front().GetHash().ToString(),
8970 state.pindexBestHeaderSent = pBestIndex;
8972 fRevertToInv =
true;
8979 if (!peer->m_blocks_for_headers_relay.empty()) {
8981 peer->m_blocks_for_headers_relay.back();
8992 "Announcing block %s not on main chain (tip=%s)\n",
9001 if (!PeerHasHeader(&state, pindex)) {
9002 peer->m_blocks_for_inv_relay.push_back(hashToAnnounce);
9004 "%s: sending inv peer=%d hash=%s\n", __func__,
9009 peer->m_blocks_for_headers_relay.clear();
9016 std::vector<CInv> vInv;
9017 auto addInvAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
9018 vInv.emplace_back(type, hash);
9029 LOCK(peer->m_block_inv_mutex);
9031 vInv.reserve(std::max<size_t>(peer->m_blocks_for_inv_relay.size(),
9037 for (
const BlockHash &hash : peer->m_blocks_for_inv_relay) {
9040 peer->m_blocks_for_inv_relay.clear();
9043 auto computeNextInvSendTime =
9044 [&](std::chrono::microseconds &next)
9048 if (next < current_time) {
9049 fSendTrickle =
true;
9051 next = NextInvToInbounds(
9056 next = current_time;
9060 return fSendTrickle;
9064 if (peer->m_proof_relay !=
nullptr) {
9065 LOCK(peer->m_proof_relay->m_proof_inventory_mutex);
9067 if (computeNextInvSendTime(
9068 peer->m_proof_relay->m_next_inv_send_time)) {
9070 peer->m_proof_relay->m_proof_inventory_to_send.begin();
9072 peer->m_proof_relay->m_proof_inventory_to_send.end()) {
9075 it = peer->m_proof_relay->m_proof_inventory_to_send.erase(
9078 if (peer->m_proof_relay->m_proof_inventory_known_filter
9079 .contains(proofid)) {
9083 peer->m_proof_relay->m_proof_inventory_known_filter.insert(
9086 peer->m_proof_relay->m_recently_announced_proofs.insert(
9092 if (
auto tx_relay = peer->GetTxRelay()) {
9093 LOCK(tx_relay->m_tx_inventory_mutex);
9095 const bool fSendTrickle =
9096 computeNextInvSendTime(tx_relay->m_next_inv_send_time);
9101 LOCK(tx_relay->m_bloom_filter_mutex);
9102 if (!tx_relay->m_relay_txs) {
9103 tx_relay->m_tx_inventory_to_send.clear();
9108 if (fSendTrickle && tx_relay->m_send_mempool) {
9109 auto vtxinfo = m_mempool.
infoAll();
9110 tx_relay->m_send_mempool =
false;
9112 tx_relay->m_fee_filter_received.load()};
9114 LOCK(tx_relay->m_bloom_filter_mutex);
9116 for (
const auto &txinfo : vtxinfo) {
9117 const TxId &txid = txinfo.tx->GetId();
9118 tx_relay->m_tx_inventory_to_send.erase(txid);
9121 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
9124 if (tx_relay->m_bloom_filter &&
9125 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
9129 tx_relay->m_tx_inventory_known_filter.insert(txid);
9132 addInvAndMaybeFlush(
MSG_TX, txid);
9134 tx_relay->m_last_mempool_req =
9135 std::chrono::duration_cast<std::chrono::seconds>(
9142 std::vector<std::set<TxId>::iterator> vInvTx;
9143 vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size());
9144 for (std::set<TxId>::iterator it =
9145 tx_relay->m_tx_inventory_to_send.begin();
9146 it != tx_relay->m_tx_inventory_to_send.end(); it++) {
9147 vInvTx.push_back(it);
9150 tx_relay->m_fee_filter_received.load()};
9155 CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool);
9156 std::make_heap(vInvTx.begin(), vInvTx.end(),
9157 compareInvMempoolOrder);
9161 unsigned int nRelayedTransactions = 0;
9162 LOCK(tx_relay->m_bloom_filter_mutex);
9163 while (!vInvTx.empty() &&
9168 std::pop_heap(vInvTx.begin(), vInvTx.end(),
9169 compareInvMempoolOrder);
9170 std::set<TxId>::iterator it = vInvTx.back();
9172 const TxId txid = *it;
9174 tx_relay->m_tx_inventory_to_send.erase(it);
9176 if (tx_relay->m_tx_inventory_known_filter.contains(txid) &&
9177 tx_relay->m_avalanche_stalled_txids.count(txid) == 0) {
9181 auto txinfo = m_mempool.
info(txid);
9187 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
9190 if (tx_relay->m_bloom_filter &&
9191 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
9196 tx_relay->m_recently_announced_invs.insert(txid);
9197 addInvAndMaybeFlush(
MSG_TX, txid);
9198 nRelayedTransactions++;
9199 tx_relay->m_tx_inventory_known_filter.insert(txid);
9200 tx_relay->m_avalanche_stalled_txids.erase(txid);
9206 if (!vInv.empty()) {
9213 CNodeState &state = *State(pto->
GetId());
9216 auto stalling_timeout = m_block_stalling_timeout.load();
9217 if (state.m_stalling_since.count() &&
9218 state.m_stalling_since < current_time - stalling_timeout) {
9223 LogPrintf(
"Peer=%d is stalling block download, disconnecting\n",
9228 const auto new_timeout =
9230 if (stalling_timeout != new_timeout &&
9231 m_block_stalling_timeout.compare_exchange_strong(
9232 stalling_timeout, new_timeout)) {
9235 "Increased stalling timeout temporarily to %d seconds\n",
9247 if (state.vBlocksInFlight.size() > 0) {
9248 QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
9249 int nOtherPeersWithValidatedDownloads =
9250 m_peers_downloading_from - 1;
9252 state.m_downloading_since +
9253 std::chrono::seconds{consensusParams.nPowTargetSpacing} *
9256 nOtherPeersWithValidatedDownloads)) {
9257 LogPrintf(
"Timeout downloading block %s from peer=%d, "
9259 queuedBlock.pindex->GetBlockHash().ToString(),
9267 if (state.fSyncStarted &&
9268 peer->m_headers_sync_timeout < std::chrono::microseconds::max()) {
9271 if (current_time > peer->m_headers_sync_timeout &&
9272 nSyncStarted == 1 &&
9273 (m_num_preferred_download_peers -
9274 state.fPreferredDownload >=
9283 LogPrintf(
"Timeout downloading headers from peer=%d, "
9289 LogPrintf(
"Timeout downloading headers from noban "
9290 "peer=%d, not disconnecting\n",
9296 state.fSyncStarted =
false;
9298 peer->m_headers_sync_timeout = 0us;
9304 peer->m_headers_sync_timeout = std::chrono::microseconds::max();
9310 ConsiderEviction(*pto, *peer, GetTime<std::chrono::seconds>());
9313 std::vector<CInv> vGetData;
9321 CNodeState &state = *State(pto->
GetId());
9323 if (CanServeBlocks(*peer) &&
9324 ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) ||
9327 std::vector<const CBlockIndex *> vToDownload;
9329 auto get_inflight_budget = [&state]() {
9332 static_cast<int>(state.vBlocksInFlight.size()));
9338 FindNextBlocksToDownload(*peer, get_inflight_budget(), vToDownload,
9341 !IsLimitedPeer(*peer)) {
9347 m_chainman.GetSnapshotBaseBlock());
9349 TryDownloadingHistoricalBlocks(
9350 *peer, get_inflight_budget(), vToDownload, from_tip,
9351 Assert(m_chainman.GetSnapshotBaseBlock()));
9355 BlockRequested(config, pto->
GetId(), *pindex);
9360 if (state.vBlocksInFlight.empty() && staller != -1) {
9361 if (State(staller)->m_stalling_since == 0us) {
9362 State(staller)->m_stalling_since = current_time;
9369 auto addGetDataAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
9370 CInv inv(type, hash);
9373 vGetData.push_back(std::move(inv));
9384 LOCK(cs_proofrequest);
9385 std::vector<std::pair<NodeId, avalanche::ProofId>> expired;
9387 m_proofrequest.GetRequestable(pto->
GetId(), current_time, &expired);
9388 for (
const auto &entry : expired) {
9390 "timeout of inflight proof %s from peer=%d\n",
9391 entry.second.ToString(), entry.first);
9393 for (
const auto &proofid : requestable) {
9394 if (!AlreadyHaveProof(proofid)) {
9396 m_proofrequest.RequestedData(
9397 pto->
GetId(), proofid,
9404 m_proofrequest.ForgetInvId(proofid);
9414 std::vector<std::pair<NodeId, TxId>> expired;
9416 m_txrequest.GetRequestable(pto->
GetId(), current_time, &expired);
9417 for (
const auto &entry : expired) {
9419 entry.second.ToString(), entry.first);
9421 for (
const TxId &txid : requestable) {
9425 if (!AlreadyHaveTx(txid,
false)) {
9426 addGetDataAndMaybeFlush(
MSG_TX, txid);
9427 m_txrequest.RequestedData(
9434 m_txrequest.ForgetInvId(txid);
9438 if (!vGetData.empty()) {
9443 MaybeSendFeefilter(*pto, *peer, current_time);
9447bool PeerManagerImpl::ReceivedAvalancheProof(
CNode &
node, Peer &peer,
9452 LogError(
"ReceivedAvalancheProof: proof is null\n");
9458 AddKnownProof(peer, proofid);
9470 return node.m_avalanche_pubkey.has_value());
9471 auto saveProofIfStaker = [
this, isStaker](
const CNode &
node,
9473 const NodeId nodeid) ->
bool {
9485 LOCK(cs_proofrequest);
9486 m_proofrequest.ReceivedResponse(nodeid, proofid);
9488 if (AlreadyHaveProof(proofid)) {
9489 m_proofrequest.ForgetInvId(proofid);
9490 saveProofIfStaker(
node, proofid, nodeid);
9498 const auto now{GetTime<std::chrono::seconds>()};
9502 return pm.registerProof(proof, state);
9504 WITH_LOCK(cs_proofrequest, m_proofrequest.ForgetInvId(proofid));
9505 RelayProof(proofid);
9507 node.m_last_proof_time = now;
9510 nodeid, proofid.ToString());
9530 auto × = peer.m_invalid_avaproof_times;
9534 std::find_if(times.begin(), times.end(), [now](
const auto &t) {
9535 return t > now - AVALANCHE_INVALID_AVAPROOFS_INTERVAL;
9537 times.push_back(now);
9539 Misbehaving(peer,
"too-many-invalid-avaproofs");
9550 "Not polling the avalanche proof (%s): peer=%d, proofid %s\n",
9551 state.
IsValid() ?
"not-worth-polling"
9553 nodeid, proofid.ToString());
9556 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::string ToString() 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.
bool GetUseAddrmanOutgoing() const
Fee rate in satoshis per virtualbyte: Amount / vB the feerate is represented internally as FeeFrac.
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
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.
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
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::vector< uint8_t > GetKey() const
std::string ToStringAddrPort() 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 setAvalancheFinalized(const CTxMemPoolEntryRef &tx, const Consensus::Params ¶ms, const CBlockIndex &active_chain_tip, Chainstate &active_chainstate, std::vector< TxId > &finalizedTxIds) EXCLUSIVE_LOCKS_REQUIRED(bool isAvalancheFinalizedPreConsensus(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
bool CompareTopologically(const TxId &txida, const TxId &txidb) const
TxMempoolInfo info(const TxId &txid) const
size_t DynamicMemoryUsage() const
std::vector< TxMempoolInfo > infoAll() const
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)
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
Double ended buffer combining vector and stream-like interfaces.
void ignore(size_t num_ignore)
uint64_t rand64() noexcept
Generate a random 64-bit integer.
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< 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 StartScheduledTasks(CScheduler &scheduler)=0
Begin running background tasks, should only be called once.
virtual bool IgnoresIncomingTxs()=0
Whether this node ignores txs received over p2p.
virtual void ProcessMessage(const Config &config, CNode &pfrom, const std::string &msg_type, DataStream &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 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.
void BlockInvalidated(const CBlockIndex *pindex, const std::shared_ptr< const CBlock > &block)
void TransactionInvalidated(const CTransactionRef &tx, std::shared_ptr< const std::vector< Coin > > spent_coins)
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 addNode(NodeId nodeid, const ProofId &proofid, size_t max_elements)
Node API.
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
void clearRemoteProofs(NodeId nodeid)
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
const ProofPool & getDanglingProofPool() 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 isPreconsensusActivated(const CBlockIndex *pprev) const EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizationTip)
bool sendHello(CNode *pfrom) EXCLUSIVE_LOCKS_REQUIRED(!cs_delayedAvahelloNodeIds)
Send a avahello message.
void setRecentlyFinalized(const uint256 &itemId) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
size_t getMaxElementPoll() const
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
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)
void forEachProof(Callable &&func) const
std::vector< uint32_t > indices
constexpr bool IsNull() const
std::string ToString() const
std::string GetHex() const
Generate a new block, without valid proof-of-work.
bool ReadRawBlock(std::vector< uint8_t > &block, const FlatFilePos &pos) const
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool LoadingBlocks() const
bool IsPruneMode() const
Whether running in -prune mode.
bool ReadBlock(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
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 LogDebug(category,...)
CSerializedNetMsg Make(std::string msg_type, Args &&...args)
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 AVALANCHE_INVALID_AVAPROOFS_INTERVAL
Interval to look back for bad avaproofs.
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 constexpr auto GETAVAPROOFS_INTERVAL
Minimum time between 2 successive getavaproofs messages from the same peer.
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 constexpr size_t AVALANCHE_MAX_INVALID_AVAPROOFS
Maximum number of failed avaproof registrations (e.g.
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_LEGACY
Legacy maximum element poll.
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.
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.
static const int AVALANCHE_MAX_ELEMENT_BUMP_VERSION
Avalanche can poll up to 1024 items per message starting with this version.
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
static std::string ToString(const CService &ip)
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.
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
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
StakeContenderIds are unique for each block to ensure that the peer polling for their acceptance has ...
ValidationSignals * signals
ValidationSignals * signals
CFeeRate min_relay_feerate
A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation)
#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.
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::optional< std::vector< Coin > > GetSpentCoins(const CTransactionRef &ptx, const CCoinsViewCache &coins_view)
Get the coins spent by ptx from the coins_view.
arith_uint256 CalculateClaimedHeadersWork(const std::vector< CBlockHeader > &headers)
Return the sum of the claimed work on a given set of headers.
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...