Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 784 Lines • ▼ Show 20 Lines | private: | ||||
std::map<BlockHash, std::pair<NodeId, std::list<QueuedBlock>::iterator>> | std::map<BlockHash, std::pair<NodeId, std::list<QueuedBlock>::iterator>> | ||||
mapBlocksInFlight GUARDED_BY(cs_main); | mapBlocksInFlight GUARDED_BY(cs_main); | ||||
/** When our tip was last updated. */ | /** When our tip was last updated. */ | ||||
std::atomic<int64_t> m_last_tip_update{0}; | std::atomic<int64_t> m_last_tip_update{0}; | ||||
/** | /** | ||||
* Determine whether or not a peer can request a transaction, and return it | |||||
* (or nullptr if not found or not allowed). | |||||
*/ | |||||
CTransactionRef FindTxForGetData(const CNode &peer, const TxId &txid, | |||||
const std::chrono::seconds mempool_req, | |||||
const std::chrono::seconds now) | |||||
LOCKS_EXCLUDED(cs_main); | |||||
void ProcessGetData(const Config &config, CNode &pfrom, Peer &peer, | |||||
const std::atomic<bool> &interruptMsgProc) | |||||
EXCLUSIVE_LOCKS_REQUIRED(!cs_main, peer.m_getdata_requests_mutex); | |||||
/** Relay map. */ | |||||
typedef std::map<TxId, CTransactionRef> MapRelay; | |||||
MapRelay mapRelay GUARDED_BY(cs_main); | |||||
/** | |||||
* Expiration-time ordered list of (expire time, relay map entry) pairs, | |||||
* protected by cs_main). | |||||
*/ | |||||
std::deque<std::pair<std::chrono::microseconds, MapRelay::iterator>> | |||||
g_relay_expiration GUARDED_BY(cs_main); | |||||
/** | |||||
* Checks if address relay is permitted with peer. If needed, initializes | * Checks if address relay is permitted with peer. If needed, initializes | ||||
* the m_addr_known bloom filter and sets m_addr_relay_enabled to true. | * the m_addr_known bloom filter and sets m_addr_relay_enabled to true. | ||||
* | * | ||||
* @return True if address relay is enabled with peer | * @return True if address relay is enabled with peer | ||||
* False if address relay is disallowed | * False if address relay is disallowed | ||||
*/ | */ | ||||
bool SetupAddressRelay(CNode &node, Peer &peer); | bool SetupAddressRelay(CNode &node, Peer &peer); | ||||
}; | }; | ||||
Show All 18 Lines | |||||
std::list<NodeId> lNodesAnnouncingHeaderAndIDs GUARDED_BY(cs_main); | std::list<NodeId> lNodesAnnouncingHeaderAndIDs GUARDED_BY(cs_main); | ||||
/** Number of preferable block download peers. */ | /** Number of preferable block download peers. */ | ||||
int nPreferredDownload GUARDED_BY(cs_main) = 0; | int nPreferredDownload GUARDED_BY(cs_main) = 0; | ||||
/** Number of peers from which we're downloading blocks. */ | /** Number of peers from which we're downloading blocks. */ | ||||
int nPeersWithValidatedDownloads GUARDED_BY(cs_main) = 0; | int nPeersWithValidatedDownloads GUARDED_BY(cs_main) = 0; | ||||
/** Relay map. */ | |||||
typedef std::map<uint256, CTransactionRef> MapRelay; | |||||
MapRelay mapRelay GUARDED_BY(cs_main); | |||||
/** | |||||
* Expiration-time ordered list of (expire time, relay map entry) pairs, | |||||
* protected by cs_main). | |||||
*/ | |||||
std::deque<std::pair<std::chrono::microseconds, MapRelay::iterator>> | |||||
g_relay_expiration GUARDED_BY(cs_main); | |||||
struct IteratorComparator { | struct IteratorComparator { | ||||
template <typename I> bool operator()(const I &a, const I &b) const { | template <typename I> bool operator()(const I &a, const I &b) const { | ||||
return &(*a) < &(*b); | return &(*a) < &(*b); | ||||
} | } | ||||
}; | }; | ||||
/** | /** | ||||
* Index from the parents' COutPoint into the mapOrphanTransactions. Used | * Index from the parents' COutPoint into the mapOrphanTransactions. Used | ||||
▲ Show 20 Lines • Show All 1,775 Lines • ▼ Show 20 Lines | if (send && pindex->nStatus.hasData()) { | ||||
connman.PushMessage(&pfrom, | connman.PushMessage(&pfrom, | ||||
msgMaker.Make(NetMsgType::INV, vInv)); | msgMaker.Make(NetMsgType::INV, vInv)); | ||||
peer.m_continuation_block = BlockHash(); | peer.m_continuation_block = BlockHash(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
//! Determine whether or not a peer can request a transaction, and return it (or | CTransactionRef PeerManagerImpl::FindTxForGetData( | ||||
//! nullptr if not found or not allowed). | const CNode &peer, const TxId &txid, const std::chrono::seconds mempool_req, | ||||
static CTransactionRef FindTxForGetData(const CTxMemPool &mempool, | const std::chrono::seconds now) LOCKS_EXCLUDED(cs_main) { | ||||
const CNode &peer, const TxId &txid, | auto txinfo = m_mempool.info(txid); | ||||
const std::chrono::seconds mempool_req, | |||||
const std::chrono::seconds now) | |||||
LOCKS_EXCLUDED(cs_main) { | |||||
auto txinfo = mempool.info(txid); | |||||
if (txinfo.tx) { | if (txinfo.tx) { | ||||
// If a TX could have been INVed in reply to a MEMPOOL request, | // If a TX could have been INVed in reply to a MEMPOOL request, | ||||
// or is older than UNCONDITIONAL_RELAY_DELAY, permit the request | // or is older than UNCONDITIONAL_RELAY_DELAY, permit the request | ||||
// unconditionally. | // unconditionally. | ||||
if ((mempool_req.count() && txinfo.m_time <= mempool_req) || | if ((mempool_req.count() && txinfo.m_time <= mempool_req) || | ||||
txinfo.m_time <= now - UNCONDITIONAL_RELAY_DELAY) { | txinfo.m_time <= now - UNCONDITIONAL_RELAY_DELAY) { | ||||
return std::move(txinfo.tx); | return std::move(txinfo.tx); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | FindProofForGetData(const CNode &peer, const avalanche::ProofId &proofid, | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
if (State(peer.GetId())->m_recently_announced_proofs.contains(proofid)) { | if (State(peer.GetId())->m_recently_announced_proofs.contains(proofid)) { | ||||
return proof; | return proof; | ||||
} | } | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
static void ProcessGetData(const Config &config, CNode &pfrom, Peer &peer, | void PeerManagerImpl::ProcessGetData(const Config &config, CNode &pfrom, | ||||
CConnman &connman, CTxMemPool &mempool, | Peer &peer, | ||||
const std::atomic<bool> &interruptMsgProc) | const std::atomic<bool> &interruptMsgProc) | ||||
EXCLUSIVE_LOCKS_REQUIRED(peer.m_getdata_requests_mutex) | EXCLUSIVE_LOCKS_REQUIRED(peer.m_getdata_requests_mutex) | ||||
LOCKS_EXCLUDED(::cs_main) { | LOCKS_EXCLUDED(::cs_main) { | ||||
AssertLockNotHeld(cs_main); | AssertLockNotHeld(cs_main); | ||||
std::deque<CInv>::iterator it = peer.m_getdata_requests.begin(); | std::deque<CInv>::iterator it = peer.m_getdata_requests.begin(); | ||||
std::vector<CInv> vNotFound; | std::vector<CInv> vNotFound; | ||||
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); | const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); | ||||
Show All 18 Lines | while (it != peer.m_getdata_requests.end()) { | ||||
} | } | ||||
const CInv &inv = *it; | const CInv &inv = *it; | ||||
if (it->IsMsgProof()) { | if (it->IsMsgProof()) { | ||||
const avalanche::ProofId proofid(inv.hash); | const avalanche::ProofId proofid(inv.hash); | ||||
auto proof = FindProofForGetData(pfrom, proofid, now); | auto proof = FindProofForGetData(pfrom, proofid, now); | ||||
if (proof) { | if (proof) { | ||||
connman.PushMessage( | m_connman.PushMessage( | ||||
&pfrom, msgMaker.Make(NetMsgType::AVAPROOF, *proof)); | &pfrom, msgMaker.Make(NetMsgType::AVAPROOF, *proof)); | ||||
g_avalanche->withPeerManager([&](avalanche::PeerManager &pm) { | g_avalanche->withPeerManager([&](avalanche::PeerManager &pm) { | ||||
pm.removeUnbroadcastProof(proofid); | pm.removeUnbroadcastProof(proofid); | ||||
}); | }); | ||||
} else { | } else { | ||||
vNotFound.push_back(inv); | vNotFound.push_back(inv); | ||||
} | } | ||||
++it; | ++it; | ||||
continue; | continue; | ||||
} | } | ||||
if (it->IsMsgTx()) { | if (it->IsMsgTx()) { | ||||
if (pfrom.m_tx_relay == nullptr) { | if (pfrom.m_tx_relay == nullptr) { | ||||
// Ignore GETDATA requests for transactions from blocks-only | // Ignore GETDATA requests for transactions from blocks-only | ||||
// peers. | // peers. | ||||
continue; | continue; | ||||
} | } | ||||
const TxId txid(inv.hash); | const TxId txid(inv.hash); | ||||
CTransactionRef tx = | CTransactionRef tx = | ||||
FindTxForGetData(mempool, pfrom, txid, mempool_req, now); | FindTxForGetData(pfrom, txid, mempool_req, now); | ||||
if (tx) { | if (tx) { | ||||
int nSendFlags = 0; | int nSendFlags = 0; | ||||
connman.PushMessage( | m_connman.PushMessage( | ||||
&pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *tx)); | &pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *tx)); | ||||
mempool.RemoveUnbroadcastTx(txid); | m_mempool.RemoveUnbroadcastTx(txid); | ||||
// As we're going to send tx, make sure its unconfirmed parents | // As we're going to send tx, make sure its unconfirmed parents | ||||
// are made requestable. | // are made requestable. | ||||
std::vector<TxId> parent_ids_to_add; | std::vector<TxId> parent_ids_to_add; | ||||
{ | { | ||||
LOCK(mempool.cs); | LOCK(m_mempool.cs); | ||||
auto txiter = mempool.GetIter(tx->GetId()); | auto txiter = m_mempool.GetIter(tx->GetId()); | ||||
if (txiter) { | if (txiter) { | ||||
const CTxMemPoolEntry::Parents &parents = | const CTxMemPoolEntry::Parents &parents = | ||||
(*txiter)->GetMemPoolParentsConst(); | (*txiter)->GetMemPoolParentsConst(); | ||||
parent_ids_to_add.reserve(parents.size()); | parent_ids_to_add.reserve(parents.size()); | ||||
for (const CTxMemPoolEntry &parent : parents) { | for (const CTxMemPoolEntry &parent : parents) { | ||||
if (parent.GetTime() > | if (parent.GetTime() > | ||||
now - UNCONDITIONAL_RELAY_DELAY) { | now - UNCONDITIONAL_RELAY_DELAY) { | ||||
parent_ids_to_add.push_back( | parent_ids_to_add.push_back( | ||||
Show All 25 Lines | while (it != peer.m_getdata_requests.end()) { | ||||
break; | break; | ||||
} | } | ||||
// Only process one BLOCK item per call, since they're uncommon and can be | // Only process one BLOCK item per call, since they're uncommon and can be | ||||
// expensive to process. | // expensive to process. | ||||
if (it != peer.m_getdata_requests.end() && !pfrom.fPauseSend) { | if (it != peer.m_getdata_requests.end() && !pfrom.fPauseSend) { | ||||
const CInv &inv = *it++; | const CInv &inv = *it++; | ||||
if (inv.IsGenBlkMsg()) { | if (inv.IsGenBlkMsg()) { | ||||
ProcessGetBlockData(config, pfrom, peer, inv, connman); | ProcessGetBlockData(config, pfrom, peer, inv, m_connman); | ||||
} | } | ||||
// else: If the first item on the queue is an unknown type, we erase it | // else: If the first item on the queue is an unknown type, we erase it | ||||
// and continue processing the queue on the next call. | // and continue processing the queue on the next call. | ||||
} | } | ||||
peer.m_getdata_requests.erase(peer.m_getdata_requests.begin(), it); | peer.m_getdata_requests.erase(peer.m_getdata_requests.begin(), it); | ||||
if (!vNotFound.empty()) { | if (!vNotFound.empty()) { | ||||
// Let the peer know that we didn't find what it asked for, so it | // Let the peer know that we didn't find what it asked for, so it | ||||
// doesn't have to wait around forever. SPV clients care about this | // doesn't have to wait around forever. SPV clients care about this | ||||
// message: it's needed when they are recursively walking the | // message: it's needed when they are recursively walking the | ||||
// dependencies of relevant unconfirmed transactions. SPV clients want | // dependencies of relevant unconfirmed transactions. SPV clients want | ||||
// to do that because they want to know about (and store and rebroadcast | // to do that because they want to know about (and store and rebroadcast | ||||
// and risk analyze) the dependencies of transactions relevant to them, | // and risk analyze) the dependencies of transactions relevant to them, | ||||
// without having to download the entire memory pool. Also, other nodes | // without having to download the entire memory pool. Also, other nodes | ||||
// can use these messages to automatically request a transaction from | // can use these messages to automatically request a transaction from | ||||
// some other peer that annnounced it, and stop waiting for us to | // some other peer that annnounced it, and stop waiting for us to | ||||
// respond. In normal operation, we often send NOTFOUND messages for | // respond. In normal operation, we often send NOTFOUND messages for | ||||
// parents of transactions that we relay; if a peer is missing a parent, | // parents of transactions that we relay; if a peer is missing a parent, | ||||
// they may assume we have them and request the parents from us. | // they may assume we have them and request the parents from us. | ||||
connman.PushMessage(&pfrom, | m_connman.PushMessage(&pfrom, | ||||
msgMaker.Make(NetMsgType::NOTFOUND, vNotFound)); | msgMaker.Make(NetMsgType::NOTFOUND, vNotFound)); | ||||
} | } | ||||
} | } | ||||
void PeerManagerImpl::SendBlockTransactions( | void PeerManagerImpl::SendBlockTransactions( | ||||
CNode &pfrom, const CBlock &block, const BlockTransactionsRequest &req) { | CNode &pfrom, const CBlock &block, const BlockTransactionsRequest &req) { | ||||
BlockTransactions resp(req); | BlockTransactions resp(req); | ||||
for (size_t i = 0; i < req.indices.size(); i++) { | for (size_t i = 0; i < req.indices.size(); i++) { | ||||
if (req.indices[i] >= block.vtx.size()) { | if (req.indices[i] >= block.vtx.size()) { | ||||
▲ Show 20 Lines • Show All 1,288 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::GETDATA) { | ||||
LogPrint(BCLog::NET, "received getdata for: %s peer=%d\n", | LogPrint(BCLog::NET, "received getdata for: %s peer=%d\n", | ||||
vInv[0].ToString(), pfrom.GetId()); | vInv[0].ToString(), pfrom.GetId()); | ||||
} | } | ||||
{ | { | ||||
LOCK(peer->m_getdata_requests_mutex); | LOCK(peer->m_getdata_requests_mutex); | ||||
peer->m_getdata_requests.insert(peer->m_getdata_requests.end(), | peer->m_getdata_requests.insert(peer->m_getdata_requests.end(), | ||||
vInv.begin(), vInv.end()); | vInv.begin(), vInv.end()); | ||||
ProcessGetData(config, pfrom, *peer, m_connman, m_mempool, | ProcessGetData(config, pfrom, *peer, interruptMsgProc); | ||||
interruptMsgProc); | |||||
} | } | ||||
return; | return; | ||||
} | } | ||||
if (msg_type == NetMsgType::GETBLOCKS) { | if (msg_type == NetMsgType::GETBLOCKS) { | ||||
CBlockLocator locator; | CBlockLocator locator; | ||||
uint256 hashStop; | uint256 hashStop; | ||||
▲ Show 20 Lines • Show All 1,577 Lines • ▼ Show 20 Lines | bool PeerManagerImpl::ProcessMessages(const Config &config, CNode *pfrom, | ||||
PeerRef peer = GetPeerRef(pfrom->GetId()); | PeerRef peer = GetPeerRef(pfrom->GetId()); | ||||
if (peer == nullptr) { | if (peer == nullptr) { | ||||
return false; | return false; | ||||
} | } | ||||
{ | { | ||||
LOCK(peer->m_getdata_requests_mutex); | LOCK(peer->m_getdata_requests_mutex); | ||||
if (!peer->m_getdata_requests.empty()) { | if (!peer->m_getdata_requests.empty()) { | ||||
ProcessGetData(config, *pfrom, *peer, m_connman, m_mempool, | ProcessGetData(config, *pfrom, *peer, interruptMsgProc); | ||||
interruptMsgProc); | |||||
} | } | ||||
} | } | ||||
{ | { | ||||
LOCK2(cs_main, g_cs_orphans); | LOCK2(cs_main, g_cs_orphans); | ||||
if (!peer->m_orphan_work_set.empty()) { | if (!peer->m_orphan_work_set.empty()) { | ||||
ProcessOrphanTx(config, peer->m_orphan_work_set); | ProcessOrphanTx(config, peer->m_orphan_work_set); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,274 Lines • Show Last 20 Lines |