Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 929 Lines • ▼ Show 20 Lines | void PeerManager::AddTxAnnouncement(const CNode &node, const TxId &txid, | ||||
NodeId nodeid = node.GetId(); | NodeId nodeid = node.GetId(); | ||||
if (!node.HasPermission(PF_RELAY) && | if (!node.HasPermission(PF_RELAY) && | ||||
m_txrequest.Count(nodeid) >= MAX_PEER_TX_ANNOUNCEMENTS) { | m_txrequest.Count(nodeid) >= MAX_PEER_TX_ANNOUNCEMENTS) { | ||||
// Too many queued announcements from this peer | // Too many queued announcements from this peer | ||||
return; | return; | ||||
} | } | ||||
const CNodeState *state = State(nodeid); | const CNodeState *state = State(nodeid); | ||||
// Decide the TxRequestTracker parameters for this announcement: | // Decide the InvRequestTracker parameters for this announcement: | ||||
// - "preferred": if fPreferredDownload is set (= outbound, or PF_NOBAN | // - "preferred": if fPreferredDownload is set (= outbound, or PF_NOBAN | ||||
// permission) | // permission) | ||||
// - "reqtime": current time plus delays for: | // - "reqtime": current time plus delays for: | ||||
// - NONPREF_PEER_TX_DELAY for announcements from non-preferred | // - NONPREF_PEER_TX_DELAY for announcements from non-preferred | ||||
// connections | // connections | ||||
// - OVERLOADED_PEER_TX_DELAY for announcements from peers which have at | // - OVERLOADED_PEER_TX_DELAY for announcements from peers which have at | ||||
// least MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't | // least MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't | ||||
// have PF_RELAY). | // have PF_RELAY). | ||||
▲ Show 20 Lines • Show All 526 Lines • ▼ Show 20 Lines | void PeerManager::BlockConnected(const std::shared_ptr<const CBlock> &pblock, | ||||
LOCK(g_cs_recent_confirmed_transactions); | LOCK(g_cs_recent_confirmed_transactions); | ||||
for (const CTransactionRef &ptx : pblock->vtx) { | for (const CTransactionRef &ptx : pblock->vtx) { | ||||
g_recent_confirmed_transactions->insert(ptx->GetId()); | g_recent_confirmed_transactions->insert(ptx->GetId()); | ||||
} | } | ||||
} | } | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
for (const auto &ptx : pblock->vtx) { | for (const auto &ptx : pblock->vtx) { | ||||
m_txrequest.ForgetTxId(ptx->GetId()); | m_txrequest.ForgetInvId(ptx->GetId()); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void PeerManager::BlockDisconnected(const std::shared_ptr<const CBlock> &block, | void PeerManager::BlockDisconnected(const std::shared_ptr<const CBlock> &block, | ||||
const CBlockIndex *pindex) { | const CBlockIndex *pindex) { | ||||
// To avoid relay problems with transactions that were previously | // To avoid relay problems with transactions that were previously | ||||
// confirmed, clear our filter of recently confirmed transactions whenever | // confirmed, clear our filter of recently confirmed transactions whenever | ||||
▲ Show 20 Lines • Show All 1,848 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::TX) { | ||||
if (!AlreadyHaveTx(txid, m_mempool) && | if (!AlreadyHaveTx(txid, m_mempool) && | ||||
AcceptToMemoryPool(config, m_mempool, state, ptx, | AcceptToMemoryPool(config, m_mempool, state, ptx, | ||||
false /* bypass_limits */, | false /* bypass_limits */, | ||||
Amount::zero() /* nAbsurdFee */)) { | Amount::zero() /* nAbsurdFee */)) { | ||||
m_mempool.check(&::ChainstateActive().CoinsTip()); | m_mempool.check(&::ChainstateActive().CoinsTip()); | ||||
// As this version of the transaction was acceptable, we can forget | // As this version of the transaction was acceptable, we can forget | ||||
// about any requests for it. | // about any requests for it. | ||||
m_txrequest.ForgetTxId(tx.GetId()); | m_txrequest.ForgetInvId(tx.GetId()); | ||||
RelayTransaction(tx.GetId(), m_connman); | RelayTransaction(tx.GetId(), m_connman); | ||||
for (size_t i = 0; i < tx.vout.size(); i++) { | for (size_t i = 0; i < tx.vout.size(); i++) { | ||||
auto it_by_prev = | auto it_by_prev = | ||||
mapOrphanTransactionsByPrev.find(COutPoint(txid, i)); | mapOrphanTransactionsByPrev.find(COutPoint(txid, i)); | ||||
if (it_by_prev != mapOrphanTransactionsByPrev.end()) { | if (it_by_prev != mapOrphanTransactionsByPrev.end()) { | ||||
for (const auto &elem : it_by_prev->second) { | for (const auto &elem : it_by_prev->second) { | ||||
pfrom.orphan_work_set.insert(elem->first); | pfrom.orphan_work_set.insert(elem->first); | ||||
} | } | ||||
Show All 31 Lines | if (msg_type == NetMsgType::TX) { | ||||
if (!AlreadyHaveTx(_txid, m_mempool)) { | if (!AlreadyHaveTx(_txid, m_mempool)) { | ||||
AddTxAnnouncement(pfrom, _txid, current_time); | AddTxAnnouncement(pfrom, _txid, current_time); | ||||
} | } | ||||
} | } | ||||
AddOrphanTx(ptx, pfrom.GetId()); | AddOrphanTx(ptx, pfrom.GetId()); | ||||
// Once added to the orphan pool, a tx is considered | // Once added to the orphan pool, a tx is considered | ||||
// AlreadyHave, and we shouldn't request it anymore. | // AlreadyHave, and we shouldn't request it anymore. | ||||
m_txrequest.ForgetTxId(tx.GetId()); | m_txrequest.ForgetInvId(tx.GetId()); | ||||
// DoS prevention: do not allow mapOrphanTransactions to grow | // DoS prevention: do not allow mapOrphanTransactions to grow | ||||
// unbounded (see CVE-2012-3789) | // unbounded (see CVE-2012-3789) | ||||
unsigned int nMaxOrphanTx = (unsigned int)std::max( | unsigned int nMaxOrphanTx = (unsigned int)std::max( | ||||
int64_t(0), gArgs.GetArg("-maxorphantx", | int64_t(0), gArgs.GetArg("-maxorphantx", | ||||
DEFAULT_MAX_ORPHAN_TRANSACTIONS)); | DEFAULT_MAX_ORPHAN_TRANSACTIONS)); | ||||
unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx); | unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx); | ||||
if (nEvicted > 0) { | if (nEvicted > 0) { | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
"mapOrphan overflow, removed %u tx\n", nEvicted); | "mapOrphan overflow, removed %u tx\n", nEvicted); | ||||
} | } | ||||
} else { | } else { | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
"not keeping orphan with rejected parents %s\n", | "not keeping orphan with rejected parents %s\n", | ||||
tx.GetId().ToString()); | tx.GetId().ToString()); | ||||
// We will continue to reject this tx since it has rejected | // We will continue to reject this tx since it has rejected | ||||
// parents so avoid re-requesting it from other peers. | // parents so avoid re-requesting it from other peers. | ||||
recentRejects->insert(tx.GetId()); | recentRejects->insert(tx.GetId()); | ||||
m_txrequest.ForgetTxId(tx.GetId()); | m_txrequest.ForgetInvId(tx.GetId()); | ||||
} | } | ||||
} else { | } else { | ||||
assert(recentRejects); | assert(recentRejects); | ||||
recentRejects->insert(tx.GetId()); | recentRejects->insert(tx.GetId()); | ||||
m_txrequest.ForgetTxId(tx.GetId()); | m_txrequest.ForgetInvId(tx.GetId()); | ||||
if (RecursiveDynamicUsage(*ptx) < 100000) { | if (RecursiveDynamicUsage(*ptx) < 100000) { | ||||
AddToCompactExtraTransactions(ptx); | AddToCompactExtraTransactions(ptx); | ||||
} | } | ||||
if (pfrom.HasPermission(PF_FORCERELAY)) { | if (pfrom.HasPermission(PF_FORCERELAY)) { | ||||
// Always relay transactions received from whitelisted peers, | // Always relay transactions received from whitelisted peers, | ||||
// even if they were already in the mempool or rejected from it | // even if they were already in the mempool or rejected from it | ||||
▲ Show 20 Lines • Show All 927 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::NOTFOUND) { | ||||
vRecv >> vInv; | vRecv >> vInv; | ||||
if (vInv.size() <= | if (vInv.size() <= | ||||
MAX_PEER_TX_ANNOUNCEMENTS + MAX_BLOCKS_IN_TRANSIT_PER_PEER) { | MAX_PEER_TX_ANNOUNCEMENTS + MAX_BLOCKS_IN_TRANSIT_PER_PEER) { | ||||
LOCK(::cs_main); | LOCK(::cs_main); | ||||
for (CInv &inv : vInv) { | for (CInv &inv : vInv) { | ||||
if (inv.IsMsgTx()) { | if (inv.IsMsgTx()) { | ||||
// If we receive a NOTFOUND message for a tx we requested, | // If we receive a NOTFOUND message for a tx we requested, | ||||
// mark the announcement for it as completed in | // mark the announcement for it as completed in | ||||
// TxRequestTracker. | // InvRequestTracker. | ||||
m_txrequest.ReceivedResponse(pfrom.GetId(), TxId(inv.hash)); | m_txrequest.ReceivedResponse(pfrom.GetId(), TxId(inv.hash)); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
// Ignore unknown commands for extensibility | // Ignore unknown commands for extensibility | ||||
▲ Show 20 Lines • Show All 1,025 Lines • ▼ Show 20 Lines | if (!vInv.empty()) { | ||||
LogPrint(BCLog::NET, "Requesting tx %s peer=%d\n", | LogPrint(BCLog::NET, "Requesting tx %s peer=%d\n", | ||||
txid.ToString(), pto->GetId()); | txid.ToString(), pto->GetId()); | ||||
vGetData.emplace_back(MSG_TX, txid); | vGetData.emplace_back(MSG_TX, txid); | ||||
if (vGetData.size() >= MAX_GETDATA_SZ) { | if (vGetData.size() >= MAX_GETDATA_SZ) { | ||||
m_connman.PushMessage( | m_connman.PushMessage( | ||||
pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); | pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); | ||||
vGetData.clear(); | vGetData.clear(); | ||||
} | } | ||||
m_txrequest.RequestedTx(pto->GetId(), txid, | m_txrequest.RequestedData(pto->GetId(), txid, | ||||
current_time + GETDATA_TX_INTERVAL); | current_time + GETDATA_TX_INTERVAL); | ||||
} else { | } else { | ||||
// We have already seen this transaction, no need to download. | // We have already seen this transaction, no need to download. | ||||
// This is just a belt-and-suspenders, as this should already be | // This is just a belt-and-suspenders, as this should already be | ||||
// called whenever a transaction becomes AlreadyHaveTx(). | // called whenever a transaction becomes AlreadyHaveTx(). | ||||
m_txrequest.ForgetTxId(txid); | m_txrequest.ForgetInvId(txid); | ||||
} | } | ||||
} | } | ||||
if (!vGetData.empty()) { | if (!vGetData.empty()) { | ||||
m_connman.PushMessage(pto, | m_connman.PushMessage(pto, | ||||
msgMaker.Make(NetMsgType::GETDATA, vGetData)); | msgMaker.Make(NetMsgType::GETDATA, vGetData)); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 75 Lines • Show Last 20 Lines |