Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show All 36 Lines | |||||
#if defined(NDEBUG) | #if defined(NDEBUG) | ||||
#error "Bitcoin cannot be compiled without assertions." | #error "Bitcoin cannot be compiled without assertions." | ||||
#endif | #endif | ||||
// Used only to inform the wallet of when we last received a block. | // Used only to inform the wallet of when we last received a block. | ||||
std::atomic<int64_t> nTimeBestReceived(0); | std::atomic<int64_t> nTimeBestReceived(0); | ||||
struct IteratorComparator { | OrphanPool g_orphanPool; | ||||
template <typename I> bool operator()(const I &a, const I &b) { | |||||
return &(*a) < &(*b); | |||||
} | |||||
}; | |||||
struct COrphanTx { | |||||
// When modifying, adapt the copy of this definition in tests/DoS_tests. | |||||
CTransactionRef tx; | |||||
NodeId fromPeer; | |||||
int64_t nTimeExpire; | |||||
}; | |||||
std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main); | |||||
std::map<COutPoint, | |||||
std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> | |||||
mapOrphanTransactionsByPrev GUARDED_BY(cs_main); | |||||
void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||
static size_t vExtraTxnForCompactIt = 0; | |||||
static std::vector<std::pair<uint256, CTransactionRef>> | |||||
vExtraTxnForCompact GUARDED_BY(cs_main); | |||||
// SHA256("main address relay")[0:8] | // SHA256("main address relay")[0:8] | ||||
static const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; | static const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; | ||||
// Internal stuff | // Internal stuff | ||||
namespace { | namespace { | ||||
/** Number of nodes with fSyncStarted. */ | /** Number of nodes with fSyncStarted. */ | ||||
int nSyncStarted = 0; | int nSyncStarted = 0; | ||||
▲ Show 20 Lines • Show All 614 Lines • ▼ Show 20 Lines | void PeerLogicValidation::FinalizeNode(const Config &config, NodeId nodeid, | ||||
if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { | if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { | ||||
fUpdateConnectionTime = true; | fUpdateConnectionTime = true; | ||||
} | } | ||||
for (const QueuedBlock &entry : state->vBlocksInFlight) { | for (const QueuedBlock &entry : state->vBlocksInFlight) { | ||||
mapBlocksInFlight.erase(entry.hash); | mapBlocksInFlight.erase(entry.hash); | ||||
} | } | ||||
EraseOrphansFor(nodeid); | g_orphanPool.EraseOrphansFor(nodeid); | ||||
nPreferredDownload -= state->fPreferredDownload; | nPreferredDownload -= state->fPreferredDownload; | ||||
nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0); | nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0); | ||||
assert(nPeersWithValidatedDownloads >= 0); | assert(nPeersWithValidatedDownloads >= 0); | ||||
g_outbound_peers_with_protect_from_disconnect -= | g_outbound_peers_with_protect_from_disconnect -= | ||||
state->m_chain_sync.m_protect; | state->m_chain_sync.m_protect; | ||||
assert(g_outbound_peers_with_protect_from_disconnect >= 0); | assert(g_outbound_peers_with_protect_from_disconnect >= 0); | ||||
mapNodeState.erase(nodeid); | mapNodeState.erase(nodeid); | ||||
Show All 28 Lines | bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { | ||||
return true; | return true; | ||||
} | } | ||||
////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////// | ||||
// | // | ||||
// mapOrphanTransactions | // mapOrphanTransactions | ||||
// | // | ||||
static void AddToCompactExtraTransactions(const CTransactionRef &tx) | void OrphanPool::AddToCompactExtraTransactions(const CTransactionRef &tx) { | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | LOCK(cs); | ||||
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; | ||||
} | } | ||||
if (!vExtraTxnForCompact.size()) { | if (!vExtraTxnForCompact.size()) { | ||||
vExtraTxnForCompact.resize(max_extra_txn); | vExtraTxnForCompact.resize(max_extra_txn); | ||||
} | } | ||||
vExtraTxnForCompact[vExtraTxnForCompactIt] = | vExtraTxnForCompact[vExtraTxnForCompactIt] = | ||||
std::make_pair(tx->GetId(), tx); | std::make_pair(tx->GetId(), tx); | ||||
vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % max_extra_txn; | vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % max_extra_txn; | ||||
} | } | ||||
bool AddOrphanTx(const CTransactionRef &tx, NodeId peer) | bool OrphanPool::AddOrphanTx(const CTransactionRef &tx, NodeId peer) { | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | LOCK(cs); | ||||
const uint256 &txid = tx->GetId(); | const uint256 &txid = tx->GetId(); | ||||
if (mapOrphanTransactions.count(txid)) { | if (mapOrphanTransactions.count(txid)) { | ||||
return false; | return false; | ||||
} | } | ||||
// Ignore big transactions, to avoid a send-big-orphans memory exhaustion | // Ignore big transactions, to avoid a send-big-orphans memory exhaustion | ||||
// attack. If a peer has a legitimate large transaction with a missing | // attack. If a peer has a legitimate large transaction with a missing | ||||
// parent then we assume it will rebroadcast it later, after the parent | // parent then we assume it will rebroadcast it later, after the parent | ||||
Show All 18 Lines | bool OrphanPool::AddOrphanTx(const CTransactionRef &tx, NodeId peer) { | ||||
AddToCompactExtraTransactions(tx); | AddToCompactExtraTransactions(tx); | ||||
LogPrint(BCLog::MEMPOOL, "stored orphan tx %s (mapsz %u outsz %u)\n", | LogPrint(BCLog::MEMPOOL, "stored orphan tx %s (mapsz %u outsz %u)\n", | ||||
txid.ToString(), mapOrphanTransactions.size(), | txid.ToString(), mapOrphanTransactions.size(), | ||||
mapOrphanTransactionsByPrev.size()); | mapOrphanTransactionsByPrev.size()); | ||||
return true; | return true; | ||||
} | } | ||||
static int EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | int OrphanPool::EraseOrphanTx(uint256 hash) { | ||||
LOCK(cs); | |||||
std::map<uint256, COrphanTx>::iterator it = | std::map<uint256, COrphanTx>::iterator it = | ||||
mapOrphanTransactions.find(hash); | mapOrphanTransactions.find(hash); | ||||
if (it == mapOrphanTransactions.end()) { | if (it == mapOrphanTransactions.end()) { | ||||
return 0; | return 0; | ||||
} | } | ||||
for (const CTxIn &txin : it->second.tx->vin) { | for (const CTxIn &txin : it->second.tx->vin) { | ||||
auto itPrev = mapOrphanTransactionsByPrev.find(txin.prevout); | auto itPrev = mapOrphanTransactionsByPrev.find(txin.prevout); | ||||
if (itPrev == mapOrphanTransactionsByPrev.end()) { | if (itPrev == mapOrphanTransactionsByPrev.end()) { | ||||
continue; | continue; | ||||
} | } | ||||
itPrev->second.erase(it); | itPrev->second.erase(it); | ||||
if (itPrev->second.empty()) { | if (itPrev->second.empty()) { | ||||
mapOrphanTransactionsByPrev.erase(itPrev); | mapOrphanTransactionsByPrev.erase(itPrev); | ||||
} | } | ||||
} | } | ||||
mapOrphanTransactions.erase(it); | mapOrphanTransactions.erase(it); | ||||
return 1; | return 1; | ||||
} | } | ||||
void EraseOrphansFor(NodeId peer) { | void OrphanPool::EraseOrphansFor(NodeId peer) { | ||||
LOCK(cs); | |||||
int nErased = 0; | int nErased = 0; | ||||
std::map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin(); | std::map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin(); | ||||
while (iter != mapOrphanTransactions.end()) { | while (iter != mapOrphanTransactions.end()) { | ||||
// Increment to avoid iterator becoming invalid. | // Increment to avoid iterator becoming invalid. | ||||
std::map<uint256, COrphanTx>::iterator maybeErase = iter++; | std::map<uint256, COrphanTx>::iterator maybeErase = iter++; | ||||
if (maybeErase->second.fromPeer == peer) { | if (maybeErase->second.fromPeer == peer) { | ||||
nErased += EraseOrphanTx(maybeErase->second.tx->GetId()); | nErased += EraseOrphanTx(maybeErase->second.tx->GetId()); | ||||
} | } | ||||
} | } | ||||
if (nErased > 0) { | if (nErased > 0) { | ||||
LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, | LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, | ||||
peer); | peer); | ||||
} | } | ||||
} | } | ||||
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) | unsigned int OrphanPool::LimitOrphanTxSize(unsigned int nMaxOrphans) { | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | LOCK(cs); | ||||
unsigned int nEvicted = 0; | unsigned int nEvicted = 0; | ||||
static int64_t nNextSweep; | static int64_t nNextSweep; | ||||
int64_t nNow = GetTime(); | int64_t nNow = GetTime(); | ||||
if (nNextSweep <= nNow) { | if (nNextSweep <= nNow) { | ||||
// Sweep out expired orphan pool entries: | // Sweep out expired orphan pool entries: | ||||
int nErased = 0; | int nErased = 0; | ||||
int64_t nMinExpTime = | int64_t nMinExpTime = | ||||
nNow + ORPHAN_TX_EXPIRE_TIME - ORPHAN_TX_EXPIRE_INTERVAL; | nNow + ORPHAN_TX_EXPIRE_TIME - ORPHAN_TX_EXPIRE_INTERVAL; | ||||
std::map<uint256, COrphanTx>::iterator iter = | std::map<uint256, COrphanTx>::iterator iter = | ||||
mapOrphanTransactions.begin(); | mapOrphanTransactions.begin(); | ||||
while (iter != mapOrphanTransactions.end()) { | while (iter != mapOrphanTransactions.end()) { | ||||
std::map<uint256, COrphanTx>::iterator maybeErase = iter++; | std::map<uint256, COrphanTx>::iterator maybeErase = iter++; | ||||
if (maybeErase->second.nTimeExpire <= nNow) { | if (maybeErase->second.nTimeExpire <= nNow) { | ||||
nErased += EraseOrphanTx(maybeErase->second.tx->GetId()); | nErased += EraseOrphanTx(maybeErase->second.tx->GetId()); | ||||
} else { | } else { | ||||
nMinExpTime = | nMinExpTime = | ||||
std::min(maybeErase->second.nTimeExpire, nMinExpTime); | std::min(maybeErase->second.nTimeExpire, nMinExpTime); | ||||
} | } | ||||
} | } | ||||
// Sweep again 5 minutes after the next entry that expires in order to | // Sweep again 5 minutes after the next entry that expires in order | ||||
// to | |||||
// batch the linear scan. | // batch the linear scan. | ||||
jasonbcox: move this comment to the above line. silly linter | |||||
nNextSweep = nMinExpTime + ORPHAN_TX_EXPIRE_INTERVAL; | nNextSweep = nMinExpTime + ORPHAN_TX_EXPIRE_INTERVAL; | ||||
if (nErased > 0) { | if (nErased > 0) { | ||||
LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx due to expiration\n", | LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx due to expiration\n", | ||||
nErased); | nErased); | ||||
} | } | ||||
} | } | ||||
while (mapOrphanTransactions.size() > nMaxOrphans) { | while (mapOrphanTransactions.size() > nMaxOrphans) { | ||||
// Evict a random orphan: | // Evict a random orphan: | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | void PeerLogicValidation::BlockConnected( | ||||
std::vector<uint256> vOrphanErase; | std::vector<uint256> vOrphanErase; | ||||
for (const CTransactionRef &ptx : pblock->vtx) { | for (const CTransactionRef &ptx : pblock->vtx) { | ||||
const CTransaction &tx = *ptx; | const CTransaction &tx = *ptx; | ||||
// Which orphan pool entries must we evict? | // Which orphan pool entries must we evict? | ||||
for (size_t j = 0; j < tx.vin.size(); j++) { | for (size_t j = 0; j < tx.vin.size(); j++) { | ||||
auto itByPrev = mapOrphanTransactionsByPrev.find(tx.vin[j].prevout); | auto itByPrev = g_orphanPool.mapOrphanTransactionsByPrev.find( | ||||
if (itByPrev == mapOrphanTransactionsByPrev.end()) { | tx.vin[j].prevout); | ||||
if (itByPrev == g_orphanPool.mapOrphanTransactionsByPrev.end()) { | |||||
jasonbcoxUnsubmitted Not Done Inline ActionsA bit surprising that these calls on mapOrphanTransactionsByPrev do not have LOCK() applied. const methods should be thread safe, but use of auto here makes me wonder if that is necessarily enforced. jasonbcox: A bit surprising that these calls on mapOrphanTransactionsByPrev do not have LOCK() applied. | |||||
schancelAuthorUnsubmitted Done Inline ActionsHmm yeah. Good catch. This needs to be encapsulated schancel: Hmm yeah. Good catch. This needs to be encapsulated | |||||
continue; | continue; | ||||
} | } | ||||
for (auto mi = itByPrev->second.begin(); | for (auto mi = itByPrev->second.begin(); | ||||
mi != itByPrev->second.end(); ++mi) { | mi != itByPrev->second.end(); ++mi) { | ||||
const CTransaction &orphanTx = *(*mi)->second.tx; | const CTransaction &orphanTx = *(*mi)->second.tx; | ||||
const uint256 &orphanHash = orphanTx.GetHash(); | const uint256 &orphanHash = orphanTx.GetHash(); | ||||
vOrphanErase.push_back(orphanHash); | vOrphanErase.push_back(orphanHash); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Erase orphan transactions include or precluded by this block | // Erase orphan transactions include or precluded by this block | ||||
if (vOrphanErase.size()) { | if (vOrphanErase.size()) { | ||||
int nErased = 0; | int nErased = 0; | ||||
for (uint256 &orphanId : vOrphanErase) { | for (uint256 &orphanId : vOrphanErase) { | ||||
nErased += EraseOrphanTx(orphanId); | nErased += g_orphanPool.EraseOrphanTx(orphanId); | ||||
jasonbcoxUnsubmitted Not Done Inline ActionsEraseOrphanTx() calls LOCK(), so this call is safe compared to the above. jasonbcox: EraseOrphanTx() calls LOCK(), so this call is safe compared to the above. | |||||
} | } | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
"Erased %d orphan tx included or conflicted by block\n", | "Erased %d orphan tx included or conflicted by block\n", | ||||
nErased); | nErased); | ||||
} | } | ||||
g_last_tip_update = GetTime(); | g_last_tip_update = GetTime(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | switch (inv.type) { | ||||
// Use pcoinsTip->HaveCoinInCache as a quick approximation to | // Use pcoinsTip->HaveCoinInCache as a quick approximation to | ||||
// exclude requesting or processing some txs which have already been | // exclude requesting or processing some txs which have already been | ||||
// included in a block. As this is best effort, we only check for | // included in a block. As this is best effort, we only check for | ||||
// output 0 and 1. This works well enough in practice and we get | // output 0 and 1. This works well enough in practice and we get | ||||
// diminishing returns with 2 onward. | // diminishing returns with 2 onward. | ||||
return recentRejects->contains(inv.hash) || | return recentRejects->contains(inv.hash) || | ||||
mempool.exists(inv.hash) || | mempool.exists(inv.hash) || | ||||
mapOrphanTransactions.count(inv.hash) || | g_orphanPool.mapOrphanTransactions.count(inv.hash) || | ||||
jasonbcoxUnsubmitted Not Done Inline ActionsLOCK()? jasonbcox: LOCK()? | |||||
pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 0)) || | pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 0)) || | ||||
pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1)); | pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1)); | ||||
} | } | ||||
case MSG_BLOCK: | case MSG_BLOCK: | ||||
return mapBlockIndex.count(inv.hash); | return mapBlockIndex.count(inv.hash); | ||||
} | } | ||||
// Don't know what it is, just say we already got one | // Don't know what it is, just say we already got one | ||||
return true; | return true; | ||||
▲ Show 20 Lines • Show All 1,269 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::TX) { | ||||
"(poolsz %u txn, %u kB)\n", | "(poolsz %u txn, %u kB)\n", | ||||
pfrom->GetId(), tx.GetId().ToString(), mempool.size(), | pfrom->GetId(), tx.GetId().ToString(), mempool.size(), | ||||
mempool.DynamicMemoryUsage() / 1000); | mempool.DynamicMemoryUsage() / 1000); | ||||
// Recursively process any orphan transactions that depended on this | // Recursively process any orphan transactions that depended on this | ||||
// one | // one | ||||
std::set<NodeId> setMisbehaving; | std::set<NodeId> setMisbehaving; | ||||
while (!vWorkQueue.empty()) { | while (!vWorkQueue.empty()) { | ||||
auto itByPrev = | auto itByPrev = g_orphanPool.mapOrphanTransactionsByPrev.find( | ||||
mapOrphanTransactionsByPrev.find(vWorkQueue.front()); | vWorkQueue.front()); | ||||
vWorkQueue.pop_front(); | vWorkQueue.pop_front(); | ||||
if (itByPrev == mapOrphanTransactionsByPrev.end()) { | if (itByPrev == | ||||
g_orphanPool.mapOrphanTransactionsByPrev.end()) { | |||||
jasonbcoxUnsubmitted Not Done Inline ActionsLOCK()? Same logic as above. jasonbcox: LOCK()? Same logic as above. | |||||
continue; | continue; | ||||
} | } | ||||
for (auto mi = itByPrev->second.begin(); | for (auto mi = itByPrev->second.begin(); | ||||
mi != itByPrev->second.end(); ++mi) { | mi != itByPrev->second.end(); ++mi) { | ||||
const CTransactionRef &porphanTx = (*mi)->second.tx; | const CTransactionRef &porphanTx = (*mi)->second.tx; | ||||
const CTransaction &orphanTx = *porphanTx; | const CTransaction &orphanTx = *porphanTx; | ||||
const uint256 &orphanId = orphanTx.GetId(); | const uint256 &orphanId = orphanTx.GetId(); | ||||
NodeId fromPeer = (*mi)->second.fromPeer; | NodeId fromPeer = (*mi)->second.fromPeer; | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::TX) { | ||||
recentRejects->insert(orphanId); | recentRejects->insert(orphanId); | ||||
} | } | ||||
} | } | ||||
mempool.check(pcoinsTip); | mempool.check(pcoinsTip); | ||||
} | } | ||||
} | } | ||||
for (const uint256 &hash : vEraseQueue) { | for (const uint256 &hash : vEraseQueue) { | ||||
EraseOrphanTx(hash); | g_orphanPool.EraseOrphanTx(hash); | ||||
} | } | ||||
} else if (fMissingInputs) { | } else if (fMissingInputs) { | ||||
// It may be the case that the orphans parents have all been | // It may be the case that the orphans parents have all been | ||||
// rejected. | // rejected. | ||||
bool fRejectedParents = false; | bool fRejectedParents = false; | ||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
if (recentRejects->contains(txin.prevout.GetTxId())) { | if (recentRejects->contains(txin.prevout.GetTxId())) { | ||||
fRejectedParents = true; | fRejectedParents = true; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (!fRejectedParents) { | if (!fRejectedParents) { | ||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
// FIXME: MSG_TX should use a TxHash, not a TxId. | // FIXME: MSG_TX should use a TxHash, not a TxId. | ||||
CInv _inv(MSG_TX, txin.prevout.GetTxId()); | CInv _inv(MSG_TX, txin.prevout.GetTxId()); | ||||
pfrom->AddInventoryKnown(_inv); | pfrom->AddInventoryKnown(_inv); | ||||
if (!AlreadyHave(_inv)) { | if (!AlreadyHave(_inv)) { | ||||
pfrom->AskFor(_inv); | pfrom->AskFor(_inv); | ||||
} | } | ||||
} | } | ||||
AddOrphanTx(ptx, pfrom->GetId()); | g_orphanPool.AddOrphanTx(ptx, pfrom->GetId()); | ||||
// DoS prevention: do not allow mapOrphanTransactions to grow | // DoS prevention: do not allow mapOrphanTransactions to grow | ||||
// unbounded | // unbounded | ||||
unsigned int nMaxOrphanTx = (unsigned int)std::max( | unsigned int nMaxOrphanTx = (unsigned int)std::max( | ||||
int64_t(0), | int64_t(0), | ||||
gArgs.GetArg("-maxorphantx", | gArgs.GetArg("-maxorphantx", | ||||
DEFAULT_MAX_ORPHAN_TRANSACTIONS)); | DEFAULT_MAX_ORPHAN_TRANSACTIONS)); | ||||
unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx); | unsigned int nEvicted = | ||||
g_orphanPool.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()); | ||||
} | } | ||||
} else { | } else { | ||||
if (!state.CorruptionPossible()) { | if (!state.CorruptionPossible()) { | ||||
// Do not use rejection cache for witness transactions or | // Do not use rejection cache for witness transactions or | ||||
// witness-stripped transactions, as they can have been | // witness-stripped transactions, as they can have been | ||||
// malleated. See https://github.com/bitcoin/bitcoin/issues/8279 | // malleated. See https://github.com/bitcoin/bitcoin/issues/8279 | ||||
// for details. | // for details. | ||||
assert(recentRejects); | assert(recentRejects); | ||||
recentRejects->insert(tx.GetId()); | recentRejects->insert(tx.GetId()); | ||||
if (RecursiveDynamicUsage(*ptx) < 100000) { | if (RecursiveDynamicUsage(*ptx) < 100000) { | ||||
AddToCompactExtraTransactions(ptx); | g_orphanPool.AddToCompactExtraTransactions(ptx); | ||||
} | } | ||||
} | } | ||||
if (pfrom->fWhitelisted && | if (pfrom->fWhitelisted && | ||||
gArgs.GetBoolArg("-whitelistforcerelay", | gArgs.GetBoolArg("-whitelistforcerelay", | ||||
DEFAULT_WHITELISTFORCERELAY)) { | DEFAULT_WHITELISTFORCERELAY)) { | ||||
// 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 176 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
LogPrint(BCLog::NET, "Peer sent us compact block " | LogPrint(BCLog::NET, "Peer sent us compact block " | ||||
"we were already syncing!\n"); | "we were already syncing!\n"); | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
PartiallyDownloadedBlock &partialBlock = | PartiallyDownloadedBlock &partialBlock = | ||||
*(*queuedBlockIt)->partialBlock; | *(*queuedBlockIt)->partialBlock; | ||||
ReadStatus status = | ReadStatus status = partialBlock.InitData( | ||||
partialBlock.InitData(cmpctblock, vExtraTxnForCompact); | cmpctblock, g_orphanPool.vExtraTxnForCompact); | ||||
if (status == READ_STATUS_INVALID) { | if (status == READ_STATUS_INVALID) { | ||||
// Reset in-flight state in case of whitelist | // Reset in-flight state in case of whitelist | ||||
MarkBlockAsReceived(pindex->GetBlockHash()); | MarkBlockAsReceived(pindex->GetBlockHash()); | ||||
Misbehaving(pfrom, 100, "invalid-cmpctblk"); | Misbehaving(pfrom, 100, "invalid-cmpctblk"); | ||||
LogPrintf("Peer %d sent us invalid compact block\n", | LogPrintf("Peer %d sent us invalid compact block\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
return true; | return true; | ||||
} else if (status == READ_STATUS_FAILED) { | } else if (status == READ_STATUS_FAILED) { | ||||
Show All 25 Lines | else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req)); | pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req)); | ||||
} | } | ||||
} else { | } else { | ||||
// This block is either already in flight from a different | // This block is either already in flight from a different | ||||
// peer, or this peer has too many blocks outstanding to | // peer, or this peer has too many blocks outstanding to | ||||
// download from. Optimistically try to reconstruct anyway | // download from. Optimistically try to reconstruct anyway | ||||
// since we might be able to without any round trips. | // since we might be able to without any round trips. | ||||
PartiallyDownloadedBlock tempBlock(config, &mempool); | PartiallyDownloadedBlock tempBlock(config, &mempool); | ||||
ReadStatus status = | ReadStatus status = tempBlock.InitData( | ||||
tempBlock.InitData(cmpctblock, vExtraTxnForCompact); | cmpctblock, g_orphanPool.vExtraTxnForCompact); | ||||
if (status != READ_STATUS_OK) { | if (status != READ_STATUS_OK) { | ||||
// TODO: don't ignore failures | // TODO: don't ignore failures | ||||
return true; | return true; | ||||
} | } | ||||
std::vector<CTransactionRef> dummy; | std::vector<CTransactionRef> dummy; | ||||
status = tempBlock.FillBlock(*pblock, dummy); | status = tempBlock.FillBlock(*pblock, dummy); | ||||
if (status == READ_STATUS_OK) { | if (status == READ_STATUS_OK) { | ||||
fBlockReconstructed = true; | fBlockReconstructed = true; | ||||
▲ Show 20 Lines • Show All 1,440 Lines • ▼ Show 20 Lines | bool PeerLogicValidation::SendMessages(const Config &config, CNode *pto, | ||||
return true; | return true; | ||||
} | } | ||||
class CNetProcessingCleanup { | class CNetProcessingCleanup { | ||||
public: | public: | ||||
CNetProcessingCleanup() {} | CNetProcessingCleanup() {} | ||||
~CNetProcessingCleanup() { | ~CNetProcessingCleanup() { | ||||
// orphan transactions | // orphan transactions | ||||
mapOrphanTransactions.clear(); | g_orphanPool.mapOrphanTransactions.clear(); | ||||
mapOrphanTransactionsByPrev.clear(); | g_orphanPool.mapOrphanTransactionsByPrev.clear(); | ||||
} | } | ||||
} instance_of_cnetprocessingcleanup; | } instance_of_cnetprocessingcleanup; |
move this comment to the above line. silly linter