Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 2,018 Lines • ▼ Show 20 Lines | if (txinfo.tx) { | ||||
return mi->second; | return mi->second; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return {}; | return {}; | ||||
} | } | ||||
//! Determine whether or not a peer can request a proof, and return it (or | |||||
//! nullptr if not found or not allowed). | |||||
static std::shared_ptr<avalanche::Proof> | |||||
FindProofForGetData(const CNode &peer, const avalanche::ProofId &proofid, | |||||
const std::chrono::seconds now) { | |||||
auto proof = g_avalanche->getProof(proofid); | |||||
// We don't have this proof | |||||
if (!proof) { | |||||
return nullptr; | |||||
} | |||||
auto proofTime = std::chrono::duration_cast<std::chrono::seconds>( | |||||
g_avalanche->getProofTime(proofid).time_since_epoch()); | |||||
// If we know that proof for long enough, allow for requesting it | |||||
if (proofTime <= now - UNCONDITIONAL_RELAY_DELAY) { | |||||
return proof; | |||||
} | |||||
{ | |||||
LOCK(cs_main); | |||||
// Otherwise, the proofs must have been announced recently. | |||||
if (State(peer.GetId()) | |||||
->m_recently_announced_proofs.contains(proofid)) { | |||||
return proof; | |||||
} | |||||
} | |||||
return nullptr; | |||||
} | |||||
static void ProcessGetData(const Config &config, CNode &pfrom, | static void ProcessGetData(const Config &config, CNode &pfrom, | ||||
CConnman &connman, CTxMemPool &mempool, | CConnman &connman, CTxMemPool &mempool, | ||||
const std::atomic<bool> &interruptMsgProc) | const std::atomic<bool> &interruptMsgProc) | ||||
LOCKS_EXCLUDED(cs_main) { | LOCKS_EXCLUDED(cs_main) { | ||||
AssertLockNotHeld(cs_main); | AssertLockNotHeld(cs_main); | ||||
std::deque<CInv>::iterator it = pfrom.vRecvGetData.begin(); | std::deque<CInv>::iterator it = pfrom.vRecvGetData.begin(); | ||||
std::vector<CInv> vNotFound; | std::vector<CInv> vNotFound; | ||||
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); | const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); | ||||
const std::chrono::seconds now = GetTime<std::chrono::seconds>(); | const std::chrono::seconds now = GetTime<std::chrono::seconds>(); | ||||
// Get last mempool request time | // Get last mempool request time | ||||
const std::chrono::seconds mempool_req = | const std::chrono::seconds mempool_req = | ||||
pfrom.m_tx_relay != nullptr | pfrom.m_tx_relay != nullptr | ||||
? pfrom.m_tx_relay->m_last_mempool_req.load() | ? pfrom.m_tx_relay->m_last_mempool_req.load() | ||||
: std::chrono::seconds::min(); | : std::chrono::seconds::min(); | ||||
// Process as many TX items from the front of the getdata queue as | // Process as many TX or AVA_PROOF items from the front of the getdata | ||||
// possible, since they're common and it's efficient to batch process | // queue as possible, since they're common and it's efficient to batch | ||||
// them. | // process them. | ||||
while (it != pfrom.vRecvGetData.end() && it->IsMsgTx()) { | while (it != pfrom.vRecvGetData.end()) { | ||||
if (interruptMsgProc) { | if (interruptMsgProc) { | ||||
return; | return; | ||||
} | } | ||||
// The send buffer provides backpressure. If there's no space in | // The send buffer provides backpressure. If there's no space in | ||||
// the buffer, pause processing until the next call. | // the buffer, pause processing until the next call. | ||||
if (pfrom.fPauseSend) { | if (pfrom.fPauseSend) { | ||||
break; | break; | ||||
} | } | ||||
const CInv &inv = *it++; | const CInv &inv = *it; | ||||
if (it->IsMsgProof()) { | |||||
auto proof = | |||||
FindProofForGetData(pfrom, avalanche::ProofId{inv.hash}, now); | |||||
if (proof) { | |||||
connman.PushMessage( | |||||
&pfrom, msgMaker.Make(NetMsgType::AVAPROOF, *proof)); | |||||
// TODO Remove from the set of unbroadcasted proof ids | |||||
} else { | |||||
vNotFound.push_back(inv); | |||||
} | |||||
++it; | |||||
continue; | |||||
} | |||||
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; | ||||
} | } | ||||
CTransactionRef tx = | CTransactionRef tx = | ||||
FindTxForGetData(pfrom, TxId{inv.hash}, mempool_req, now); | FindTxForGetData(pfrom, TxId{inv.hash}, mempool_req, now); | ||||
if (tx) { | if (tx) { | ||||
int nSendFlags = 0; | int nSendFlags = 0; | ||||
connman.PushMessage(&pfrom, | connman.PushMessage( | ||||
msgMaker.Make(nSendFlags, NetMsgType::TX, *tx)); | &pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *tx)); | ||||
mempool.RemoveUnbroadcastTx(TxId(inv.hash)); | mempool.RemoveUnbroadcastTx(TxId(inv.hash)); | ||||
// As we're going to send tx, make sure its unconfirmed parents are | // As we're going to send tx, make sure its unconfirmed parents | ||||
// made requestable. | // are made requestable. | ||||
for (const auto &txin : tx->vin) { | for (const auto &txin : tx->vin) { | ||||
auto txinfo = mempool.info(txin.prevout.GetTxId()); | auto txinfo = mempool.info(txin.prevout.GetTxId()); | ||||
if (txinfo.tx && | if (txinfo.tx && | ||||
txinfo.m_time > now - UNCONDITIONAL_RELAY_DELAY) { | txinfo.m_time > now - UNCONDITIONAL_RELAY_DELAY) { | ||||
// Relaying a transaction with a recent but unconfirmed | // Relaying a transaction with a recent but unconfirmed | ||||
// parent. | // parent. | ||||
if (WITH_LOCK( | if (WITH_LOCK( | ||||
pfrom.m_tx_relay->cs_tx_inventory, | pfrom.m_tx_relay->cs_tx_inventory, | ||||
return !pfrom.m_tx_relay->filterInventoryKnown | return !pfrom.m_tx_relay->filterInventoryKnown | ||||
.contains(txin.prevout.GetTxId()))) { | .contains( | ||||
txin.prevout.GetTxId()))) { | |||||
LOCK(cs_main); | LOCK(cs_main); | ||||
State(pfrom.GetId()) | State(pfrom.GetId()) | ||||
->m_recently_announced_invs.insert( | ->m_recently_announced_invs.insert( | ||||
txin.prevout.GetTxId()); | txin.prevout.GetTxId()); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
vNotFound.push_back(inv); | vNotFound.push_back(inv); | ||||
} | } | ||||
++it; | |||||
continue; | |||||
} | |||||
// It's neither a proof nor a transaction | |||||
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 != pfrom.vRecvGetData.end() && !pfrom.fPauseSend) { | if (it != pfrom.vRecvGetData.end() && !pfrom.fPauseSend) { | ||||
const CInv &inv = *it++; | const CInv &inv = *it++; | ||||
if (inv.IsGenBlkMsg()) { | if (inv.IsGenBlkMsg()) { | ||||
ProcessGetBlockData(config, pfrom, inv, connman, interruptMsgProc); | ProcessGetBlockData(config, pfrom, inv, connman, interruptMsgProc); | ||||
▲ Show 20 Lines • Show All 3,582 Lines • Show Last 20 Lines |