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>
115 "Max protocol message length must be greater than largest "
116 "possible INV message");
173 std::chrono::seconds(2),
174 std::chrono::seconds(2),
175 std::chrono::seconds(60),
182 std::chrono::seconds(2),
183 std::chrono::seconds(2),
184 std::chrono::seconds(60),
217 "MAX_BLOCKTXN_DEPTH too high");
276 std::chrono::seconds{1},
277 "INVENTORY_RELAY_MAX too low");
328 std::unique_ptr<PartiallyDownloadedBlock> partialBlock;
333 std::chrono::seconds timeAdded;
335 StalledTxId(
TxId txid_, std::chrono::seconds timeAdded_)
336 : txid(txid_), timeAdded(timeAdded_){};
342using StalledTxIdSet = boost::multi_index_container<
344 boost::multi_index::indexed_by<
346 boost::multi_index::hashed_unique<
347 boost::multi_index::tag<by_txid>,
348 boost::multi_index::member<StalledTxId, TxId, &StalledTxId::txid>,
351 boost::multi_index::ordered_non_unique<
352 boost::multi_index::tag<by_time>,
353 boost::multi_index::member<StalledTxId, std::chrono::seconds,
354 &StalledTxId::timeAdded>>>>;
391 std::atomic<ServiceFlags> m_their_services{
NODE_NONE};
394 Mutex m_misbehavior_mutex;
399 bool m_should_discourage
GUARDED_BY(m_misbehavior_mutex){
false};
402 Mutex m_block_inv_mutex;
408 std::vector<BlockHash> m_blocks_for_inv_relay
GUARDED_BY(m_block_inv_mutex);
414 std::vector<BlockHash>
415 m_blocks_for_headers_relay
GUARDED_BY(m_block_inv_mutex);
426 std::atomic<int> m_starting_height{-1};
429 std::atomic<uint64_t> m_ping_nonce_sent{0};
431 std::atomic<std::chrono::microseconds> m_ping_start{0us};
433 std::atomic<bool> m_ping_queued{
false};
443 std::chrono::microseconds m_next_send_feefilter
456 bool m_relay_txs
GUARDED_BY(m_bloom_filter_mutex){
false};
461 std::unique_ptr<CBloomFilter>
477 GUARDED_BY(m_tx_inventory_mutex){50000, 0.000001};
483 std::set<TxId> m_tx_inventory_to_send
GUARDED_BY(m_tx_inventory_mutex);
489 bool m_send_mempool
GUARDED_BY(m_tx_inventory_mutex){
false};
491 std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
496 std::chrono::microseconds
497 m_next_inv_send_time
GUARDED_BY(m_tx_inventory_mutex){0};
503 std::atomic<Amount> m_fee_filter_received{
Amount::zero()};
509 m_avalanche_stalled_txids
GUARDED_BY(m_tx_inventory_mutex);
517 LOCK(m_tx_relay_mutex);
519 m_tx_relay = std::make_unique<Peer::TxRelay>();
520 return m_tx_relay.get();
524 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
526 const TxRelay *GetTxRelay() const
528 return WITH_LOCK(m_tx_relay_mutex,
return m_tx_relay.get());
533 std::set<avalanche::ProofId>
534 m_proof_inventory_to_send
GUARDED_BY(m_proof_inventory_mutex);
537 GUARDED_BY(m_proof_inventory_mutex){10000, 0.000001};
544 std::chrono::microseconds m_next_inv_send_time{0};
548 std::atomic<std::chrono::seconds> lastSharedProofsUpdate{0s};
549 std::atomic<bool> compactproofs_requested{
false};
556 const std::unique_ptr<ProofRelay> m_proof_relay;
561 std::vector<CAddress>
573 std::unique_ptr<CRollingBloomFilter>
591 std::atomic_bool m_addr_relay_enabled{
false};
595 mutable Mutex m_addr_send_times_mutex;
597 std::chrono::microseconds
598 m_next_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
600 std::chrono::microseconds
601 m_next_local_addr_send
GUARDED_BY(m_addr_send_times_mutex){0};
606 std::atomic_bool m_wants_addrv2{
false};
610 mutable Mutex m_addr_token_bucket_mutex;
615 double m_addr_token_bucket
GUARDED_BY(m_addr_token_bucket_mutex){1.0};
617 std::chrono::microseconds
619 GetTime<std::chrono::microseconds>()};
621 std::atomic<uint64_t> m_addr_rate_limited{0};
626 std::atomic<uint64_t> m_addr_processed{0};
632 bool m_inv_triggered_getheaders_before_sync
636 Mutex m_getdata_requests_mutex;
638 std::deque<CInv> m_getdata_requests
GUARDED_BY(m_getdata_requests_mutex);
645 Mutex m_headers_sync_mutex;
650 std::unique_ptr<HeadersSyncState>
655 std::atomic<bool> m_sent_sendheaders{
false};
658 std::chrono::microseconds m_headers_sync_timeout
669 : m_id(id), m_our_services{our_services},
670 m_proof_relay(fRelayProofs ?
std::make_unique<ProofRelay>()
674 mutable Mutex m_tx_relay_mutex;
677 std::unique_ptr<TxRelay> m_tx_relay
GUARDED_BY(m_tx_relay_mutex);
680using PeerRef = std::shared_ptr<Peer>;
698 bool fSyncStarted{
false};
701 std::chrono::microseconds m_stalling_since{0us};
702 std::list<QueuedBlock> vBlocksInFlight;
705 std::chrono::microseconds m_downloading_since{0us};
707 bool fPreferredDownload{
false};
712 bool m_requested_hb_cmpctblocks{
false};
714 bool m_provides_cmpctblocks{
false};
742 struct ChainSyncTimeoutState {
745 std::chrono::seconds m_timeout{0s};
749 bool m_sent_getheaders{
false};
752 bool m_protect{
false};
755 ChainSyncTimeoutState m_chain_sync;
758 int64_t m_last_block_announcement{0};
761 const bool m_is_inbound;
763 CNodeState(
bool is_inbound) : m_is_inbound(is_inbound) {}
774 const std::shared_ptr<const CBlock> &pblock,
782 bool fInitialDownload)
override
788 const std::shared_ptr<const CBlock> &pblock)
override
797 !m_headers_presync_mutex);
799 std::atomic<bool> &interrupt)
override
801 !m_recent_confirmed_transactions_mutex,
802 !m_most_recent_block_mutex, !cs_proofrequest,
803 !m_headers_presync_mutex, g_msgproc_mutex);
806 !m_recent_confirmed_transactions_mutex,
807 !m_most_recent_block_mutex, !cs_proofrequest,
813 std::optional<std::string>
820 void RelayTransaction(const
TxId &txid) override
822 void RelayProof(const
avalanche::ProofId &proofid) override
824 void SetBestHeight(
int height)
override { m_best_height = height; };
827 Misbehaving(*
Assert(GetPeerRef(peer_id)),
"");
830 const std::string &msg_type,
DataStream &vRecv,
831 const std::chrono::microseconds time_received,
832 const std::atomic<bool> &interruptMsgProc)
override
834 !m_recent_confirmed_transactions_mutex,
835 !m_most_recent_block_mutex, !cs_proofrequest,
836 !m_headers_presync_mutex, g_msgproc_mutex);
838 int64_t time_in_seconds)
override;
845 void ConsiderEviction(
CNode &pto, Peer &peer,
846 std::chrono::seconds time_in_seconds)
853 void EvictExtraOutboundPeers(std::chrono::seconds now)
860 void ReattemptInitialBroadcast(
CScheduler &scheduler)
866 void UpdateAvalancheStatistics()
const;
871 void AvalanchePeriodicNetworking(
CScheduler &scheduler)
const;
889 void Misbehaving(Peer &peer,
const std::string &message);
901 void MaybePunishNodeForBlock(
NodeId nodeid,
903 bool via_compact_block,
904 const std::string &message =
"")
912 const
std::
string &message = "")
924 bool MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer);
942 bool maybe_add_extra_compact_tx)
945 struct PackageToValidate {
947 const std::vector<NodeId> m_senders;
952 : m_txns{parent, child}, m_senders{parent_sender, child_sender} {}
955 Assume(m_txns.size() == 2);
957 "parent %s (sender=%d) + child %s (sender=%d)",
958 m_txns.front()->GetId().ToString(), m_senders.front(),
959 m_txns.back()->GetId().ToString(), m_senders.back());
968 void ProcessPackageResult(
const PackageToValidate &package_to_validate,
978 std::optional<PackageToValidate> Find1P1CPackage(
const CTransactionRef &ptx,
1005 bool ProcessOrphanTx(
const Config &config, Peer &peer)
1018 void ProcessHeadersMessage(
const Config &config,
CNode &pfrom, Peer &peer,
1019 std::vector<CBlockHeader> &&headers,
1020 bool via_compact_block)
1030 bool CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
1040 void HandleUnconnectingHeaders(
CNode &pfrom, Peer &peer,
1041 const std::vector<CBlockHeader> &headers)
1045 CheckHeadersAreContinuous(
const std::vector<CBlockHeader> &headers)
const;
1065 bool IsContinuationOfLowWorkHeadersSync(Peer &peer,
CNode &pfrom,
1066 std::vector<CBlockHeader> &headers)
1068 !m_headers_presync_mutex, g_msgproc_mutex);
1082 bool TryLowWorkHeadersSync(Peer &peer,
CNode &pfrom,
1084 std::vector<CBlockHeader> &headers)
1086 !m_headers_presync_mutex, g_msgproc_mutex);
1092 bool IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header)
1106 void HeadersDirectFetchBlocks(
const Config &config,
CNode &pfrom,
1109 void UpdatePeerStateForReceivedHeaders(
CNode &pfrom, Peer &peer,
1111 bool received_new_header,
1112 bool may_have_more_headers)
1115 void SendBlockTransactions(
CNode &pfrom, Peer &peer,
const CBlock &block,
1124 std::chrono::microseconds current_time)
1134 std::chrono::microseconds current_time,
bool preferred)
1139 m_connman.PushMessage(&
node, std::move(
msg));
1141 template <
typename... Args>
1142 void MakeAndPushMessage(
CNode &
node, std::string msg_type,
1143 Args &&...args)
const {
1145 std::forward<Args>(args)...));
1149 void PushNodeVersion(
const Config &config,
CNode &pnode,
const Peer &peer);
1157 void MaybeSendPing(
CNode &node_to, Peer &peer,
1158 std::chrono::microseconds now);
1161 void MaybeSendAddr(
CNode &
node, Peer &peer,
1162 std::chrono::microseconds current_time)
1169 void MaybeSendSendHeaders(
CNode &
node, Peer &peer)
1173 void MaybeSendFeefilter(
CNode &
node, Peer &peer,
1174 std::chrono::microseconds current_time)
1186 void RelayAddress(
NodeId originator,
const CAddress &addr,
bool fReachable)
1207 Mutex cs_proofrequest;
1212 std::atomic<int> m_best_height{-1};
1217 const Options m_opts;
1219 bool RejectIncomingTxs(
const CNode &peer)
const;
1231 mutable Mutex m_peer_mutex;
1238 std::map<NodeId, PeerRef> m_peer_map
GUARDED_BY(m_peer_mutex);
1247 const CNodeState *State(
NodeId pnode)
const
1252 std::atomic<std::chrono::microseconds> m_next_inv_to_inbounds{0us};
1259 m_last_block_inv_triggering_headers_sync
GUARDED_BY(g_msgproc_mutex){};
1267 std::map<BlockHash, std::pair<NodeId, bool>>
1277 std::atomic<std::chrono::seconds> m_block_stalling_timeout{
1291 bool AlreadyHaveTx(
const TxId &txid,
bool include_reconsiderable)
1293 !m_recent_confirmed_transactions_mutex);
1356 mutable Mutex m_recent_confirmed_transactions_mutex;
1358 GUARDED_BY(m_recent_confirmed_transactions_mutex){24'000, 0.000'001};
1367 std::chrono::microseconds
1368 NextInvToInbounds(std::chrono::microseconds now,
1369 std::chrono::seconds average_interval)
1374 mutable Mutex m_most_recent_block_mutex;
1375 std::shared_ptr<const CBlock>
1376 m_most_recent_block
GUARDED_BY(m_most_recent_block_mutex);
1377 std::shared_ptr<const CBlockHeaderAndShortTxIDs>
1378 m_most_recent_compact_block
GUARDED_BY(m_most_recent_block_mutex);
1380 std::unique_ptr<const std::map<TxId, CTransactionRef>>
1381 m_most_recent_block_txs
GUARDED_BY(m_most_recent_block_mutex);
1386 Mutex m_headers_presync_mutex;
1397 using HeadersPresyncStats =
1398 std::pair<arith_uint256, std::optional<std::pair<int64_t, uint32_t>>>;
1400 std::map<NodeId, HeadersPresyncStats>
1401 m_headers_presync_stats
GUARDED_BY(m_headers_presync_mutex){};
1405 std::atomic_bool m_headers_presync_should_signal{
false};
1413 bool IsBlockRequested(
const BlockHash &hash)
1417 bool IsBlockRequestedFromOutbound(
const BlockHash &hash)
1428 void RemoveBlockRequest(
const BlockHash &hash,
1429 std::optional<NodeId> from_peer)
1438 bool BlockRequested(
const Config &config,
NodeId nodeid,
1440 std::list<QueuedBlock>::iterator **pit =
nullptr)
1449 void FindNextBlocksToDownload(const Peer &peer,
unsigned int count,
1455 void TryDownloadingHistoricalBlocks(
1456 const Peer &peer,
unsigned int count,
1490 const Peer &peer, CNodeState *state,
1492 int nWindowEnd, const
CChain *activeChain =
nullptr,
1493 NodeId *nodeStaller =
nullptr)
1503 std::atomic<
std::chrono::seconds> m_last_tip_update{0s};
1510 const std::chrono::seconds mempool_req,
1511 const std::chrono::seconds now)
1516 void ProcessGetData(
const Config &config,
CNode &pfrom, Peer &peer,
1517 const std::atomic<bool> &interruptMsgProc)
1519 peer.m_getdata_requests_mutex,
1525 const std::shared_ptr<const CBlock> &block,
1526 bool force_processing,
bool min_pow_checked);
1534 void MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid)
1553 std::vector<CTransactionRef>
1554 vExtraTxnForCompact
GUARDED_BY(g_msgproc_mutex);
1556 size_t vExtraTxnForCompactIt
GUARDED_BY(g_msgproc_mutex) = 0;
1561 void ProcessBlockAvailability(
NodeId nodeid)
1576 bool BlockRequestAllowed(const
CBlockIndex *pindex)
1578 bool AlreadyHaveBlock(const
BlockHash &block_hash)
1580 bool AlreadyHaveProof(const
avalanche::ProofId &proofid);
1581 void ProcessGetBlockData(const
Config &config,
CNode &pfrom, Peer &peer,
1604 bool PrepareBlockFilterRequest(
CNode &
node, Peer &peer,
1606 uint32_t start_height,
1608 uint32_t max_height_diff,
1650 uint32_t GetAvalancheVoteForBlock(const
BlockHash &hash) const
1661 const
TxId &
id) const
1663 !m_recent_confirmed_transactions_mutex);
1672 bool SetupAddressRelay(const
CNode &
node, Peer &peer)
1675 void AddAddressKnown(Peer &peer, const
CAddress &addr)
1677 void PushAddress(Peer &peer, const
CAddress &addr)
1685 bool ReceivedAvalancheProof(
CNode &
node, Peer &peer,
1691 const
std::chrono::seconds now)
1694 bool isPreferredDownloadPeer(const
CNode &pfrom);
1697const CNodeState *PeerManagerImpl::State(
NodeId pnode) const
1699 std::map<NodeId, CNodeState>::const_iterator it = m_node_states.find(pnode);
1700 if (it == m_node_states.end()) {
1707CNodeState *PeerManagerImpl::State(
NodeId pnode)
1709 return const_cast<CNodeState *
>(std::as_const(*this).State(pnode));
1717static bool IsAddrCompatible(
const Peer &peer,
const CAddress &addr) {
1721void PeerManagerImpl::AddAddressKnown(Peer &peer,
const CAddress &addr) {
1722 assert(peer.m_addr_known);
1723 peer.m_addr_known->insert(addr.
GetKey());
1726void PeerManagerImpl::PushAddress(Peer &peer,
const CAddress &addr) {
1730 assert(peer.m_addr_known);
1731 if (addr.
IsValid() && !peer.m_addr_known->contains(addr.
GetKey()) &&
1732 IsAddrCompatible(peer, addr)) {
1733 if (peer.m_addrs_to_send.size() >= m_opts.max_addr_to_send) {
1734 peer.m_addrs_to_send[m_rng.randrange(peer.m_addrs_to_send.size())] =
1737 peer.m_addrs_to_send.push_back(addr);
1742static void AddKnownTx(Peer &peer,
const TxId &txid) {
1743 auto tx_relay = peer.GetTxRelay();
1748 LOCK(tx_relay->m_tx_inventory_mutex);
1749 tx_relay->m_tx_inventory_known_filter.insert(txid);
1753 if (peer.m_proof_relay !=
nullptr) {
1754 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
1755 peer.m_proof_relay->m_proof_inventory_known_filter.insert(proofid);
1759bool PeerManagerImpl::isPreferredDownloadPeer(
const CNode &pfrom) {
1761 const CNodeState *state = State(pfrom.
GetId());
1762 return state && state->fPreferredDownload;
1765static bool CanServeBlocks(
const Peer &peer) {
1773static bool IsLimitedPeer(
const Peer &peer) {
1778std::chrono::microseconds
1779PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
1780 std::chrono::seconds average_interval) {
1781 if (m_next_inv_to_inbounds.load() < now) {
1786 m_next_inv_to_inbounds =
1787 now + m_rng.rand_exp_duration(average_interval);
1789 return m_next_inv_to_inbounds;
1792bool PeerManagerImpl::IsBlockRequested(
const BlockHash &hash) {
1793 return mapBlocksInFlight.count(hash);
1796bool PeerManagerImpl::IsBlockRequestedFromOutbound(
const BlockHash &hash) {
1797 for (
auto range = mapBlocksInFlight.equal_range(hash);
1798 range.first != range.second; range.first++) {
1799 auto [nodeid, block_it] = range.first->second;
1800 CNodeState &nodestate = *
Assert(State(nodeid));
1801 if (!nodestate.m_is_inbound) {
1809void PeerManagerImpl::RemoveBlockRequest(
const BlockHash &hash,
1810 std::optional<NodeId> from_peer) {
1811 auto range = mapBlocksInFlight.equal_range(hash);
1812 if (range.first == range.second) {
1820 while (range.first != range.second) {
1821 auto [node_id, list_it] = range.first->second;
1823 if (from_peer && *from_peer != node_id) {
1828 CNodeState &state = *
Assert(State(node_id));
1830 if (state.vBlocksInFlight.begin() == list_it) {
1833 state.m_downloading_since =
1834 std::max(state.m_downloading_since,
1835 GetTime<std::chrono::microseconds>());
1837 state.vBlocksInFlight.erase(list_it);
1839 if (state.vBlocksInFlight.empty()) {
1841 m_peers_downloading_from--;
1843 state.m_stalling_since = 0us;
1845 range.first = mapBlocksInFlight.erase(range.first);
1849bool PeerManagerImpl::BlockRequested(
const Config &config,
NodeId nodeid,
1851 std::list<QueuedBlock>::iterator **pit) {
1854 CNodeState *state = State(nodeid);
1855 assert(state !=
nullptr);
1860 for (
auto range = mapBlocksInFlight.equal_range(hash);
1861 range.first != range.second; range.first++) {
1862 if (range.first->second.first == nodeid) {
1864 *pit = &range.first->second.second;
1871 RemoveBlockRequest(hash, nodeid);
1873 std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(
1874 state->vBlocksInFlight.end(),
1875 {&block, std::unique_ptr<PartiallyDownloadedBlock>(
1876 pit ? new PartiallyDownloadedBlock(config, &m_mempool)
1878 if (state->vBlocksInFlight.size() == 1) {
1880 state->m_downloading_since = GetTime<std::chrono::microseconds>();
1881 m_peers_downloading_from++;
1884 auto itInFlight = mapBlocksInFlight.insert(
1885 std::make_pair(hash, std::make_pair(nodeid, it)));
1888 *pit = &itInFlight->second.second;
1894void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(
NodeId nodeid) {
1900 if (m_opts.ignore_incoming_txs) {
1904 CNodeState *nodestate = State(nodeid);
1909 if (!nodestate->m_provides_cmpctblocks) {
1912 int num_outbound_hb_peers = 0;
1913 for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin();
1914 it != lNodesAnnouncingHeaderAndIDs.end(); it++) {
1915 if (*it == nodeid) {
1916 lNodesAnnouncingHeaderAndIDs.erase(it);
1917 lNodesAnnouncingHeaderAndIDs.push_back(nodeid);
1920 CNodeState *state = State(*it);
1921 if (state !=
nullptr && !state->m_is_inbound) {
1922 ++num_outbound_hb_peers;
1925 if (nodestate->m_is_inbound) {
1928 if (lNodesAnnouncingHeaderAndIDs.size() >= 3 &&
1929 num_outbound_hb_peers == 1) {
1930 CNodeState *remove_node =
1931 State(lNodesAnnouncingHeaderAndIDs.front());
1932 if (remove_node !=
nullptr && !remove_node->m_is_inbound) {
1935 std::swap(lNodesAnnouncingHeaderAndIDs.front(),
1936 *std::next(lNodesAnnouncingHeaderAndIDs.begin()));
1943 if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
1947 lNodesAnnouncingHeaderAndIDs.front(), [
this](
CNode *pnodeStop) {
1948 MakeAndPushMessage(*pnodeStop, NetMsgType::SENDCMPCT,
1950 CMPCTBLOCKS_VERSION);
1953 pnodeStop->m_bip152_highbandwidth_to = false;
1956 lNodesAnnouncingHeaderAndIDs.pop_front();
1963 lNodesAnnouncingHeaderAndIDs.push_back(pfrom->
GetId());
1968bool PeerManagerImpl::TipMayBeStale() {
1971 if (m_last_tip_update.load() == 0s) {
1972 m_last_tip_update = GetTime<std::chrono::seconds>();
1974 return m_last_tip_update.load() <
1975 GetTime<std::chrono::seconds>() -
1978 mapBlocksInFlight.empty();
1981bool PeerManagerImpl::CanDirectFetch() {
1987static bool PeerHasHeader(CNodeState *state,
const CBlockIndex *pindex)
1989 if (state->pindexBestKnownBlock &&
1990 pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) {
1993 if (state->pindexBestHeaderSent &&
1994 pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight)) {
2000void PeerManagerImpl::ProcessBlockAvailability(
NodeId nodeid) {
2001 CNodeState *state = State(nodeid);
2002 assert(state !=
nullptr);
2004 if (!state->hashLastUnknownBlock.IsNull()) {
2008 if (state->pindexBestKnownBlock ==
nullptr ||
2009 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
2010 state->pindexBestKnownBlock = pindex;
2012 state->hashLastUnknownBlock.SetNull();
2017void PeerManagerImpl::UpdateBlockAvailability(
NodeId nodeid,
2019 CNodeState *state = State(nodeid);
2020 assert(state !=
nullptr);
2022 ProcessBlockAvailability(nodeid);
2027 if (state->pindexBestKnownBlock ==
nullptr ||
2028 pindex->
nChainWork >= state->pindexBestKnownBlock->nChainWork) {
2029 state->pindexBestKnownBlock = pindex;
2034 state->hashLastUnknownBlock = hash;
2040void PeerManagerImpl::FindNextBlocksToDownload(
2041 const Peer &peer,
unsigned int count,
2042 std::vector<const CBlockIndex *> &vBlocks,
NodeId &nodeStaller) {
2047 vBlocks.reserve(vBlocks.size() +
count);
2048 CNodeState *state = State(peer.m_id);
2049 assert(state !=
nullptr);
2052 ProcessBlockAvailability(peer.m_id);
2054 if (state->pindexBestKnownBlock ==
nullptr ||
2055 state->pindexBestKnownBlock->nChainWork <
2057 state->pindexBestKnownBlock->nChainWork <
2067 const CBlockIndex *snap_base{m_chainman.GetSnapshotBaseBlock()};
2068 if (snap_base && state->pindexBestKnownBlock->GetAncestor(
2069 snap_base->nHeight) != snap_base) {
2071 "Not downloading blocks from peer=%d, which doesn't have the "
2072 "snapshot block in its best chain.\n",
2081 if (state->pindexLastCommonBlock ==
nullptr ||
2083 state->pindexLastCommonBlock->nHeight < snap_base->nHeight)) {
2084 state->pindexLastCommonBlock =
2086 .
ActiveChain()[std::min(state->pindexBestKnownBlock->nHeight,
2093 state->pindexLastCommonBlock, state->pindexBestKnownBlock);
2094 if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) {
2098 const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
2106 FindNextBlocks(vBlocks, peer, state, pindexWalk,
count, nWindowEnd,
2110void PeerManagerImpl::TryDownloadingHistoricalBlocks(
2111 const Peer &peer,
unsigned int count,
2112 std::vector<const CBlockIndex *> &vBlocks,
const CBlockIndex *from_tip,
2117 if (vBlocks.size() >=
count) {
2121 vBlocks.reserve(
count);
2122 CNodeState *state =
Assert(State(peer.m_id));
2124 if (state->pindexBestKnownBlock ==
nullptr ||
2125 state->pindexBestKnownBlock->GetAncestor(target_block->
nHeight) !=
2140 FindNextBlocks(vBlocks, peer, state, from_tip,
count,
2145void PeerManagerImpl::FindNextBlocks(std::vector<const CBlockIndex *> &vBlocks,
2146 const Peer &peer, CNodeState *state,
2148 unsigned int count,
int nWindowEnd,
2149 const CChain *activeChain,
2151 std::vector<const CBlockIndex *> vToFetch;
2153 std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
2155 while (pindexWalk->
nHeight < nMaxHeight) {
2160 int nToFetch = std::min(nMaxHeight - pindexWalk->
nHeight,
2161 std::max<int>(
count - vBlocks.size(), 128));
2162 vToFetch.resize(nToFetch);
2163 pindexWalk = state->pindexBestKnownBlock->
GetAncestor(
2164 pindexWalk->
nHeight + nToFetch);
2165 vToFetch[nToFetch - 1] = pindexWalk;
2166 for (
unsigned int i = nToFetch - 1; i > 0; i--) {
2167 vToFetch[i - 1] = vToFetch[i]->
pprev;
2180 if (pindex->nStatus.hasData() ||
2181 (activeChain && activeChain->
Contains(pindex))) {
2183 state->pindexLastCommonBlock = pindex;
2185 }
else if (!IsBlockRequested(pindex->
GetBlockHash())) {
2187 if (pindex->
nHeight > nWindowEnd) {
2189 if (vBlocks.size() == 0 && waitingfor != peer.m_id) {
2193 *nodeStaller = waitingfor;
2198 vBlocks.push_back(pindex);
2199 if (vBlocks.size() ==
count) {
2202 }
else if (waitingfor == -1) {
2214template <
class InvId>
2218 return !
node.HasPermission(
2231template <
class InvId>
2232static std::chrono::microseconds
2236 std::chrono::microseconds current_time,
bool preferred) {
2237 auto delay = std::chrono::microseconds{0};
2249 return current_time + delay;
2252void PeerManagerImpl::PushNodeVersion(
const Config &config,
CNode &pnode,
2254 uint64_t my_services{peer.m_our_services};
2255 const int64_t nTime{
count_seconds(GetTime<std::chrono::seconds>())};
2257 const int nNodeStartingHeight{m_best_height};
2268 const bool tx_relay{!RejectIncomingTxs(pnode)};
2277 nNodeStartingHeight, tx_relay, extraEntropy);
2281 "send version message: version %d, blocks=%d, them=%s, "
2282 "txrelay=%d, peer=%d\n",
2287 "send version message: version %d, blocks=%d, "
2288 "txrelay=%d, peer=%d\n",
2293void PeerManagerImpl::AddTxAnnouncement(
2295 std::chrono::microseconds current_time) {
2303 const bool preferred = isPreferredDownloadPeer(
node);
2305 current_time, preferred);
2307 m_txrequest.ReceivedInv(
node.GetId(), txid, preferred, reqtime);
2310void PeerManagerImpl::AddProofAnnouncement(
2312 std::chrono::microseconds current_time,
bool preferred) {
2323 m_proofrequest.ReceivedInv(
node.GetId(), proofid, preferred, reqtime);
2326void PeerManagerImpl::UpdateLastBlockAnnounceTime(
NodeId node,
2327 int64_t time_in_seconds) {
2329 CNodeState *state = State(
node);
2331 state->m_last_block_announcement = time_in_seconds;
2335void PeerManagerImpl::InitializeNode(
const Config &config,
CNode &
node,
2340 m_node_states.emplace_hint(m_node_states.end(),
2341 std::piecewise_construct,
2342 std::forward_as_tuple(nodeid),
2343 std::forward_as_tuple(
node.IsInboundConn()));
2344 assert(m_txrequest.Count(nodeid) == 0);
2352 PeerRef peer = std::make_shared<Peer>(nodeid, our_services, !!m_avalanche);
2355 m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer);
2357 if (!
node.IsInboundConn()) {
2358 PushNodeVersion(config,
node, *peer);
2362void PeerManagerImpl::ReattemptInitialBroadcast(
CScheduler &scheduler) {
2365 for (
const TxId &txid : unbroadcast_txids) {
2367 if (m_mempool.
exists(txid)) {
2368 RelayTransaction(txid);
2379 auto unbroadcasted_proofids =
2383 auto it = unbroadcasted_proofids.begin();
2384 while (it != unbroadcasted_proofids.end()) {
2387 if (!pm.isBoundToPeer(*it)) {
2388 pm.removeUnbroadcastProof(*it);
2389 it = unbroadcasted_proofids.erase(it);
2396 return unbroadcasted_proofids;
2400 for (
const auto &proofid : unbroadcasted_proofids) {
2401 RelayProof(proofid);
2408 const auto reattemptBroadcastInterval =
2410 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2411 reattemptBroadcastInterval);
2414void PeerManagerImpl::UpdateAvalancheStatistics()
const {
2420void PeerManagerImpl::AvalanchePeriodicNetworking(
CScheduler &scheduler)
const {
2421 const auto now = GetTime<std::chrono::seconds>();
2422 std::vector<NodeId> avanode_ids;
2423 bool fQuorumEstablished;
2424 bool fShouldRequestMoreNodes;
2434 fShouldRequestMoreNodes =
2442 avanode_ids.push_back(pnode->GetId());
2445 PeerRef peer = GetPeerRef(pnode->
GetId());
2446 if (peer ==
nullptr) {
2450 if (peer->m_proof_relay &&
2451 now > (peer->m_proof_relay->lastSharedProofsUpdate.load() +
2453 peer->m_proof_relay->sharedProofs = {};
2457 if (avanode_ids.empty()) {
2465 for (
NodeId avanodeId : avanode_ids) {
2466 const bool sentGetavaaddr =
2469 MakeAndPushMessage(*pavanode, NetMsgType::GETAVAADDR);
2470 PeerRef peer = GetPeerRef(avanodeId);
2471 WITH_LOCK(peer->m_addr_token_bucket_mutex,
2472 peer->m_addr_token_bucket +=
2473 m_opts.max_addr_to_send);
2481 if (sentGetavaaddr && fQuorumEstablished && !fShouldRequestMoreNodes) {
2496 avanode_ids.resize(std::min<size_t>(avanode_ids.size(), 3));
2499 for (
NodeId nodeid : avanode_ids) {
2502 PeerRef peer = GetPeerRef(nodeid);
2503 if (peer->m_proof_relay) {
2505 peer->m_proof_relay->compactproofs_requested =
true;
2515 const auto avalanchePeriodicNetworkingInterval =
2517 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2518 avalanchePeriodicNetworkingInterval);
2521void PeerManagerImpl::FinalizeNode(
const Config &config,
const CNode &
node) {
2531 PeerRef peer = RemovePeer(nodeid);
2534 m_peer_map.erase(nodeid);
2536 CNodeState *state = State(nodeid);
2537 assert(state !=
nullptr);
2539 if (state->fSyncStarted) {
2543 for (
const QueuedBlock &entry : state->vBlocksInFlight) {
2545 mapBlocksInFlight.equal_range(entry.pindex->GetBlockHash());
2546 while (range.first != range.second) {
2547 auto [node_id, list_it] = range.first->second;
2548 if (node_id != nodeid) {
2551 range.first = mapBlocksInFlight.erase(range.first);
2558 m_txrequest.DisconnectedPeer(nodeid);
2559 m_num_preferred_download_peers -= state->fPreferredDownload;
2560 m_peers_downloading_from -= (!state->vBlocksInFlight.empty());
2561 assert(m_peers_downloading_from >= 0);
2562 m_outbound_peers_with_protect_from_disconnect -=
2563 state->m_chain_sync.m_protect;
2564 assert(m_outbound_peers_with_protect_from_disconnect >= 0);
2566 m_node_states.erase(nodeid);
2568 if (m_node_states.empty()) {
2570 assert(mapBlocksInFlight.empty());
2571 assert(m_num_preferred_download_peers == 0);
2572 assert(m_peers_downloading_from == 0);
2573 assert(m_outbound_peers_with_protect_from_disconnect == 0);
2574 assert(m_txrequest.Size() == 0);
2576 return orphanage.Size();
2581 if (
node.fSuccessfullyConnected && !
node.IsBlockOnlyConn() &&
2582 !
node.IsInboundConn()) {
2589 LOCK(m_headers_presync_mutex);
2590 m_headers_presync_stats.erase(nodeid);
2593 WITH_LOCK(cs_proofrequest, m_proofrequest.DisconnectedPeer(nodeid));
2598PeerRef PeerManagerImpl::GetPeerRef(
NodeId id)
const {
2600 auto it = m_peer_map.find(
id);
2601 return it != m_peer_map.end() ? it->second :
nullptr;
2604PeerRef PeerManagerImpl::RemovePeer(
NodeId id) {
2607 auto it = m_peer_map.find(
id);
2608 if (it != m_peer_map.end()) {
2609 ret = std::move(it->second);
2610 m_peer_map.erase(it);
2615bool PeerManagerImpl::GetNodeStateStats(
NodeId nodeid,
2619 const CNodeState *state = State(nodeid);
2620 if (state ==
nullptr) {
2624 ? state->pindexBestKnownBlock->nHeight
2627 ? state->pindexLastCommonBlock->nHeight
2629 for (
const QueuedBlock &queue : state->vBlocksInFlight) {
2636 PeerRef peer = GetPeerRef(nodeid);
2637 if (peer ==
nullptr) {
2649 auto ping_wait{0us};
2650 if ((0 != peer->m_ping_nonce_sent) &&
2651 (0 != peer->m_ping_start.load().count())) {
2653 GetTime<std::chrono::microseconds>() - peer->m_ping_start.load();
2656 if (
auto tx_relay = peer->GetTxRelay()) {
2658 return tx_relay->m_relay_txs);
2670 LOCK(peer->m_headers_sync_mutex);
2671 if (peer->m_headers_sync) {
2679void PeerManagerImpl::AddToCompactExtraTransactions(
const CTransactionRef &tx) {
2680 if (m_opts.max_extra_txs <= 0) {
2684 if (!vExtraTxnForCompact.size()) {
2685 vExtraTxnForCompact.resize(m_opts.max_extra_txs);
2688 vExtraTxnForCompact[vExtraTxnForCompactIt] = tx;
2689 vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
2692void PeerManagerImpl::Misbehaving(Peer &peer,
const std::string &message) {
2693 LOCK(peer.m_misbehavior_mutex);
2695 const std::string message_prefixed =
2696 message.empty() ?
"" : (
": " + message);
2697 peer.m_should_discourage =
true;
2702void PeerManagerImpl::MaybePunishNodeForBlock(
NodeId nodeid,
2704 bool via_compact_block,
2705 const std::string &message) {
2706 PeerRef peer{GetPeerRef(nodeid)};
2717 if (!via_compact_block) {
2719 Misbehaving(*peer, message);
2726 CNodeState *node_state = State(nodeid);
2727 if (node_state ==
nullptr) {
2734 if (!via_compact_block && !node_state->m_is_inbound) {
2736 Misbehaving(*peer, message);
2746 Misbehaving(*peer, message);
2752 Misbehaving(*peer, message);
2758 if (message !=
"") {
2763void PeerManagerImpl::MaybePunishNodeForTx(
NodeId nodeid,
2765 const std::string &message) {
2766 PeerRef peer{GetPeerRef(nodeid)};
2773 Misbehaving(*peer, message);
2791 if (message !=
"") {
2796bool PeerManagerImpl::BlockRequestAllowed(
const CBlockIndex *pindex) {
2802 (m_chainman.m_best_header !=
nullptr) &&
2803 (m_chainman.m_best_header->GetBlockTime() - pindex->
GetBlockTime() <
2806 *m_chainman.m_best_header, *pindex, *m_chainman.m_best_header,
2810std::optional<std::string>
2811PeerManagerImpl::FetchBlock(
const Config &config,
NodeId peer_id,
2814 return "Loading blocks ...";
2820 CNodeState *state = State(peer_id);
2821 if (state ==
nullptr) {
2822 return "Peer does not exist";
2826 RemoveBlockRequest(block_index.
GetBlockHash(), std::nullopt);
2831 if (!BlockRequested(config, peer_id, block_index)) {
2832 return "Already requested from this peer";
2841 this->MakeAndPushMessage(*node, NetMsgType::GETDATA, invs);
2844 return "Node not fully connected";
2849 return std::nullopt;
2852std::unique_ptr<PeerManager>
2856 return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman,
2865 : m_rng{opts.deterministic_rng},
2867 m_chainparams(chainman.GetParams()), m_connman(connman),
2868 m_addrman(addrman), m_banman(banman), m_chainman(chainman),
2869 m_mempool(pool), m_avalanche(
avalanche), m_opts{opts} {}
2871void PeerManagerImpl::StartScheduledTasks(
CScheduler &scheduler) {
2878 "peer eviction timer should be less than stale tip check timer");
2881 this->CheckForStaleTipAndEvictPeers();
2887 const auto reattemptBroadcastInterval =
2889 scheduler.
scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); },
2890 reattemptBroadcastInterval);
2895 UpdateAvalancheStatistics();
2901 const auto avalanchePeriodicNetworkingInterval =
2903 scheduler.
scheduleFromNow([&] { AvalanchePeriodicNetworking(scheduler); },
2904 avalanchePeriodicNetworkingInterval);
2913void PeerManagerImpl::BlockConnected(
2914 ChainstateRole role,
const std::shared_ptr<const CBlock> &pblock,
2918 m_last_tip_update = GetTime<std::chrono::seconds>();
2922 auto stalling_timeout = m_block_stalling_timeout.load();
2925 const auto new_timeout =
2926 std::max(std::chrono::duration_cast<std::chrono::seconds>(
2927 stalling_timeout * 0.85),
2929 if (m_block_stalling_timeout.compare_exchange_strong(stalling_timeout,
2949 LOCK(m_recent_confirmed_transactions_mutex);
2951 m_recent_confirmed_transactions.insert(ptx->GetId());
2956 for (
const auto &ptx : pblock->vtx) {
2957 m_txrequest.ForgetInvId(ptx->GetId());
2962void PeerManagerImpl::BlockDisconnected(
2963 const std::shared_ptr<const CBlock> &block,
const CBlockIndex *pindex) {
2972 LOCK(m_recent_confirmed_transactions_mutex);
2973 m_recent_confirmed_transactions.reset();
2980void PeerManagerImpl::NewPoWValidBlock(
2981 const CBlockIndex *pindex,
const std::shared_ptr<const CBlock> &pblock) {
2982 std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock =
2983 std::make_shared<const CBlockHeaderAndShortTxIDs>(
2988 if (pindex->
nHeight <= m_highest_fast_announce) {
2991 m_highest_fast_announce = pindex->
nHeight;
2994 const std::shared_future<CSerializedNetMsg> lazy_ser{
2995 std::async(std::launch::deferred, [&] {
3000 auto most_recent_block_txs =
3001 std::make_unique<std::map<TxId, CTransactionRef>>();
3002 for (
const auto &tx : pblock->vtx) {
3003 most_recent_block_txs->emplace(tx->GetId(), tx);
3006 LOCK(m_most_recent_block_mutex);
3007 m_most_recent_block_hash = hashBlock;
3008 m_most_recent_block = pblock;
3009 m_most_recent_compact_block = pcmpctblock;
3010 m_most_recent_block_txs = std::move(most_recent_block_txs);
3014 [
this, pindex, &lazy_ser, &hashBlock](
CNode *pnode)
3022 ProcessBlockAvailability(pnode->
GetId());
3023 CNodeState &state = *State(pnode->
GetId());
3027 if (state.m_requested_hb_cmpctblocks &&
3028 !PeerHasHeader(&state, pindex) &&
3029 PeerHasHeader(&state, pindex->
pprev)) {
3031 "%s sending header-and-ids %s to peer=%d\n",
3032 "PeerManager::NewPoWValidBlock",
3033 hashBlock.ToString(), pnode->
GetId());
3036 PushMessage(*pnode, ser_cmpctblock.Copy());
3037 state.pindexBestHeaderSent = pindex;
3046void PeerManagerImpl::UpdatedBlockTip(
const CBlockIndex *pindexNew,
3048 bool fInitialDownload) {
3049 SetBestHeight(pindexNew->
nHeight);
3053 if (fInitialDownload) {
3058 std::vector<BlockHash> vHashes;
3060 while (pindexToAnnounce != pindexFork) {
3062 pindexToAnnounce = pindexToAnnounce->
pprev;
3072 for (
auto &it : m_peer_map) {
3073 Peer &peer = *it.second;
3074 LOCK(peer.m_block_inv_mutex);
3076 peer.m_blocks_for_headers_relay.push_back(hash);
3088void PeerManagerImpl::BlockChecked(
const CBlock &block,
3093 std::map<BlockHash, std::pair<NodeId, bool>>::iterator it =
3094 mapBlockSource.find(hash);
3098 if (state.
IsInvalid() && it != mapBlockSource.end() &&
3099 State(it->second.first)) {
3100 MaybePunishNodeForBlock(it->second.first, state,
3101 !it->second.second);
3110 mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
3111 if (it != mapBlockSource.end()) {
3112 MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
3116 if (it != mapBlockSource.end()) {
3117 mapBlockSource.erase(it);
3126bool PeerManagerImpl::AlreadyHaveTx(
const TxId &txid,
3127 bool include_reconsiderable) {
3129 hashRecentRejectsChainTip) {
3134 hashRecentRejectsChainTip =
3136 m_recent_rejects.reset();
3137 m_recent_rejects_package_reconsiderable.reset();
3141 return orphanage.HaveTx(txid);
3147 return conflicting.HaveTx(txid);
3152 if (include_reconsiderable &&
3153 m_recent_rejects_package_reconsiderable.contains(txid)) {
3158 LOCK(m_recent_confirmed_transactions_mutex);
3159 if (m_recent_confirmed_transactions.contains(txid)) {
3164 return m_recent_rejects.contains(txid) || m_mempool.
exists(txid);
3167bool PeerManagerImpl::AlreadyHaveBlock(
const BlockHash &block_hash) {
3172 if (!
Assume(m_avalanche)) {
3177 if (localProof && localProof->getId() == proofid) {
3186void PeerManagerImpl::SendPings() {
3188 for (
auto &it : m_peer_map) {
3189 it.second->m_ping_queued =
true;
3193void PeerManagerImpl::RelayTransaction(
const TxId &txid) {
3195 for (
auto &it : m_peer_map) {
3196 Peer &peer = *it.second;
3197 auto tx_relay = peer.GetTxRelay();
3201 LOCK(tx_relay->m_tx_inventory_mutex);
3207 if (tx_relay->m_next_inv_send_time == 0s) {
3211 if (!tx_relay->m_tx_inventory_known_filter.contains(txid) ||
3212 tx_relay->m_avalanche_stalled_txids.count(txid) > 0) {
3213 tx_relay->m_tx_inventory_to_send.insert(txid);
3220 for (
auto &it : m_peer_map) {
3221 Peer &peer = *it.second;
3223 if (!peer.m_proof_relay) {
3226 LOCK(peer.m_proof_relay->m_proof_inventory_mutex);
3227 if (!peer.m_proof_relay->m_proof_inventory_known_filter.contains(
3229 peer.m_proof_relay->m_proof_inventory_to_send.insert(proofid);
3234void PeerManagerImpl::RelayAddress(
NodeId originator,
const CAddress &addr,
3250 const auto current_time{GetTime<std::chrono::seconds>()};
3253 const uint64_t time_addr{
3254 (
static_cast<uint64_t
>(
count_seconds(current_time)) + hash_addr) /
3264 unsigned int nRelayNodes = (fReachable || (hasher.Finalize() & 1)) ? 2 : 1;
3265 std::array<std::pair<uint64_t, Peer *>, 2> best{
3266 {{0,
nullptr}, {0,
nullptr}}};
3267 assert(nRelayNodes <= best.size());
3271 for (
auto &[
id, peer] : m_peer_map) {
3272 if (peer->m_addr_relay_enabled &&
id != originator &&
3273 IsAddrCompatible(*peer, addr)) {
3275 for (
unsigned int i = 0; i < nRelayNodes; i++) {
3276 if (hashKey > best[i].first) {
3277 std::copy(best.begin() + i, best.begin() + nRelayNodes - 1,
3278 best.begin() + i + 1);
3279 best[i] = std::make_pair(hashKey, peer.get());
3286 for (
unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
3287 PushAddress(*best[i].second, addr);
3291void PeerManagerImpl::ProcessGetBlockData(
const Config &config,
CNode &pfrom,
3292 Peer &peer,
const CInv &inv) {
3295 std::shared_ptr<const CBlock> a_recent_block;
3296 std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
3298 LOCK(m_most_recent_block_mutex);
3299 a_recent_block = m_most_recent_block;
3300 a_recent_compact_block = m_most_recent_compact_block;
3303 bool need_activate_chain =
false;
3317 need_activate_chain =
true;
3321 if (need_activate_chain) {
3324 state, a_recent_block, m_avalanche)) {
3332 bool can_direct_fetch{
false};
3340 if (!BlockRequestAllowed(pindex)) {
3342 "%s: ignoring request from peer=%i for old "
3343 "block that isn't in the main chain\n",
3344 __func__, pfrom.
GetId());
3350 (((m_chainman.m_best_header !=
nullptr) &&
3351 (m_chainman.m_best_header->GetBlockTime() -
3359 "historical block serving limit reached, disconnect peer=%d\n",
3372 (tip->nHeight - pindex->
nHeight >
3375 "Ignore block request below NODE_NETWORK_LIMITED "
3376 "threshold, disconnect peer=%d\n",
3386 if (!pindex->nStatus.hasData()) {
3389 can_direct_fetch = CanDirectFetch();
3393 std::shared_ptr<const CBlock> pblock;
3394 auto handle_block_read_error = [&]() {
3396 return m_chainman.
m_blockman.IsBlockPruned(*pindex))) {
3398 "Block was pruned before it could be read, disconnect "
3402 LogError(
"Cannot load block from disk, disconnect peer=%d\n",
3408 if (a_recent_block && a_recent_block->GetHash() == pindex->
GetBlockHash()) {
3409 pblock = a_recent_block;
3414 std::vector<uint8_t> block_data;
3416 handle_block_read_error();
3423 std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
3425 handle_block_read_error();
3428 pblock = pblockRead;
3434 bool sendMerkleBlock =
false;
3436 if (
auto tx_relay = peer.GetTxRelay()) {
3437 LOCK(tx_relay->m_bloom_filter_mutex);
3438 if (tx_relay->m_bloom_filter) {
3439 sendMerkleBlock =
true;
3444 if (sendMerkleBlock) {
3455 typedef std::pair<size_t, uint256> PairType;
3458 *pblock->vtx[pair.first]);
3468 if (can_direct_fetch &&
3470 if (a_recent_compact_block &&
3471 a_recent_compact_block->header.GetHash() ==
3474 *a_recent_compact_block);
3488 LOCK(peer.m_block_inv_mutex);
3491 if (hash == peer.m_continuation_block) {
3495 std::vector<CInv> vInv;
3498 peer.m_continuation_block =
BlockHash();
3504PeerManagerImpl::FindTxForGetData(
const Peer &peer,
const TxId &txid,
3505 const std::chrono::seconds mempool_req,
3506 const std::chrono::seconds now) {
3507 auto txinfo = m_mempool.
info(txid);
3512 if ((mempool_req.count() && txinfo.m_time <= mempool_req) ||
3514 return std::move(txinfo.tx);
3523 Assume(peer.GetTxRelay())->m_recently_announced_invs.contains(txid);
3524 if (recent && txinfo.tx) {
3525 return std::move(txinfo.tx);
3530 LOCK(m_most_recent_block_mutex);
3531 if (m_most_recent_block_txs !=
nullptr) {
3532 auto it = m_most_recent_block_txs->find(txid);
3533 if (it != m_most_recent_block_txs->end()) {
3546PeerManagerImpl::FindProofForGetData(
const Peer &peer,
3548 const std::chrono::seconds now) {
3551 bool send_unconditionally =
3577 if (send_unconditionally) {
3582 if (peer.m_proof_relay->m_recently_announced_proofs.contains(proofid)) {
3589void PeerManagerImpl::ProcessGetData(
3591 const std::atomic<bool> &interruptMsgProc) {
3594 auto tx_relay = peer.GetTxRelay();
3596 std::deque<CInv>::iterator it = peer.m_getdata_requests.begin();
3597 std::vector<CInv> vNotFound;
3599 const auto now{GetTime<std::chrono::seconds>()};
3601 const auto mempool_req = tx_relay !=
nullptr
3602 ? tx_relay->m_last_mempool_req.load()
3603 : std::chrono::seconds::min();
3608 while (it != peer.m_getdata_requests.end() &&
3609 (it->IsMsgProof() || it->IsMsgTx())) {
3610 if (interruptMsgProc) {
3619 const CInv &inv = *it++;
3623 vNotFound.push_back(inv);
3627 auto proof = FindProofForGetData(peer, proofid, now);
3634 vNotFound.push_back(inv);
3641 if (tx_relay ==
nullptr) {
3655 std::vector<TxId> parent_ids_to_add;
3658 auto tx_iter = m_mempool.
GetIter(tx->GetId());
3660 auto &pentry = *tx_iter;
3662 (*pentry)->GetMemPoolParentsConst();
3663 parent_ids_to_add.reserve(parents.size());
3664 for (
const auto &parent : parents) {
3665 if (parent.get()->GetTime() >
3667 parent_ids_to_add.push_back(
3668 parent.get()->GetTx().GetId());
3673 for (
const TxId &parent_txid : parent_ids_to_add) {
3676 if (
WITH_LOCK(tx_relay->m_tx_inventory_mutex,
3677 return !tx_relay->m_tx_inventory_known_filter
3678 .contains(parent_txid))) {
3679 tx_relay->m_recently_announced_invs.insert(parent_txid);
3683 vNotFound.push_back(inv);
3695 if (it != peer.m_getdata_requests.end() && !pfrom.
fPauseSend) {
3696 const CInv &inv = *it++;
3698 ProcessGetBlockData(config, pfrom, peer, inv);
3704 peer.m_getdata_requests.erase(peer.m_getdata_requests.begin(), it);
3706 if (!vNotFound.empty()) {
3723void PeerManagerImpl::SendBlockTransactions(
3727 for (
size_t i = 0; i < req.
indices.size(); i++) {
3729 Misbehaving(peer,
"getblocktxn with out-of-bounds tx indices");
3738bool PeerManagerImpl::CheckHeadersPoW(
const std::vector<CBlockHeader> &headers,
3743 Misbehaving(peer,
"header with invalid proof of work");
3748 if (!CheckHeadersAreContinuous(headers)) {
3749 Misbehaving(peer,
"non-continuous headers sequence");
3762 near_chaintip_work =
3775void PeerManagerImpl::HandleUnconnectingHeaders(
3776 CNode &pfrom, Peer &peer,
const std::vector<CBlockHeader> &headers) {
3780 if (MaybeSendGetHeaders(pfrom,
GetLocator(best_header), peer)) {
3783 "received header %s: missing prev block %s, sending getheaders "
3784 "(%d) to end (peer=%d)\n",
3786 headers[0].hashPrevBlock.ToString(), best_header->nHeight,
3794 UpdateBlockAvailability(pfrom.
GetId(), headers.back().GetHash()));
3797bool PeerManagerImpl::CheckHeadersAreContinuous(
3798 const std::vector<CBlockHeader> &headers)
const {
3801 if (!hashLastBlock.
IsNull() && header.hashPrevBlock != hashLastBlock) {
3804 hashLastBlock = header.GetHash();
3809bool PeerManagerImpl::IsContinuationOfLowWorkHeadersSync(
3810 Peer &peer,
CNode &pfrom, std::vector<CBlockHeader> &headers) {
3811 if (peer.m_headers_sync) {
3812 auto result = peer.m_headers_sync->ProcessNextHeaders(
3816 if (result.success) {
3817 peer.m_last_getheaders_timestamp = {};
3819 if (result.request_more) {
3820 auto locator = peer.m_headers_sync->NextHeadersRequestLocator();
3823 Assume(!locator.vHave.empty());
3827 if (!locator.vHave.empty()) {
3830 bool sent_getheaders =
3831 MaybeSendGetHeaders(pfrom, locator, peer);
3834 locator.vHave.front().ToString(), pfrom.
GetId());
3839 peer.m_headers_sync.reset(
nullptr);
3844 LOCK(m_headers_presync_mutex);
3845 m_headers_presync_stats.erase(pfrom.
GetId());
3848 HeadersPresyncStats stats;
3849 stats.first = peer.m_headers_sync->GetPresyncWork();
3850 if (peer.m_headers_sync->GetState() ==
3852 stats.second = {peer.m_headers_sync->GetPresyncHeight(),
3853 peer.m_headers_sync->GetPresyncTime()};
3857 LOCK(m_headers_presync_mutex);
3858 m_headers_presync_stats[pfrom.
GetId()] = stats;
3860 m_headers_presync_stats.find(m_headers_presync_bestpeer);
3861 bool best_updated =
false;
3862 if (best_it == m_headers_presync_stats.end()) {
3867 const HeadersPresyncStats *stat_best{
nullptr};
3868 for (
const auto &[_peer, _stat] : m_headers_presync_stats) {
3869 if (!stat_best || _stat > *stat_best) {
3874 m_headers_presync_bestpeer = peer_best;
3875 best_updated = (peer_best == pfrom.
GetId());
3876 }
else if (best_it->first == pfrom.
GetId() ||
3877 stats > best_it->second) {
3880 m_headers_presync_bestpeer = pfrom.
GetId();
3881 best_updated =
true;
3883 if (best_updated && stats.second.has_value()) {
3886 m_headers_presync_should_signal =
true;
3890 if (result.success) {
3893 headers.swap(result.pow_validated_headers);
3896 return result.success;
3904bool PeerManagerImpl::TryLowWorkHeadersSync(
3906 std::vector<CBlockHeader> &headers) {
3913 arith_uint256 minimum_chain_work = GetAntiDoSWorkThreshold();
3917 if (total_work < minimum_chain_work) {
3931 LOCK(peer.m_headers_sync_mutex);
3932 peer.m_headers_sync.reset(
3934 chain_start_header, minimum_chain_work));
3939 (void)IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
3942 "Ignoring low-work chain (height=%u) from peer=%d\n",
3943 chain_start_header->
nHeight + headers.size(),
3955bool PeerManagerImpl::IsAncestorOfBestHeaderOrTip(
const CBlockIndex *header) {
3956 return header !=
nullptr &&
3957 ((m_chainman.m_best_header !=
nullptr &&
3959 m_chainman.m_best_header->GetAncestor(header->
nHeight)) ||
3963bool PeerManagerImpl::MaybeSendGetHeaders(
CNode &pfrom,
3970 if (current_time - peer.m_last_getheaders_timestamp >
3973 peer.m_last_getheaders_timestamp = current_time;
3985void PeerManagerImpl::HeadersDirectFetchBlocks(
const Config &config,
3989 CNodeState *nodestate = State(pfrom.
GetId());
3993 std::vector<const CBlockIndex *> vToFetch;
3999 if (!pindexWalk->nStatus.hasData() &&
4002 vToFetch.push_back(pindexWalk);
4004 pindexWalk = pindexWalk->
pprev;
4015 std::vector<CInv> vGetData;
4018 if (nodestate->vBlocksInFlight.size() >=
4024 BlockRequested(config, pfrom.
GetId(), *pindex);
4028 if (vGetData.size() > 1) {
4030 "Downloading blocks toward %s (%d) via headers "
4035 if (vGetData.size() > 0) {
4036 if (!m_opts.ignore_incoming_txs &&
4037 nodestate->m_provides_cmpctblocks && vGetData.size() == 1 &&
4038 mapBlocksInFlight.size() == 1 &&
4055void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(
4057 bool received_new_header,
bool may_have_more_headers) {
4060 CNodeState *nodestate = State(pfrom.
GetId());
4068 if (received_new_header &&
4070 nodestate->m_last_block_announcement =
GetTime();
4078 if (nodestate->pindexBestKnownBlock &&
4079 nodestate->pindexBestKnownBlock->nChainWork <
4090 LogPrintf(
"Disconnecting outbound peer %d -- headers "
4091 "chain has insufficient work\n",
4105 nodestate->pindexBestKnownBlock !=
nullptr) {
4106 if (m_outbound_peers_with_protect_from_disconnect <
4108 nodestate->pindexBestKnownBlock->nChainWork >=
4110 !nodestate->m_chain_sync.m_protect) {
4113 nodestate->m_chain_sync.m_protect =
true;
4114 ++m_outbound_peers_with_protect_from_disconnect;
4119void PeerManagerImpl::ProcessHeadersMessage(
const Config &config,
CNode &pfrom,
4121 std::vector<CBlockHeader> &&headers,
4122 bool via_compact_block) {
4123 size_t nCount = headers.size();
4131 LOCK(peer.m_headers_sync_mutex);
4132 if (peer.m_headers_sync) {
4133 peer.m_headers_sync.reset(
nullptr);
4134 LOCK(m_headers_presync_mutex);
4135 m_headers_presync_stats.erase(pfrom.
GetId());
4140 peer.m_last_getheaders_timestamp = {};
4148 if (!CheckHeadersPoW(headers, m_chainparams.
GetConsensus(), peer)) {
4163 bool already_validated_work =
false;
4166 bool have_headers_sync =
false;
4168 LOCK(peer.m_headers_sync_mutex);
4170 already_validated_work =
4171 IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);
4183 if (headers.empty()) {
4187 have_headers_sync = !!peer.m_headers_sync;
4193 headers[0].hashPrevBlock))};
4194 bool headers_connect_blockindex{chain_start_header !=
nullptr};
4196 if (!headers_connect_blockindex) {
4200 HandleUnconnectingHeaders(pfrom, peer, headers);
4208 peer.m_last_getheaders_timestamp = {};
4217 last_received_header =
4219 if (IsAncestorOfBestHeaderOrTip(last_received_header)) {
4220 already_validated_work =
true;
4228 already_validated_work =
true;
4234 if (!already_validated_work &&
4235 TryLowWorkHeadersSync(peer, pfrom, chain_start_header, headers)) {
4247 bool received_new_header{last_received_header ==
nullptr};
4252 state, &pindexLast)) {
4254 MaybePunishNodeForBlock(pfrom.
GetId(), state, via_compact_block,
4255 "invalid header received");
4261 LogError(
"headers message processed but no pindexLast\n");
4270 if (MaybeSendGetHeaders(pfrom,
GetLocator(pindexLast), peer)) {
4273 "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
4274 pindexLast->
nHeight, pfrom.
GetId(), peer.m_starting_height);
4278 UpdatePeerStateForReceivedHeaders(pfrom, peer, *pindexLast,
4279 received_new_header,
4283 HeadersDirectFetchBlocks(config, pfrom, *pindexLast);
4286void PeerManagerImpl::ProcessInvalidTx(
NodeId nodeid,
4289 bool maybe_add_extra_compact_tx) {
4294 const TxId &txid = ptx->GetId();
4314 m_recent_rejects_package_reconsiderable.insert(txid);
4316 m_recent_rejects.insert(txid);
4318 m_txrequest.ForgetInvId(txid);
4321 AddToCompactExtraTransactions(ptx);
4324 MaybePunishNodeForTx(nodeid, state);
4330 return orphanage.EraseTx(txid);
4344 m_txrequest.ForgetInvId(tx->GetId());
4350 orphanage.
EraseTx(tx->GetId());
4355 "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
4356 nodeid, tx->GetId().ToString(), m_mempool.
size(),
4359 RelayTransaction(tx->GetId());
4362void PeerManagerImpl::ProcessPackageResult(
4363 const PackageToValidate &package_to_validate,
4369 const auto &
package = package_to_validate.m_txns;
4370 const auto &senders = package_to_validate.m_senders;
4373 m_recent_rejects_package_reconsiderable.insert(
GetPackageHash(package));
4377 if (!
Assume(package.size() == 2)) {
4383 auto package_iter = package.rbegin();
4384 auto senders_iter = senders.rbegin();
4385 while (package_iter != package.rend()) {
4386 const auto &tx = *package_iter;
4387 const NodeId nodeid = *senders_iter;
4388 const auto it_result{package_result.
m_tx_results.find(tx->GetId())};
4392 const auto &tx_result = it_result->second;
4393 switch (tx_result.m_result_type) {
4395 ProcessValidTx(nodeid, tx);
4405 ProcessInvalidTx(nodeid, tx, tx_result.m_state,
4422std::optional<PeerManagerImpl::PackageToValidate>
4428 const auto &parent_txid{ptx->GetId()};
4430 Assume(m_recent_rejects_package_reconsiderable.contains(parent_txid));
4436 const auto cpfp_candidates_same_peer{
4442 for (
const auto &child : cpfp_candidates_same_peer) {
4443 Package maybe_cpfp_package{ptx, child};
4444 if (!m_recent_rejects_package_reconsiderable.contains(
4446 return PeerManagerImpl::PackageToValidate{ptx, child, nodeid,
4460 const auto cpfp_candidates_different_peer{
4470 std::vector<size_t> tx_indices(cpfp_candidates_different_peer.size());
4471 std::iota(tx_indices.begin(), tx_indices.end(), 0);
4472 Shuffle(tx_indices.begin(), tx_indices.end(), m_rng);
4474 for (
const auto index : tx_indices) {
4477 const auto [child_tx, child_sender] =
4478 cpfp_candidates_different_peer.at(index);
4479 Package maybe_cpfp_package{ptx, child_tx};
4480 if (!m_recent_rejects_package_reconsiderable.contains(
4482 return PeerManagerImpl::PackageToValidate{ptx, child_tx, nodeid,
4486 return std::nullopt;
4489bool PeerManagerImpl::ProcessOrphanTx(
const Config &config, Peer &peer) {
4495 return orphanage.GetTxToReconsider(peer.m_id);
4500 const TxId &orphanTxId = porphanTx->GetId();
4505 ProcessValidTx(peer.m_id, porphanTx);
4511 " invalid orphan tx %s from peer=%d. %s\n",
4518 ProcessInvalidTx(peer.m_id, porphanTx, state,
4529bool PeerManagerImpl::PrepareBlockFilterRequest(
4531 const BlockHash &stop_hash, uint32_t max_height_diff,
4533 const bool supported_filter_type =
4536 if (!supported_filter_type) {
4538 "peer %d requested unsupported block filter type: %d\n",
4539 node.GetId(),
static_cast<uint8_t
>(filter_type));
4540 node.fDisconnect =
true;
4550 if (!stop_index || !BlockRequestAllowed(stop_index)) {
4553 node.fDisconnect =
true;
4558 uint32_t stop_height = stop_index->
nHeight;
4559 if (start_height > stop_height) {
4562 "peer %d sent invalid getcfilters/getcfheaders with "
4564 "start height %d and stop height %d\n",
4565 node.GetId(), start_height, stop_height);
4566 node.fDisconnect =
true;
4569 if (stop_height - start_height >= max_height_diff) {
4571 "peer %d requested too many cfilters/cfheaders: %d / %d\n",
4572 node.GetId(), stop_height - start_height + 1, max_height_diff);
4573 node.fDisconnect =
true;
4578 if (!filter_index) {
4587void PeerManagerImpl::ProcessGetCFilters(
CNode &
node, Peer &peer,
4589 uint8_t filter_type_ser;
4590 uint32_t start_height;
4593 vRecv >> filter_type_ser >> start_height >> stop_hash;
4600 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4606 std::vector<BlockFilter> filters;
4609 "Failed to find block filter in index: filter_type=%s, "
4610 "start_height=%d, stop_hash=%s\n",
4616 for (
const auto &filter : filters) {
4621void PeerManagerImpl::ProcessGetCFHeaders(
CNode &
node, Peer &peer,
4623 uint8_t filter_type_ser;
4624 uint32_t start_height;
4627 vRecv >> filter_type_ser >> start_height >> stop_hash;
4634 if (!PrepareBlockFilterRequest(
node, peer, filter_type, start_height,
4641 if (start_height > 0) {
4643 stop_index->
GetAncestor(
static_cast<int>(start_height - 1));
4646 "Failed to find block filter header in index: "
4647 "filter_type=%s, block_hash=%s\n",
4654 std::vector<uint256> filter_hashes;
4658 "Failed to find block filter hashes in index: filter_type=%s, "
4659 "start_height=%d, stop_hash=%s\n",
4666 stop_index->
GetBlockHash(), prev_header, filter_hashes);
4669void PeerManagerImpl::ProcessGetCFCheckPt(
CNode &
node, Peer &peer,
4671 uint8_t filter_type_ser;
4674 vRecv >> filter_type_ser >> stop_hash;
4681 if (!PrepareBlockFilterRequest(
4682 node, peer, filter_type, 0, stop_hash,
4683 std::numeric_limits<uint32_t>::max(),
4684 stop_index, filter_index)) {
4692 for (
int i = headers.size() - 1; i >= 0; i--) {
4698 "Failed to find block filter header in index: "
4699 "filter_type=%s, block_hash=%s\n",
4722PeerManagerImpl::GetAvalancheVoteForBlock(
const BlockHash &hash)
const {
4733 if (pindex->nStatus.isInvalid()) {
4738 if (pindex->nStatus.isOnParkedChain()) {
4746 if (pindex == pindexFork) {
4751 if (pindexFork != pindexTip) {
4756 if (!pindex->nStatus.hasData()) {
4767 const TxId &
id)
const {
4769 if (
WITH_LOCK(m_recent_confirmed_transactions_mutex,
4770 return m_recent_confirmed_transactions.contains(
id))) {
4779 if (m_recent_rejects.contains(
id)) {
4791 if (
auto iter = m_mempool.
GetIter(
id)) {
4792 mempool_tx = (**iter)->GetSharedTx();
4797 return conflicting.HaveTx(id);
4804 return orphanage.HaveTx(id);
4870 const std::shared_ptr<const CBlock> &block,
4871 bool force_processing,
4872 bool min_pow_checked) {
4873 bool new_block{
false};
4875 &new_block, m_avalanche);
4877 node.m_last_block_time = GetTime<std::chrono::seconds>();
4882 RemoveBlockRequest(block->GetHash(), std::nullopt);
4885 mapBlockSource.erase(block->GetHash());
4889void PeerManagerImpl::ProcessMessage(
4890 const Config &config,
CNode &pfrom,
const std::string &msg_type,
4891 DataStream &vRecv,
const std::chrono::microseconds time_received,
4892 const std::atomic<bool> &interruptMsgProc) {
4898 PeerRef peer = GetPeerRef(pfrom.
GetId());
4899 if (peer ==
nullptr) {
4905 "Avalanche is not initialized, ignoring %s message\n",
4920 uint64_t nNonce = 1;
4923 std::string cleanSubVer;
4924 int starting_height = -1;
4926 uint64_t nExtraEntropy = 1;
4928 vRecv >> nVersion >> Using<CustomUintFormatter<8>>(nServices) >> nTime;
4941 "peer=%d does not offer the expected services "
4942 "(%08x offered, %08x expected); disconnecting\n",
4943 pfrom.
GetId(), nServices,
4953 "peer=%d does not offer the avalanche service; disconnecting\n",
4962 "peer=%d using obsolete version %i; disconnecting\n",
4963 pfrom.
GetId(), nVersion);
4968 if (!vRecv.
empty()) {
4977 if (!vRecv.
empty()) {
4978 std::string strSubVer;
4982 if (!vRecv.
empty()) {
4983 vRecv >> starting_height;
4985 if (!vRecv.
empty()) {
4988 if (!vRecv.
empty()) {
4989 vRecv >> nExtraEntropy;
4993 LogPrintf(
"connected to self at %s, disconnecting\n",
5006 PushNodeVersion(config, pfrom, *peer);
5010 const int greatest_common_version =
5022 peer->m_their_services = nServices;
5026 pfrom.cleanSubVer = cleanSubVer;
5028 peer->m_starting_height = starting_height;
5036 (fRelay || (peer->m_our_services &
NODE_BLOOM))) {
5037 auto *
const tx_relay = peer->SetTxRelay();
5039 LOCK(tx_relay->m_bloom_filter_mutex);
5041 tx_relay->m_relay_txs = fRelay;
5054 CNodeState *state = State(pfrom.
GetId());
5055 state->fPreferredDownload =
5059 m_num_preferred_download_peers += state->fPreferredDownload;
5065 bool send_getaddr{
false};
5067 send_getaddr = SetupAddressRelay(pfrom, *peer);
5078 peer->m_getaddr_sent =
true;
5082 WITH_LOCK(peer->m_addr_token_bucket_mutex,
5083 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
5104 std::string remoteAddr;
5110 "receive version message: [%s] %s: version %d, blocks=%d, "
5111 "us=%s, txrelay=%d, peer=%d%s\n",
5114 pfrom.
GetId(), remoteAddr);
5116 int64_t currentTime =
GetTime();
5117 int64_t nTimeOffset = nTime - currentTime;
5122 Misbehaving(*peer,
"Ignoring invalid timestamp in version message");
5132 "feeler connection completed peer=%d; disconnecting\n",
5141 Misbehaving(*peer,
"non-version message before version handshake");
5148 "ignoring redundant verack message from peer=%d\n",
5154 LogPrintf(
"New outbound peer connected: version: %d, blocks=%d, "
5156 pfrom.
nVersion.load(), peer->m_starting_height,
5179 AddKnownProof(*peer, localProof->getId());
5183 peer->m_proof_relay->m_recently_announced_proofs.insert(
5184 localProof->getId());
5189 if (
auto tx_relay = peer->GetTxRelay()) {
5198 return tx_relay->m_tx_inventory_to_send.empty() &&
5199 tx_relay->m_next_inv_send_time == 0s));
5208 Misbehaving(*peer,
"non-verack message before version handshake");
5213 const auto ser_params{
5222 std::vector<CAddress> vAddr;
5226 if (!SetupAddressRelay(pfrom, *peer)) {
5232 if (vAddr.size() > m_opts.max_addr_to_send) {
5233 Misbehaving(*peer,
strprintf(
"%s message size = %u", msg_type,
5239 std::vector<CAddress> vAddrOk;
5240 const auto current_a_time{Now<NodeSeconds>()};
5243 const auto current_time = GetTime<std::chrono::microseconds>();
5245 LOCK(peer->m_addr_token_bucket_mutex);
5248 const auto time_diff =
5249 std::max(current_time - peer->m_addr_token_timestamp, 0us);
5250 const double increment =
5252 peer->m_addr_token_bucket =
5253 std::min<double>(peer->m_addr_token_bucket + increment,
5257 peer->m_addr_token_timestamp = current_time;
5259 const bool rate_limited =
5261 uint64_t num_proc = 0;
5262 uint64_t num_rate_limit = 0;
5263 Shuffle(vAddr.begin(), vAddr.end(), m_rng);
5265 if (interruptMsgProc) {
5270 LOCK(peer->m_addr_token_bucket_mutex);
5272 if (peer->m_addr_token_bucket < 1.0) {
5278 peer->m_addr_token_bucket -= 1.0;
5291 addr.
nTime > current_a_time + 10min) {
5292 addr.
nTime = current_a_time - 5 * 24h;
5294 AddAddressKnown(*peer, addr);
5303 if (addr.
nTime > current_a_time - 10min && !peer->m_getaddr_sent &&
5306 RelayAddress(pfrom.
GetId(), addr, fReachable);
5310 vAddrOk.push_back(addr);
5313 peer->m_addr_processed += num_proc;
5314 peer->m_addr_rate_limited += num_rate_limit;
5316 "Received addr: %u addresses (%u processed, %u rate-limited) "
5318 vAddr.size(), num_proc, num_rate_limit, pfrom.
GetId());
5320 m_addrman.
Add(vAddrOk, pfrom.
addr, 2h);
5321 if (vAddr.size() < 1000) {
5322 peer->m_getaddr_sent =
false;
5329 "addrfetch connection completed peer=%d; disconnecting\n",
5337 peer->m_wants_addrv2 =
true;
5342 peer->m_prefers_headers =
true;
5347 bool sendcmpct_hb{
false};
5348 uint64_t sendcmpct_version{0};
5349 vRecv >> sendcmpct_hb >> sendcmpct_version;
5356 CNodeState *nodestate = State(pfrom.
GetId());
5357 nodestate->m_provides_cmpctblocks =
true;
5358 nodestate->m_requested_hb_cmpctblocks = sendcmpct_hb;
5367 std::vector<CInv> vInv;
5370 Misbehaving(*peer,
strprintf(
"inv message size = %u", vInv.size()));
5374 const bool reject_tx_invs{RejectIncomingTxs(pfrom)};
5376 const auto current_time{GetTime<std::chrono::microseconds>()};
5377 std::optional<BlockHash> best_block;
5379 auto logInv = [&](
const CInv &inv,
bool fAlreadyHave) {
5381 fAlreadyHave ?
"have" :
"new", pfrom.
GetId());
5384 for (
CInv &inv : vInv) {
5385 if (interruptMsgProc) {
5397 const bool fAlreadyHave = AlreadyHaveBlock(
BlockHash(inv.
hash));
5398 logInv(inv, fAlreadyHave);
5401 UpdateBlockAvailability(pfrom.
GetId(), hash);
5403 !IsBlockRequested(hash)) {
5410 best_block = std::move(hash);
5421 const bool fAlreadyHave = AlreadyHaveProof(proofid);
5422 logInv(inv, fAlreadyHave);
5423 AddKnownProof(*peer, proofid);
5425 if (!fAlreadyHave && m_avalanche &&
5427 const bool preferred = isPreferredDownloadPeer(pfrom);
5429 LOCK(cs_proofrequest);
5430 AddProofAnnouncement(pfrom, proofid, current_time,
5439 const bool fAlreadyHave =
5440 AlreadyHaveTx(txid,
true);
5441 logInv(inv, fAlreadyHave);
5443 AddKnownTx(*peer, txid);
5444 if (reject_tx_invs) {
5446 "transaction (%s) inv sent in violation of "
5447 "protocol, disconnecting peer=%d\n",
5451 }
else if (!fAlreadyHave &&
5453 AddTxAnnouncement(pfrom, txid, current_time);
5460 "Unknown inv type \"%s\" received from peer=%d\n",
5477 if (state.fSyncStarted ||
5478 (!peer->m_inv_triggered_getheaders_before_sync &&
5479 *best_block != m_last_block_inv_triggering_headers_sync)) {
5480 if (MaybeSendGetHeaders(
5481 pfrom,
GetLocator(m_chainman.m_best_header), *peer)) {
5483 m_chainman.m_best_header->nHeight,
5484 best_block->ToString(), pfrom.
GetId());
5486 if (!state.fSyncStarted) {
5487 peer->m_inv_triggered_getheaders_before_sync =
true;
5491 m_last_block_inv_triggering_headers_sync = *best_block;
5500 std::vector<CInv> vInv;
5504 strprintf(
"getdata message size = %u", vInv.size()));
5509 vInv.size(), pfrom.
GetId());
5511 if (vInv.size() > 0) {
5517 LOCK(peer->m_getdata_requests_mutex);
5518 peer->m_getdata_requests.insert(peer->m_getdata_requests.end(),
5519 vInv.begin(), vInv.end());
5520 ProcessGetData(config, pfrom, *peer, interruptMsgProc);
5529 vRecv >> locator >> hashStop;
5533 "getblocks locator size %lld > %d, disconnect peer=%d\n",
5547 std::shared_ptr<const CBlock> a_recent_block;
5549 LOCK(m_most_recent_block_mutex);
5550 a_recent_block = m_most_recent_block;
5554 state, a_recent_block, m_avalanche)) {
5572 (pindex ? pindex->
nHeight : -1),
5575 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5584 const int nPrunedBlocksLikelyToHave =
5588 (!pindex->nStatus.hasData() ||
5590 nPrunedBlocksLikelyToHave)) {
5593 " getblocks stopping, pruned or too old block at %d %s\n",
5598 peer->m_block_inv_mutex,
5599 peer->m_blocks_for_inv_relay.push_back(pindex->
GetBlockHash()));
5600 if (--nLimit <= 0) {
5606 peer->m_continuation_block = pindex->GetBlockHash();
5618 std::shared_ptr<const CBlock> recent_block;
5620 LOCK(m_most_recent_block_mutex);
5621 if (m_most_recent_block_hash == req.
blockhash) {
5622 recent_block = m_most_recent_block;
5627 SendBlockTransactions(pfrom, *peer, *recent_block, req);
5637 if (!pindex || !pindex->nStatus.hasData()) {
5640 "Peer %d sent us a getblocktxn for a block we don't have\n",
5651 if (!block_pos.IsNull()) {
5658 LogError(
"getblocktxn: block read failed for block %s\n",
5664 SendBlockTransactions(pfrom, *peer, block, req);
5676 "Peer %d sent us a getblocktxn for a block > %i deep\n",
5681 WITH_LOCK(peer->m_getdata_requests_mutex,
5682 peer->m_getdata_requests.push_back(inv));
5691 vRecv >> locator >> hashStop;
5695 "getheaders locator size %lld > %d, disconnect peer=%d\n",
5704 "Ignoring getheaders from peer=%d while importing/reindexing\n",
5718 if (m_chainman.
ActiveTip() ==
nullptr ||
5723 "Ignoring getheaders from peer=%d because active chain "
5724 "has too little work; sending empty response\n",
5729 std::vector<CBlock>());
5733 CNodeState *nodestate = State(pfrom.
GetId());
5742 if (!BlockRequestAllowed(pindex)) {
5744 "%s: ignoring request from peer=%i for old block "
5745 "header that isn't in the main chain\n",
5746 __func__, pfrom.
GetId());
5760 std::vector<CBlock> vHeaders;
5763 (pindex ? pindex->
nHeight : -1),
5766 for (; pindex; pindex = m_chainman.
ActiveChain().Next(pindex)) {
5768 if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) {
5785 nodestate->pindexBestHeaderSent =
5792 if (RejectIncomingTxs(pfrom)) {
5794 "transaction sent in violation of protocol peer=%d\n",
5810 const CTransaction &tx = *ptx;
5811 const TxId &txid = tx.GetId();
5812 AddKnownTx(*peer, txid);
5817 m_txrequest.ReceivedResponse(pfrom.
GetId(), txid);
5819 if (AlreadyHaveTx(txid,
true)) {
5825 if (!m_mempool.
exists(tx.GetId())) {
5827 "Not relaying non-mempool transaction %s from "
5828 "forcerelay peer=%d\n",
5829 tx.GetId().ToString(), pfrom.
GetId());
5831 LogPrintf(
"Force relaying tx %s from peer=%d\n",
5832 tx.GetId().ToString(), pfrom.
GetId());
5833 RelayTransaction(tx.GetId());
5837 if (m_recent_rejects_package_reconsiderable.contains(txid)) {
5845 "found tx %s in reconsiderable rejects, looking for "
5846 "child in orphanage\n",
5848 if (
auto package_to_validate{
5849 Find1P1CPackage(ptx, pfrom.
GetId())}) {
5852 package_to_validate->m_txns,
5855 "package evaluation for %s: %s (%s)\n",
5856 package_to_validate->ToString(),
5858 ?
"package accepted"
5859 :
"package rejected",
5861 ProcessPackageResult(package_to_validate.value(),
5890 ProcessValidTx(pfrom.
GetId(), ptx);
5896 bool fRejectedParents =
false;
5900 std::vector<TxId> unique_parents;
5901 unique_parents.reserve(tx.vin.size());
5902 for (
const CTxIn &txin : tx.vin) {
5905 unique_parents.push_back(txin.prevout.GetTxId());
5907 std::sort(unique_parents.begin(), unique_parents.end());
5908 unique_parents.erase(
5909 std::unique(unique_parents.begin(), unique_parents.end()),
5910 unique_parents.end());
5918 std::optional<TxId> rejected_parent_reconsiderable;
5919 for (
const TxId &parent_txid : unique_parents) {
5920 if (m_recent_rejects.contains(parent_txid)) {
5921 fRejectedParents =
true;
5925 if (m_recent_rejects_package_reconsiderable.contains(
5927 !m_mempool.
exists(parent_txid)) {
5932 if (rejected_parent_reconsiderable.has_value()) {
5933 fRejectedParents =
true;
5936 rejected_parent_reconsiderable = parent_txid;
5939 if (!fRejectedParents) {
5940 const auto current_time{
5941 GetTime<std::chrono::microseconds>()};
5943 for (
const TxId &parent_txid : unique_parents) {
5945 AddKnownTx(*peer, parent_txid);
5949 if (!AlreadyHaveTx(parent_txid,
5951 AddTxAnnouncement(pfrom, parent_txid, current_time);
5957 if (
unsigned int nEvicted =
5961 if (orphanage.AddTx(ptx,
5963 AddToCompactExtraTransactions(ptx);
5966 m_opts.max_orphan_txs, m_rng);
5969 "orphanage overflow, removed %u tx\n",
5975 m_txrequest.ForgetInvId(tx.GetId());
5979 "not keeping orphan with rejected parents %s\n",
5980 tx.GetId().ToString());
5983 m_recent_rejects.insert(tx.GetId());
5984 m_txrequest.ForgetInvId(tx.GetId());
5988 ProcessInvalidTx(pfrom.
GetId(), ptx, state,
5998 "tx %s failed but reconsiderable, looking for child in "
6001 if (
auto package_to_validate{
6002 Find1P1CPackage(ptx, pfrom.
GetId())}) {
6005 package_to_validate->m_txns,
false)};
6007 "package evaluation for %s: %s (%s)\n",
6008 package_to_validate->ToString(),
6010 ?
"package accepted"
6011 :
"package rejected",
6013 ProcessPackageResult(package_to_validate.value(),
6022 m_txrequest.ForgetInvId(tx.GetId());
6024 unsigned int nEvicted{0};
6031 m_opts.max_conflicting_txs, m_rng);
6036 "conflicting pool overflow, removed %u tx\n",
6049 "Unexpected cmpctblock message received from peer %d\n",
6056 vRecv >> cmpctblock;
6057 }
catch (std::ios_base::failure &e) {
6059 Misbehaving(*peer,
"cmpctblock-bad-indexes");
6063 bool received_new_header =
false;
6076 MaybeSendGetHeaders(
6077 pfrom,
GetLocator(m_chainman.m_best_header), *peer);
6083 GetAntiDoSWorkThreshold()) {
6087 "Ignoring low-work compact block from peer %d\n",
6093 received_new_header =
true;
6103 MaybePunishNodeForBlock(pfrom.
GetId(), state,
6105 "invalid header via cmpctblock");
6110 if (received_new_header) {
6111 LogInfo(
"Saw new cmpctblock header hash=%s peer=%d\n",
6112 blockhash.ToString(), pfrom.
GetId());
6119 bool fProcessBLOCKTXN =
false;
6125 bool fRevertToHeaderProcessing =
false;
6129 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6130 bool fBlockReconstructed =
false;
6138 "cmpctblock: header accepted but no pindex for block %s\n",
6139 blockhash.ToString());
6146 CNodeState *nodestate = State(pfrom.
GetId());
6150 if (received_new_header &&
6153 nodestate->m_last_block_announcement =
GetTime();
6156 if (pindex->nStatus.hasData()) {
6163 size_t already_in_flight =
6164 std::distance(range_flight.first, range_flight.second);
6165 bool requested_block_from_this_peer{
false};
6169 bool first_in_flight =
6170 already_in_flight == 0 ||
6171 (range_flight.first->second.first == pfrom.
GetId());
6173 while (range_flight.first != range_flight.second) {
6174 if (range_flight.first->second.first == pfrom.
GetId()) {
6175 requested_block_from_this_peer =
true;
6178 range_flight.first++;
6187 if (requested_block_from_this_peer) {
6191 std::vector<CInv> vInv(1);
6200 if (!already_in_flight && !CanDirectFetch()) {
6208 nodestate->vBlocksInFlight.size() <
6210 requested_block_from_this_peer) {
6211 std::list<QueuedBlock>::iterator *queuedBlockIt =
nullptr;
6212 if (!BlockRequested(config, pfrom.
GetId(), *pindex,
6214 if (!(*queuedBlockIt)->partialBlock) {
6216 ->partialBlock.reset(
6223 "we were already syncing!\n");
6229 *(*queuedBlockIt)->partialBlock;
6231 partialBlock.
InitData(cmpctblock, vExtraTxnForCompact);
6237 Misbehaving(*peer,
"invalid compact block");
6240 if (first_in_flight) {
6243 std::vector<CInv> vInv(1);
6256 for (
size_t i = 0; i < cmpctblock.
BlockTxCount(); i++) {
6267 fProcessBLOCKTXN =
true;
6268 }
else if (first_in_flight) {
6275 IsBlockRequestedFromOutbound(blockhash) ||
6298 tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
6303 std::vector<CTransactionRef> dummy;
6304 status = tempBlock.FillBlock(*pblock, dummy);
6306 fBlockReconstructed =
true;
6310 if (requested_block_from_this_peer) {
6314 std::vector<CInv> vInv(1);
6321 fRevertToHeaderProcessing =
true;
6326 if (fProcessBLOCKTXN) {
6328 blockTxnMsg, time_received, interruptMsgProc);
6331 if (fRevertToHeaderProcessing) {
6337 return ProcessHeadersMessage(config, pfrom, *peer,
6342 if (fBlockReconstructed) {
6347 mapBlockSource.emplace(pblock->GetHash(),
6348 std::make_pair(pfrom.
GetId(),
false));
6359 ProcessBlock(config, pfrom, pblock,
true,
6368 RemoveBlockRequest(pblock->GetHash(), std::nullopt);
6378 "Unexpected blocktxn message received from peer %d\n",
6386 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6387 bool fBlockRead =
false;
6391 auto range_flight = mapBlocksInFlight.equal_range(resp.
blockhash);
6392 size_t already_in_flight =
6393 std::distance(range_flight.first, range_flight.second);
6394 bool requested_block_from_this_peer{
false};
6398 bool first_in_flight =
6399 already_in_flight == 0 ||
6400 (range_flight.first->second.first == pfrom.
GetId());
6402 while (range_flight.first != range_flight.second) {
6403 auto [node_id, block_it] = range_flight.first->second;
6404 if (node_id == pfrom.
GetId() && block_it->partialBlock) {
6405 requested_block_from_this_peer =
true;
6408 range_flight.first++;
6411 if (!requested_block_from_this_peer) {
6413 "Peer %d sent us block transactions for block "
6414 "we weren't expecting\n",
6420 *range_flight.first->second.second->partialBlock;
6428 "invalid compact block/non-matching block transactions");
6431 if (first_in_flight) {
6433 std::vector<CInv> invs;
6440 "Peer %d sent us a compact block but it failed to "
6441 "reconstruct, waiting on first download to complete\n",
6474 std::make_pair(pfrom.
GetId(),
false));
6485 ProcessBlock(config, pfrom, pblock,
true,
6495 "Unexpected headers message received from peer %d\n",
6500 std::vector<CBlockHeader> headers;
6507 strprintf(
"too-many-headers: headers message size = %u",
6511 headers.resize(nCount);
6512 for (
unsigned int n = 0; n < nCount; n++) {
6513 vRecv >> headers[n];
6518 ProcessHeadersMessage(config, pfrom, *peer, std::move(headers),
6524 if (m_headers_presync_should_signal.exchange(
false)) {
6525 HeadersPresyncStats stats;
6527 LOCK(m_headers_presync_mutex);
6529 m_headers_presync_stats.find(m_headers_presync_bestpeer);
6530 if (it != m_headers_presync_stats.end()) {
6536 stats.first, stats.second->first, stats.second->second);
6547 "Unexpected block message received from peer %d\n",
6552 std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
6556 pblock->GetHash().ToString(), pfrom.
GetId());
6561 pblock->hashPrevBlock))};
6565 "Received mutated block from peer=%d\n", peer->m_id);
6566 Misbehaving(*peer,
"mutated block");
6568 RemoveBlockRequest(pblock->GetHash(), peer->m_id));
6578 const BlockHash hash = pblock->GetHash();
6579 bool min_pow_checked =
false;
6584 forceProcessing = IsBlockRequested(hash);
6585 RemoveBlockRequest(hash, pfrom.
GetId());
6589 mapBlockSource.emplace(hash, std::make_pair(pfrom.
GetId(),
true));
6595 GetAntiDoSWorkThreshold()) {
6596 min_pow_checked =
true;
6599 ProcessBlock(config, pfrom, pblock, forceProcessing, min_pow_checked);
6609 if (pfrom.m_avalanche_pubkey.has_value()) {
6612 "Ignoring avahello from peer %d: already in our node set\n",
6618 vRecv >> delegation;
6625 if (!delegation.
verify(state, pubkey)) {
6626 Misbehaving(*peer,
"invalid-delegation");
6629 pfrom.m_avalanche_pubkey = std::move(pubkey);
6632 sighasher << delegation.
getId();
6640 if (!(*pfrom.m_avalanche_pubkey)
6641 .VerifySchnorr(sighasher.GetHash(),
sig)) {
6642 Misbehaving(*peer,
"invalid-avahello-signature");
6649 if (!AlreadyHaveProof(proofid)) {
6650 const bool preferred = isPreferredDownloadPeer(pfrom);
6651 LOCK(cs_proofrequest);
6652 AddProofAnnouncement(pfrom, proofid,
6653 GetTime<std::chrono::microseconds>(),
6661 vRecv >> max_elements;
6665 Misbehaving(*peer,
"avahello-max-elements-too-low");
6673 return pm.
addNode(pfrom.
GetId(), proofid, max_elements);
6684 WITH_LOCK(peer->m_addr_token_bucket_mutex,
6685 peer->m_addr_token_bucket += m_opts.max_addr_to_send);
6689 peer->m_proof_relay->compactproofs_requested =
true;
6700 const auto now = Now<SteadyMilliseconds>();
6706 last_poll + std::chrono::milliseconds(m_opts.avalanche_cooldown)) {
6708 "Ignoring repeated avapoll from peer %d: cooldown not "
6723 strprintf(
"too-many-ava-poll: poll message size = %u", nCount));
6727 std::vector<avalanche::Vote> votes;
6728 votes.reserve(nCount);
6730 bool fPreconsensus{
false};
6731 bool fStakingPreconsensus{
false};
6736 fStakingPreconsensus =
6740 for (
unsigned int n = 0; n < nCount; n++) {
6748 if (!quorum_established) {
6749 votes.emplace_back(vote, inv.
hash);
6756 if (fPreconsensus) {
6758 GetAvalancheVoteForTx(*m_avalanche,
TxId(inv.
hash));
6770 if (fStakingPreconsensus) {
6777 "poll inv type %d unknown from peer=%d\n",
6782 votes.emplace_back(vote, inv.
hash);
6808 if (!pfrom.m_avalanche_pubkey.has_value() ||
6809 !(*pfrom.m_avalanche_pubkey)
6810 .VerifySchnorr(verifier.GetHash(),
sig)) {
6811 Misbehaving(*peer,
"invalid-ava-response-signature");
6816 auto now = GetTime<std::chrono::seconds>();
6818 std::vector<avalanche::VoteItemUpdate> updates;
6819 bool disconnect{
false};
6822 disconnect, error)) {
6824 Misbehaving(*peer, error);
6842 "Repeated failure to register votes from peer %d: %s\n",
6843 pfrom.
GetId(), error);
6846 Misbehaving(*peer, error);
6859 auto logVoteUpdate = [](
const auto &voteUpdate,
6860 const std::string &voteItemTypeStr,
6861 const auto &voteItemId) {
6862 std::string voteOutcome;
6863 bool alwaysPrint =
false;
6864 switch (voteUpdate.getStatus()) {
6866 voteOutcome =
"invalidated";
6870 voteOutcome =
"rejected";
6873 voteOutcome =
"accepted";
6876 voteOutcome =
"finalized";
6879 alwaysPrint = voteItemTypeStr !=
"tx";
6882 voteOutcome =
"stalled";
6891 alwaysPrint &= (voteItemTypeStr !=
"contender");
6894 LogPrintf(
"Avalanche %s %s %s\n", voteOutcome, voteItemTypeStr,
6895 voteItemId.ToString());
6899 voteItemTypeStr, voteItemId.ToString());
6903 bool shouldActivateBestChain =
false;
6905 bool fPreconsensus{
false};
6906 bool fStakingPreconsensus{
false};
6911 fStakingPreconsensus =
6915 for (
const auto &u : updates) {
6920 if (
auto pitem = std::get_if<const avalanche::ProofRef>(&item)) {
6924 logVoteUpdate(u,
"proof", proofid);
6926 auto rejectionMode =
6928 auto nextCooldownTimePoint = GetTime<std::chrono::seconds>();
6929 switch (u.getStatus()) {
6945 return pm.rejectProof(proofid,
6949 "ERROR: Failed to reject proof: %s\n",
6955 nextCooldownTimePoint += std::chrono::seconds(
6956 m_opts.avalanche_peer_replacement_cooldown);
6962 avalanche::PeerManager::
6963 RegistrationMode::FORCE_ACCEPT);
6966 [&](const avalanche::Peer &peer) {
6967 pm.updateNextPossibleConflictTime(
6969 nextCooldownTimePoint);
6970 if (u.getStatus() ==
6971 avalanche::VoteStatus::
6973 pm.setFinalized(peer.peerid);
6981 "ERROR: Failed to accept proof: %s\n",
6988 auto getBlockFromIndex = [
this](
const CBlockIndex *pindex)
6989 -> std::shared_ptr<const CBlock> {
6992 std::shared_ptr<const CBlock> pblock =
WITH_LOCK(
6993 m_most_recent_block_mutex,
return m_most_recent_block);
6995 if (!pblock || pblock->GetHash() != pindex->
GetBlockHash()) {
6996 std::shared_ptr<CBlock> pblockRead =
6997 std::make_shared<CBlock>();
7000 LogError(
"getBlockFromIndex: cannot load block from "
7005 pblock = pblockRead;
7010 if (
auto pitem = std::get_if<const CBlockIndex *>(&item)) {
7013 shouldActivateBestChain =
true;
7017 switch (u.getStatus()) {
7022 LogPrintf(
"ERROR: Database error: %s\n",
7031 LogPrintf(
"ERROR: Database error: %s\n",
7036 auto pblock = getBlockFromIndex(pindex);
7038 LogError(
"avaresponse: failed to get invalidated "
7039 "block from index\n");
7056 std::unique_ptr<node::CBlockTemplate> blockTemplate;
7060 chainstate.UnparkBlock(pindex);
7062 const bool newlyFinalized =
7063 !chainstate.IsBlockAvalancheFinalized(pindex) &&
7064 chainstate.AvalancheFinalizeBlock(pindex,
7069 if (fPreconsensus && newlyFinalized) {
7079 std::unordered_set<TxId, SaltedTxIdHasher>
7080 confirmedTxIdsInNonFinalizedBlocks;
7081 bool missing_block =
false;
7083 block !=
nullptr && block != pindex;
7084 block = block->pprev) {
7086 getBlockFromIndex(block);
7087 if (!currentBlock) {
7089 "avaresponse: failed to get "
7090 "finalized block descendant from "
7093 missing_block =
true;
7096 for (
const auto &tx : currentBlock->vtx) {
7097 confirmedTxIdsInNonFinalizedBlocks
7098 .insert(tx->GetId());
7102 if (missing_block) {
7114 confirmedTxIdsInNonFinalizedBlocks);
7126 config, chainstate, &m_mempool,
7128 blockAssembler.pblocktemplate.reset(
7131 if (blockAssembler.pblocktemplate) {
7132 blockAssembler.addTxs(m_mempool);
7133 blockTemplate = std::move(
7134 blockAssembler.pblocktemplate);
7139 if (blockTemplate) {
7144 for (
const auto &templateEntry :
7158 if (fStakingPreconsensus) {
7160 std::get_if<const avalanche::StakeContenderId>(&item)) {
7162 logVoteUpdate(u,
"contender", contenderId);
7164 switch (u.getStatus()) {
7185 if (!fPreconsensus) {
7189 if (
auto pitem = std::get_if<const CTransactionRef>(&item)) {
7193 const TxId &txid = tx->GetId();
7194 const auto status{u.getStatus()};
7199 logVoteUpdate(u,
"tx", txid);
7211 std::shared_ptr<const std::vector<Coin>> spentCoins;
7223 _spentCoins.has_value()
7224 ? std::make_shared<const std::vector<Coin>>(
7225 std::move(*_spentCoins))
7229 if (m_mempool.
exists(txid)) {
7233 std::vector<CTransactionRef> conflictingTxs =
7239 if (conflictingTxs.size() > 0) {
7247 "Attempting to pull a now invalid "
7248 "conflicting tx %s to mempool\n",
7249 conflictingTxs[0]->GetId().
ToString());
7256 for (
const auto &conflictingTx :
7259 conflictingTx->GetId());
7278 m_recent_rejects.insert(txid);
7280 AddToCompactExtraTransactions(tx);
7295 return conflicting.HaveTx(txid);
7298 std::vector<CTransactionRef>
7299 mempool_conflicting_txs;
7300 for (
const auto &txin : tx->vin) {
7305 mempool_conflicting_txs.push_back(
7306 std::move(conflict));
7313 LogError(
"accepted tx %s failed mempool "
7321 [&txid, &mempool_conflicting_txs](
7326 if (mempool_conflicting_txs.size() >
7329 mempool_conflicting_txs[0],
7338 auto it = m_mempool.
GetIter(txid);
7339 if (!it.has_value()) {
7342 "Error: finalized tx (%s) is not in the "
7348 std::vector<TxId> finalizedTxIds;
7349 m_mempool.setAvalancheFinalized(
7354 for (
const auto &finalized_txid : finalizedTxIds) {
7359 logVoteUpdate(u,
"tx", finalized_txid);
7367 std::vector<CTransactionRef>
7370 for (
const auto &conflictingTx :
7372 m_recent_rejects.insert(
7373 conflictingTx->GetId());
7375 conflictingTx->GetId());
7401 m_txrequest.ForgetInvId(txid);
7407 for (
auto &it : m_peer_map) {
7408 auto tx_relay = (*it.second).GetTxRelay();
7413 LOCK(tx_relay->m_tx_inventory_mutex);
7420 auto &stalled_by_time =
7421 tx_relay->m_avalanche_stalled_txids
7423 if (stalled_by_time.size() >=
7425 stalled_by_time.erase(
7426 stalled_by_time.begin()->timeAdded);
7429 tx_relay->m_avalanche_stalled_txids.insert(
7434 AddToCompactExtraTransactions(tx);
7442 if (shouldActivateBestChain) {
7445 state,
nullptr, m_avalanche)) {
7460 ReceivedAvalancheProof(pfrom, *peer, proof);
7469 if (peer->m_proof_relay ==
nullptr) {
7473 peer->m_proof_relay->lastSharedProofsUpdate =
7474 GetTime<std::chrono::seconds>();
7476 peer->m_proof_relay->sharedProofs =
7482 peer->m_proof_relay->sharedProofs);
7492 if (peer->m_proof_relay ==
nullptr) {
7497 if (!peer->m_proof_relay->compactproofs_requested) {
7501 peer->m_proof_relay->compactproofs_requested =
false;
7505 vRecv >> compactProofs;
7506 }
catch (std::ios_base::failure &e) {
7508 Misbehaving(*peer,
"avaproofs-bad-indexes");
7514 if (!ReceivedAvalancheProof(pfrom, *peer, prefilledProof.proof)) {
7544 auto shortIdProcessor =
7548 if (shortIdProcessor.hasOutOfBoundIndex()) {
7551 Misbehaving(*peer,
"avaproofs-bad-indexes");
7554 if (!shortIdProcessor.isEvenlyDistributed()) {
7559 std::vector<std::pair<avalanche::ProofId, bool>> remoteProofsStatus;
7566 shortIdProcessor.matchKnownItem(shortid, peer.
proof);
7573 remoteProofsStatus.emplace_back(peer.
getProofId(),
7584 for (
size_t i = 0; i < compactProofs.
size(); i++) {
7585 if (shortIdProcessor.getItem(i) ==
nullptr) {
7601 return pfrom.m_avalanche_pubkey.has_value())) {
7604 for (
const auto &[proofid, present] : remoteProofsStatus) {
7614 if (peer->m_proof_relay ==
nullptr) {
7621 auto requestedIndiceIt = proofreq.
indices.begin();
7622 uint32_t treeIndice = 0;
7623 peer->m_proof_relay->sharedProofs.forEachLeaf([&](
const auto &proof) {
7624 if (requestedIndiceIt == proofreq.
indices.end()) {
7629 if (treeIndice++ == *requestedIndiceIt) {
7631 requestedIndiceIt++;
7637 peer->m_proof_relay->sharedProofs = {};
7650 "Ignoring \"getaddr\" from %s connection. peer=%d\n",
7657 Assume(SetupAddressRelay(pfrom, *peer));
7661 if (peer->m_getaddr_recvd) {
7666 peer->m_getaddr_recvd =
true;
7668 peer->m_addrs_to_send.clear();
7669 std::vector<CAddress> vAddr;
7670 const size_t maxAddrToSend = m_opts.max_addr_to_send;
7678 for (
const CAddress &addr : vAddr) {
7679 PushAddress(*peer, addr);
7685 auto now = GetTime<std::chrono::seconds>();
7695 if (!SetupAddressRelay(pfrom, *peer)) {
7697 "Ignoring getavaaddr message from %s peer=%d\n",
7702 auto availabilityScoreComparator = [](
const CNode *lhs,
7705 double scoreRhs = rhs->getAvailabilityScore();
7707 if (scoreLhs != scoreRhs) {
7708 return scoreLhs > scoreRhs;
7717 std::set<
const CNode *,
decltype(availabilityScoreComparator)> avaNodes(
7718 availabilityScoreComparator);
7725 avaNodes.insert(pnode);
7726 if (avaNodes.size() > m_opts.max_addr_to_send) {
7727 avaNodes.erase(std::prev(avaNodes.end()));
7731 peer->m_addrs_to_send.clear();
7732 for (
const CNode *pnode : avaNodes) {
7733 PushAddress(*peer, pnode->
addr);
7744 "mempool request with bloom filters disabled, "
7745 "disconnect peer=%d\n",
7756 "mempool request with bandwidth limit reached, "
7757 "disconnect peer=%d\n",
7764 if (
auto tx_relay = peer->GetTxRelay()) {
7765 LOCK(tx_relay->m_tx_inventory_mutex);
7766 tx_relay->m_send_mempool =
true;
7795 const auto ping_end = time_received;
7798 bool bPingFinished =
false;
7799 std::string sProblem;
7801 if (nAvail >=
sizeof(nonce)) {
7806 if (peer->m_ping_nonce_sent != 0) {
7807 if (nonce == peer->m_ping_nonce_sent) {
7810 bPingFinished =
true;
7811 const auto ping_time = ping_end - peer->m_ping_start.load();
7812 if (ping_time.count() >= 0) {
7817 sProblem =
"Timing mishap";
7821 sProblem =
"Nonce mismatch";
7825 bPingFinished =
true;
7826 sProblem =
"Nonce zero";
7830 sProblem =
"Unsolicited pong without ping";
7835 bPingFinished =
true;
7836 sProblem =
"Short payload";
7839 if (!(sProblem.empty())) {
7841 "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
7842 pfrom.
GetId(), sProblem, peer->m_ping_nonce_sent, nonce,
7845 if (bPingFinished) {
7846 peer->m_ping_nonce_sent = 0;
7854 "filterload received despite not offering bloom services "
7855 "from peer=%d; disconnecting\n",
7865 Misbehaving(*peer,
"too-large bloom filter");
7866 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7868 LOCK(tx_relay->m_bloom_filter_mutex);
7869 tx_relay->m_bloom_filter.reset(
new CBloomFilter(filter));
7870 tx_relay->m_relay_txs =
true;
7880 "filteradd received despite not offering bloom services "
7881 "from peer=%d; disconnecting\n",
7886 std::vector<uint8_t> vData;
7895 }
else if (
auto tx_relay = peer->GetTxRelay()) {
7896 LOCK(tx_relay->m_bloom_filter_mutex);
7897 if (tx_relay->m_bloom_filter) {
7898 tx_relay->m_bloom_filter->insert(vData);
7906 Misbehaving(*peer,
"bad filteradd message");
7914 "filterclear received despite not offering bloom services "
7915 "from peer=%d; disconnecting\n",
7920 auto tx_relay = peer->GetTxRelay();
7926 LOCK(tx_relay->m_bloom_filter_mutex);
7927 tx_relay->m_bloom_filter =
nullptr;
7928 tx_relay->m_relay_txs =
true;
7937 vRecv >> newFeeFilter;
7939 if (
auto tx_relay = peer->GetTxRelay()) {
7940 tx_relay->m_fee_filter_received = newFeeFilter;
7949 ProcessGetCFilters(pfrom, *peer, vRecv);
7954 ProcessGetCFHeaders(pfrom, *peer, vRecv);
7959 ProcessGetCFCheckPt(pfrom, *peer, vRecv);
7964 std::vector<CInv> vInv;
7970 for (
CInv &inv : vInv) {
7976 m_txrequest.ReceivedResponse(pfrom.
GetId(),
TxId(inv.
hash));
7983 LOCK(cs_proofrequest);
7984 m_proofrequest.ReceivedResponse(
7998bool PeerManagerImpl::MaybeDiscourageAndDisconnect(
CNode &pnode, Peer &peer) {
8000 LOCK(peer.m_misbehavior_mutex);
8003 if (!peer.m_should_discourage) {
8007 peer.m_should_discourage =
false;
8013 LogPrintf(
"Warning: not punishing noban peer %d!\n", peer.m_id);
8019 LogPrintf(
"Warning: not punishing manually connected peer %d!\n",
8028 "Warning: disconnecting but not discouraging %s peer %d!\n",
8045bool PeerManagerImpl::ProcessMessages(
const Config &config,
CNode *pfrom,
8046 std::atomic<bool> &interruptMsgProc) {
8049 PeerRef peer = GetPeerRef(pfrom->
GetId());
8050 if (peer ==
nullptr) {
8055 LOCK(peer->m_getdata_requests_mutex);
8056 if (!peer->m_getdata_requests.empty()) {
8057 ProcessGetData(config, *pfrom, *peer, interruptMsgProc);
8061 const bool processed_orphan = ProcessOrphanTx(config, *peer);
8067 if (processed_orphan) {
8074 LOCK(peer->m_getdata_requests_mutex);
8075 if (!peer->m_getdata_requests.empty()) {
8092 bool fMoreWork = poll_result->second;
8096 msg.m_recv.size(),
msg.m_recv.data());
8098 if (m_opts.capture_messages) {
8104 ProcessMessage(config, *pfrom,
msg.m_type,
msg.m_recv,
msg.m_time,
8106 if (interruptMsgProc) {
8111 LOCK(peer->m_getdata_requests_mutex);
8112 if (!peer->m_getdata_requests.empty()) {
8121 return orphanage.HaveTxToReconsider(peer->m_id);
8125 }
catch (
const std::exception &e) {
8128 e.what(),
typeid(e).name());
8137void PeerManagerImpl::ConsiderEviction(
CNode &pto, Peer &peer,
8138 std::chrono::seconds time_in_seconds) {
8141 CNodeState &state = *State(pto.
GetId());
8144 state.fSyncStarted) {
8151 if (state.pindexBestKnownBlock !=
nullptr &&
8152 state.pindexBestKnownBlock->nChainWork >=
8154 if (state.m_chain_sync.m_timeout != 0s) {
8155 state.m_chain_sync.m_timeout = 0s;
8156 state.m_chain_sync.m_work_header =
nullptr;
8157 state.m_chain_sync.m_sent_getheaders =
false;
8159 }
else if (state.m_chain_sync.m_timeout == 0s ||
8160 (state.m_chain_sync.m_work_header !=
nullptr &&
8161 state.pindexBestKnownBlock !=
nullptr &&
8162 state.pindexBestKnownBlock->nChainWork >=
8163 state.m_chain_sync.m_work_header->nChainWork)) {
8169 state.m_chain_sync.m_work_header = m_chainman.
ActiveChain().
Tip();
8170 state.m_chain_sync.m_sent_getheaders =
false;
8171 }
else if (state.m_chain_sync.m_timeout > 0s &&
8172 time_in_seconds > state.m_chain_sync.m_timeout) {
8177 if (state.m_chain_sync.m_sent_getheaders) {
8180 "Disconnecting outbound peer %d for old chain, best known "
8183 state.pindexBestKnownBlock !=
nullptr
8184 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
8188 assert(state.m_chain_sync.m_work_header);
8193 MaybeSendGetHeaders(
8194 pto,
GetLocator(state.m_chain_sync.m_work_header->pprev),
8198 "sending getheaders to outbound peer=%d to verify chain "
8199 "work (current best known block:%s, benchmark blockhash: "
8202 state.pindexBestKnownBlock !=
nullptr
8203 ? state.pindexBestKnownBlock->GetBlockHash().ToString()
8205 state.m_chain_sync.m_work_header->GetBlockHash()
8207 state.m_chain_sync.m_sent_getheaders =
true;
8214 state.m_chain_sync.m_timeout =
8221void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now) {
8230 std::pair<NodeId, std::chrono::seconds> youngest_peer{-1, 0},
8231 next_youngest_peer{-1, 0};
8237 if (pnode->
GetId() > youngest_peer.first) {
8238 next_youngest_peer = youngest_peer;
8239 youngest_peer.first = pnode->GetId();
8240 youngest_peer.second = pnode->m_last_block_time;
8244 NodeId to_disconnect = youngest_peer.first;
8245 if (youngest_peer.second > next_youngest_peer.second) {
8248 to_disconnect = next_youngest_peer.first;
8260 CNodeState *node_state = State(pnode->
GetId());
8261 if (node_state ==
nullptr ||
8263 node_state->vBlocksInFlight.empty())) {
8266 "disconnecting extra block-relay-only peer=%d "
8267 "(last block received at time %d)\n",
8274 "keeping block-relay-only peer=%d chosen for eviction "
8275 "(connect time: %d, blocks_in_flight: %d)\n",
8277 node_state->vBlocksInFlight.size());
8293 int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
8304 CNodeState *state = State(pnode->
GetId());
8305 if (state ==
nullptr) {
8310 if (state->m_chain_sync.m_protect) {
8313 if (state->m_last_block_announcement < oldest_block_announcement ||
8314 (state->m_last_block_announcement == oldest_block_announcement &&
8315 pnode->
GetId() > worst_peer)) {
8316 worst_peer = pnode->
GetId();
8317 oldest_block_announcement = state->m_last_block_announcement;
8321 if (worst_peer == -1) {
8325 bool disconnected = m_connman.
ForNode(
8333 CNodeState &state = *State(pnode->
GetId());
8335 state.vBlocksInFlight.empty()) {
8337 "disconnecting extra outbound peer=%d (last block "
8338 "announcement received at time %d)\n",
8339 pnode->
GetId(), oldest_block_announcement);
8344 "keeping outbound peer=%d chosen for eviction "
8345 "(connect time: %d, blocks_in_flight: %d)\n",
8347 state.vBlocksInFlight.size());
8362void PeerManagerImpl::CheckForStaleTipAndEvictPeers() {
8365 auto now{GetTime<std::chrono::seconds>()};
8367 EvictExtraOutboundPeers(now);
8369 if (now > m_stale_tip_check_time) {
8375 LogPrintf(
"Potential stale tip detected, will try using extra "
8376 "outbound peer (last tip update: %d seconds ago)\n",
8385 if (!m_initial_sync_finished && CanDirectFetch()) {
8387 m_initial_sync_finished =
true;
8391void PeerManagerImpl::MaybeSendPing(
CNode &node_to, Peer &peer,
8392 std::chrono::microseconds now) {
8394 node_to, std::chrono::duration_cast<std::chrono::seconds>(now)) &&
8395 peer.m_ping_nonce_sent &&
8406 bool pingSend =
false;
8408 if (peer.m_ping_queued) {
8413 if (peer.m_ping_nonce_sent == 0 &&
8423 }
while (nonce == 0);
8424 peer.m_ping_queued =
false;
8425 peer.m_ping_start = now;
8427 peer.m_ping_nonce_sent = nonce;
8432 peer.m_ping_nonce_sent = 0;
8438void PeerManagerImpl::MaybeSendAddr(
CNode &
node, Peer &peer,
8439 std::chrono::microseconds current_time) {
8441 if (!peer.m_addr_relay_enabled) {
8445 LOCK(peer.m_addr_send_times_mutex);
8447 peer.m_next_local_addr_send < current_time) {
8454 if (peer.m_next_local_addr_send != 0us) {
8455 peer.m_addr_known->reset();
8458 CAddress local_addr{*local_service, peer.m_our_services,
8459 Now<NodeSeconds>()};
8460 PushAddress(peer, local_addr);
8462 peer.m_next_local_addr_send =
8468 if (current_time <= peer.m_next_addr_send) {
8472 peer.m_next_addr_send =
8475 const size_t max_addr_to_send = m_opts.max_addr_to_send;
8476 if (!
Assume(peer.m_addrs_to_send.size() <= max_addr_to_send)) {
8479 peer.m_addrs_to_send.resize(max_addr_to_send);
8484 auto addr_already_known =
8487 bool ret = peer.m_addr_known->contains(addr.
GetKey());
8489 peer.m_addr_known->insert(addr.
GetKey());
8493 peer.m_addrs_to_send.erase(std::remove_if(peer.m_addrs_to_send.begin(),
8494 peer.m_addrs_to_send.end(),
8495 addr_already_known),
8496 peer.m_addrs_to_send.end());
8499 if (peer.m_addrs_to_send.empty()) {
8503 const char *msg_type;
8505 if (peer.m_wants_addrv2) {
8515 peer.m_addrs_to_send));
8516 peer.m_addrs_to_send.clear();
8519 if (peer.m_addrs_to_send.capacity() > 40) {
8520 peer.m_addrs_to_send.shrink_to_fit();
8524void PeerManagerImpl::MaybeSendSendHeaders(
CNode &
node, Peer &peer) {
8529 if (!peer.m_sent_sendheaders &&
8532 CNodeState &state = *State(
node.GetId());
8533 if (state.pindexBestKnownBlock !=
nullptr &&
8534 state.pindexBestKnownBlock->nChainWork >
8541 peer.m_sent_sendheaders =
true;
8546void PeerManagerImpl::MaybeSendFeefilter(
8547 CNode &pto, Peer &peer, std::chrono::microseconds current_time) {
8548 if (m_opts.ignore_incoming_txs) {
8572 static const Amount MAX_FILTER{m_fee_filter_rounder.round(
MAX_MONEY)};
8573 if (peer.m_fee_filter_sent == MAX_FILTER) {
8576 peer.m_next_send_feefilter = 0us;
8579 if (current_time > peer.m_next_send_feefilter) {
8580 Amount filterToSend = m_fee_filter_rounder.round(currentFilter);
8584 if (filterToSend != peer.m_fee_filter_sent) {
8586 peer.m_fee_filter_sent = filterToSend;
8588 peer.m_next_send_feefilter =
8596 peer.m_next_send_feefilter &&
8597 (currentFilter < 3 * peer.m_fee_filter_sent / 4 ||
8598 currentFilter > 4 * peer.m_fee_filter_sent / 3)) {
8599 peer.m_next_send_feefilter =
8607class CompareInvMempoolOrder {
8611 explicit CompareInvMempoolOrder(
CTxMemPool *_mempool) : mp(_mempool) {}
8613 bool operator()(std::set<TxId>::iterator a, std::set<TxId>::iterator b) {
8623bool PeerManagerImpl::RejectIncomingTxs(
const CNode &peer)
const {
8632 if (m_opts.ignore_incoming_txs &&
8639bool PeerManagerImpl::SetupAddressRelay(
const CNode &
node, Peer &peer) {
8643 if (
node.IsBlockOnlyConn()) {
8647 if (!peer.m_addr_relay_enabled.exchange(
true)) {
8651 peer.m_addr_known = std::make_unique<CRollingBloomFilter>(5000, 0.001);
8657bool PeerManagerImpl::SendMessages(
const Config &config,
CNode *pto) {
8660 PeerRef peer = GetPeerRef(pto->
GetId());
8669 if (MaybeDiscourageAndDisconnect(*pto, *peer)) {
8678 const auto current_time{GetTime<std::chrono::microseconds>()};
8683 "addrfetch connection timeout; disconnecting peer=%d\n",
8689 MaybeSendPing(*pto, *peer, current_time);
8696 bool sync_blocks_and_headers_from_peer =
false;
8698 MaybeSendAddr(*pto, *peer, current_time);
8700 MaybeSendSendHeaders(*pto, *peer);
8705 CNodeState &state = *State(pto->
GetId());
8708 if (m_chainman.m_best_header ==
nullptr) {
8715 if (state.fPreferredDownload) {
8716 sync_blocks_and_headers_from_peer =
true;
8727 if (m_num_preferred_download_peers == 0 ||
8728 mapBlocksInFlight.empty()) {
8729 sync_blocks_and_headers_from_peer =
true;
8733 if (!state.fSyncStarted && CanServeBlocks(*peer) &&
8737 if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) ||
8739 const CBlockIndex *pindexStart = m_chainman.m_best_header;
8748 if (pindexStart->
pprev) {
8749 pindexStart = pindexStart->
pprev;
8751 if (MaybeSendGetHeaders(*pto,
GetLocator(pindexStart), *peer)) {
8754 "initial getheaders (%d) to peer=%d (startheight:%d)\n",
8756 peer->m_starting_height);
8758 state.fSyncStarted =
true;
8759 peer->m_headers_sync_timeout =
8764 std::chrono::microseconds{
8766 Ticks<std::chrono::seconds>(
8768 m_chainman.m_best_header->Time()) /
8785 LOCK(peer->m_block_inv_mutex);
8786 std::vector<CBlock> vHeaders;
8788 ((!peer->m_prefers_headers &&
8789 (!state.m_requested_hb_cmpctblocks ||
8790 peer->m_blocks_for_headers_relay.size() > 1)) ||
8791 peer->m_blocks_for_headers_relay.size() >
8796 ProcessBlockAvailability(pto->
GetId());
8798 if (!fRevertToInv) {
8799 bool fFoundStartingHeader =
false;
8803 for (
const BlockHash &hash : peer->m_blocks_for_headers_relay) {
8809 fRevertToInv =
true;
8812 if (pBestIndex !=
nullptr && pindex->
pprev != pBestIndex) {
8823 fRevertToInv =
true;
8826 pBestIndex = pindex;
8827 if (fFoundStartingHeader) {
8830 }
else if (PeerHasHeader(&state, pindex)) {
8833 }
else if (pindex->
pprev ==
nullptr ||
8834 PeerHasHeader(&state, pindex->
pprev)) {
8837 fFoundStartingHeader =
true;
8842 fRevertToInv =
true;
8847 if (!fRevertToInv && !vHeaders.empty()) {
8848 if (vHeaders.size() == 1 && state.m_requested_hb_cmpctblocks) {
8853 "%s sending header-and-ids %s to peer=%d\n",
8854 __func__, vHeaders.front().GetHash().ToString(),
8857 std::optional<CSerializedNetMsg> cached_cmpctblock_msg;
8859 LOCK(m_most_recent_block_mutex);
8860 if (m_most_recent_block_hash ==
8862 cached_cmpctblock_msg =
8864 *m_most_recent_compact_block);
8867 if (cached_cmpctblock_msg.has_value()) {
8869 std::move(cached_cmpctblock_msg.value()));
8873 block, *pBestIndex)};
8880 state.pindexBestHeaderSent = pBestIndex;
8881 }
else if (peer->m_prefers_headers) {
8882 if (vHeaders.size() > 1) {
8884 "%s: %u headers, range (%s, %s), to peer=%d\n",
8885 __func__, vHeaders.size(),
8886 vHeaders.front().GetHash().ToString(),
8887 vHeaders.back().GetHash().ToString(),
8891 "%s: sending header %s to peer=%d\n", __func__,
8892 vHeaders.front().GetHash().ToString(),
8896 state.pindexBestHeaderSent = pBestIndex;
8898 fRevertToInv =
true;
8905 if (!peer->m_blocks_for_headers_relay.empty()) {
8907 peer->m_blocks_for_headers_relay.back();
8918 "Announcing block %s not on main chain (tip=%s)\n",
8927 if (!PeerHasHeader(&state, pindex)) {
8928 peer->m_blocks_for_inv_relay.push_back(hashToAnnounce);
8930 "%s: sending inv peer=%d hash=%s\n", __func__,
8935 peer->m_blocks_for_headers_relay.clear();
8942 std::vector<CInv> vInv;
8943 auto addInvAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
8944 vInv.emplace_back(type, hash);
8955 LOCK(peer->m_block_inv_mutex);
8957 vInv.reserve(std::max<size_t>(peer->m_blocks_for_inv_relay.size(),
8963 for (
const BlockHash &hash : peer->m_blocks_for_inv_relay) {
8966 peer->m_blocks_for_inv_relay.clear();
8969 auto computeNextInvSendTime =
8970 [&](std::chrono::microseconds &next)
8974 if (next < current_time) {
8975 fSendTrickle =
true;
8977 next = NextInvToInbounds(
8982 next = current_time;
8986 return fSendTrickle;
8990 if (peer->m_proof_relay !=
nullptr) {
8991 LOCK(peer->m_proof_relay->m_proof_inventory_mutex);
8993 if (computeNextInvSendTime(
8994 peer->m_proof_relay->m_next_inv_send_time)) {
8996 peer->m_proof_relay->m_proof_inventory_to_send.begin();
8998 peer->m_proof_relay->m_proof_inventory_to_send.end()) {
9001 it = peer->m_proof_relay->m_proof_inventory_to_send.erase(
9004 if (peer->m_proof_relay->m_proof_inventory_known_filter
9005 .contains(proofid)) {
9009 peer->m_proof_relay->m_proof_inventory_known_filter.insert(
9012 peer->m_proof_relay->m_recently_announced_proofs.insert(
9018 if (
auto tx_relay = peer->GetTxRelay()) {
9019 LOCK(tx_relay->m_tx_inventory_mutex);
9021 const bool fSendTrickle =
9022 computeNextInvSendTime(tx_relay->m_next_inv_send_time);
9027 LOCK(tx_relay->m_bloom_filter_mutex);
9028 if (!tx_relay->m_relay_txs) {
9029 tx_relay->m_tx_inventory_to_send.clear();
9034 if (fSendTrickle && tx_relay->m_send_mempool) {
9035 auto vtxinfo = m_mempool.
infoAll();
9036 tx_relay->m_send_mempool =
false;
9038 tx_relay->m_fee_filter_received.load()};
9040 LOCK(tx_relay->m_bloom_filter_mutex);
9042 for (
const auto &txinfo : vtxinfo) {
9043 const TxId &txid = txinfo.tx->GetId();
9044 tx_relay->m_tx_inventory_to_send.erase(txid);
9047 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
9050 if (tx_relay->m_bloom_filter &&
9051 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
9055 tx_relay->m_tx_inventory_known_filter.insert(txid);
9058 addInvAndMaybeFlush(
MSG_TX, txid);
9060 tx_relay->m_last_mempool_req =
9061 std::chrono::duration_cast<std::chrono::seconds>(
9068 std::vector<std::set<TxId>::iterator> vInvTx;
9069 vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size());
9070 for (std::set<TxId>::iterator it =
9071 tx_relay->m_tx_inventory_to_send.begin();
9072 it != tx_relay->m_tx_inventory_to_send.end(); it++) {
9073 vInvTx.push_back(it);
9076 tx_relay->m_fee_filter_received.load()};
9081 CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool);
9082 std::make_heap(vInvTx.begin(), vInvTx.end(),
9083 compareInvMempoolOrder);
9087 unsigned int nRelayedTransactions = 0;
9088 LOCK(tx_relay->m_bloom_filter_mutex);
9089 while (!vInvTx.empty() &&
9094 std::pop_heap(vInvTx.begin(), vInvTx.end(),
9095 compareInvMempoolOrder);
9096 std::set<TxId>::iterator it = vInvTx.back();
9098 const TxId txid = *it;
9100 tx_relay->m_tx_inventory_to_send.erase(it);
9102 if (tx_relay->m_tx_inventory_known_filter.contains(txid) &&
9103 tx_relay->m_avalanche_stalled_txids.count(txid) == 0) {
9107 auto txinfo = m_mempool.
info(txid);
9113 if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
9116 if (tx_relay->m_bloom_filter &&
9117 !tx_relay->m_bloom_filter->IsRelevantAndUpdate(
9122 tx_relay->m_recently_announced_invs.insert(txid);
9123 addInvAndMaybeFlush(
MSG_TX, txid);
9124 nRelayedTransactions++;
9125 tx_relay->m_tx_inventory_known_filter.insert(txid);
9126 tx_relay->m_avalanche_stalled_txids.erase(txid);
9132 if (!vInv.empty()) {
9139 CNodeState &state = *State(pto->
GetId());
9142 auto stalling_timeout = m_block_stalling_timeout.load();
9143 if (state.m_stalling_since.count() &&
9144 state.m_stalling_since < current_time - stalling_timeout) {
9149 LogPrintf(
"Peer=%d is stalling block download, disconnecting\n",
9154 const auto new_timeout =
9156 if (stalling_timeout != new_timeout &&
9157 m_block_stalling_timeout.compare_exchange_strong(
9158 stalling_timeout, new_timeout)) {
9161 "Increased stalling timeout temporarily to %d seconds\n",
9173 if (state.vBlocksInFlight.size() > 0) {
9174 QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
9175 int nOtherPeersWithValidatedDownloads =
9176 m_peers_downloading_from - 1;
9178 state.m_downloading_since +
9179 std::chrono::seconds{consensusParams.nPowTargetSpacing} *
9182 nOtherPeersWithValidatedDownloads)) {
9183 LogPrintf(
"Timeout downloading block %s from peer=%d, "
9185 queuedBlock.pindex->GetBlockHash().ToString(),
9193 if (state.fSyncStarted &&
9194 peer->m_headers_sync_timeout < std::chrono::microseconds::max()) {
9197 if (current_time > peer->m_headers_sync_timeout &&
9198 nSyncStarted == 1 &&
9199 (m_num_preferred_download_peers -
9200 state.fPreferredDownload >=
9209 LogPrintf(
"Timeout downloading headers from peer=%d, "
9215 LogPrintf(
"Timeout downloading headers from noban "
9216 "peer=%d, not disconnecting\n",
9222 state.fSyncStarted =
false;
9224 peer->m_headers_sync_timeout = 0us;
9230 peer->m_headers_sync_timeout = std::chrono::microseconds::max();
9236 ConsiderEviction(*pto, *peer, GetTime<std::chrono::seconds>());
9239 std::vector<CInv> vGetData;
9247 CNodeState &state = *State(pto->
GetId());
9249 if (CanServeBlocks(*peer) &&
9250 ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) ||
9253 std::vector<const CBlockIndex *> vToDownload;
9255 auto get_inflight_budget = [&state]() {
9258 static_cast<int>(state.vBlocksInFlight.size()));
9264 FindNextBlocksToDownload(*peer, get_inflight_budget(), vToDownload,
9267 !IsLimitedPeer(*peer)) {
9273 m_chainman.GetSnapshotBaseBlock());
9275 TryDownloadingHistoricalBlocks(
9276 *peer, get_inflight_budget(), vToDownload, from_tip,
9277 Assert(m_chainman.GetSnapshotBaseBlock()));
9281 BlockRequested(config, pto->
GetId(), *pindex);
9286 if (state.vBlocksInFlight.empty() && staller != -1) {
9287 if (State(staller)->m_stalling_since == 0us) {
9288 State(staller)->m_stalling_since = current_time;
9295 auto addGetDataAndMaybeFlush = [&](uint32_t type,
const uint256 &hash) {
9296 CInv inv(type, hash);
9299 vGetData.push_back(std::move(inv));
9310 LOCK(cs_proofrequest);
9311 std::vector<std::pair<NodeId, avalanche::ProofId>> expired;
9313 m_proofrequest.GetRequestable(pto->
GetId(), current_time, &expired);
9314 for (
const auto &entry : expired) {
9316 "timeout of inflight proof %s from peer=%d\n",
9317 entry.second.ToString(), entry.first);
9319 for (
const auto &proofid : requestable) {
9320 if (!AlreadyHaveProof(proofid)) {
9322 m_proofrequest.RequestedData(
9323 pto->
GetId(), proofid,
9330 m_proofrequest.ForgetInvId(proofid);
9340 std::vector<std::pair<NodeId, TxId>> expired;
9342 m_txrequest.GetRequestable(pto->
GetId(), current_time, &expired);
9343 for (
const auto &entry : expired) {
9345 entry.second.ToString(), entry.first);
9347 for (
const TxId &txid : requestable) {
9351 if (!AlreadyHaveTx(txid,
false)) {
9352 addGetDataAndMaybeFlush(
MSG_TX, txid);
9353 m_txrequest.RequestedData(
9360 m_txrequest.ForgetInvId(txid);
9364 if (!vGetData.empty()) {
9369 MaybeSendFeefilter(*pto, *peer, current_time);
9373bool PeerManagerImpl::ReceivedAvalancheProof(
CNode &
node, Peer &peer,
9376 LogError(
"ReceivedAvalancheProof: proof is null\n");
9382 AddKnownProof(peer, proofid);
9394 return node.m_avalanche_pubkey.has_value());
9395 auto saveProofIfStaker = [
this, isStaker](
const CNode &
node,
9397 const NodeId nodeid) ->
bool {
9409 LOCK(cs_proofrequest);
9410 m_proofrequest.ReceivedResponse(nodeid, proofid);
9412 if (AlreadyHaveProof(proofid)) {
9413 m_proofrequest.ForgetInvId(proofid);
9414 saveProofIfStaker(
node, proofid, nodeid);
9424 return pm.registerProof(proof, state);
9426 WITH_LOCK(cs_proofrequest, m_proofrequest.ForgetInvId(proofid));
9427 RelayProof(proofid);
9429 node.m_last_proof_time = GetTime<std::chrono::seconds>();
9432 nodeid, proofid.ToString());
9454 "Not polling the avalanche proof (%s): peer=%d, proofid %s\n",
9455 state.
IsValid() ?
"not-worth-polling"
9457 nodeid, proofid.ToString());
9460 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
void TransactionInvalidated(const CTransactionRef &tx, std::shared_ptr< const std::vector< Coin > > spent_coins)
Used to create a Merkle proof (usually from a subset of transactions), which consists of a block head...
std::vector< std::pair< size_t, uint256 > > vMatchedTxn
Public only for unit testing and relay testing (not relayed).
bool IsRelayable() const
Whether this address should be relayed to other peers even if we can't reach it ourselves.
static constexpr SerParams V1
bool IsAddrV1Compatible() const
Check if the current object can be serialized in pre-ADDRv2/BIP155 format.
Transport protocol agnostic message container.
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)
const CFeeRate m_min_relay_feerate
auto withConflicting(Callable &&func) const EXCLUSIVE_LOCKS_REQUIRED(!cs_conflicting)
void removeForFinalizedBlock(const std::unordered_set< TxId, SaltedTxIdHasher > &confirmedTxIdsInNonFinalizedBlocks) EXCLUSIVE_LOCKS_REQUIRED(cs)
unsigned long size() const
std::optional< txiter > GetIter(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Returns an iterator to the given txid, if found.
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr< const CBlock > &block)
Notifies listeners that a block which builds directly on our current tip has been received and connec...
virtual void BlockConnected(ChainstateRole role, const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex)
Notifies listeners of a block being connected.
virtual void BlockChecked(const CBlock &, const BlockValidationState &)
Notifies listeners of a block validation result.
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
Notifies listeners when the block chain tip advances.
virtual void BlockDisconnected(const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex)
Notifies listeners of a block being disconnected.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex *GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(Chainstate ActiveChainstate)() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
const CBlockIndex * GetBackgroundSyncTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
The tip of the background sync chain.
MempoolAcceptResult ProcessTransaction(const CTransactionRef &tx, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Try to add a transaction to the memory pool.
bool IsInitialBlockDownload() const
Check whether we are doing an initial block download (synchronizing from disk or network)
bool ProcessNewBlock(const std::shared_ptr< const CBlock > &block, bool force_processing, bool min_pow_checked, bool *new_block, avalanche::Processor *const avalanche=nullptr) LOCKS_EXCLUDED(cs_main)
Process an incoming block.
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
bool BackgroundSyncInProgress() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
The state of a background sync (for net processing)
bool ProcessNewBlockHeaders(const std::vector< CBlockHeader > &block, bool min_pow_checked, BlockValidationState &state, const CBlockIndex **ppindex=nullptr, const std::optional< CCheckpointData > &test_checkpoints=std::nullopt) LOCKS_EXCLUDED(cs_main)
Process incoming block headers.
const arith_uint256 & MinimumChainWork() const
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
void MaybeRebalanceCaches() EXCLUSIVE_LOCKS_REQUIRED(void ReportHeadersPresync(const arith_uint256 &work, int64_t height, int64_t timestamp)
Check to see if caches are out of balance and if so, call ResizeCoinsCaches() as needed.
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
virtual uint64_t GetMaxBlockSize() const =0
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.
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 removeUnbroadcastProof(const ProofId &proofid)
const ProofRadixTree & getShareableProofsSnapshot() const
bool isBoundToPeer(const ProofId &proofid) const
bool saveRemoteProof(const ProofId &proofid, const NodeId nodeid, const bool present)
void forEachPeer(Callable &&func) const
void setInvalid(const ProofId &proofid)
bool isInvalid(const ProofId &proofid) const
bool isImmature(const ProofId &proofid) const
auto getUnbroadcastProofs() const
bool isInConflictingPool(const ProofId &proofid) const
void sendResponse(CNode *pfrom, Response response) const
bool addToReconcile(const AnyVoteItem &item) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
bool isStakingPreconsensusActivated(const CBlockIndex *pprev) const
int64_t getAvaproofsNodeCounter() const
bool sendHello(CNode *pfrom) EXCLUSIVE_LOCKS_REQUIRED(!cs_delayedAvahelloNodeIds)
Send a avahello message.
void setRecentlyFinalized(const uint256 &itemId) EXCLUSIVE_LOCKS_REQUIRED(!cs_finalizedItems)
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)
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
const ProofId & getProofId() const
StakeContenderIds are unique for each block to ensure that the peer polling for their acceptance has ...
#define AssertLockNotHeld(cs)
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
#define EXCLUSIVE_LOCKS_REQUIRED(...)
#define LOCKS_EXCLUDED(...)
#define NO_THREAD_SAFETY_ANALYSIS
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
constexpr int64_t count_microseconds(std::chrono::microseconds t)
constexpr int64_t count_seconds(std::chrono::seconds t)
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
double CountSecondsDouble(SecondsDouble t)
Helper to count the seconds in any std::chrono::duration type.
NodeClock::time_point GetAdjustedTime()
void AddTimeData(const CNetAddr &ip, int64_t nOffsetSample)
#define TRACE6(context, event, a, b, c, d, e, f)
@ AVALANCHE
Removed by avalanche vote.
std::string SanitizeString(std::string_view str, int rule)
Remove unsafe chars.
arith_uint256 CalculateHeadersWork(const std::vector< CBlockHeader > &headers)
Return the sum of the work on a given set of headers.
bool HasValidProofOfWork(const std::vector< CBlockHeader > &headers, const Consensus::Params &consensusParams)
Check with the proof of work on each blockheader matches the value in nBits.
PackageMempoolAcceptResult ProcessNewPackage(Chainstate &active_chainstate, CTxMemPool &pool, const Package &package, bool test_accept)
Validate (and maybe submit) a package to the mempool.
bool IsBlockMutated(const CBlock &block)
Check if a block has been mutated (with respect to its merkle root).
std::optional< std::vector< Coin > > GetSpentCoins(const CTransactionRef &ptx, const CCoinsViewCache &coins_view)
Get the coins spent by ptx from the coins_view.
static const unsigned int MIN_BLOCKS_TO_KEEP
Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pr...
CMainSignals & GetMainSignals()