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 802 Lines • ▼ Show 20 Lines | void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
/** Stack of nodes which we have set to announce using compact blocks */ | /** Stack of nodes which we have set to announce using compact blocks */ | ||||
std::list<NodeId> lNodesAnnouncingHeaderAndIDs GUARDED_BY(cs_main); | std::list<NodeId> lNodesAnnouncingHeaderAndIDs GUARDED_BY(cs_main); | ||||
/** 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; | ||||
/** Storage for orphan information */ | |||||
TxOrphanage m_orphanage; | |||||
/** | /** | ||||
* 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 20 Lines • Show All 816 Lines • ▼ Show 20 Lines | fUpdateConnectionTime = false; | ||||
!node.IsBlockOnlyConn() && !node.IsInboundConn()) { | !node.IsBlockOnlyConn() && !node.IsInboundConn()) { | ||||
// Only change visible addrman state for outbound, full-relay peers | // Only change visible addrman state for outbound, full-relay peers | ||||
fUpdateConnectionTime = true; | fUpdateConnectionTime = true; | ||||
} | } | ||||
for (const QueuedBlock &entry : state->vBlocksInFlight) { | for (const QueuedBlock &entry : state->vBlocksInFlight) { | ||||
mapBlocksInFlight.erase(entry.hash); | mapBlocksInFlight.erase(entry.hash); | ||||
} | } | ||||
WITH_LOCK(g_cs_orphans, EraseOrphansFor(nodeid)); | WITH_LOCK(g_cs_orphans, m_orphanage.EraseForPeer(nodeid)); | ||||
m_txrequest.DisconnectedPeer(nodeid); | m_txrequest.DisconnectedPeer(nodeid); | ||||
nPreferredDownload -= state->fPreferredDownload; | nPreferredDownload -= state->fPreferredDownload; | ||||
nPeersWithValidatedDownloads -= | nPeersWithValidatedDownloads -= | ||||
(state->nBlocksInFlightValidHeaders != 0); | (state->nBlocksInFlightValidHeaders != 0); | ||||
assert(nPeersWithValidatedDownloads >= 0); | assert(nPeersWithValidatedDownloads >= 0); | ||||
m_outbound_peers_with_protect_from_disconnect -= | m_outbound_peers_with_protect_from_disconnect -= | ||||
state->m_chain_sync.m_protect; | state->m_chain_sync.m_protect; | ||||
assert(m_outbound_peers_with_protect_from_disconnect >= 0); | assert(m_outbound_peers_with_protect_from_disconnect >= 0); | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { | ||||
stats.m_ping_wait = ping_wait; | stats.m_ping_wait = ping_wait; | ||||
stats.m_addr_processed = peer->m_addr_processed.load(); | stats.m_addr_processed = peer->m_addr_processed.load(); | ||||
stats.m_addr_rate_limited = peer->m_addr_rate_limited.load(); | stats.m_addr_rate_limited = peer->m_addr_rate_limited.load(); | ||||
stats.m_addr_relay_enabled = peer->m_addr_relay_enabled.load(); | stats.m_addr_relay_enabled = peer->m_addr_relay_enabled.load(); | ||||
return true; | return true; | ||||
} | } | ||||
////////////////////////////////////////////////////////////////////////////// | |||||
// | |||||
// mapOrphanTransactions | |||||
// | |||||
static void AddToCompactExtraTransactions(const CTransactionRef &tx) | static void AddToCompactExtraTransactions(const CTransactionRef &tx) | ||||
EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans) { | EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans) { | ||||
size_t max_extra_txn = gArgs.GetArg("-blockreconstructionextratxn", | size_t max_extra_txn = gArgs.GetArg("-blockreconstructionextratxn", | ||||
DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN); | DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN); | ||||
if (max_extra_txn <= 0) { | if (max_extra_txn <= 0) { | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 210 Lines • ▼ Show 20 Lines | PeerManagerImpl::PeerManagerImpl(const CChainParams &chainparams, | ||||
// schedule next run for 2-5 minutes in the future | // schedule next run for 2-5 minutes in the future | ||||
const auto requestAvalancheNodesInteval = 2min + GetRandMillis(3min); | const auto requestAvalancheNodesInteval = 2min + GetRandMillis(3min); | ||||
scheduler.scheduleFromNow([&] { MaybeRequestAvalancheNodes(scheduler); }, | scheduler.scheduleFromNow([&] { MaybeRequestAvalancheNodes(scheduler); }, | ||||
requestAvalancheNodesInteval); | requestAvalancheNodesInteval); | ||||
} | } | ||||
/** | /** | ||||
* Evict orphan txn pool entries (EraseOrphanTx) based on a newly connected | * Evict orphan txn pool entries based on a newly connected | ||||
* block, remember the recently confirmed transactions, and delete tracked | * block, remember the recently confirmed transactions, and delete tracked | ||||
* announcements for them. Also save the time of the last tip update. | * announcements for them. Also save the time of the last tip update. | ||||
*/ | */ | ||||
void PeerManagerImpl::BlockConnected( | void PeerManagerImpl::BlockConnected( | ||||
const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) { | const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) { | ||||
EraseOrphansForBlock(*pblock); | m_orphanage.EraseForBlock(*pblock); | ||||
m_last_tip_update = GetTime(); | m_last_tip_update = GetTime(); | ||||
{ | { | ||||
LOCK(m_recent_confirmed_transactions_mutex); | LOCK(m_recent_confirmed_transactions_mutex); | ||||
for (const CTransactionRef &ptx : pblock->vtx) { | for (const CTransactionRef &ptx : pblock->vtx) { | ||||
m_recent_confirmed_transactions->insert(ptx->GetId()); | m_recent_confirmed_transactions->insert(ptx->GetId()); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | if (::ChainActive().Tip()->GetBlockHash() != hashRecentRejectsChainTip) { | ||||
// If the chain tip has changed previously rejected transactions | // If the chain tip has changed previously rejected transactions | ||||
// might be now valid, e.g. due to a nLockTime'd tx becoming | // might be now valid, e.g. due to a nLockTime'd tx becoming | ||||
// valid, or a double-spend. Reset the rejects filter and give | // valid, or a double-spend. Reset the rejects filter and give | ||||
// those txs a second chance. | // those txs a second chance. | ||||
hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash(); | hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash(); | ||||
recentRejects->reset(); | recentRejects->reset(); | ||||
} | } | ||||
if (HaveOrphanTx(txid)) { | if (m_orphanage.HaveTx(txid)) { | ||||
return true; | return true; | ||||
} | } | ||||
{ | { | ||||
LOCK(m_recent_confirmed_transactions_mutex); | LOCK(m_recent_confirmed_transactions_mutex); | ||||
if (m_recent_confirmed_transactions->contains(txid)) { | if (m_recent_confirmed_transactions->contains(txid)) { | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 743 Lines • ▼ Show 20 Lines | |||||
void PeerManagerImpl::ProcessOrphanTx(const Config &config, | void PeerManagerImpl::ProcessOrphanTx(const Config &config, | ||||
std::set<TxId> &orphan_work_set) { | std::set<TxId> &orphan_work_set) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
AssertLockHeld(g_cs_orphans); | AssertLockHeld(g_cs_orphans); | ||||
while (!orphan_work_set.empty()) { | while (!orphan_work_set.empty()) { | ||||
const TxId orphanTxId = *orphan_work_set.begin(); | const TxId orphanTxId = *orphan_work_set.begin(); | ||||
orphan_work_set.erase(orphan_work_set.begin()); | orphan_work_set.erase(orphan_work_set.begin()); | ||||
const auto [porphanTx, from_peer] = GetOrphanTx(orphanTxId); | const auto [porphanTx, from_peer] = m_orphanage.GetTx(orphanTxId); | ||||
if (porphanTx == nullptr) { | if (porphanTx == nullptr) { | ||||
continue; | continue; | ||||
} | } | ||||
TxValidationState state; | TxValidationState state; | ||||
if (AcceptToMemoryPool(::ChainstateActive(), config, m_mempool, state, | if (AcceptToMemoryPool(::ChainstateActive(), config, m_mempool, state, | ||||
porphanTx, false /* bypass_limits */)) { | porphanTx, false /* bypass_limits */)) { | ||||
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", | LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", | ||||
orphanTxId.ToString()); | orphanTxId.ToString()); | ||||
RelayTransaction(orphanTxId, m_connman); | RelayTransaction(orphanTxId, m_connman); | ||||
AddChildrenToWorkSet(*porphanTx, orphan_work_set); | m_orphanage.AddChildrenToWorkSet(*porphanTx, orphan_work_set); | ||||
EraseOrphanTx(orphanTxId); | m_orphanage.EraseTx(orphanTxId); | ||||
break; | break; | ||||
} else if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) { | } else if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) { | ||||
if (state.IsInvalid()) { | if (state.IsInvalid()) { | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
" invalid orphan tx %s from peer=%d. %s\n", | " invalid orphan tx %s from peer=%d. %s\n", | ||||
orphanTxId.ToString(), from_peer, state.ToString()); | orphanTxId.ToString(), from_peer, state.ToString()); | ||||
// Punish peer that gave us an invalid orphan tx | // Punish peer that gave us an invalid orphan tx | ||||
MaybePunishNodeForTx(from_peer, state); | MaybePunishNodeForTx(from_peer, state); | ||||
} | } | ||||
// Has inputs but not accepted to mempool | // Has inputs but not accepted to mempool | ||||
// Probably non-standard or insufficient fee | // Probably non-standard or insufficient fee | ||||
LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", | LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", | ||||
orphanTxId.ToString()); | orphanTxId.ToString()); | ||||
assert(recentRejects); | assert(recentRejects); | ||||
recentRejects->insert(orphanTxId); | recentRejects->insert(orphanTxId); | ||||
EraseOrphanTx(orphanTxId); | m_orphanage.EraseTx(orphanTxId); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
m_mempool.check(m_chainman.ActiveChainstate()); | m_mempool.check(m_chainman.ActiveChainstate()); | ||||
} | } | ||||
/** | /** | ||||
* Validation logic for compact filters request handling. | * Validation logic for compact filters request handling. | ||||
▲ Show 20 Lines • Show All 1,265 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::TX) { | ||||
if (AcceptToMemoryPool(::ChainstateActive(), config, m_mempool, state, | if (AcceptToMemoryPool(::ChainstateActive(), config, m_mempool, state, | ||||
ptx, false /* bypass_limits */)) { | ptx, false /* bypass_limits */)) { | ||||
m_mempool.check(m_chainman.ActiveChainstate()); | m_mempool.check(m_chainman.ActiveChainstate()); | ||||
// 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.ForgetInvId(tx.GetId()); | m_txrequest.ForgetInvId(tx.GetId()); | ||||
RelayTransaction(tx.GetId(), m_connman); | RelayTransaction(tx.GetId(), m_connman); | ||||
AddChildrenToWorkSet(tx, peer->m_orphan_work_set); | m_orphanage.AddChildrenToWorkSet(tx, peer->m_orphan_work_set); | ||||
pfrom.m_last_tx_time = GetTime<std::chrono::seconds>(); | pfrom.m_last_tx_time = GetTime<std::chrono::seconds>(); | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
"AcceptToMemoryPool: peer=%d: accepted %s " | "AcceptToMemoryPool: peer=%d: accepted %s " | ||||
"(poolsz %u txn, %u kB)\n", | "(poolsz %u txn, %u kB)\n", | ||||
pfrom.GetId(), tx.GetId().ToString(), m_mempool.size(), | pfrom.GetId(), tx.GetId().ToString(), m_mempool.size(), | ||||
m_mempool.DynamicMemoryUsage() / 1000); | m_mempool.DynamicMemoryUsage() / 1000); | ||||
Show All 30 Lines | if (msg_type == NetMsgType::TX) { | ||||
for (const TxId &parent_txid : unique_parents) { | for (const TxId &parent_txid : unique_parents) { | ||||
// FIXME: MSG_TX should use a TxHash, not a TxId. | // FIXME: MSG_TX should use a TxHash, not a TxId. | ||||
pfrom.AddKnownTx(parent_txid); | pfrom.AddKnownTx(parent_txid); | ||||
if (!AlreadyHaveTx(parent_txid)) { | if (!AlreadyHaveTx(parent_txid)) { | ||||
AddTxAnnouncement(pfrom, parent_txid, current_time); | AddTxAnnouncement(pfrom, parent_txid, current_time); | ||||
} | } | ||||
} | } | ||||
if (OrphanageAddTx(ptx, pfrom.GetId())) { | if (m_orphanage.AddTx(ptx, pfrom.GetId())) { | ||||
AddToCompactExtraTransactions(ptx); | AddToCompactExtraTransactions(ptx); | ||||
} | } | ||||
// 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.ForgetInvId(tx.GetId()); | m_txrequest.ForgetInvId(tx.GetId()); | ||||
// DoS prevention: do not allow mapOrphanTransactions to grow | // DoS prevention: do not allow m_orphanage 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 = m_orphanage.LimitOrphans(nMaxOrphanTx); | ||||
if (nEvicted > 0) { | if (nEvicted > 0) { | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
"mapOrphan overflow, removed %u tx\n", nEvicted); | "orphanage 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()); | ||||
▲ Show 20 Lines • Show All 2,497 Lines • ▼ Show 20 Lines | // | ||||
pto->m_tx_relay->m_next_send_feefilter = | pto->m_tx_relay->m_next_send_feefilter = | ||||
current_time + GetRandomDuration<std::chrono::microseconds>( | current_time + GetRandomDuration<std::chrono::microseconds>( | ||||
MAX_FEEFILTER_CHANGE_DELAY); | MAX_FEEFILTER_CHANGE_DELAY); | ||||
} | } | ||||
} | } | ||||
} // release cs_main | } // release cs_main | ||||
return true; | return true; | ||||
} | } | ||||
class CNetProcessingCleanup { | |||||
public: | |||||
CNetProcessingCleanup() {} | |||||
~CNetProcessingCleanup() { | |||||
// orphan transactions | |||||
mapOrphanTransactions.clear(); | |||||
mapOrphanTransactionsByPrev.clear(); | |||||
} | |||||
}; | |||||
static CNetProcessingCleanup instance_of_cnetprocessingcleanup; |