54#include <boost/multi_index/hashed_index.hpp>
55#include <boost/multi_index/member.hpp>
56#include <boost/multi_index/ordered_index.hpp>
57#include <boost/multi_index_container.hpp>
69#include <unordered_set>
118 "Max protocol message length must be greater than largest "
119 "possible INV message");
176 std::chrono::seconds(2),
177 std::chrono::seconds(2),
178 std::chrono::seconds(60),
185 std::chrono::seconds(2),
186 std::chrono::seconds(2),
187 std::chrono::seconds(60),
220 "MAX_BLOCKTXN_DEPTH too high");
279 std::chrono::seconds{1},
280 "INVENTORY_RELAY_MAX too low");
331 std::unique_ptr<PartiallyDownloadedBlock> partialBlock;
336 std::chrono::seconds timeAdded;
338 StalledTxId(
TxId txid_, std::chrono::seconds timeAdded_)
339 : txid(txid_), timeAdded(timeAdded_){};
345using StalledTxIdSet = boost::multi_index_container<
347 boost::multi_index::indexed_by<
349 boost::multi_index::hashed_unique<
350 boost::multi_index::tag<by_txid>,
351 boost::multi_index::member<StalledTxId, TxId, &StalledTxId::txid>,
354 boost::multi_index::ordered_non_unique<
355 boost::multi_index::tag<by_time>,
356 boost::multi_index::member<StalledTxId, std::chrono::seconds,
357 &StalledTxId::timeAdded>>>>;
394 std::atomic<ServiceFlags> m_their_services{
NODE_NONE};
397 Mutex m_misbehavior_mutex;
402 bool m_should_discourage
GUARDED_BY(m_misbehavior_mutex){
false};
405 Mutex m_block_inv_mutex;
411 std::vector<BlockHash> m_blocks_for_inv_relay
GUARDED_BY(m_block_inv_mutex);
417 std::vector<BlockHash>
418 m_blocks_for_headers_relay
GUARDED_BY(m_block_inv_mutex);
429 std::atomic<int> m_starting_height{-1};
432 std::atomic<uint64_t> m_ping_nonce_sent{0};
434 std::atomic<std::chrono::microseconds> m_ping_start{0us};
436 std::atomic<bool> m_ping_queued{
false};
446 std::chrono::microseconds m_next_send_feefilter
459 bool m_relay_txs
GUARDED_BY(m_bloom_filter_mutex){
false};
464 std::unique_ptr<CBloomFilter>
480 GUARDED_BY(m_tx_inventory_mutex){50000, 0.000001};
486 std::set<TxId> m_tx_inventory_to_send
GUARDED_BY(m_tx_inventory_mutex);
492 bool m_send_mempool
GUARDED_BY(m_tx_inventory_mutex){
false};
494 std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
499 std::chrono::microseconds
500 m_next_inv_send_time
GUARDED_BY(m_tx_inventory_mutex){0};
506 std::atomic<Amount> m_fee_filter_received{
Amount::zero()};
512 m_avalanche_stalled_txids
GUARDED_BY(m_tx_inventory_mutex);
520 LOCK(m_tx_relay_mutex);
522 m_tx_relay = std::make_unique<Peer::TxRelay>();
523 return m_tx_relay.get();
527 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
529 const TxRelay *GetTxRelay() const
531 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
536 std::set<avalanche::ProofId>
537 m_proof_inventory_to_send
GUARDED_BY(m_proof_inventory_mutex);
540 GUARDED_BY(m_proof_inventory_mutex){10000, 0.000001};
547 std::chrono::microseconds m_next_inv_send_time{0};
551 std::atomic<std::chrono::seconds> lastSharedProofsUpdate{0s};
552 std::atomic<bool> compactproofs_requested{
false};
559 const std::unique_ptr<ProofRelay> m_proof_relay;
564 std::vector<CAddress>
576 std::unique_ptr<CRollingBloomFilter>
594 std::atomic_bool m_addr_relay_enabled{
false};
598 mutable Mutex m_addr_send_times_mutex;
600 std::chrono::microseconds
601 m_next_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
603 std::chrono::microseconds
604 m_next_local_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
609 std::atomic_bool m_wants_addrv2{
false};
613 mutable Mutex m_addr_token_bucket_mutex;
618 double m_addr_token_bucket
GUARDED_BY(m_addr_token_bucket_mutex){1.0};
620 std::chrono::microseconds
622 GetTime<std::chrono::microseconds>()};
624 std::atomic<uint64_t> m_addr_rate_limited{0};
629 std::atomic<uint64_t> m_addr_processed{0};
635 bool m_inv_triggered_getheaders_before_sync
639 Mutex m_getdata_requests_mutex;
641 std::deque<CInv> m_getdata_requests
GUARDED_BY(m_getdata_requests_mutex);
648 Mutex m_headers_sync_mutex;
653 std::unique_ptr<HeadersSyncState>
658 std::atomic<bool> m_sent_sendheaders{
false};
661 std::chrono::microseconds m_headers_sync_timeout
672 : m_id(id), m_our_services{our_services},
673 m_proof_relay(fRelayProofs ?
std::make_unique<ProofRelay>()
677 mutable Mutex m_tx_relay_mutex;
680 std::unique_ptr<TxRelay> m_tx_relay
GUARDED_BY(m_tx_relay_mutex);
683using PeerRef = std::shared_ptr<Peer>;
701 bool fSyncStarted{
false};
704 std::chrono::microseconds m_stalling_since{0us};
705 std::list<QueuedBlock> vBlocksInFlight;
708 std::chrono::microseconds m_downloading_since{0us};
710 bool fPreferredDownload{
false};
715 bool m_requested_hb_cmpctblocks{
false};
717 bool m_provides_cmpctblocks{
false};
745 struct ChainSyncTimeoutState {
748 std::chrono::seconds m_timeout{0s};
752 bool m_sent_getheaders{
false};
755 bool m_protect{
false};
758 ChainSyncTimeoutState m_chain_sync;
761 int64_t m_last_block_announcement{0};
764 const bool m_is_inbound;
766 CNodeState(
bool is_inbound) : m_is_inbound(is_inbound) {}
777 const std::shared_ptr<const CBlock> &pblock,
785 bool fInitialDownload)
override
791 const std::shared_ptr<const CBlock> &pblock)
override
800 !m_headers_presync_mutex);
802 std::atomic<bool> &interrupt)
override
804 !m_recent_confirmed_transactions_mutex,
805 !m_most_recent_block_mutex, !cs_proofrequest,
806 !m_headers_presync_mutex, g_msgproc_mutex);
809 !m_recent_confirmed_transactions_mutex,
810 !m_most_recent_block_mutex, !cs_proofrequest,
816 std::optional<std::string>
823 void RelayTransaction(const
TxId &txid) override
825 void RelayProof(const
avalanche::ProofId &proofid) override
827 void SetBestHeight(
int height)
override { m_best_height = height; };
830 Misbehaving(*
Assert(GetPeerRef(peer_id)),
"");
833 const std::string &msg_type,
DataStream &vRecv,
834 const std::chrono::microseconds time_received,
835 const std::atomic<bool> &interruptMsgProc)
override
837 !m_recent_confirmed_transactions_mutex,
838 !m_most_recent_block_mutex, !cs_proofrequest,
839 !m_headers_presync_mutex, g_msgproc_mutex);
841 int64_t time_in_seconds)
override;
848 void ConsiderEviction(
CNode &pto, Peer &peer,
849 std::chrono::seconds time_in_seconds)
856 void EvictExtraOutboundPeers(std::chrono::seconds now)
863 void ReattemptInitialBroadcast(
CScheduler &scheduler)
869 void UpdateAvalancheStatistics()
const;
874 void AvalanchePeriodicNetworking(
CScheduler &scheduler)
const;
892 void Misbehaving(Peer &peer,
const std::string &message);
904 void MaybePunishNodeForBlock(
NodeId nodeid,
906 bool via_compact_block,
907 const std::string &message =
"")
915 const
std::
string &message = "")
927 bool MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer);
945 bool maybe_add_extra_compact_tx)
948 struct PackageToValidate {
950 const std::vector<NodeId> m_senders;
955 : m_txns{parent, child}, m_senders{parent_sender, child_sender} {}
958 Assume(m_txns.size() == 2);
960 "parent %s (sender=%d) + child %s (sender=%d)",
961 m_txns.front()->GetId().ToString(), m_senders.front(),
962 m_txns.back()->GetId().ToString(), m_senders.back());
971 void ProcessPackageResult(
const PackageToValidate &package_to_validate,
981 std::optional<PackageToValidate> Find1P1CPackage(
const CTransactionRef &ptx,
1008 bool ProcessOrphanTx(
const Config &config, Peer &peer)
1021 void ProcessHeadersMessage(
const Config &config,
CNode &pfrom, Peer &peer,
1022 std::vector<CBlockHeader> &&headers,
1023 bool via_compact_block)
1033 bool CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
1043 void HandleUnconnectingHeaders(
CNode &pfrom, Peer &peer,
1044 const std::vector<CBlockHeader> &headers)
1048 CheckHeadersAreContinuous(
const std::vector<CBlockHeader> &headers)
const;
1068 bool IsContinuationOfLowWorkHeadersSync(Peer &peer,
CNode &pfrom,
1069 std::vector<CBlockHeader> &headers)
1071 !m_headers_presync_mutex, g_msgproc_mutex);
1085 bool TryLowWorkHeadersSync(Peer &peer,
CNode &pfrom,
1087 std::vector<CBlockHeader> &headers)
1089 !m_headers_presync_mutex, g_msgproc_mutex);
1095 bool IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header)
1109 void HeadersDirectFetchBlocks(
const Config &config,
CNode &pfrom,
1112 void UpdatePeerStateForReceivedHeaders(
CNode &pfrom, Peer &peer,
1114 bool received_new_header,
1115 bool may_have_more_headers)
1118 void SendBlockTransactions(
CNode &pfrom, Peer &peer,
const CBlock &block,
1127 std::chrono::microseconds current_time)
1137 std::chrono::microseconds current_time,
bool preferred)
1142 m_connman.PushMessage(&
node, std::move(
msg));
1144 template <
typename... Args>
1145 void MakeAndPushMessage(
CNode &
node, std::string msg_type,
1146 Args &&...args)
const {
1148 std::forward<Args>(args)...));
1152 void PushNodeVersion(
const Config &config,
CNode &pnode,
const Peer &peer);
1160 void MaybeSendPing(
CNode &node_to, Peer &peer,
1161 std::chrono::microseconds now);
1164 void MaybeSendAddr(
CNode &
node, Peer &peer,
1165 std::chrono::microseconds current_time)
1172 void MaybeSendSendHeaders(
CNode &
node, Peer &peer)
1176 void MaybeSendFeefilter(
CNode &
node, Peer &peer,
1177 std::chrono::microseconds current_time)
1189 void RelayAddress(
NodeId originator,
const CAddress &addr,
bool fReachable)
1210 Mutex cs_proofrequest;
1215 std::atomic<int> m_best_height{-1};
1220 const Options m_opts;
1222 bool RejectIncomingTxs(
const CNode &peer)
const;
1234 mutable Mutex m_peer_mutex;
1241 std::map<NodeId, PeerRef> m_peer_map
GUARDED_BY(m_peer_mutex);
1250 const CNodeState *State(
NodeId pnode)
const
1255 std::atomic<std::chrono::microseconds> m_next_inv_to_inbounds{0us};
1262 m_last_block_inv_triggering_headers_sync
GUARDED_BY(g_msgproc_mutex){};
1270 std::map<BlockHash, std::pair<NodeId, bool>>
1280 std::atomic<std::chrono::seconds> m_block_stalling_timeout{
1294 bool AlreadyHaveTx(
const TxId &txid,
bool include_reconsiderable)
1296 !m_recent_confirmed_transactions_mutex);
1359 mutable Mutex m_recent_confirmed_transactions_mutex;
1361 GUARDED_BY(m_recent_confirmed_transactions_mutex){24'000, 0.000'001};
1370 std::chrono::microseconds
1371 NextInvToInbounds(std::chrono::microseconds now,
1372 std::chrono::seconds average_interval)
1377 mutable Mutex m_most_recent_block_mutex;
1378 std::shared_ptr<const CBlock>
1379 m_most_recent_block
GUARDED_BY(m_most_recent_block_mutex);
1380 std::shared_ptr<const CBlockHeaderAndShortTxIDs>
1381 m_most_recent_compact_block
GUARDED_BY(m_most_recent_block_mutex);
1383 std::unique_ptr<const std::map<TxId, CTransactionRef>>
1384 m_most_recent_block_txs
GUARDED_BY(m_most_recent_block_mutex);
1389 Mutex m_headers_presync_mutex;
1400 using HeadersPresyncStats =
1401 std::pair<arith_uint256, std::optional<std::pair<int64_t, uint32_t>>>;
1403 std::map<NodeId, HeadersPresyncStats>
1404 m_headers_presync_stats
GUARDED_BY(m_headers_presync_mutex){};
1408 std::atomic_bool m_headers_presync_should_signal{
false};
1416 bool IsBlockRequested(
const BlockHash &hash)
1420 bool IsBlockRequestedFromOutbound(
const BlockHash &hash)
1431 void RemoveBlockRequest(
const BlockHash &hash,
1432 std::optional<NodeId> from_peer)
1441 bool BlockRequested(
const Config &config,
NodeId nodeid,
1443 std::list<QueuedBlock>::iterator **pit =
nullptr)
1452 void FindNextBlocksToDownload(const Peer &peer,
unsigned int count,
1458 void TryDownloadingHistoricalBlocks(
1459 const Peer &peer,
unsigned int count,
1493 const Peer &peer, CNodeState *state,
1495 int nWindowEnd, const
CChain *activeChain =
nullptr,
1496 NodeId *nodeStaller =
nullptr)
1506 std::atomic<
std::chrono::seconds> m_last_tip_update{0s};
1513 const std::chrono::seconds mempool_req,
1514 const std::chrono::seconds now)
1519 void ProcessGetData(
const Config &config,
CNode &pfrom, Peer &peer,
1520 const std::atomic<bool> &interruptMsgProc)
1522 peer.m_getdata_requests_mutex,
1528 const std::shared_ptr<const CBlock> &block,
1529 bool force_processing,
bool min_pow_checked);
1537 void MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid)
1556 std::vector<CTransactionRef>
1557 vExtraTxnForCompact
GUARDED_BY(g_msgproc_mutex);
1559 size_t vExtraTxnForCompactIt
GUARDED_BY(g_msgproc_mutex) = 0;
1564 void ProcessBlockAvailability(
NodeId nodeid)
1579 bool BlockRequestAllowed(const
CBlockIndex *pindex)
1581 bool AlreadyHaveBlock(const
BlockHash &block_hash)
1583 bool AlreadyHaveProof(const
avalanche::ProofId &proofid);
1584 void ProcessGetBlockData(const
Config &config,
CNode &pfrom, Peer &peer,
1607 bool PrepareBlockFilterRequest(
CNode &
node, Peer &peer,
1609 uint32_t start_height,
1611 uint32_t max_height_diff,
1653 uint32_t GetAvalancheVoteForBlock(const
BlockHash &hash) const
1664 const
TxId &
id) const
1666 !m_recent_confirmed_transactions_mutex);
1675 bool SetupAddressRelay(const
CNode &
node, Peer &peer)
1678 void AddAddressKnown(Peer &peer, const
CAddress &addr)
1680 void PushAddress(Peer &peer, const
CAddress &addr)
1688 bool ReceivedAvalancheProof(
CNode &
node, Peer &peer,
1694 const
std::chrono::seconds now)
1697 bool isPreferredDownloadPeer(const
CNode &pfrom);
1700const CNodeState *PeerManagerImpl::State(
NodeId pnode) const
1702 std::map<NodeId, CNodeState>::const_iterator it = m_node_states.find(pnode);
1703 if (it == m_node_states.end()) {
1710CNodeState *PeerManagerImpl::State(
NodeId pnode)
1712 return const_cast<CNodeState *
>(std::as_const(*this).State(pnode));
1720static bool IsAddrCompatible(
const Peer &peer,
const CAddress &addr) {
1724void PeerManagerImpl::AddAddressKnown(Peer &peer,
const CAddress &addr) {
1725 assert(peer.m_addr_known);
1726 peer.m_addr_known->insert(addr.
GetKey());
1729void PeerManagerImpl::PushAddress(Peer &peer,
const CAddress &addr) {
1733 assert(peer.m_addr_known);
1734 if (addr.
IsValid() && !peer.m_addr_known->contains(addr.
GetKey()) &&
1735 IsAddrCompatible(peer, addr)) {
1736 if (peer.m_addrs_to_send.size() >= m_opts.max_addr_to_send) {
1737 peer.m_addrs_to_send[m_rng.randrange(peer.m_addrs_to_send.size())] =
1740 peer.m_addrs_to_send.push_back(addr);
1745static void AddKnownTx(Peer &peer,
const TxId &txid) {
1746 auto tx_relay = peer.GetTxRelay();
1751 LOCK(tx_relay->m_tx_inventory_mutex);
1752 tx_relay->m_tx_inventory_known_filter.insert(txid);
1756 if (peer.m_proof_relay !=
nullptr) {
1757 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
1758 peer.m_proof_relay->m_proof_inventory_known_filter.insert(proofid);
1762bool PeerManagerImpl::isPreferredDownloadPeer(
const CNode &pfrom) {
1764 const CNodeState *state = State(pfrom.
GetId());
1765 return state && state->fPreferredDownload;
1768static bool CanServeBlocks(
const Peer &peer) {
1776static bool IsLimitedPeer(
const Peer &peer) {
1781std::chrono::microseconds
1782PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
1783 std::chrono::seconds average_interval) {
1784 if (m_next_inv_to_inbounds.load() < now) {
1789 m_next_inv_to_inbounds =
1790 now + m_rng.rand_exp_duration(average_interval);
1792 return m_next_inv_to_inbounds;
1795bool PeerManagerImpl::IsBlockRequested(
const BlockHash &hash) {
1796 return mapBlocksInFlight.count(hash);
1799bool PeerManagerImpl::IsBlockRequestedFromOutbound(
const BlockHash &hash) {
1800 for (
auto range = mapBlocksInFlight.equal_range(hash);
1801 range.first != range.second; range.first++) {
1802 auto [nodeid, block_it] = range.first->second;
1803 CNodeState &nodestate = *
Assert(State(nodeid));
1804 if (!nodestate.m_is_inbound) {
1812void PeerManagerImpl::RemoveBlockRequest(
const BlockHash &hash,
1813 std::optional<NodeId> from_peer) {
1814 auto range = mapBlocksInFlight.equal_range(hash);
1815 if (range.first == range.second) {
1823 while (range.first != range.second) {
1824 auto [node_id, list_it] = range.first->second;
1826 if (from_peer && *from_peer != node_id) {
1831 CNodeState &state = *
Assert(State(node_id));
1833 if (state.vBlocksInFlight.begin() == list_it) {
1836 state.m_downloading_since =
1837 std::max(state.m_downloading_since,
1838 GetTime<std::chrono::microseconds>());
1840 state.vBlocksInFlight.erase(list_it);
1842 if (state.vBlocksInFlight.empty()) {
1844 m_peers_downloading_from--;
1846 state.m_stalling_since = 0us;
1848 range.first = mapBlocksInFlight.erase(range.first);
1852bool PeerManagerImpl::BlockRequested(
const Config &config,
NodeId nodeid,
1854 std::list<QueuedBlock>::iterator **pit) {
1857 CNodeState *state = State(nodeid);
1858 assert(state !=
nullptr);
1863 for (
auto range = mapBlocksInFlight.equal_range(hash);
1864 range.first != range.second; range.first++) {
1865 if (range.first->second.first == nodeid) {
1867 *pit = &range.first->second.second;
1874 RemoveBlockRequest(hash, nodeid);
1876 std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(
1877 state->vBlocksInFlight.end(),
1878 {&block, std::unique_ptr<PartiallyDownloadedBlock>(
1879 pit ? new PartiallyDownloadedBlock(config, &m_mempool)
1881 if (state->vBlocksInFlight.size() == 1) {
1883 state->m_downloading_since = GetTime<std::chrono::microseconds>();
1884 m_peers_downloading_from++;
1887 auto itInFlight = mapBlocksInFlight.insert(
1888 std::make_pair(hash, std::make_pair(nodeid, it)));
1891 *pit = &itInFlight->second.second;
1897void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid) {
1903 if (m_opts.ignore_incoming_txs) {
1907 CNodeState *nodestate = State(nodeid);
1912 if (!nodestate->m_provides_cmpctblocks) {
1915 int num_outbound_hb_peers = 0;
1916 for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin();
1917 it != lNodesAnnouncingHeaderAndIDs.end(); it++) {
1918 if (*it == nodeid) {
1919 lNodesAnnouncingHeaderAndIDs.erase(it);
1920 lNodesAnnouncingHeaderAndIDs.push_back(nodeid);
1923 CNodeState *state = State(*it);
1924 if (state !=
nullptr && !state->m_is_inbound) {
1925 ++num_outbound_hb_peers;
1928 if (nodestate->m_is_inbound) {
1931 if (lNodesAnnouncingHeaderAndIDs.size() >= 3 &&
1932 num_outbound_hb_peers == 1) {
1933 CNodeState *remove_node =
1934 State(lNodesAnnouncingHeaderAndIDs.front());
1935 if (remove_node !=
nullptr && !remove_node->m_is_inbound) {
1938 std::swap(lNodesAnnouncingHeaderAndIDs.front(),
1939 *std::next(lNodesAnnouncingHeaderAndIDs.begin()));
1946 if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
1950 lNodesAnnouncingHeaderAndIDs.front(), [
this](
CNode *pnodeStop) {
1951 MakeAndPushMessage(*pnodeStop, NetMsgType::SENDCMPCT,
1953 CMPCTBLOCKS_VERSION);
1956 pnodeStop->m_bip152_highbandwidth_to = false;
1959 lNodesAnnouncingHeaderAndIDs.pop_front();
1966 lNodesAnnouncingHeaderAndIDs.push_back(pfrom->
GetId());
1971bool PeerManagerImpl::TipMayBeStale() {
1974 if (m_last_tip_update.load() == 0s) {
1975 m_last_tip_update = GetTime<std::chrono::seconds>();
1977 return m_last_tip_update.load() <
1978 GetTime<std::chrono::seconds>() -
1981 mapBlocksInFlight.empty();
1984bool PeerManagerImpl::CanDirectFetch() {
1990static bool PeerHasHeader(CNodeState *state,
const CBlockIndex *pindex)
1992 if (state->pindexBestKnownBlock &&
1993 pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) {
1996 if (state->pindexBestHeaderSent &&
1997 pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight)) {
2003void PeerManagerImpl::ProcessBlockAvailability(
NodeId nodeid) {
2004 CNodeState *state = State(nodeid);
2005 assert(state !=
nullptr);
2007 if (!state->hashLastUnknownBlock.IsNull()) {
2011 if (state->pindexBestKnownBlock ==
nullptr ||
2012 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
2013 state->pindexBestKnownBlock = pindex;
2015 state->hashLastUnknownBlock.SetNull();
2020void PeerManagerImpl::UpdateBlockAvailability(
NodeId nodeid,
2022 CNodeState *state = State(nodeid);
2023 assert(state !=
nullptr);
2025 ProcessBlockAvailability(nodeid);
2030 if (state->pindexBestKnownBlock ==
nullptr ||
2031 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
2032 state->pindexBestKnownBlock = pindex;
2037 state->hashLastUnknownBlock = hash;
2043void PeerManagerImpl::FindNextBlocksToDownload(
2044 const Peer &peer,
unsigned int count,
2045 std::vector<const CBlockIndex *> &vBlocks,
NodeId &nodeStaller) {
2050 vBlocks.reserve(vBlocks.size() +
count);
2051 CNodeState *state = State(peer.m_id);
2052 assert(state !=
nullptr);
2055 ProcessBlockAvailability(peer.m_id);
2057 if (state->pindexBestKnownBlock ==
nullptr ||
2058 state->pindexBestKnownBlock->nChainWork <
2060 state->pindexBestKnownBlock->nChainWork <
2070 const CBlockIndex *snap_base{m_chainman.GetSnapshotBaseBlock()};
2071 if (snap_base && state->pindexBestKnownBlock->GetAncestor(
2072 snap_base->nHeight) != snap_base) {
2074 "Not downloading blocks from peer=%d, which doesn't have the "
2075 "snapshot block in its best chain.\n",
2084 if (state->pindexLastCommonBlock ==
nullptr ||
2086 state->pindexLastCommonBlock->nHeight < snap_base->nHeight)) {
2087 state->pindexLastCommonBlock =
2089 .
ActiveChain()[std::min(state->pindexBestKnownBlock->nHeight,
2096 state->pindexLastCommonBlock, state->pindexBestKnownBlock);
2097 if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) {
2101 const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
2109 FindNextBlocks(vBlocks, peer, state, pindexWalk,
count, nWindowEnd,
2113void PeerManagerImpl::TryDownloadingHistoricalBlocks(
2114 const Peer &peer,
unsigned int count,
2115 std::vector<const CBlockIndex *> &vBlocks,
const CBlockIndex *from_tip,
2120 if (vBlocks.size() >=
count) {
2124 vBlocks.reserve(
count);
2125 CNodeState *state =
Assert(State(peer.m_id));
2127 if (state->pindexBestKnownBlock ==
nullptr ||
2128 state->pindexBestKnownBlock->GetAncestor(target_block->
nHeight) !=
2143 FindNextBlocks(vBlocks, peer, state, from_tip,
count,
2148void PeerManagerImpl::FindNextBlocks(std::vector<const CBlockIndex *> &vBlocks,
2149 const Peer &peer, CNodeState *state,
2151 unsigned int count,
int nWindowEnd,
2152 const CChain *activeChain,
2154 std::vector<const CBlockIndex *> vToFetch;
2156 std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
2158 while (pindexWalk->
nHeight < nMaxHeight) {
2163 int nToFetch = std::min(nMaxHeight - pindexWalk->
nHeight,
2164 std::max<int>(
count - vBlocks.size(), 128));
2165 vToFetch.resize(nToFetch);
2166 pindexWalk = state->pindexBestKnownBlock->
GetAncestor(
2167 pindexWalk->
nHeight + nToFetch);
2168 vToFetch[nToFetch - 1] = pindexWalk;
2169 for (
unsigned int i = nToFetch - 1; i > 0; i--) {
2170 vToFetch[i - 1] = vToFetch[i]->
pprev;
2183 if (pindex->nStatus.hasData() ||
2184 (activeChain && activeChain->
Contains(pindex))) {
2186 state->pindexLastCommonBlock = pindex;
2188 }
else if (!IsBlockRequested(pindex->
GetBlockHash())) {
2190 if (pindex->
nHeight > nWindowEnd) {
2192 if (vBlocks.size() == 0 && waitingfor != peer.m_id) {
2196 *nodeStaller = waitingfor;
2201 vBlocks.push_back(pindex);
2202 if (vBlocks.size() ==
count) {
2205 }
else if (waitingfor == -1) {
2217template <
class InvId>
2221 return !
node.HasPermission(
2234template <
class InvId>
2235static std::chrono::microseconds
2239 std::chrono::microseconds current_time,
bool preferred) {
2240 auto delay = std::chrono::microseconds{0};
2252 return current_time + delay;
2255void PeerManagerImpl::PushNodeVersion(
const Config &config,
CNode &pnode,
2257 uint64_t my_services{peer.m_our_services};
2258 const int64_t nTime{
count_seconds(GetTime<std::chrono::seconds>())};
2260 const int nNodeStartingHeight{m_best_height};
2271 const bool tx_relay{!RejectIncomingTxs(pnode)};
2280 nNodeStartingHeight, tx_relay, extraEntropy);
2284 "send version message: version %d, blocks=%d, them=%s, "
2285 "txrelay=%d, peer=%d\n",
2290 "send version message: version %d, blocks=%d, "
2291 "txrelay=%d, peer=%d\n",
2296void PeerManagerImpl::AddTxAnnouncement(
2298 std::chrono::microseconds current_time) {
2306 const bool preferred = isPreferredDownloadPeer(
node);
2308 current_time, preferred);
2310 m_txrequest.ReceivedInv(
node.GetId(), txid, preferred, reqtime);
2313void PeerManagerImpl::AddProofAnnouncement(
2315 std::chrono::microseconds current_time,
bool preferred) {
2326 m_proofrequest.ReceivedInv(
node.GetId(), proofid, preferred, reqtime);
2329void PeerManagerImpl::UpdateLastBlockAnnounceTime(
NodeId node,
2330 int64_t time_in_seconds) {
2332 CNodeState *state = State(
node);
2334 state->m_last_block_announcement = time_in_seconds;
2338void PeerManagerImpl::InitializeNode(
const Config &config,
CNode &
node,
2343 m_node_states.emplace_hint(m_node_states.end(),
2344 std::piecewise_construct,
2345 std::forward_as_tuple(nodeid),
2346 std::forward_as_tuple(
node.IsInboundConn()));
2347 assert(m_txrequest.Count(nodeid) == 0);
2355 PeerRef peer = std::make_shared<Peer>(nodeid, our_services, !!m_avalanche);
2358 m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer);
2360 if (!
node.IsInboundConn()) {
2361 PushNodeVersion(config,
node, *peer);
2365void PeerManagerImpl::ReattemptInitialBroadcast(
CScheduler &scheduler) {
2368 for (
const TxId &txid : unbroadcast_txids) {
2370 if (m_mempool.
exists(txid)) {
2371 RelayTransaction(txid);
2382 auto unbroadcasted_proofids =
2386 auto it = unbroadcasted_proofids.begin();
2387 while (it != unbroadcasted_proofids.end()) {
2390 if (!pm.isBoundToPeer(*it)) {
2391 pm.removeUnbroadcastProof(*it);
2392 it = unbroadcasted_proofids.erase(it);
2399 return unbroadcasted_proofids;
2403 for (
const auto &proofid : unbroadcasted_proofids) {
2404 RelayProof(proofid);
2411 const auto reattemptBroadcastInterval =
2413 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2414 reattemptBroadcastInterval);
2417void PeerManagerImpl::UpdateAvalancheStatistics()
const {
2423void PeerManagerImpl::AvalanchePeriodicNetworking(
CScheduler &scheduler)
const {
2424 const auto now = GetTime<std::chrono::seconds>();
2425 std::vector<NodeId> avanode_ids;
2426 bool fQuorumEstablished;
2427 bool fShouldRequestMoreNodes;
2437 fShouldRequestMoreNodes =
2445 avanode_ids.push_back(pnode->GetId());
2448 PeerRef peer = GetPeerRef(pnode->
GetId());
2449 if (peer ==
nullptr) {
2453 if (peer->m_proof_relay &&
2454 now > (peer->m_proof_relay->lastSharedProofsUpdate.load() +
2456 peer->m_proof_relay->sharedProofs = {};
2460 if (avanode_ids.empty()) {
2468 for (
NodeId avanodeId : avanode_ids) {
2469 const bool sentGetavaaddr =
2472 MakeAndPushMessage(*pavanode, NetMsgType::GETAVAADDR);
2473 PeerRef peer = GetPeerRef(avanodeId);
2474 WITH_LOCK(peer->m_addr_token_bucket_mutex,
2475 peer->m_addr_token_bucket +=
2476 m_opts.max_addr_to_send);
2484 if (sentGetavaaddr && fQuorumEstablished && !fShouldRequestMoreNodes) {
2499 avanode_ids.resize(std::min<size_t>(avanode_ids.size(), 3));
2502 for (
NodeId nodeid : avanode_ids) {
2505 PeerRef peer = GetPeerRef(nodeid);
2506 if (peer->m_proof_relay) {
2508 peer->m_proof_relay->compactproofs_requested =
true;
2518 const auto avalanchePeriodicNetworkingInterval =
2520 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2521 avalanchePeriodicNetworkingInterval);
2524void PeerManagerImpl::FinalizeNode(
const Config &config,
const CNode &
node) {
2534 PeerRef peer = RemovePeer(nodeid);
2537 m_peer_map.erase(nodeid);
2539 CNodeState *state = State(nodeid);
2540 assert(state !=
nullptr);
2542 if (state->fSyncStarted) {
2546 for (
const QueuedBlock &entry : state->vBlocksInFlight) {
2548 mapBlocksInFlight.equal_range(entry.pindex->GetBlockHash());
2549 while (range.first != range.second) {
2550 auto [node_id, list_it] = range.first->second;
2551 if (node_id != nodeid) {
2554 range.first = mapBlocksInFlight.erase(range.first);
2561 m_txrequest.DisconnectedPeer(nodeid);
2562 m_num_preferred_download_peers -= state->fPreferredDownload;
2563 m_peers_downloading_from -= (!state->vBlocksInFlight.empty());
2564 assert(m_peers_downloading_from >= 0);
2565 m_outbound_peers_with_protect_from_disconnect -=
2566 state->m_chain_sync.m_protect;
2567 assert(m_outbound_peers_with_protect_from_disconnect >= 0);
2569 m_node_states.erase(nodeid);
2571 if (m_node_states.empty()) {
2573 assert(mapBlocksInFlight.empty());
2574 assert(m_num_preferred_download_peers == 0);
2575 assert(m_peers_downloading_from == 0);
2576 assert(m_outbound_peers_with_protect_from_disconnect == 0);
2577 assert(m_txrequest.Size() == 0);
2579 return orphanage.Size();
2584 if (
node.fSuccessfullyConnected && !
node.IsBlockOnlyConn() &&
2585 !
node.IsInboundConn()) {
2592 LOCK(m_headers_presync_mutex);
2593 m_headers_presync_stats.erase(nodeid);
2596 WITH_LOCK(cs_proofrequest, m_proofrequest.DisconnectedPeer(nodeid));
2601PeerRef PeerManagerImpl::GetPeerRef(
NodeId id)
const {
2603 auto it = m_peer_map.find(
id);
2604 return it != m_peer_map.end() ? it->second :
nullptr;
2607PeerRef PeerManagerImpl::RemovePeer(
NodeId id) {
2610 auto it = m_peer_map.find(
id);
2611 if (it != m_peer_map.end()) {
2612 ret = std::move(it->second);
2613 m_peer_map.erase(it);
2618bool PeerManagerImpl::GetNodeStateStats(
NodeId nodeid,
2622 const CNodeState *state = State(nodeid);
2623 if (state ==
nullptr) {
2627 ? state->pindexBestKnownBlock->nHeight
2630 ? state->pindexLastCommonBlock->nHeight
2632 for (
const QueuedBlock &queue : state->vBlocksInFlight) {
2639 PeerRef peer = GetPeerRef(nodeid);
2640 if (peer ==
nullptr) {
2652 auto ping_wait{0us};
2653 if ((0 != peer->m_ping_nonce_sent) &&
2654 (0 != peer->m_ping_start.load().count())) {
2656 GetTime<std::chrono::microseconds>() - peer->m_ping_start.load();
2659 if (
auto tx_relay = peer->GetTxRelay()) {
2661 return tx_relay->m_relay_txs);
2673 LOCK(peer->m_headers_sync_mutex);
2674 if (peer->m_headers_sync) {
2682void PeerManagerImpl::AddToCompactExtraTransactions(
const CTransactionRef &tx) {
2683 if (m_opts.max_extra_txs <= 0) {
2687 if (!vExtraTxnForCompact.size()) {
2688 vExtraTxnForCompact.resize(m_opts.max_extra_txs);
2691 vExtraTxnForCompact[vExtraTxnForCompactIt] = tx;
2692 vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
2695void PeerManagerImpl::Misbehaving(Peer &peer,
const std::string &message) {
2696 LOCK(peer.m_misbehavior_mutex);
2698 const std::string message_prefixed =
2699 message.empty() ?
"" : (
": " + message);
2700 peer.m_should_discourage =
true;
2705void PeerManagerImpl::MaybePunishNodeForBlock(
NodeId nodeid,
2707 bool via_compact_block,
2708 const std::string &message) {
2709 PeerRef peer{GetPeerRef(nodeid)};
2720 if (!via_compact_block) {
2722 Misbehaving(*peer, message);
2729 CNodeState *node_state = State(nodeid);
2730 if (node_state ==
nullptr) {
2737 if (!via_compact_block && !node_state->m_is_inbound) {
2739 Misbehaving(*peer, message);
2749 Misbehaving(*peer, message);
2755 Misbehaving(*peer, message);
2761 if (message !=
"") {
2766void PeerManagerImpl::MaybePunishNodeForTx(
NodeId nodeid,
2768 const std::string &message) {
2769 PeerRef peer{GetPeerRef(nodeid)};
2776 Misbehaving(*peer, message);
2794 if (message !=
"") {
2799bool PeerManagerImpl::BlockRequestAllowed(
const CBlockIndex *pindex) {
2805 (m_chainman.m_best_header !=
nullptr) &&
2806 (m_chainman.m_best_header->GetBlockTime() - pindex->
GetBlockTime() <
2809 *m_chainman.m_best_header, *pindex, *m_chainman.m_best_header,
2813std::optional<std::string>
2814PeerManagerImpl::FetchBlock(
const Config &config,
NodeId peer_id,
2817 return "Loading blocks ...";
2823 CNodeState *state = State(peer_id);
2824 if (state ==
nullptr) {
2825 return "Peer does not exist";
2829 RemoveBlockRequest(block_index.
GetBlockHash(), std::nullopt);
2834 if (!BlockRequested(config, peer_id, block_index)) {
2835 return "Already requested from this peer";
2844 this->MakeAndPushMessage(*node, NetMsgType::GETDATA, invs);
2847 return "Node not fully connected";
2852 return std::nullopt;
2855std::unique_ptr<PeerManager>
2859 return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman,
2868 : m_rng{opts.deterministic_rng},
2870 m_chainparams(chainman.GetParams()), m_connman(connman),
2871 m_addrman(addrman), m_banman(banman), m_chainman(chainman),
2872 m_mempool(pool), m_avalanche(
avalanche), m_opts{opts} {}
2874void PeerManagerImpl::StartScheduledTasks(
CScheduler &scheduler) {
2881 "peer eviction timer should be less than stale tip check timer");
2884 this->CheckForStaleTipAndEvictPeers();
2890 const auto reattemptBroadcastInterval =
2892 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2893 reattemptBroadcastInterval);
2898 UpdateAvalancheStatistics();
2904 const auto avalanchePeriodicNetworkingInterval =
2906 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2907 avalanchePeriodicNetworkingInterval);
2916void PeerManagerImpl::BlockConnected(
2917 ChainstateRole role,
const std::shared_ptr<const CBlock> &pblock,
2921 m_last_tip_update = GetTime<std::chrono::seconds>();
2925 auto stalling_timeout = m_block_stalling_timeout.load();
2928 const auto new_timeout =
2929 std::max(std::chrono::duration_cast<std::chrono::seconds>(
2930 stalling_timeout * 0.85),
2932 if (m_block_stalling_timeout.compare_exchange_strong(stalling_timeout,
2952 LOCK(m_recent_confirmed_transactions_mutex);
2954 m_recent_confirmed_transactions.insert(ptx->GetId());
2959 for (
const auto &ptx : pblock->vtx) {
2960 m_txrequest.ForgetInvId(ptx->GetId());
2965void PeerManagerImpl::BlockDisconnected(
2966 const std::shared_ptr<const CBlock> &block,
const CBlockIndex *pindex) {
2975 LOCK(m_recent_confirmed_transactions_mutex);
2976 m_recent_confirmed_transactions.reset();
2983void PeerManagerImpl::NewPoWValidBlock(
2984 const CBlockIndex *pindex,
const std::shared_ptr<const CBlock> &pblock) {
2985 std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock =
2986 std::make_shared<const CBlockHeaderAndShortTxIDs>(
2991 if (pindex->
nHeight <= m_highest_fast_announce) {
2994 m_highest_fast_announce = pindex->
nHeight;
2997 const std::shared_future<CSerializedNetMsg> lazy_ser{
2998 std::async(std::launch::deferred, [&] {
3003 auto most_recent_block_txs =
3004 std::make_unique<std::map<TxId, CTransactionRef>>();
3005 for (
const auto &tx : pblock->vtx) {
3006 most_recent_block_txs->emplace(tx->GetId(), tx);
3009 LOCK(m_most_recent_block_mutex);
3010 m_most_recent_block_hash = hashBlock;
3011 m_most_recent_block = pblock;
3012 m_most_recent_compact_block = pcmpctblock;
3013 m_most_recent_block_txs = std::move(most_recent_block_txs);
3017 [
this, pindex, &lazy_ser, &hashBlock](
CNode *pnode)
3025 ProcessBlockAvailability(pnode->
GetId());
3026 CNodeState &state = *State(pnode->
GetId());
3030 if (state.m_requested_hb_cmpctblocks &&
3031 !PeerHasHeader(&state, pindex) &&
3032 PeerHasHeader(&state, pindex->
pprev)) {
3034 "%s sending header-and-ids %s to peer=%d\n",
3035 "PeerManager::NewPoWValidBlock",
3036 hashBlock.ToString(), pnode->
GetId());
3039 PushMessage(*pnode, ser_cmpctblock.Copy());
3040 state.pindexBestHeaderSent = pindex;
3049void PeerManagerImpl::UpdatedBlockTip(
const CBlockIndex *pindexNew,
3051 bool fInitialDownload) {
3052 SetBestHeight(pindexNew->
nHeight);
3056 if (fInitialDownload) {
3061 std::vector<BlockHash> vHashes;
3063 while (pindexToAnnounce != pindexFork) {
3065 pindexToAnnounce = pindexToAnnounce->
pprev;
3075 for (
auto &it : m_peer_map) {
3076 Peer &peer = *it.second;
3077 LOCK(peer.m_block_inv_mutex);
3079 peer.m_blocks_for_headers_relay.push_back(hash);
3091void PeerManagerImpl::BlockChecked(
const CBlock &block,
3096 std::map<BlockHash, std::pair<NodeId, bool>>::iterator it =
3097 mapBlockSource.find(hash);
3101 if (state.
IsInvalid() && it != mapBlockSource.end() &&
3102 State(it->second.first)) {
3103 MaybePunishNodeForBlock(it->second.first, state,
3104 !it->second.second);
3113 mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
3114 if (it != mapBlockSource.end()) {
3115 MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
3119 if (it != mapBlockSource.end()) {
3120 mapBlockSource.erase(it);
3129bool PeerManagerImpl::AlreadyHaveTx(
const TxId &txid,
3130 bool include_reconsiderable) {
3132 hashRecentRejectsChainTip) {
3137 hashRecentRejectsChainTip =
3139 m_recent_rejects.reset();
3140 m_recent_rejects_package_reconsiderable.reset();
3144 return orphanage.HaveTx(txid);
3150 return conflicting.HaveTx(txid);
3155 if (include_reconsiderable &&
3156 m_recent_rejects_package_reconsiderable.contains(txid)) {
3161 LOCK(m_recent_confirmed_transactions_mutex);
3162 if (m_recent_confirmed_transactions.contains(txid)) {
3167 return m_recent_rejects.contains(txid) || m_mempool.
exists(txid);
3170bool PeerManagerImpl::AlreadyHaveBlock(
const BlockHash &block_hash) {
3175 if (!
Assume(m_avalanche)) {
3180 if (localProof && localProof->getId() == proofid) {
3189void PeerManagerImpl::SendPings() {
3191 for (
auto &it : m_peer_map) {
3192 it.second->m_ping_queued =
true;
3196void PeerManagerImpl::RelayTransaction(
const TxId &txid) {
3198 for (
auto &it : m_peer_map) {
3199 Peer &peer = *it.second;
3200 auto tx_relay = peer.GetTxRelay();
3204 LOCK(tx_relay->m_tx_inventory_mutex);
3210 if (tx_relay->m_next_inv_send_time == 0s) {
3214 if (!tx_relay->m_tx_inventory_known_filter.contains(txid) ||
3215 tx_relay->m_avalanche_stalled_txids.count(txid) > 0) {
3216 tx_relay->m_tx_inventory_to_send.insert(txid);
3223 for (
auto &it : m_peer_map) {
3224 Peer &peer = *it.second;
3226 if (!peer.m_proof_relay) {
3229 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
3230 if (!peer.m_proof_relay->m_proof_inventory_known_filter.contains(
3232 peer.m_proof_relay->m_proof_inventory_to_send.insert(proofid);
3237void PeerManagerImpl::RelayAddress(
NodeId originator,
const CAddress &addr,
3253 const auto current_time{GetTime<std::chrono::seconds>()};
3256 const uint64_t time_addr{
3257 (
static_cast<uint64_t
>(
count_seconds(current_time)) + hash_addr) /
3267 unsigned int nRelayNodes = (fReachable || (hasher.Finalize() & 1)) ? 2 : 1;
3268 std::array<std::pair<uint64_t, Peer *>, 2> best{
3269 {{0,
nullptr}, {0,
nullptr}}};
3270 assert(nRelayNodes <= best.size());
3274 for (
auto &[
id, peer] : m_peer_map) {
3275 if (peer->m_addr_relay_enabled &&
id != originator &&
3276 IsAddrCompatible(*peer, addr)) {
3278 for (
unsigned int i = 0; i < nRelayNodes; i++) {
3279 if (hashKey > best[i].first) {
3280 std::copy(best.begin() + i, best.begin() + nRelayNodes - 1,
3281 best.begin() + i + 1);
3282 best[i] = std::make_pair(hashKey, peer.get());
3289 for (
unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
3290 PushAddress(*best[i].second, addr);
3294void PeerManagerImpl::ProcessGetBlockData(
const Config &config,
CNode &pfrom,
3295 Peer &peer,
const CInv &inv) {
3298 std::shared_ptr<const CBlock> a_recent_block;
3299 std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
3301 LOCK(m_most_recent_block_mutex);
3302 a_recent_block = m_most_recent_block;
3303 a_recent_compact_block = m_most_recent_compact_block;
3306 bool need_activate_chain =
false;
3320 need_activate_chain =
true;
3324 if (need_activate_chain) {
3327 state, a_recent_block, m_avalanche)) {
3335 bool can_direct_fetch{
false};
3343 if (!BlockRequestAllowed(pindex)) {
3345 "%s: ignoring request from peer=%i for old "
3346 "block that isn't in the main chain\n",
3347 __func__, pfrom.
GetId());
3353 (((m_chainman.m_best_header !=
nullptr) &&
3354 (m_chainman.m_best_header->GetBlockTime() -
3362 "historical block serving limit reached, disconnect peer=%d\n",
3375 (tip->nHeight - pindex->
nHeight >
3378 "Ignore block request below NODE_NETWORK_LIMITED "
3379 "threshold, disconnect peer=%d\n",
3389 if (!pindex->nStatus.hasData()) {
3392 can_direct_fetch = CanDirectFetch();
3396 std::shared_ptr<const CBlock> pblock;
3397 auto handle_block_read_error = [&]() {
3399 return m_chainman.
m_blockman.IsBlockPruned(*pindex))) {
3401 "Block was pruned before it could be read, disconnect "
3405 LogError(
"Cannot load block from disk, disconnect peer=%d\n",
3411 if (a_recent_block && a_recent_block->GetHash() == pindex->
GetBlockHash()) {
3412 pblock = a_recent_block;
3417 std::vector<uint8_t> block_data;
3419 handle_block_read_error();
3426 std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
3428 handle_block_read_error();
3431 pblock = pblockRead;
3437 bool sendMerkleBlock =
false;
3439 if (
auto tx_relay = peer.GetTxRelay()) {
3440 LOCK(tx_relay->m_bloom_filter_mutex);
3441 if (tx_relay->m_bloom_filter) {
3442 sendMerkleBlock =
true;
3447 if (sendMerkleBlock) {
3458 typedef std::pair<size_t, uint256> PairType;
3461 *pblock->vtx[pair.first]);
3471 if (can_direct_fetch &&
3473 if (a_recent_compact_block &&
3474 a_recent_compact_block->header.GetHash() ==
3477 *a_recent_compact_block);
3491 LOCK(peer.m_block_inv_mutex);
3494 if (hash == peer.m_continuation_block) {
3498 std::vector<CInv> vInv;
3501 peer.m_continuation_block =
BlockHash();
3507PeerManagerImpl::FindTxForGetData(
const Peer &peer,
const TxId &txid,
3508 const std::chrono::seconds mempool_req,
3509 const std::chrono::seconds now) {
3510 auto txinfo = m_mempool.
info(txid);
3515 if ((mempool_req.count() && txinfo.m_time <= mempool_req) ||
3517 return std::move(txinfo.tx);
3526 Assume(peer.GetTxRelay())->m_recently_announced_invs.contains(txid);
3527 if (recent && txinfo.tx) {
3528 return std::move(txinfo.tx);
3533 LOCK(m_most_recent_block_mutex);
3534 if (m_most_recent_block_txs !=
nullptr) {
3535 auto it = m_most_recent_block_txs->find(txid);
3536 if (it != m_most_recent_block_txs->end()) {
3549PeerManagerImpl::FindProofForGetData(
const Peer &peer,
3551 const std::chrono::seconds now) {
3554 bool send_unconditionally =
3580 if (send_unconditionally) {
3585 if (peer.m_proof_relay->m_recently_announced_proofs.contains(proofid)) {
3592void PeerManagerImpl::ProcessGetData(
3594 const std::atomic<bool> &interruptMsgProc) {
3597 auto tx_relay = peer.GetTxRelay();
3599 std::deque<CInv>::iterator it = peer.m_getdata_requests.begin();
3600 std::vector<CInv> vNotFound;
3602 const auto now{GetTime<std::chrono::seconds>()};
3604 const auto mempool_req = tx_relay !=
nullptr
3605 ? tx_relay->m_last_mempool_req.load()
3606 : std::chrono::seconds::min();
3611 while (it != peer.m_getdata_requests.end() &&
3612 (it->IsMsgProof() || it->IsMsgTx())) {
3613 if (interruptMsgProc) {
3622 const CInv &inv = *it++;
3626 vNotFound.push_back(inv);
3630 auto proof = FindProofForGetData(peer, proofid, now);
3637 vNotFound.push_back(inv);
3644 if (tx_relay ==
nullptr) {
3658 std::vector<TxId> parent_ids_to_add;
3661 auto tx_iter = m_mempool.
GetIter(tx->GetId());
3663 auto &pentry = *tx_iter;
3665 (*pentry)->GetMemPoolParentsConst();
3666 parent_ids_to_add.reserve(parents.size());
3667 for (
const auto &parent : parents) {
3668 if (parent.get()->GetTime() >
3670 parent_ids_to_add.push_back(
3671 parent.get()->GetTx().GetId());
3676 for (
const TxId &parent_txid : parent_ids_to_add) {
3679 if (
WITH_LOCK(tx_relay->m_tx_inventory_mutex,
3680 return !tx_relay->m_tx_inventory_known_filter
3681 .contains(parent_txid))) {
3682 tx_relay->m_recently_announced_invs.insert(parent_txid);
3686 vNotFound.push_back(inv);
3698 if (it != peer.m_getdata_requests.end() && !pfrom.
fPauseSend) {
3699 const CInv &inv = *it++;
3701 ProcessGetBlockData(config, pfrom, peer, inv);
3707 peer.m_getdata_requests.erase(peer.m_getdata_requests.begin(), it);
3709 if (!vNotFound.empty()) {
3726void PeerManagerImpl::SendBlockTransactions(
3730 for (
size_t i = 0; i < req.
indices.size(); i++) {
3732 Misbehaving(peer,
"getblocktxn with out-of-bounds tx indices");
3741bool PeerManagerImpl::CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
3746 Misbehaving(peer,
"header with invalid proof of work");
3751 if (!CheckHeadersAreContinuous(headers)) {
3752 Misbehaving(peer,
"non-continuous headers sequence");
3765 near_chaintip_work =
3778void PeerManagerImpl::HandleUnconnectingHeaders(
3779 CNode &pfrom, Peer &peer,
const std::vector<CBlockHeader> &headers) {
3783 if (MaybeSendGetHeaders(pfrom,
GetLocator(best_header), peer)) {
3786 "received header %s: missing prev block %s, sending getheaders "
3787 "(%d) to end (peer=%d)\n",
3789 headers[0].hashPrevBlock.ToString(), best_header->nHeight,
3797 UpdateBlockAvailability(pfrom.
GetId(), headers.back().GetHash()));
3800bool PeerManagerImpl::CheckHeadersAreContinuous(
3801 const std::vector<CBlockHeader> &headers)
const {
3804 if (!hashLastBlock.
IsNull() && header.hashPrevBlock != hashLastBlock) {
3807 hashLastBlock = header.GetHash();
3812bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(
3813 Peer &peer,
CNode &pfrom, std::vector<CBlockHeader> &headers) {
3814 if (peer.m_headers_sync) {
3815 auto result = peer.m_headers_sync->ProcessNextHeaders(
3819 if (result.success) {
3820 peer.m_last_getheaders_timestamp = {};
3822 if (result.request_more) {
3823 auto locator = peer.m_headers_sync->NextHeadersRequestLocator();
3826 Assume(!locator.vHave.empty());
3830 if (!locator.vHave.empty()) {
3833 bool sent_getheaders =
3834 MaybeSendGetHeaders(pfrom, locator, peer);
3837 locator.vHave.front().ToString(), pfrom.
GetId());
3842 peer.m_headers_sync.reset(
nullptr);
3847 LOCK(m_headers_presync_mutex);
3848 m_headers_presync_stats.erase(pfrom.
GetId());
3851 HeadersPresyncStats stats;
3852 stats.first = peer.m_headers_sync->GetPresyncWork();
3853 if (peer.m_headers_sync->GetState() ==
3855 stats.second = {peer.m_headers_sync->GetPresyncHeight(),
3856 peer.m_headers_sync->GetPresyncTime()};
3860 LOCK(m_headers_presync_mutex);
3861 m_headers_presync_stats[pfrom.
GetId()] = stats;
3863 m_headers_presync_stats.find(m_headers_presync_bestpeer);
3864 bool best_updated =
false;
3865 if (best_it == m_headers_presync_stats.end()) {
3870 const HeadersPresyncStats *stat_best{
nullptr};
3871 for (
const auto &[_peer, _stat] : m_headers_presync_stats) {
3872 if (!stat_best || _stat > *stat_best) {
3877 m_headers_presync_bestpeer = peer_best;
3878 best_updated = (peer_best == pfrom.
GetId());
3879 }
else if (best_it->first == pfrom.
GetId() ||
3880 stats > best_it->second) {
3883 m_headers_presync_bestpeer = pfrom.
GetId();
3884 best_updated =
true;
3886 if (best_updated && stats.second.has_value()) {
3889 m_headers_presync_should_signal =
true;
3893 if (result.success) {
3896 headers.swap(result.pow_validated_headers);
3899 return result.success;
3907bool PeerManagerImpl::TryLowWorkHeadersSync(
3909 std::vector<CBlockHeader> &headers) {
3916 arith_uint256 minimum_chain_work = GetAntiDoSWorkThreshold();
3920 if (total_work < minimum_chain_work) {
3934 LOCK(peer.m_headers_sync_mutex);
3935 peer.m_headers_sync.reset(
3937 chain_start_header, minimum_chain_work));
3942 (void)IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
3945 "Ignoring low-work chain (height=%u) from peer=%d\n",
3946 chain_start_header->
nHeight + headers.size(),
3958bool PeerManagerImpl::IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header) {
3959 return header !=
nullptr &&
3960 ((m_chainman.m_best_header !=
nullptr &&
3962 m_chainman.m_best_header->GetAncestor(header->
nHeight)) ||
3966bool PeerManagerImpl::MaybeSendGetHeaders(
CNode &pfrom,
3973 if (current_time - peer.m_last_getheaders_timestamp >
3976 peer.m_last_getheaders_timestamp = current_time;
3988void PeerManagerImpl::HeadersDirectFetchBlocks(
const Config &config,
3992 CNodeState *nodestate = State(pfrom.
GetId());
3996 std::vector<const CBlockIndex *> vToFetch;
4002 if (!pindexWalk->nStatus.hasData() &&
4005 vToFetch.push_back(pindexWalk);
4007 pindexWalk = pindexWalk->
pprev;
4018 std::vector<CInv> vGetData;
4021 if (nodestate->vBlocksInFlight.size() >=
4027 BlockRequested(config, pfrom.
GetId(), *pindex);
4031 if (vGetData.size() > 1) {
4033 "Downloading blocks toward %s (%d) via headers "
4038 if (vGetData.size() > 0) {
4039 if (!m_opts.ignore_incoming_txs &&
4040 nodestate->m_provides_cmpctblocks && vGetData.size() == 1 &&
4041 mapBlocksInFlight.size() == 1 &&
4058void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(
4060 bool received_new_header,
bool may_have_more_headers) {
4063 CNodeState *nodestate = State(pfrom.
GetId());
4071 if (received_new_header &&
4073 nodestate->m_last_block_announcement =
GetTime();
4081 if (nodestate->pindexBestKnownBlock &&
4082 nodestate->pindexBestKnownBlock->nChainWork <
4093 LogPrintf(
"Disconnecting outbound peer %d -- headers "
4094 "chain has insufficient work\n",
4108 nodestate->pindexBestKnownBlock !=
nullptr) {
4109 if (m_outbound_peers_with_protect_from_disconnect <
4111 nodestate->pindexBestKnownBlock->nChainWork >=
4113 !nodestate->m_chain_sync.m_protect) {
4116 nodestate->m_chain_sync.m_protect =
true;
4117 ++m_outbound_peers_with_protect_from_disconnect;
4122void PeerManagerImpl::ProcessHeadersMessage(
const Config &config,
CNode &pfrom,
4124 std::vector<CBlockHeader> &&headers,
4125 bool via_compact_block) {
4126 size_t nCount = headers.size();
4134 LOCK(peer.m_headers_sync_mutex);
4135 if (peer.m_headers_sync) {
4136 peer.m_headers_sync.reset(
nullptr);
4137 LOCK(m_headers_presync_mutex);
4138 m_headers_presync_stats.erase(pfrom.
GetId());
4143 peer.m_last_getheaders_timestamp = {};
4151 if (!CheckHeadersPoW(headers, m_chainparams.
GetConsensus(), peer)) {
4166 bool already_validated_work =
false;
4169 bool have_headers_sync =
false;
4171 LOCK(peer.m_headers_sync_mutex);
4173 already_validated_work =
4174 IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
4186 if (headers.empty()) {
4190 have_headers_sync = !!peer.m_headers_sync;
4196 headers[0].hashPrevBlock))};
4197 bool headers_connect_blockindex{chain_start_header !=
nullptr};
4199 if (!headers_connect_blockindex) {
4203 HandleUnconnectingHeaders(pfrom, peer, headers);
4211 peer.m_last_getheaders_timestamp = {};
4220 last_received_header =
4222 if (IsAncestorOfBestHeaderOrTip(last_received_header)) {
4223 already_validated_work =
true;
4231 already_validated_work =
true;
4237 if (!already_validated_work &&
4238 TryLowWorkHeadersSync(peer, pfrom, chain_start_header, headers)) {
4250 bool received_new_header{last_received_header ==
nullptr};
4255 state, &pindexLast)) {
4257 MaybePunishNodeForBlock(pfrom.
GetId(), state, via_compact_block,
4258 "invalid header received");
4264 LogError(
"headers message processed but no pindexLast\n");
4273 if (MaybeSendGetHeaders(pfrom,
GetLocator(pindexLast), peer)) {
4276 "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
4277 pindexLast->
nHeight, pfrom.
GetId(), peer.m_starting_height);
4281 UpdatePeerStateForReceivedHeaders(pfrom, peer, *pindexLast,
4282 received_new_header,
4286 HeadersDirectFetchBlocks(config, pfrom, *pindexLast);
4289void PeerManagerImpl::ProcessInvalidTx(
NodeId nodeid,
4292 bool maybe_add_extra_compact_tx) {
4297 const TxId &txid = ptx->GetId();
4317 m_recent_rejects_package_reconsiderable.insert(txid);
4319 m_recent_rejects.insert(txid);
4321 m_txrequest.ForgetInvId(txid);
4324 AddToCompactExtraTransactions(ptx);
4327 MaybePunishNodeForTx(nodeid, state);
4333 return orphanage.EraseTx(txid);
4347 m_txrequest.ForgetInvId(tx->GetId());
4353 orphanage.
EraseTx(tx->GetId());
4358 "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
4359 nodeid, tx->GetId().ToString(), m_mempool.
size(),
4362 RelayTransaction(tx->GetId());
4365void PeerManagerImpl::ProcessPackageResult(
4366 const PackageToValidate &package_to_validate,
4372 const auto &
package = package_to_validate.m_txns;
4373 const auto &senders = package_to_validate.m_senders;
4376 m_recent_rejects_package_reconsiderable.insert(
GetPackageHash(package));
4380 if (!
Assume(package.size() == 2)) {
4386 auto package_iter = package.rbegin();
4387 auto senders_iter = senders.rbegin();
4388 while (package_iter != package.rend()) {
4389 const auto &tx = *package_iter;
4390 const NodeId nodeid = *senders_iter;
4391 const auto it_result{package_result.
m_tx_results.find(tx->GetId())};
4395 const auto &tx_result = it_result->second;
4396 switch (tx_result.m_result_type) {
4398 ProcessValidTx(nodeid, tx);
4408 ProcessInvalidTx(nodeid, tx, tx_result.m_state,
4425std::optional<PeerManagerImpl::PackageToValidate>
4431 const auto &parent_txid{ptx->GetId()};
4433 Assume(m_recent_rejects_package_reconsiderable.contains(parent_txid));
4439 const auto cpfp_candidates_same_peer{
4445 for (
const auto &child : cpfp_candidates_same_peer) {
4446 Package maybe_cpfp_package{ptx, child};
4447 if (!m_recent_rejects_package_reconsiderable.contains(
4449 return PeerManagerImpl::PackageToValidate{ptx, child, nodeid,
4463 const auto cpfp_candidates_different_peer{
4473 std::vector<size_t> tx_indices(cpfp_candidates_different_peer.size());
4474 std::iota(tx_indices.begin(), tx_indices.end(), 0);
4475 Shuffle(tx_indices.begin(), tx_indices.end(), m_rng);
4477 for (
const auto index : tx_indices) {
4480 const auto [child_tx, child_sender] =
4481 cpfp_candidates_different_peer.at(index);
4482 Package maybe_cpfp_package{ptx, child_tx};
4483 if (!m_recent_rejects_package_reconsiderable.contains(
4485 return PeerManagerImpl::PackageToValidate{ptx, child_tx, nodeid,
4489 return std::nullopt;
4492bool PeerManagerImpl::ProcessOrphanTx(
const Config &config, Peer &peer) {
4498 return orphanage.GetTxToReconsider(peer.m_id);
4503 const TxId &orphanTxId = porphanTx->GetId();
4508 ProcessValidTx(peer.m_id, porphanTx);
4514 " invalid orphan tx %s from peer=%d. %s\n",
4521 ProcessInvalidTx(peer.m_id, porphanTx, state,
4532bool PeerManagerImpl::PrepareBlockFilterRequest(
4534 const BlockHash &stop_hash, uint32_t max_height_diff,
4536 const bool supported_filter_type =
4539 if (!supported_filter_type) {
4541 "peer %d requested unsupported block filter type: %d\n",
4542 node.GetId(),
static_cast<uint8_t
>(filter_type));
4543 node.fDisconnect =
true;
4553 if (!stop_index || !BlockRequestAllowed(stop_index)) {
4556 node.fDisconnect =
true;
4561 uint32_t stop_height = stop_index->
nHeight;
4562 if (start_height > stop_height) {
4565 "peer %d sent invalid getcfilters/getcfheaders with "
4567 "start height %d and stop height %d\n",
4568 node.GetId(), start_height, stop_height);
4569 node.fDisconnect =
true;
4572 if (stop_height - start_height >= max_height_diff) {
4574 "peer %d requested too many cfilters/cfheaders: %d / %d\n",
4575 node.GetId(), stop_height - start_height + 1, max_height_diff);
4576 node.fDisconnect =
true;
4581 if (!filter_index) {
4590void PeerManagerImpl::ProcessGetCFilters(
CNode &
node, Peer &peer,
4592 uint8_t filter_type_ser;
4593 uint32_t start_height;
4596 vRecv >> filter_type_ser >> start_height >> stop_hash;
4603 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4609 std::vector<BlockFilter> filters;
4612 "Failed to find block filter in index: filter_type=%s, "
4613 "start_height=%d, stop_hash=%s\n",
4619 for (
const auto &filter : filters) {
4624void PeerManagerImpl::ProcessGetCFHeaders(
CNode &
node, Peer &peer,
4626 uint8_t filter_type_ser;
4627 uint32_t start_height;
4630 vRecv >> filter_type_ser >> start_height >> stop_hash;
4637 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4644 if (start_height > 0) {
4646 stop_index->
GetAncestor(
static_cast<int>(start_height - 1));
4649 "Failed to find block filter header in index: "
4650 "filter_type=%s, block_hash=%s\n",
4657 std::vector<uint256> filter_hashes;
4661 "Failed to find block filter hashes in index: filter_type=%s, "
4662 "start_height=%d, stop_hash=%s\n",
4669 stop_index->
GetBlockHash(), prev_header, filter_hashes);
4672void PeerManagerImpl::ProcessGetCFCheckPt(
CNode &
node, Peer &peer,
4674 uint8_t filter_type_ser;
4677 vRecv >> filter_type_ser >> stop_hash;
4684 if (!PrepareBlockFilterRequest(
4685 node, peer, filter_type, 0, stop_hash,
4686 std::numeric_limits<uint32_t>::max(),
4687 stop_index, filter_index)) {
4695 for (
int i = headers.size() - 1; i >= 0; i--) {
4701 "Failed to find block filter header in index: "
4702 "filter_type=%s, block_hash=%s\n",
4725PeerManagerImpl::GetAvalancheVoteForBlock(
const BlockHash &hash)
const {
4736 if (pindex->nStatus.isInvalid()) {
4741 if (pindex->nStatus.isOnParkedChain()) {
4749 if (pindex == pindexFork) {
4754 if (pindexFork != pindexTip) {
4759 if (!pindex->nStatus.hasData()) {
4770 const TxId &
id)
const {
4772 if (
WITH_LOCK(m_recent_confirmed_transactions_mutex,
4773 return m_recent_confirmed_transactions.contains(
id))) {
4782 if (m_recent_rejects.contains(
id)) {
4794 if (
auto iter = m_mempool.
GetIter(
id)) {
4795 mempool_tx = (**iter)->GetSharedTx();
4800 return conflicting.HaveTx(id);
4807 return orphanage.HaveTx(id);
4873 const std::shared_ptr<const CBlock> &block,
4874 bool force_processing,
4875 bool min_pow_checked) {
4876 bool new_block{
false};
4878 &new_block, m_avalanche);
4880 node.m_last_block_time = GetTime<std::chrono::seconds>();
4885 RemoveBlockRequest(block->GetHash(), std::nullopt);
4888 mapBlockSource.erase(block->GetHash());
4892void PeerManagerImpl::ProcessMessage(
4893 const Config &config,
CNode &pfrom,
const std::string &msg_type,
4894 DataStream &vRecv,
const std::chrono::microseconds time_received,
4895 const std::atomic<bool> &interruptMsgProc) {
4901 PeerRef peer = GetPeerRef(pfrom.
GetId());
4902 if (peer ==
nullptr) {
4908 "Avalanche is not initialized, ignoring %s message\n",
4923 uint64_t nNonce = 1;
4926 std::string cleanSubVer;
4927 int starting_height = -1;
4929 uint64_t nExtraEntropy = 1;
4931 vRecv >> nVersion >> Using<CustomUintFormatter<8>>(nServices) >> nTime;
4944 "peer=%d does not offer the expected services "
4945 "(%08x offered, %08x expected); disconnecting\n",
4946 pfrom.
GetId(), nServices,
4956 "peer=%d does not offer the avalanche service; disconnecting\n",
4965 "peer=%d using obsolete version %i; disconnecting\n",
4966 pfrom.
GetId(), nVersion);
4971 if (!vRecv.
empty()) {
4980 if (!vRecv.
empty()) {
4981 std::string strSubVer;
4985 if (!vRecv.
empty()) {
4986 vRecv >> starting_height;
4988 if (!vRecv.
empty()) {
4991 if (!vRecv.
empty()) {
4992 vRecv >> nExtraEntropy;
4996 LogPrintf(
"connected to self at %s, disconnecting\n",
5009 PushNodeVersion(config, pfrom, *peer);
5013 const int greatest_common_version =
5025 peer->m_their_services = nServices;
5029 pfrom.cleanSubVer = cleanSubVer;
5031 peer->m_starting_height = starting_height;
5039 (fRelay || (peer->m_our_services &
NODE_BLOOM))) {
5040 auto *
const tx_relay = peer->SetTxRelay();
5042 LOCK(tx_relay->m_bloom_filter_mutex);
5044 tx_relay->m_relay_txs = fRelay;
5057 CNodeState *state = State(pfrom.
GetId());
5058 state->fPreferredDownload =
5062 m_num_preferred_download_peers += state->fPreferredDownload;
5068 bool send_getaddr{
false};
5070 send_getaddr = SetupAddressRelay(pfrom, *peer);
5081 peer->m_getaddr_sent =
true;
5085 WITH_LOCK(peer->m_addr_token_bucket_mutex,
5086 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
5107 std::string remoteAddr;
5113 "receive version message: [%s] %s: version %d, blocks=%d, "
5114 "us=%s, txrelay=%d, peer=%d%s\n",
5117 pfrom.
GetId(), remoteAddr);
5119 int64_t currentTime =
GetTime();
5120 int64_t nTimeOffset = nTime - currentTime;
5125 Misbehaving(*peer,
"Ignoring invalid timestamp in version message");
5135 "feeler connection completed peer=%d; disconnecting\n",
5144 Misbehaving(*peer,
"non-version message before version handshake");
5151 "ignoring redundant verack message from peer=%d\n",
5157 LogPrintf(
"New outbound peer connected: version: %d, blocks=%d, "
5159 pfrom.
nVersion.load(), peer->m_starting_height,
5182 AddKnownProof(*peer, localProof->getId());
5186 peer->m_proof_relay->m_recently_announced_proofs.insert(
5187 localProof->getId());
5192 if (
auto tx_relay = peer->GetTxRelay()) {
5201 return tx_relay->m_tx_inventory_to_send.empty() &&
5202 tx_relay->m_next_inv_send_time == 0s));
5211 Misbehaving(*peer,
"non-verack message before version handshake");
5216 const auto ser_params{
5225 std::vector<CAddress> vAddr;
5229 if (!SetupAddressRelay(pfrom, *peer)) {
5235 if (vAddr.size() > m_opts.max_addr_to_send) {
5236 Misbehaving(*peer,
strprintf(
"%s message size = %u", msg_type,
5242 std::vector<CAddress> vAddrOk;
5243 const auto current_a_time{Now<NodeSeconds>()};
5246 const auto current_time = GetTime<std::chrono::microseconds>();
5248 LOCK(peer->m_addr_token_bucket_mutex);
5251 const auto time_diff =
5252 std::max(current_time - peer->m_addr_token_timestamp, 0us);
5253 const double increment =
5255 peer->m_addr_token_bucket =
5256 std::min<double>(peer->m_addr_token_bucket + increment,
5260 peer->m_addr_token_timestamp = current_time;
5262 const bool rate_limited =
5264 uint64_t num_proc = 0;
5265 uint64_t num_rate_limit = 0;
5266 Shuffle(vAddr.begin(), vAddr.end(), m_rng);
5268 if (interruptMsgProc) {
5273 LOCK(peer->m_addr_token_bucket_mutex);
5275 if (peer->m_addr_token_bucket < 1.0) {
5281 peer->m_addr_token_bucket -= 1.0;
5294 addr.
nTime > current_a_time + 10min) {
5295 addr.
nTime = current_a_time - 5 * 24h;
5297 AddAddressKnown(*peer, addr);
5306 if (addr.
nTime > current_a_time - 10min && !peer->m_getaddr_sent &&
5309 RelayAddress(pfrom.
GetId(), addr, fReachable);
5313 vAddrOk.push_back(addr);
5316 peer->m_addr_processed += num_proc;
5317 peer->m_addr_rate_limited += num_rate_limit;
5319 "Received addr: %u addresses (%u processed, %u rate-limited) "
5321 vAddr.size(), num_proc, num_rate_limit, pfrom.
GetId());
5323 m_addrman.
Add(vAddrOk, pfrom.
addr, 2h);
5324 if (vAddr.size() < 1000) {
5325 peer->m_getaddr_sent =
false;
5332 "addrfetch connection completed peer=%d; disconnecting\n",
5340 peer->m_wants_addrv2 =
true;
5345 peer->m_prefers_headers =
true;
5350 bool sendcmpct_hb{
false};
5351 uint64_t sendcmpct_version{0};
5352 vRecv >> sendcmpct_hb >> sendcmpct_version;
5359 CNodeState *nodestate = State(pfrom.
GetId());
5360 nodestate->m_provides_cmpctblocks =
true;
5361 nodestate->m_requested_hb_cmpctblocks = sendcmpct_hb;
5370 std::vector<CInv> vInv;
5373 Misbehaving(*peer,
strprintf(
"inv message size = %u", vInv.size()));
5377 const bool reject_tx_invs{RejectIncomingTxs(pfrom)};
5379 const auto current_time{GetTime<std::chrono::microseconds>()};
5380 std::optional<BlockHash> best_block;
5382 auto logInv = [&](
const CInv &inv,
bool fAlreadyHave) {
5384 fAlreadyHave ?
"have" :
"new", pfrom.
GetId());
5387 for (
CInv &inv : vInv) {
5388 if (interruptMsgProc) {
5400 const bool fAlreadyHave = AlreadyHaveBlock(
BlockHash(inv.
hash));
5401 logInv(inv, fAlreadyHave);
5404 UpdateBlockAvailability(pfrom.
GetId(), hash);
5406 !IsBlockRequested(hash)) {
5413 best_block = std::move(hash);
5424 const bool fAlreadyHave = AlreadyHaveProof(proofid);
5425 logInv(inv, fAlreadyHave);
5426 AddKnownProof(*peer, proofid);
5428 if (!fAlreadyHave && m_avalanche &&
5430 const bool preferred = isPreferredDownloadPeer(pfrom);
5432 LOCK(cs_proofrequest);
5433 AddProofAnnouncement(pfrom, proofid, current_time,
5442 const bool fAlreadyHave =
5443 AlreadyHaveTx(txid,
true);
5444 logInv(inv, fAlreadyHave);
5446 AddKnownTx(*peer, txid);
5447 if (reject_tx_invs) {
5449 "transaction (%s) inv sent in violation of "
5450 "protocol, disconnecting peer=%d\n",
5454 }
else if (!fAlreadyHave &&
5456 AddTxAnnouncement(pfrom, txid, current_time);
5463 "Unknown inv type \"%s\" received from peer=%d\n",
5480 if (state.fSyncStarted ||
5481 (!peer->m_inv_triggered_getheaders_before_sync &&
5482 *best_block != m_last_block_inv_triggering_headers_sync)) {
5483 if (MaybeSendGetHeaders(
5484 pfrom,
GetLocator(m_chainman.m_best_header), *peer)) {
5486 m_chainman.m_best_header->nHeight,
5487 best_block->ToString(), pfrom.
GetId());
5489 if (!state.fSyncStarted) {
5490 peer->m_inv_triggered_getheaders_before_sync =
true;
5494 m_last_block_inv_triggering_headers_sync = *best_block;
5503 std::vector<CInv> vInv;
5507 strprintf(
"getdata message size = %u", vInv.size()));
5512 vInv.size(), pfrom.
GetId());
5514 if (vInv.size() > 0) {
5520 LOCK(peer->m_getdata_requests_mutex);
5521 peer->m_getdata_requests.insert(peer->m_getdata_requests.end(),
5522 vInv.begin(), vInv.end());
5523 ProcessGetData(config, pfrom, *peer, interruptMsgProc);
5532 vRecv >> locator >> hashStop;
5536 "getblocks locator size %lld > %d, disconnect peer=%d\n",
5550 std::shared_ptr<const CBlock> a_recent_block;
5552 LOCK(m_most_recent_block_mutex);
5553 a_recent_block = m_most_recent_block;
5557 state, a_recent_block, m_avalanche)) {
5575 (pindex ? pindex->
nHeight : -1),
5578 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5587 const int nPrunedBlocksLikelyToHave =
5591 (!pindex->nStatus.hasData() ||
5593 nPrunedBlocksLikelyToHave)) {
5596 " getblocks stopping, pruned or too old block at %d %s\n",
5601 peer->m_block_inv_mutex,
5602 peer->m_blocks_for_inv_relay.push_back(pindex->
GetBlockHash()));
5603 if (--nLimit <= 0) {
5609 peer->m_continuation_block = pindex->GetBlockHash();
5621 std::shared_ptr<const CBlock> recent_block;
5623 LOCK(m_most_recent_block_mutex);
5624 if (m_most_recent_block_hash == req.
blockhash) {
5625 recent_block = m_most_recent_block;
5630 SendBlockTransactions(pfrom, *peer, *recent_block, req);
5640 if (!pindex || !pindex->nStatus.hasData()) {
5643 "Peer %d sent us a getblocktxn for a block we don't have\n",
5654 if (!block_pos.IsNull()) {
5661 LogError(
"getblocktxn: block read failed for block %s\n",
5667 SendBlockTransactions(pfrom, *peer, block, req);
5679 "Peer %d sent us a getblocktxn for a block > %i deep\n",
5684 WITH_LOCK(peer->m_getdata_requests_mutex,
5685 peer->m_getdata_requests.push_back(inv));
5694 vRecv >> locator >> hashStop;
5698 "getheaders locator size %lld > %d, disconnect peer=%d\n",
5707 "Ignoring getheaders from peer=%d while importing/reindexing\n",
5721 if (m_chainman.
ActiveTip() ==
nullptr ||
5726 "Ignoring getheaders from peer=%d because active chain "
5727 "has too little work; sending empty response\n",
5732 std::vector<CBlock>());
5736 CNodeState *nodestate = State(pfrom.
GetId());
5745 if (!BlockRequestAllowed(pindex)) {
5747 "%s: ignoring request from peer=%i for old block "
5748 "header that isn't in the main chain\n",
5749 __func__, pfrom.
GetId());
5763 std::vector<CBlock> vHeaders;
5766 (pindex ? pindex->
nHeight : -1),
5769 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5771 if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) {
5788 nodestate->pindexBestHeaderSent =
5795 if (RejectIncomingTxs(pfrom)) {
5797 "transaction sent in violation of protocol peer=%d\n",
5813 const CTransaction &tx = *ptx;
5814 const TxId &txid = tx.GetId();
5815 AddKnownTx(*peer, txid);
5820 m_txrequest.ReceivedResponse(pfrom.
GetId(), txid);
5822 if (AlreadyHaveTx(txid,
true)) {
5828 if (!m_mempool.
exists(tx.GetId())) {
5830 "Not relaying non-mempool transaction %s from "
5831 "forcerelay peer=%d\n",
5832 tx.GetId().ToString(), pfrom.
GetId());
5834 LogPrintf(
"Force relaying tx %s from peer=%d\n",
5835 tx.GetId().ToString(), pfrom.
GetId());
5836 RelayTransaction(tx.GetId());
5840 if (m_recent_rejects_package_reconsiderable.contains(txid)) {
5848 "found tx %s in reconsiderable rejects, looking for "
5849 "child in orphanage\n",
5851 if (
auto package_to_validate{
5852 Find1P1CPackage(ptx, pfrom.
GetId())}) {
5855 package_to_validate->m_txns,
5858 "package evaluation for %s: %s (%s)\n",
5859 package_to_validate->ToString(),
5861 ?
"package accepted"
5862 :
"package rejected",
5864 ProcessPackageResult(package_to_validate.value(),
5893 ProcessValidTx(pfrom.
GetId(), ptx);
5899 bool fRejectedParents =
false;
5903 std::vector<TxId> unique_parents;
5904 unique_parents.reserve(tx.vin.size());
5905 for (
const CTxIn &txin : tx.vin) {
5908 unique_parents.push_back(txin.prevout.GetTxId());
5910 std::sort(unique_parents.begin(), unique_parents.end());
5911 unique_parents.erase(
5912 std::unique(unique_parents.begin(), unique_parents.end()),
5913 unique_parents.end());
5921 std::optional<TxId> rejected_parent_reconsiderable;
5922 for (
const TxId &parent_txid : unique_parents) {
5923 if (m_recent_rejects.contains(parent_txid)) {
5924 fRejectedParents =
true;
5928 if (m_recent_rejects_package_reconsiderable.contains(
5930 !m_mempool.
exists(parent_txid)) {
5935 if (rejected_parent_reconsiderable.has_value()) {
5936 fRejectedParents =
true;
5939 rejected_parent_reconsiderable = parent_txid;
5942 if (!fRejectedParents) {
5943 const auto current_time{
5944 GetTime<std::chrono::microseconds>()};
5946 for (
const TxId &parent_txid : unique_parents) {
5948 AddKnownTx(*peer, parent_txid);
5952 if (!AlreadyHaveTx(parent_txid,
5954 AddTxAnnouncement(pfrom, parent_txid, current_time);
5960 if (
unsigned int nEvicted =
5964 if (orphanage.AddTx(ptx,
5966 AddToCompactExtraTransactions(ptx);
5969 m_opts.max_orphan_txs, m_rng);
5972 "orphanage overflow, removed %u tx\n",
5978 m_txrequest.ForgetInvId(tx.GetId());
5982 "not keeping orphan with rejected parents %s\n",
5983 tx.GetId().ToString());
5986 m_recent_rejects.insert(tx.GetId());
5987 m_txrequest.ForgetInvId(tx.GetId());
5991 ProcessInvalidTx(pfrom.
GetId(), ptx, state,
6001 "tx %s failed but reconsiderable, looking for child in "
6004 if (
auto package_to_validate{
6005 Find1P1CPackage(ptx, pfrom.
GetId())}) {
6008 package_to_validate->m_txns,
false)};
6010 "package evaluation for %s: %s (%s)\n",
6011 package_to_validate->ToString(),
6013 ?
"package accepted"
6014 :
"package rejected",
6016 ProcessPackageResult(package_to_validate.value(),
6025 m_txrequest.ForgetInvId(tx.GetId());
6027 unsigned int nEvicted{0};
6034 m_opts.max_conflicting_txs, m_rng);
6039 "conflicting pool overflow, removed %u tx\n",
6052 "Unexpected cmpctblock message received from peer %d\n",
6059 vRecv >> cmpctblock;
6060 }
catch (std::ios_base::failure &e) {
6062 Misbehaving(*peer,
"cmpctblock-bad-indexes");
6066 bool received_new_header =
false;
6079 MaybeSendGetHeaders(
6080 pfrom,
GetLocator(m_chainman.m_best_header), *peer);
6086 GetAntiDoSWorkThreshold()) {
6090 "Ignoring low-work compact block from peer %d\n",
6096 received_new_header =
true;
6106 MaybePunishNodeForBlock(pfrom.
GetId(), state,
6108 "invalid header via cmpctblock");
6113 if (received_new_header) {
6114 LogInfo(
"Saw new cmpctblock header hash=%s peer=%d\n",
6115 blockhash.ToString(), pfrom.
GetId());
6122 bool fProcessBLOCKTXN =
false;
6128 bool fRevertToHeaderProcessing =
false;
6132 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6133 bool fBlockReconstructed =
false;
6141 "cmpctblock: header accepted but no pindex for block %s\n",
6142 blockhash.ToString());
6149 CNodeState *nodestate = State(pfrom.
GetId());
6153 if (received_new_header &&
6156 nodestate->m_last_block_announcement =
GetTime();
6159 if (pindex->nStatus.hasData()) {
6166 size_t already_in_flight =
6167 std::distance(range_flight.first, range_flight.second);
6168 bool requested_block_from_this_peer{
false};
6172 bool first_in_flight =
6173 already_in_flight == 0 ||
6174 (range_flight.first->second.first == pfrom.
GetId());
6176 while (range_flight.first != range_flight.second) {
6177 if (range_flight.first->second.first == pfrom.
GetId()) {
6178 requested_block_from_this_peer =
true;
6181 range_flight.first++;
6190 if (requested_block_from_this_peer) {
6194 std::vector<CInv> vInv(1);
6203 if (!already_in_flight && !CanDirectFetch()) {
6211 nodestate->vBlocksInFlight.size() <
6213 requested_block_from_this_peer) {
6214 std::list<QueuedBlock>::iterator *queuedBlockIt =
nullptr;
6215 if (!BlockRequested(config, pfrom.
GetId(), *pindex,
6217 if (!(*queuedBlockIt)->partialBlock) {
6219 ->partialBlock.reset(
6226 "we were already syncing!\n");
6232 *(*queuedBlockIt)->partialBlock;
6234 partialBlock.
InitData(cmpctblock, vExtraTxnForCompact);
6240 Misbehaving(*peer,
"invalid compact block");
6243 if (first_in_flight) {
6246 std::vector<CInv> vInv(1);
6259 for (
size_t i = 0; i < cmpctblock.
BlockTxCount(); i++) {
6270 fProcessBLOCKTXN =
true;
6271 }
else if (first_in_flight) {
6278 IsBlockRequestedFromOutbound(blockhash) ||
6301 tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
6306 std::vector<CTransactionRef> dummy;
6307 status = tempBlock.FillBlock(*pblock, dummy);
6309 fBlockReconstructed =
true;
6313 if (requested_block_from_this_peer) {
6317 std::vector<CInv> vInv(1);
6324 fRevertToHeaderProcessing =
true;
6329 if (fProcessBLOCKTXN) {
6331 blockTxnMsg, time_received, interruptMsgProc);
6334 if (fRevertToHeaderProcessing) {
6340 return ProcessHeadersMessage(config, pfrom, *peer,
6345 if (fBlockReconstructed) {
6350 mapBlockSource.emplace(pblock->GetHash(),
6351 std::make_pair(pfrom.
GetId(),
false));
6362 ProcessBlock(config, pfrom, pblock,
true,
6371 RemoveBlockRequest(pblock->GetHash(), std::nullopt);
6381 "Unexpected blocktxn message received from peer %d\n",
6389 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6390 bool fBlockRead =
false;
6394 auto range_flight = mapBlocksInFlight.equal_range(resp.
blockhash);
6395 size_t already_in_flight =
6396 std::distance(range_flight.first, range_flight.second);
6397 bool requested_block_from_this_peer{
false};
6401 bool first_in_flight =
6402 already_in_flight == 0 ||
6403 (range_flight.first->second.first == pfrom.
GetId());
6405 while (range_flight.first != range_flight.second) {
6406 auto [node_id, block_it] = range_flight.first->second;
6407 if (node_id == pfrom.
GetId() && block_it->partialBlock) {
6408 requested_block_from_this_peer =
true;
6411 range_flight.first++;
6414 if (!requested_block_from_this_peer) {
6416 "Peer %d sent us block transactions for block "
6417 "we weren't expecting\n",
6423 *range_flight.first->second.second->partialBlock;
6431 "invalid compact block/non-matching block transactions");
6434 if (first_in_flight) {
6436 std::vector<CInv> invs;
6443 "Peer %d sent us a compact block but it failed to "
6444 "reconstruct, waiting on first download to complete\n",
6477 std::make_pair(pfrom.
GetId(),
false));
6488 ProcessBlock(config, pfrom, pblock,
true,
6498 "Unexpected headers message received from peer %d\n",
6503 std::vector<CBlockHeader> headers;
6510 strprintf(
"too-many-headers: headers message size = %u",
6514 headers.resize(nCount);
6515 for (
unsigned int n = 0; n < nCount; n++) {
6516 vRecv >> headers[n];
6521 ProcessHeadersMessage(config, pfrom, *peer, std::move(headers),
6527 if (m_headers_presync_should_signal.exchange(
false)) {
6528 HeadersPresyncStats stats;
6530 LOCK(m_headers_presync_mutex);
6532 m_headers_presync_stats.find(m_headers_presync_bestpeer);
6533 if (it != m_headers_presync_stats.end()) {
6539 stats.first, stats.second->first, stats.second->second);
6550 "Unexpected block message received from peer %d\n",
6555 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6559 pblock->GetHash().ToString(), pfrom.
GetId());
6564 pblock->hashPrevBlock))};
6568 "Received mutated block from peer=%d\n", peer->m_id);
6569 Misbehaving(*peer,
"mutated block");
6571 RemoveBlockRequest(pblock->GetHash(), peer->m_id));
6581 const BlockHash hash = pblock->GetHash();
6582 bool min_pow_checked =
false;
6587 forceProcessing = IsBlockRequested(hash);
6588 RemoveBlockRequest(hash, pfrom.
GetId());
6592 mapBlockSource.emplace(hash, std::make_pair(pfrom.
GetId(),
true));
6597 {pblock->GetBlockHeader()}) >=
6598 GetAntiDoSWorkThreshold()) {
6599 min_pow_checked =
true;
6602 ProcessBlock(config, pfrom, pblock, forceProcessing, min_pow_checked);
6612 if (pfrom.m_avalanche_pubkey.has_value()) {
6615 "Ignoring avahello from peer %d: already in our node set\n",
6621 vRecv >> delegation;
6628 if (!delegation.
verify(state, pubkey)) {
6629 Misbehaving(*peer,
"invalid-delegation");
6632 pfrom.m_avalanche_pubkey = std::move(pubkey);
6635 sighasher << delegation.
getId();
6643 if (!(*pfrom.m_avalanche_pubkey)
6644 .VerifySchnorr(sighasher.GetHash(),
sig)) {
6645 Misbehaving(*peer,
"invalid-avahello-signature");
6652 if (!AlreadyHaveProof(proofid)) {
6653 const bool preferred = isPreferredDownloadPeer(pfrom);
6654 LOCK(cs_proofrequest);
6655 AddProofAnnouncement(pfrom, proofid,
6656 GetTime<std::chrono::microseconds>(),
6664 vRecv >> max_elements;
6668 Misbehaving(*peer,
"avahello-max-elements-too-low");
6676 return pm.
addNode(pfrom.
GetId(), proofid, max_elements);
6687 WITH_LOCK(peer->m_addr_token_bucket_mutex,
6688 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
6692 peer->m_proof_relay->compactproofs_requested =
true;
6703 const auto now = Now<SteadyMilliseconds>();
6709 last_poll + std::chrono::milliseconds(m_opts.avalanche_cooldown)) {
6711 "Ignoring repeated avapoll from peer %d: cooldown not "
6726 strprintf(
"too-many-ava-poll: poll message size = %u", nCount));
6730 std::vector<avalanche::Vote> votes;
6731 votes.reserve(nCount);
6733 bool fPreconsensus{
false};
6734 bool fStakingPreconsensus{
false};
6739 fStakingPreconsensus =
6743 for (
unsigned int n = 0; n < nCount; n++) {
6751 if (!quorum_established) {
6752 votes.emplace_back(vote, inv.
hash);
6759 if (fPreconsensus) {
6761 GetAvalancheVoteForTx(*m_avalanche,
TxId(inv.
hash));
6773 if (fStakingPreconsensus) {
6780 "poll inv type %d unknown from peer=%d\n",
6785 votes.emplace_back(vote, inv.
hash);
6811 if (!pfrom.m_avalanche_pubkey.has_value() ||
6812 !(*pfrom.m_avalanche_pubkey)
6813 .VerifySchnorr(verifier.GetHash(),
sig)) {
6814 Misbehaving(*peer,
"invalid-ava-response-signature");
6819 auto now = GetTime<std::chrono::seconds>();
6821 std::vector<avalanche::VoteItemUpdate> updates;
6822 bool disconnect{
false};
6825 disconnect, error)) {
6827 Misbehaving(*peer, error);
6845 "Repeated failure to register votes from peer %d: %s\n",
6846 pfrom.
GetId(), error);
6849 Misbehaving(*peer, error);
6862 auto logVoteUpdate = [](
const auto &voteUpdate,
6863 const std::string &voteItemTypeStr,
6864 const auto &voteItemId) {
6865 std::string voteOutcome;
6866 bool alwaysPrint =
false;
6867 switch (voteUpdate.getStatus()) {
6869 voteOutcome =
"invalidated";
6873 voteOutcome =
"rejected";
6876 voteOutcome =
"accepted";
6879 voteOutcome =
"finalized";
6882 alwaysPrint = voteItemTypeStr !=
"tx";
6885 voteOutcome =
"stalled";
6894 alwaysPrint &= (voteItemTypeStr !=
"contender");
6897 LogPrintf(
"Avalanche %s %s %s\n", voteOutcome, voteItemTypeStr,
6898 voteItemId.ToString());
6902 voteItemTypeStr, voteItemId.ToString());
6906 bool shouldActivateBestChain =
false;
6908 bool fPreconsensus{
false};
6909 bool fStakingPreconsensus{
false};
6914 fStakingPreconsensus =
6918 for (
const auto &u : updates) {
6923 if (
auto pitem = std::get_if<const avalanche::ProofRef>(&item)) {
6927 logVoteUpdate(u,
"proof", proofid);
6929 auto rejectionMode =
6931 auto nextCooldownTimePoint = GetTime<std::chrono::seconds>();
6932 switch (u.getStatus()) {
6948 return pm.rejectProof(proofid,
6952 "ERROR: Failed to reject proof: %s\n",
6958 nextCooldownTimePoint += std::chrono::seconds(
6959 m_opts.avalanche_peer_replacement_cooldown);
6965 avalanche::PeerManager::
6966 RegistrationMode::FORCE_ACCEPT);
6969 [&](const avalanche::Peer &peer) {
6970 pm.updateNextPossibleConflictTime(
6972 nextCooldownTimePoint);
6973 if (u.getStatus() ==
6974 avalanche::VoteStatus::
6976 pm.setFinalized(peer.peerid);
6984 "ERROR: Failed to accept proof: %s\n",
6991 auto getBlockFromIndex = [
this](
const CBlockIndex *pindex)
6992 -> std::shared_ptr<const CBlock> {
6995 std::shared_ptr<const CBlock> pblock =
WITH_LOCK(
6996 m_most_recent_block_mutex,
return m_most_recent_block);
6998 if (!pblock || pblock->GetHash() != pindex->
GetBlockHash()) {
6999 std::shared_ptr<CBlock> pblockRead =
7000 std::make_shared<CBlock>();
7003 LogError(
"getBlockFromIndex: cannot load block from "
7008 pblock = pblockRead;
7013 if (
auto pitem = std::get_if<const CBlockIndex *>(&item)) {
7016 shouldActivateBestChain =
true;
7020 switch (u.getStatus()) {
7025 LogPrintf(
"ERROR: Database error: %s\n",
7034 LogPrintf(
"ERROR: Database error: %s\n",
7039 auto pblock = getBlockFromIndex(pindex);
7041 LogError(
"avaresponse: failed to get invalidated "
7042 "block from index\n");
7061 std::unique_ptr<node::CBlockTemplate> blockTemplate;
7065 chainstate.UnparkBlock(pindex);
7067 const bool newlyFinalized =
7068 !chainstate.IsBlockAvalancheFinalized(pindex) &&
7069 chainstate.AvalancheFinalizeBlock(pindex,
7074 if (fPreconsensus && newlyFinalized) {
7084 std::unordered_set<TxId, SaltedTxIdHasher>
7085 confirmedTxIdsInNonFinalizedBlocks;
7086 bool missing_block =
false;
7088 block !=
nullptr && block != pindex;
7089 block = block->pprev) {
7091 getBlockFromIndex(block);
7092 if (!currentBlock) {
7094 "avaresponse: failed to get "
7095 "finalized block descendant from "
7098 missing_block =
true;
7101 for (
const auto &tx : currentBlock->vtx) {
7102 confirmedTxIdsInNonFinalizedBlocks
7103 .insert(tx->GetId());
7107 if (missing_block) {
7119 confirmedTxIdsInNonFinalizedBlocks);
7131 config, chainstate, &m_mempool,
7133 blockAssembler.pblocktemplate.reset(
7136 if (blockAssembler.pblocktemplate) {
7137 blockAssembler.addTxs(m_mempool);
7138 blockTemplate = std::move(
7139 blockAssembler.pblocktemplate);
7144 if (blockTemplate) {
7149 for (
const auto &templateEntry :
7163 if (fStakingPreconsensus) {
7165 std::get_if<const avalanche::StakeContenderId>(&item)) {
7167 logVoteUpdate(u,
"contender", contenderId);
7169 switch (u.getStatus()) {
7190 if (!fPreconsensus) {
7194 if (
auto pitem = std::get_if<const CTransactionRef>(&item)) {
7198 const TxId &txid = tx->GetId();
7199 const auto status{u.getStatus()};
7204 logVoteUpdate(u,
"tx", txid);
7216 std::shared_ptr<const std::vector<Coin>> spentCoins;
7228 _spentCoins.has_value()
7229 ? std::make_shared<const std::vector<Coin>>(
7230 std::move(*_spentCoins))
7234 if (m_mempool.
exists(txid)) {
7238 std::vector<CTransactionRef> conflictingTxs =
7244 if (conflictingTxs.size() > 0) {
7252 "Attempting to pull a now invalid "
7253 "conflicting tx %s to mempool\n",
7254 conflictingTxs[0]->GetId().
ToString());
7261 for (
const auto &conflictingTx :
7264 conflictingTx->GetId());
7283 m_recent_rejects.insert(txid);
7285 AddToCompactExtraTransactions(tx);
7302 return conflicting.HaveTx(txid);
7305 std::vector<CTransactionRef>
7306 mempool_conflicting_txs;
7307 for (
const auto &txin : tx->vin) {
7312 mempool_conflicting_txs.push_back(
7313 std::move(conflict));
7320 LogError(
"accepted tx %s failed mempool "
7328 [&txid, &mempool_conflicting_txs](
7333 if (mempool_conflicting_txs.size() >
7336 mempool_conflicting_txs[0],
7345 auto it = m_mempool.
GetIter(txid);
7346 if (!it.has_value()) {
7349 "Error: finalized tx (%s) is not in the "
7355 std::vector<TxId> finalizedTxIds;
7356 m_mempool.setAvalancheFinalized(
7361 for (
const auto &finalized_txid : finalizedTxIds) {
7366 logVoteUpdate(u,
"tx", finalized_txid);
7374 std::vector<CTransactionRef>
7377 for (
const auto &conflictingTx :
7379 m_recent_rejects.insert(
7380 conflictingTx->GetId());
7382 conflictingTx->GetId());
7408 m_txrequest.ForgetInvId(txid);
7414 for (
auto &it : m_peer_map) {
7415 auto tx_relay = (*it.second).GetTxRelay();
7420 LOCK(tx_relay->m_tx_inventory_mutex);
7427 auto &stalled_by_time =
7428 tx_relay->m_avalanche_stalled_txids
7430 if (stalled_by_time.size() >=
7432 stalled_by_time.erase(
7433 stalled_by_time.begin()->timeAdded);
7436 tx_relay->m_avalanche_stalled_txids.insert(
7441 AddToCompactExtraTransactions(tx);
7449 if (shouldActivateBestChain) {
7452 state,
nullptr, m_avalanche)) {
7467 ReceivedAvalancheProof(pfrom, *peer, proof);
7476 if (peer->m_proof_relay ==
nullptr) {
7480 peer->m_proof_relay->lastSharedProofsUpdate =
7481 GetTime<std::chrono::seconds>();
7483 peer->m_proof_relay->sharedProofs =
7489 peer->m_proof_relay->sharedProofs);
7499 if (peer->m_proof_relay ==
nullptr) {
7504 if (!peer->m_proof_relay->compactproofs_requested) {
7508 peer->m_proof_relay->compactproofs_requested =
false;
7512 vRecv >> compactProofs;
7513 }
catch (std::ios_base::failure &e) {
7515 Misbehaving(*peer,
"avaproofs-bad-indexes");
7521 if (!ReceivedAvalancheProof(pfrom, *peer, prefilledProof.proof)) {
7551 auto shortIdProcessor =
7555 if (shortIdProcessor.hasOutOfBoundIndex()) {
7558 Misbehaving(*peer,
"avaproofs-bad-indexes");
7561 if (!shortIdProcessor.isEvenlyDistributed()) {
7566 std::vector<std::pair<avalanche::ProofId, bool>> remoteProofsStatus;
7570 uint64_t shortid = compactProofs.
getShortID(proofid);
7572 int added = shortIdProcessor.matchKnownItem(shortid, proof);
7584 remoteProofsStatus.emplace_back(proofid, added > 0);
7589 matchKnownProof(peer.
proof);
7598 matchKnownProof(proof);
7603 for (
size_t i = 0; i < compactProofs.
size(); i++) {
7604 if (shortIdProcessor.getItem(i) ==
nullptr) {
7620 return pfrom.m_avalanche_pubkey.has_value())) {
7625 for (
const auto &[proofid, present] : remoteProofsStatus) {
7635 if (peer->m_proof_relay ==
nullptr) {
7642 auto requestedIndiceIt = proofreq.
indices.begin();
7643 uint32_t treeIndice = 0;
7644 peer->m_proof_relay->sharedProofs.forEachLeaf([&](
const auto &proof) {
7645 if (requestedIndiceIt == proofreq.
indices.end()) {
7650 if (treeIndice++ == *requestedIndiceIt) {
7652 requestedIndiceIt++;
7658 peer->m_proof_relay->sharedProofs = {};
7671 "Ignoring \"getaddr\" from %s connection. peer=%d\n",
7678 Assume(SetupAddressRelay(pfrom, *peer));
7682 if (peer->m_getaddr_recvd) {
7687 peer->m_getaddr_recvd =
true;
7689 peer->m_addrs_to_send.clear();
7690 std::vector<CAddress> vAddr;
7691 const size_t maxAddrToSend = m_opts.max_addr_to_send;
7699 for (
const CAddress &addr : vAddr) {
7700 PushAddress(*peer, addr);
7706 auto now = GetTime<std::chrono::seconds>();
7716 if (!SetupAddressRelay(pfrom, *peer)) {
7718 "Ignoring getavaaddr message from %s peer=%d\n",
7723 using AvaNodeInfo = std::tuple<CAddress, NodeId, double>;
7724 auto availabilityScoreComparator = [](
const AvaNodeInfo &lhs,
7725 const AvaNodeInfo &rhs) {
7726 double scoreLhs = std::get<double>(lhs);
7727 double scoreRhs = std::get<double>(rhs);
7729 if (scoreLhs != scoreRhs) {
7730 return scoreLhs > scoreRhs;
7733 return std::get<NodeId>(lhs) < std::get<NodeId>(rhs);
7739 std::set<AvaNodeInfo,
decltype(availabilityScoreComparator)> avaNodes(
7740 availabilityScoreComparator);
7747 avaNodes.insert(AvaNodeInfo{pnode->
addr, pnode->
GetId(), score});
7748 if (avaNodes.size() > m_opts.max_addr_to_send) {
7749 avaNodes.erase(std::prev(avaNodes.end()));
7753 peer->m_addrs_to_send.clear();
7754 for (
const auto &nodeInfo : avaNodes) {
7755 PushAddress(*peer, std::get<CAddress>(nodeInfo));
7766 "mempool request with bloom filters disabled, "
7767 "disconnect peer=%d\n",
7778 "mempool request with bandwidth limit reached, "
7779 "disconnect peer=%d\n",
7786 if (
auto tx_relay = peer->GetTxRelay()) {
7787 LOCK(tx_relay->m_tx_inventory_mutex);
7788 tx_relay->m_send_mempool =
true;
7817 const auto ping_end = time_received;
7820 bool bPingFinished =
false;
7821 std::string sProblem;
7823 if (nAvail >=
sizeof(nonce)) {
7828 if (peer->m_ping_nonce_sent != 0) {
7829 if (nonce == peer->m_ping_nonce_sent) {
7832 bPingFinished =
true;
7833 const auto ping_time = ping_end - peer->m_ping_start.load();
7834 if (ping_time.count() >= 0) {
7839 sProblem =
"Timing mishap";
7843 sProblem =
"Nonce mismatch";
7847 bPingFinished =
true;
7848 sProblem =
"Nonce zero";
7852 sProblem =
"Unsolicited pong without ping";
7857 bPingFinished =
true;
7858 sProblem =
"Short payload";
7861 if (!(sProblem.empty())) {
7863 "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
7864 pfrom.
GetId(), sProblem, peer->m_ping_nonce_sent, nonce,
7867 if (bPingFinished) {
7868 peer->m_ping_nonce_sent = 0;
7876 "filterload received despite not offering bloom services "
7877 "from peer=%d; disconnecting\n",
7887 Misbehaving(*peer,
"too-large bloom filter");
7888 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7890 LOCK(tx_relay->m_bloom_filter_mutex);
7891 tx_relay->m_bloom_filter.reset(
new CBloomFilter(filter));
7892 tx_relay->m_relay_txs =
true;
7902 "filteradd received despite not offering bloom services "
7903 "from peer=%d; disconnecting\n",
7908 std::vector<uint8_t> vData;
7917 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7918 LOCK(tx_relay->m_bloom_filter_mutex);
7919 if (tx_relay->m_bloom_filter) {
7920 tx_relay->m_bloom_filter->insert(vData);
7928 Misbehaving(*peer,
"bad filteradd message");
7936 "filterclear received despite not offering bloom services "
7937 "from peer=%d; disconnecting\n",
7942 auto tx_relay = peer->GetTxRelay();
7948 LOCK(tx_relay->m_bloom_filter_mutex);
7949 tx_relay->m_bloom_filter =
nullptr;
7950 tx_relay->m_relay_txs =
true;
7959 vRecv >> newFeeFilter;
7961 if (
auto tx_relay = peer->GetTxRelay()) {
7962 tx_relay->m_fee_filter_received = newFeeFilter;
7971 ProcessGetCFilters(pfrom, *peer, vRecv);
7976 ProcessGetCFHeaders(pfrom, *peer, vRecv);
7981 ProcessGetCFCheckPt(pfrom, *peer, vRecv);
7986 std::vector<CInv> vInv;
7992 for (
CInv &inv : vInv) {
7998 m_txrequest.ReceivedResponse(pfrom.
GetId(),
TxId(inv.
hash));
8005 LOCK(cs_proofrequest);
8006 m_proofrequest.ReceivedResponse(
8020bool PeerManagerImpl::MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer) {
8022 LOCK(peer.m_misbehavior_mutex);
8025 if (!peer.m_should_discourage) {
8029 peer.m_should_discourage =
false;
8035 LogPrintf(
"Warning: not punishing noban peer %d!\n", peer.m_id);
8041 LogPrintf(
"Warning: not punishing manually connected peer %d!\n",
8050 "Warning: disconnecting but not discouraging %s peer %d!\n",
8067bool PeerManagerImpl::ProcessMessages(
const Config &config,
CNode *pfrom,
8068 std::atomic<bool> &interruptMsgProc) {
8071 PeerRef peer = GetPeerRef(pfrom->
GetId());
8072 if (peer ==
nullptr) {
8077 LOCK(peer->m_getdata_requests_mutex);
8078 if (!peer->m_getdata_requests.empty()) {
8079 ProcessGetData(config, *pfrom, *peer, interruptMsgProc);
8083 const bool processed_orphan = ProcessOrphanTx(config, *peer);
8089 if (processed_orphan) {
8096 LOCK(peer->m_getdata_requests_mutex);
8097 if (!peer->m_getdata_requests.empty()) {
8114 bool fMoreWork = poll_result->second;
8118 msg.m_recv.size(),
msg.m_recv.data());
8120 if (m_opts.capture_messages) {
8126 ProcessMessage(config, *pfrom,
msg.m_type,
msg.m_recv,
msg.m_time,
8128 if (interruptMsgProc) {
8133 LOCK(peer->m_getdata_requests_mutex);
8134 if (!peer->m_getdata_requests.empty()) {
8143 return orphanage.HaveTxToReconsider(peer->m_id);
8147 }
catch (
const std::exception &e) {
8150 e.what(),
typeid(e).name());
8159void PeerManagerImpl::ConsiderEviction(
CNode &pto, Peer &peer,
8160 std::chrono::seconds time_in_seconds) {
8163 CNodeState &state = *State(pto.
GetId());
8166 state.fSyncStarted) {
8173 if (state.pindexBestKnownBlock !=
nullptr &&
8174 state.pindexBestKnownBlock->nChainWork >=
8176 if (state.m_chain_sync.m_timeout != 0s) {
8177 state.m_chain_sync.m_timeout = 0s;
8178 state.m_chain_sync.m_work_header =
nullptr;
8179 state.m_chain_sync.m_sent_getheaders =
false;
8181 }
else if (state.m_chain_sync.m_timeout == 0s ||
8182 (state.m_chain_sync.m_work_header !=
nullptr &&
8183 state.pindexBestKnownBlock !=
nullptr &&
8184 state.pindexBestKnownBlock->nChainWork >=
8185 state.m_chain_sync.m_work_header->nChainWork)) {
8191 state.m_chain_sync.m_work_header = m_chainman.
ActiveChain().
Tip();
8192 state.m_chain_sync.m_sent_getheaders =
false;
8193 }
else if (state.m_chain_sync.m_timeout > 0s &&
8194 time_in_seconds > state.m_chain_sync.m_timeout) {
8199 if (state.m_chain_sync.m_sent_getheaders) {
8202 "Disconnecting outbound peer %d for old chain, best known "
8205 state.pindexBestKnownBlock !=
nullptr
8206 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
8210 assert(state.m_chain_sync.m_work_header);
8215 MaybeSendGetHeaders(
8216 pto,
GetLocator(state.m_chain_sync.m_work_header->pprev),
8220 "sending getheaders to outbound peer=%d to verify chain "
8221 "work (current best known block:%s, benchmark blockhash: "
8224 state.pindexBestKnownBlock !=
nullptr
8225 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
8227 state.m_chain_sync.m_work_header->GetBlockHash()
8229 state.m_chain_sync.m_sent_getheaders =
true;
8236 state.m_chain_sync.m_timeout =
8243void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now) {
8252 std::pair<NodeId, std::chrono::seconds> youngest_peer{-1, 0},
8253 next_youngest_peer{-1, 0};
8259 if (pnode->
GetId() > youngest_peer.first) {
8260 next_youngest_peer = youngest_peer;
8261 youngest_peer.first = pnode->GetId();
8262 youngest_peer.second = pnode->m_last_block_time;
8266 NodeId to_disconnect = youngest_peer.first;
8267 if (youngest_peer.second > next_youngest_peer.second) {
8270 to_disconnect = next_youngest_peer.first;
8282 CNodeState *node_state = State(pnode->
GetId());
8283 if (node_state ==
nullptr ||
8285 node_state->vBlocksInFlight.empty())) {
8288 "disconnecting extra block-relay-only peer=%d "
8289 "(last block received at time %d)\n",
8296 "keeping block-relay-only peer=%d chosen for eviction "
8297 "(connect time: %d, blocks_in_flight: %d)\n",
8299 node_state->vBlocksInFlight.size());
8315 int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
8326 CNodeState *state = State(pnode->
GetId());
8327 if (state ==
nullptr) {
8332 if (state->m_chain_sync.m_protect) {
8335 if (state->m_last_block_announcement < oldest_block_announcement ||
8336 (state->m_last_block_announcement == oldest_block_announcement &&
8337 pnode->
GetId() > worst_peer)) {
8338 worst_peer = pnode->
GetId();
8339 oldest_block_announcement = state->m_last_block_announcement;
8343 if (worst_peer == -1) {
8347 bool disconnected = m_connman.
ForNode(
8355 CNodeState &state = *State(pnode->
GetId());
8357 state.vBlocksInFlight.empty()) {
8359 "disconnecting extra outbound peer=%d (last block "
8360 "announcement received at time %d)\n",
8361 pnode->
GetId(), oldest_block_announcement);
8366 "keeping outbound peer=%d chosen for eviction "
8367 "(connect time: %d, blocks_in_flight: %d)\n",
8369 state.vBlocksInFlight.size());
8384void PeerManagerImpl::CheckForStaleTipAndEvictPeers() {
8387 auto now{GetTime<std::chrono::seconds>()};
8389 EvictExtraOutboundPeers(now);
8391 if (now > m_stale_tip_check_time) {
8397 LogPrintf(
"Potential stale tip detected, will try using extra "
8398 "outbound peer (last tip update: %d seconds ago)\n",
8407 if (!m_initial_sync_finished && CanDirectFetch()) {
8409 m_initial_sync_finished =
true;
8413void PeerManagerImpl::MaybeSendPing(
CNode &node_to, Peer &peer,
8414 std::chrono::microseconds now) {
8416 node_to, std::chrono::duration_cast<std::chrono::seconds>(now)) &&
8417 peer.m_ping_nonce_sent &&
8428 bool pingSend =
false;
8430 if (peer.m_ping_queued) {
8435 if (peer.m_ping_nonce_sent == 0 &&
8445 }
while (nonce == 0);
8446 peer.m_ping_queued =
false;
8447 peer.m_ping_start = now;
8449 peer.m_ping_nonce_sent = nonce;
8454 peer.m_ping_nonce_sent = 0;
8460void PeerManagerImpl::MaybeSendAddr(
CNode &
node, Peer &peer,
8461 std::chrono::microseconds current_time) {
8463 if (!peer.m_addr_relay_enabled) {
8467 LOCK(peer.m_addr_send_times_mutex);
8469 peer.m_next_local_addr_send < current_time) {
8476 if (peer.m_next_local_addr_send != 0us) {
8477 peer.m_addr_known->reset();
8480 CAddress local_addr{*local_service, peer.m_our_services,
8481 Now<NodeSeconds>()};
8482 PushAddress(peer, local_addr);
8484 peer.m_next_local_addr_send =
8490 if (current_time <= peer.m_next_addr_send) {
8494 peer.m_next_addr_send =
8497 const size_t max_addr_to_send = m_opts.max_addr_to_send;
8498 if (!
Assume(peer.m_addrs_to_send.size() <= max_addr_to_send)) {
8501 peer.m_addrs_to_send.resize(max_addr_to_send);
8506 auto addr_already_known =
8509 bool ret = peer.m_addr_known->contains(addr.
GetKey());
8511 peer.m_addr_known->insert(addr.
GetKey());
8515 peer.m_addrs_to_send.erase(std::remove_if(peer.m_addrs_to_send.begin(),
8516 peer.m_addrs_to_send.end(),
8517 addr_already_known),
8518 peer.m_addrs_to_send.end());
8521 if (peer.m_addrs_to_send.empty()) {
8525 const char *msg_type;
8527 if (peer.m_wants_addrv2) {
8537 peer.m_addrs_to_send));
8538 peer.m_addrs_to_send.clear();
8541 if (peer.m_addrs_to_send.capacity() > 40) {
8542 peer.m_addrs_to_send.shrink_to_fit();
8546void PeerManagerImpl::MaybeSendSendHeaders(
CNode &
node, Peer &peer) {
8551 if (!peer.m_sent_sendheaders &&
8554 CNodeState &state = *State(
node.GetId());
8555 if (state.pindexBestKnownBlock !=
nullptr &&
8556 state.pindexBestKnownBlock->nChainWork >
8563 peer.m_sent_sendheaders =
true;
8568void PeerManagerImpl::MaybeSendFeefilter(
8569 CNode &pto, Peer &peer, std::chrono::microseconds current_time) {
8570 if (m_opts.ignore_incoming_txs) {
8594 static const Amount MAX_FILTER{m_fee_filter_rounder.round(
MAX_MONEY)};
8595 if (peer.m_fee_filter_sent == MAX_FILTER) {
8598 peer.m_next_send_feefilter = 0us;
8601 if (current_time > peer.m_next_send_feefilter) {
8602 Amount filterToSend = m_fee_filter_rounder.round(currentFilter);
8604 filterToSend = std::max(
8606 if (filterToSend != peer.m_fee_filter_sent) {
8608 peer.m_fee_filter_sent = filterToSend;
8610 peer.m_next_send_feefilter =
8618 peer.m_next_send_feefilter &&
8619 (currentFilter < 3 * peer.m_fee_filter_sent / 4 ||
8620 currentFilter > 4 * peer.m_fee_filter_sent / 3)) {
8621 peer.m_next_send_feefilter =
8629class CompareInvMempoolOrder {
8633 explicit CompareInvMempoolOrder(
CTxMemPool *_mempool) : mp(_mempool) {}
8635 bool operator()(std::set<TxId>::iterator a, std::set<TxId>::iterator b) {
8645bool PeerManagerImpl::RejectIncomingTxs(
const CNode &peer)
const {
8654 if (m_opts.ignore_incoming_txs &&
8661bool PeerManagerImpl::SetupAddressRelay(
const CNode &
node, Peer &peer) {
8665 if (
node.IsBlockOnlyConn()) {
8669 if (!peer.m_addr_relay_enabled.exchange(
true)) {
8673 peer.m_addr_known = std::make_unique<CRollingBloomFilter>(5000, 0.001);
8679bool PeerManagerImpl::SendMessages(
const Config &config,
CNode *pto) {
8682 PeerRef peer = GetPeerRef(pto->
GetId());
8691 if (MaybeDiscourageAndDisconnect(*pto, *peer)) {
8700 const auto current_time{GetTime<std::chrono::microseconds>()};
8705 "addrfetch connection timeout; disconnecting peer=%d\n",
8711 MaybeSendPing(*pto, *peer, current_time);
8718 bool sync_blocks_and_headers_from_peer =
false;
8720 MaybeSendAddr(*pto, *peer, current_time);
8722 MaybeSendSendHeaders(*pto, *peer);
8727 CNodeState &state = *State(pto->
GetId());
8730 if (m_chainman.m_best_header ==
nullptr) {
8737 if (state.fPreferredDownload) {
8738 sync_blocks_and_headers_from_peer =
true;
8749 if (m_num_preferred_download_peers == 0 ||
8750 mapBlocksInFlight.empty()) {
8751 sync_blocks_and_headers_from_peer =
true;
8755 if (!state.fSyncStarted && CanServeBlocks(*peer) &&
8759 if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) ||
8761 const CBlockIndex *pindexStart = m_chainman.m_best_header;
8770 if (pindexStart->
pprev) {
8771 pindexStart = pindexStart->
pprev;
8773 if (MaybeSendGetHeaders(*pto,
GetLocator(pindexStart), *peer)) {
8776 "initial getheaders (%d) to peer=%d (startheight:%d)\n",
8778 peer->m_starting_height);
8780 state.fSyncStarted =
true;
8781 peer->m_headers_sync_timeout =
8786 std::chrono::microseconds{
8788 Ticks<std::chrono::seconds>(
8790 m_chainman.m_best_header->Time()) /
8807 LOCK(peer->m_block_inv_mutex);
8808 std::vector<CBlock> vHeaders;
8810 ((!peer->m_prefers_headers &&
8811 (!state.m_requested_hb_cmpctblocks ||
8812 peer->m_blocks_for_headers_relay.size() > 1)) ||
8813 peer->m_blocks_for_headers_relay.size() >
8818 ProcessBlockAvailability(pto->
GetId());
8820 if (!fRevertToInv) {
8821 bool fFoundStartingHeader =
false;
8825 for (
const BlockHash &hash : peer->m_blocks_for_headers_relay) {
8831 fRevertToInv =
true;
8834 if (pBestIndex !=
nullptr && pindex->
pprev != pBestIndex) {
8845 fRevertToInv =
true;
8848 pBestIndex = pindex;
8849 if (fFoundStartingHeader) {
8852 }
else if (PeerHasHeader(&state, pindex)) {
8855 }
else if (pindex->
pprev ==
nullptr ||
8856 PeerHasHeader(&state, pindex->
pprev)) {
8859 fFoundStartingHeader =
true;
8864 fRevertToInv =
true;
8869 if (!fRevertToInv && !vHeaders.empty()) {
8870 if (vHeaders.size() == 1 && state.m_requested_hb_cmpctblocks) {
8875 "%s sending header-and-ids %s to peer=%d\n",
8876 __func__, vHeaders.front().GetHash().ToString(),
8879 std::optional<CSerializedNetMsg> cached_cmpctblock_msg;
8881 LOCK(m_most_recent_block_mutex);
8882 if (m_most_recent_block_hash ==
8884 cached_cmpctblock_msg =
8886 *m_most_recent_compact_block);
8889 if (cached_cmpctblock_msg.has_value()) {
8891 std::move(cached_cmpctblock_msg.value()));
8895 block, *pBestIndex)};
8902 state.pindexBestHeaderSent = pBestIndex;
8903 }
else if (peer->m_prefers_headers) {
8904 if (vHeaders.size() > 1) {
8906 "%s: %u headers, range (%s, %s), to peer=%d\n",
8907 __func__, vHeaders.size(),
8908 vHeaders.front().GetHash().ToString(),
8909 vHeaders.back().GetHash().ToString(),
8913 "%s: sending header %s to peer=%d\n", __func__,
8914 vHeaders.front().GetHash().ToString(),
8918 state.pindexBestHeaderSent = pBestIndex;
8920 fRevertToInv =
true;
8927 if (!peer->m_blocks_for_headers_relay.empty()) {
8929 peer->m_blocks_for_headers_relay.back();
8940 "Announcing block %s not on main chain (tip=%s)\n",
8949 if (!PeerHasHeader(&state, pindex)) {
8950 peer->m_blocks_for_inv_relay.push_back(hashToAnnounce);
8952 "%s: sending inv peer=%d hash=%s\n", __func__,
8957 peer->m_blocks_for_headers_relay.clear();
8964 std::vector<CInv> vInv;
8965 auto addInvAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
8966 vInv.emplace_back(type, hash);
8977 LOCK(peer->m_block_inv_mutex);
8979 vInv.reserve(std::max<size_t>(peer->m_blocks_for_inv_relay.size(),
8985 for (
const BlockHash &hash : peer->m_blocks_for_inv_relay) {
8988 peer->m_blocks_for_inv_relay.clear();
8991 auto computeNextInvSendTime =
8992 [&](std::chrono::microseconds &next)
8996 if (next < current_time) {
8997 fSendTrickle =
true;
8999 next = NextInvToInbounds(
9004 next = current_time;
9008 return fSendTrickle;
9012 if (peer->m_proof_relay !=
nullptr) {
9013 LOCK(peer->m_proof_relay->m_proof_inventory_mutex);
9015 if (computeNextInvSendTime(
9016 peer->m_proof_relay->m_next_inv_send_time)) {
9018 peer->m_proof_relay->m_proof_inventory_to_send.begin();
9020 peer->m_proof_relay->m_proof_inventory_to_send.end()) {
9023 it = peer->m_proof_relay->m_proof_inventory_to_send.erase(
9026 if (peer->m_proof_relay->m_proof_inventory_known_filter
9027 .contains(proofid)) {
9031 peer->m_proof_relay->m_proof_inventory_known_filter.insert(
9034 peer->m_proof_relay->m_recently_announced_proofs.insert(
9040 if (
auto tx_relay = peer->GetTxRelay()) {
9041 LOCK(tx_relay->m_tx_inventory_mutex);
9043 const bool fSendTrickle =
9044 computeNextInvSendTime(tx_relay->m_next_inv_send_time);
9049 LOCK(tx_relay->m_bloom_filter_mutex);
9050 if (!tx_relay->m_relay_txs) {
9051 tx_relay->m_tx_inventory_to_send.clear();
9056 if (fSendTrickle && tx_relay->m_send_mempool) {
9057 auto vtxinfo = m_mempool.
infoAll();
9058 tx_relay->m_send_mempool =
false;
9060 tx_relay->m_fee_filter_received.load()};
9062 LOCK(tx_relay->m_bloom_filter_mutex);
9064 for (
const auto &txinfo : vtxinfo) {
9065 const TxId &txid = txinfo.tx->GetId();
9066 tx_relay->m_tx_inventory_to_send.erase(txid);
9069 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
9072 if (tx_relay->m_bloom_filter &&
9073 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
9077 tx_relay->m_tx_inventory_known_filter.insert(txid);
9080 addInvAndMaybeFlush(
MSG_TX, txid);
9082 tx_relay->m_last_mempool_req =
9083 std::chrono::duration_cast<std::chrono::seconds>(
9090 std::vector<std::set<TxId>::iterator> vInvTx;
9091 vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size());
9092 for (std::set<TxId>::iterator it =
9093 tx_relay->m_tx_inventory_to_send.begin();
9094 it != tx_relay->m_tx_inventory_to_send.end(); it++) {
9095 vInvTx.push_back(it);
9098 tx_relay->m_fee_filter_received.load()};
9103 CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool);
9104 std::make_heap(vInvTx.begin(), vInvTx.end(),
9105 compareInvMempoolOrder);
9109 unsigned int nRelayedTransactions = 0;
9110 LOCK(tx_relay->m_bloom_filter_mutex);
9111 while (!vInvTx.empty() &&
9116 std::pop_heap(vInvTx.begin(), vInvTx.end(),
9117 compareInvMempoolOrder);
9118 std::set<TxId>::iterator it = vInvTx.back();
9120 const TxId txid = *it;
9122 tx_relay->m_tx_inventory_to_send.erase(it);
9124 if (tx_relay->m_tx_inventory_known_filter.contains(txid) &&
9125 tx_relay->m_avalanche_stalled_txids.count(txid) == 0) {
9129 auto txinfo = m_mempool.
info(txid);
9135 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
9138 if (tx_relay->m_bloom_filter &&
9139 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
9144 tx_relay->m_recently_announced_invs.insert(txid);
9145 addInvAndMaybeFlush(
MSG_TX, txid);
9146 nRelayedTransactions++;
9147 tx_relay->m_tx_inventory_known_filter.insert(txid);
9148 tx_relay->m_avalanche_stalled_txids.erase(txid);
9154 if (!vInv.empty()) {
9161 CNodeState &state = *State(pto->
GetId());
9164 auto stalling_timeout = m_block_stalling_timeout.load();
9165 if (state.m_stalling_since.count() &&
9166 state.m_stalling_since < current_time - stalling_timeout) {
9171 LogPrintf(
"Peer=%d is stalling block download, disconnecting\n",
9176 const auto new_timeout =
9178 if (stalling_timeout != new_timeout &&
9179 m_block_stalling_timeout.compare_exchange_strong(
9180 stalling_timeout, new_timeout)) {
9183 "Increased stalling timeout temporarily to %d seconds\n",
9195 if (state.vBlocksInFlight.size() > 0) {
9196 QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
9197 int nOtherPeersWithValidatedDownloads =
9198 m_peers_downloading_from - 1;
9200 state.m_downloading_since +
9201 std::chrono::seconds{consensusParams.nPowTargetSpacing} *
9204 nOtherPeersWithValidatedDownloads)) {
9205 LogPrintf(
"Timeout downloading block %s from peer=%d, "
9207 queuedBlock.pindex->GetBlockHash().ToString(),
9215 if (state.fSyncStarted &&
9216 peer->m_headers_sync_timeout < std::chrono::microseconds::max()) {
9219 if (current_time > peer->m_headers_sync_timeout &&
9220 nSyncStarted == 1 &&
9221 (m_num_preferred_download_peers -
9222 state.fPreferredDownload >=
9231 LogPrintf(
"Timeout downloading headers from peer=%d, "
9237 LogPrintf(
"Timeout downloading headers from noban "
9238 "peer=%d, not disconnecting\n",
9244 state.fSyncStarted =
false;
9246 peer->m_headers_sync_timeout = 0us;
9252 peer->m_headers_sync_timeout = std::chrono::microseconds::max();
9258 ConsiderEviction(*pto, *peer, GetTime<std::chrono::seconds>());
9261 std::vector<CInv> vGetData;
9269 CNodeState &state = *State(pto->
GetId());
9271 if (CanServeBlocks(*peer) &&
9272 ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) ||
9275 std::vector<const CBlockIndex *> vToDownload;
9277 auto get_inflight_budget = [&state]() {
9280 static_cast<int>(state.vBlocksInFlight.size()));
9286 FindNextBlocksToDownload(*peer, get_inflight_budget(), vToDownload,
9289 !IsLimitedPeer(*peer)) {
9295 m_chainman.GetSnapshotBaseBlock());
9297 TryDownloadingHistoricalBlocks(
9298 *peer, get_inflight_budget(), vToDownload, from_tip,
9299 Assert(m_chainman.GetSnapshotBaseBlock()));
9303 BlockRequested(config, pto->
GetId(), *pindex);
9308 if (state.vBlocksInFlight.empty() && staller != -1) {
9309 if (State(staller)->m_stalling_since == 0us) {
9310 State(staller)->m_stalling_since = current_time;
9317 auto addGetDataAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
9318 CInv inv(type, hash);
9321 vGetData.push_back(std::move(inv));
9332 LOCK(cs_proofrequest);
9333 std::vector<std::pair<NodeId, avalanche::ProofId>> expired;
9335 m_proofrequest.GetRequestable(pto->
GetId(), current_time, &expired);
9336 for (
const auto &entry : expired) {
9338 "timeout of inflight proof %s from peer=%d\n",
9339 entry.second.ToString(), entry.first);
9341 for (
const auto &proofid : requestable) {
9342 if (!AlreadyHaveProof(proofid)) {
9344 m_proofrequest.RequestedData(
9345 pto->
GetId(), proofid,
9352 m_proofrequest.ForgetInvId(proofid);
9362 std::vector<std::pair<NodeId, TxId>> expired;
9364 m_txrequest.GetRequestable(pto->
GetId(), current_time, &expired);
9365 for (
const auto &entry : expired) {
9367 entry.second.ToString(), entry.first);
9369 for (
const TxId &txid : requestable) {
9373 if (!AlreadyHaveTx(txid,
false)) {
9374 addGetDataAndMaybeFlush(
MSG_TX, txid);
9375 m_txrequest.RequestedData(
9382 m_txrequest.ForgetInvId(txid);
9386 if (!vGetData.empty()) {
9391 MaybeSendFeefilter(*pto, *peer, current_time);
9395bool PeerManagerImpl::ReceivedAvalancheProof(
CNode &
node, Peer &peer,
9398 LogError(
"ReceivedAvalancheProof: proof is null\n");
9404 AddKnownProof(peer, proofid);
9416 return node.m_avalanche_pubkey.has_value());
9417 auto saveProofIfStaker = [
this, isStaker](
const CNode &
node,
9419 const NodeId nodeid) ->
bool {
9431 LOCK(cs_proofrequest);
9432 m_proofrequest.ReceivedResponse(nodeid, proofid);
9434 if (AlreadyHaveProof(proofid)) {
9435 m_proofrequest.ForgetInvId(proofid);
9436 saveProofIfStaker(
node, proofid, nodeid);
9446 return pm.registerProof(proof, state);
9448 WITH_LOCK(cs_proofrequest, m_proofrequest.ForgetInvId(proofid));
9449 RelayProof(proofid);
9451 node.m_last_proof_time = GetTime<std::chrono::seconds>();
9454 nodeid, proofid.ToString());
9476 "Not polling the avalanche proof (%s): peer=%d, proofid %s\n",
9477 state.
IsValid() ?
"not-worth-polling"
9479 nodeid, proofid.ToString());
9482 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 kilobyte: Amount / kB.
Amount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
Inv(ventory) message data.
bool IsMsgCmpctBlk() const
std::string ToString() const
bool IsMsgStakeContender() const
bool IsMsgFilteredBlk() const
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
std::chrono::seconds m_nextGetAvaAddr
uint64_t nRemoteExtraEntropy
std::optional< std::pair< CNetMessage, bool > > PollMessage() EXCLUSIVE_LOCKS_REQUIRED(!m_msg_process_queue_mutex)
Poll the next message from the processing queue of this connection.
uint64_t GetLocalExtraEntropy() const
SteadyMilliseconds m_last_poll
double getAvailabilityScore() const
std::atomic_bool m_bloom_filter_loaded
Whether this peer has loaded a bloom filter.
void updateAvailabilityScore(double decayFactor)
The availability score is calculated using an exponentially weighted average.
std::atomic< std::chrono::seconds > m_avalanche_last_message_fault
const bool m_inbound_onion
Whether this peer is an inbound onion, i.e.
std::atomic< int > m_avalanche_message_fault_counter
How much faulty messages did this node accumulate.
std::atomic< bool > m_avalanche_enabled
std::atomic< std::chrono::seconds > m_last_block_time
UNIX epoch time of the last block received from this peer that we had not yet seen (e....
std::atomic_bool fDisconnect
std::atomic< int > m_avalanche_message_fault_score
This score is incremented for every new faulty message received when m_avalanche_message_fault_counte...
std::atomic< std::chrono::seconds > m_last_tx_time
UNIX epoch time of the last transaction received from this peer that we had not yet seen (e....
void invsVoted(uint32_t count)
The node voted for count invs.
bool IsAvalancheOutboundConnection() const
An encapsulated public key.
RollingBloomFilter is a probabilistic "keep track of most recently inserted" set.
Simple class for background tasks that should be run periodically or once "after a while".
void scheduleEvery(Predicate p, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Repeat p until it return false.
void scheduleFromNow(Function f, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Call f once after the delta has passed.
A combination of a network address (CNetAddr) and a (TCP) port.
std::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 CompareTopologically(const TxId &txida, const TxId &txidb) const
TxMempoolInfo info(const TxId &txid) const
size_t DynamicMemoryUsage() const
bool setAvalancheFinalized(const CTxMemPoolEntryRef &tx, const Consensus::Params ¶ms, const CBlockIndex &active_chain_tip, std::vector< TxId > &finalizedTxIds) EXCLUSIVE_LOCKS_REQUIRED(bool isAvalancheFinalizedPreConsensus(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
std::vector< TxMempoolInfo > infoAll() const
CTransactionRef GetConflictTx(const COutPoint &prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Get the transaction in the pool that spends the same prevout.
bool exists(const TxId &txid) const
std::set< TxId > GetUnbroadcastTxs() const
Returns transactions in unbroadcast set.
auto withOrphanage(Callable &&func) const EXCLUSIVE_LOCKS_REQUIRED(!cs_orphanage)
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 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
bool isPreconsensusActivated(const CBlockIndex *pprev) const
auto withPeerManager(Callable &&func) const EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
bool registerVotes(NodeId nodeid, const Response &response, std::vector< VoteItemUpdate > &updates, bool &disconnect, std::string &error) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager
void rejectStakeContender(const StakeContenderId &contenderId) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
void avaproofsSent(NodeId nodeid) LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!cs_peerManager)
void forEachProof(Callable &&func) const
std::vector< uint32_t > indices
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 LogPrint(category,...)
#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 MINIMUM_CONNECT_TIME
Minimum time an outbound-peer-eviction candidate must be connected for, in order to evict.
static constexpr auto CHAIN_SYNC_TIMEOUT
Timeout for (unprotected) outbound peers to sync to our chainwork.
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS
Minimum blocks required to signal NODE_NETWORK_LIMITED.
static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL
Average delay between local address broadcasts.
static const int MAX_BLOCKTXN_DEPTH
Maximum depth of blocks we're willing to respond to GETBLOCKTXN requests for.
static constexpr uint64_t CMPCTBLOCKS_VERSION
The compactblocks version we support.
bool IsAvalancheMessageType(const std::string &msg_type)
static constexpr int32_t MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT
Protect at least this many outbound peers from disconnection due to slow/behind headers chain.
static std::chrono::microseconds ComputeRequestTime(const CNode &node, const InvRequestTracker< InvId > &requestTracker, const DataRequestParameters &requestParams, std::chrono::microseconds current_time, bool preferred)
Compute the request time for this announcement, current time plus delays for:
static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL
Average delay between trickled inventory transmissions for inbound peers.
static constexpr DataRequestParameters TX_REQUEST_PARAMS
static constexpr auto MAX_FEEFILTER_CHANGE_DELAY
Maximum feefilter broadcast delay after significant change.
static constexpr uint32_t MAX_GETCFILTERS_SIZE
Maximum number of compact filters that may be requested with one getcfilters.
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_BASE
Headers download timeout.
static const unsigned int MAX_GETDATA_SZ
Limit to avoid sending big packets.
static constexpr double BLOCK_DOWNLOAD_TIMEOUT_BASE
Block download timeout base, expressed in multiples of the block interval (i.e.
static constexpr auto AVALANCHE_AVAPROOFS_TIMEOUT
If no proof was requested from a compact proof message after this timeout expired,...
static constexpr auto STALE_CHECK_INTERVAL
How frequently to check for stale tips.
static constexpr unsigned int INVENTORY_MAX_RECENT_RELAY
The number of most recently announced transactions a peer can request.
static constexpr auto UNCONDITIONAL_RELAY_DELAY
How long a transaction has to be in the mempool before it can unconditionally be relayed.
static constexpr auto AVG_ADDRESS_BROADCAST_INTERVAL
Average delay between peer address broadcasts.
static const unsigned int MAX_LOCATOR_SZ
The maximum number of entries in a locator.
static constexpr double BLOCK_DOWNLOAD_TIMEOUT_PER_PEER
Additional block download timeout per parallel downloading peer (i.e.
static constexpr double MAX_ADDR_RATE_PER_SECOND
The maximum rate of address records we're willing to process on average.
static constexpr auto PING_INTERVAL
Time between pings automatically sent out for latency probing and keepalive.
static const int MAX_CMPCTBLOCK_DEPTH
Maximum depth of blocks we're willing to serve as compact blocks to peers when requested.
static constexpr DataRequestParameters PROOF_REQUEST_PARAMS
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE
Maximum number of headers to announce when relaying blocks with headers message.
static bool TooManyAnnouncements(const CNode &node, const InvRequestTracker< InvId > &requestTracker, const DataRequestParameters &requestParams)
static constexpr uint32_t MAX_GETCFHEADERS_SIZE
Maximum number of cf hashes that may be requested with one getcfheaders.
static constexpr auto BLOCK_STALLING_TIMEOUT_MAX
Maximum timeout for stalling block download.
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER
static constexpr uint64_t RANDOMIZER_ID_ADDRESS_RELAY
SHA256("main address relay")[0:8].
static constexpr size_t MAX_PCT_ADDR_TO_SEND
the maximum percentage of addresses from our addrman to return in response to a getaddr message.
static const unsigned int MAX_INV_SZ
The maximum number of entries in an 'inv' protocol message.
static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND
Maximum rate of inventory items to send per second.
static constexpr size_t MAX_ADDR_TO_SEND
The maximum number of address records permitted in an ADDR message.
static const unsigned int MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK
Maximum number of outstanding CMPCTBLOCK requests for the same block.
static const unsigned int MAX_HEADERS_RESULTS
Number of headers sent in one getheaders result.
bool IsProxy(const CNetAddr &addr)
static constexpr NodeId NO_NODE
Special NodeId that represent no node.
uint256 GetPackageHash(const Package &package)
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
static constexpr Amount DEFAULT_MIN_RELAY_TX_FEE_PER_KB(1000 *SATOSHI)
Default for -minrelaytxfee, minimum relay fee for transactions.
std::shared_ptr< const CTransaction > CTransactionRef
static constexpr size_t AVALANCHE_MAX_ELEMENT_POLL_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...