Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 389 Lines • ▼ Show 20 Lines | MarkBlockAsInFlight(const Config &config, NodeId nodeid, const uint256 &hash, | ||||
// Make sure it's not listed somewhere already. | // Make sure it's not listed somewhere already. | ||||
MarkBlockAsReceived(hash); | MarkBlockAsReceived(hash); | ||||
std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert( | std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert( | ||||
state->vBlocksInFlight.end(), | state->vBlocksInFlight.end(), | ||||
{hash, pindex, pindex != nullptr, | {hash, pindex, pindex != nullptr, | ||||
std::unique_ptr<PartiallyDownloadedBlock>( | std::unique_ptr<PartiallyDownloadedBlock>( | ||||
pit ? new PartiallyDownloadedBlock(config, &mempool) : nullptr)}); | pit ? new PartiallyDownloadedBlock(config, &g_mempool) | ||||
: nullptr)}); | |||||
state->nBlocksInFlight++; | state->nBlocksInFlight++; | ||||
state->nBlocksInFlightValidHeaders += it->fValidatedHeaders; | state->nBlocksInFlightValidHeaders += it->fValidatedHeaders; | ||||
if (state->nBlocksInFlight == 1) { | if (state->nBlocksInFlight == 1) { | ||||
// We're starting a block download (batch) from this peer. | // We're starting a block download (batch) from this peer. | ||||
state->nDownloadingSince = GetTimeMicros(); | state->nDownloadingSince = GetTimeMicros(); | ||||
} | } | ||||
if (state->nBlocksInFlightValidHeaders == 1 && pindex != nullptr) { | if (state->nBlocksInFlightValidHeaders == 1 && pindex != nullptr) { | ||||
▲ Show 20 Lines • Show All 732 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) || | g_mempool.exists(inv.hash) || | ||||
mapOrphanTransactions.count(inv.hash) || | mapOrphanTransactions.count(inv.hash) || | ||||
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 | ||||
▲ Show 20 Lines • Show All 234 Lines • ▼ Show 20 Lines | while (it != pfrom->vRecvGetData.end()) { | ||||
auto mi = mapRelay.find(inv.hash); | auto mi = mapRelay.find(inv.hash); | ||||
int nSendFlags = 0; | int nSendFlags = 0; | ||||
if (mi != mapRelay.end()) { | if (mi != mapRelay.end()) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, | ||||
msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); | msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); | ||||
push = true; | push = true; | ||||
} else if (pfrom->timeLastMempoolReq) { | } else if (pfrom->timeLastMempoolReq) { | ||||
auto txinfo = mempool.info(inv.hash); | auto txinfo = g_mempool.info(inv.hash); | ||||
// To protect privacy, do not answer getdata using the | // To protect privacy, do not answer getdata using the | ||||
// mempool when that TX couldn't have been INVed in reply to | // mempool when that TX couldn't have been INVed in reply to | ||||
// a MEMPOOL request. | // a MEMPOOL request. | ||||
if (txinfo.tx && | if (txinfo.tx && | ||||
txinfo.nTime <= pfrom->timeLastMempoolReq) { | txinfo.nTime <= pfrom->timeLastMempoolReq) { | ||||
connman->PushMessage(pfrom, | connman->PushMessage(pfrom, | ||||
msgMaker.Make(nSendFlags, | msgMaker.Make(nSendFlags, | ||||
NetMsgType::TX, | NetMsgType::TX, | ||||
▲ Show 20 Lines • Show All 1,000 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::TX) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
bool fMissingInputs = false; | bool fMissingInputs = false; | ||||
CValidationState state; | CValidationState state; | ||||
pfrom->setAskFor.erase(inv.hash); | pfrom->setAskFor.erase(inv.hash); | ||||
mapAlreadyAskedFor.erase(inv.hash); | mapAlreadyAskedFor.erase(inv.hash); | ||||
if (!AlreadyHave(inv) && AcceptToMemoryPool(config, mempool, state, ptx, | if (!AlreadyHave(inv) && | ||||
true, &fMissingInputs)) { | AcceptToMemoryPool(config, g_mempool, state, ptx, true, | ||||
mempool.check(pcoinsTip.get()); | &fMissingInputs)) { | ||||
g_mempool.check(pcoinsTip.get()); | |||||
RelayTransaction(tx, connman); | RelayTransaction(tx, connman); | ||||
for (size_t i = 0; i < tx.vout.size(); i++) { | for (size_t i = 0; i < tx.vout.size(); i++) { | ||||
vWorkQueue.emplace_back(inv.hash, i); | vWorkQueue.emplace_back(inv.hash, i); | ||||
} | } | ||||
pfrom->nLastTXTime = GetTime(); | pfrom->nLastTXTime = GetTime(); | ||||
LogPrint(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s " | LogPrint(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s " | ||||
"(poolsz %u txn, %u kB)\n", | "(poolsz %u txn, %u kB)\n", | ||||
pfrom->GetId(), tx.GetId().ToString(), mempool.size(), | pfrom->GetId(), tx.GetId().ToString(), g_mempool.size(), | ||||
mempool.DynamicMemoryUsage() / 1000); | g_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 = | ||||
mapOrphanTransactionsByPrev.find(vWorkQueue.front()); | mapOrphanTransactionsByPrev.find(vWorkQueue.front()); | ||||
vWorkQueue.pop_front(); | vWorkQueue.pop_front(); | ||||
Show All 11 Lines | else if (strCommand == NetMsgType::TX) { | ||||
// to counter-DoS based on orphan resolution (that is, | // to counter-DoS based on orphan resolution (that is, | ||||
// feeding people an invalid transaction based on LegitTxX | // feeding people an invalid transaction based on LegitTxX | ||||
// in order to get anyone relaying LegitTxX banned) | // in order to get anyone relaying LegitTxX banned) | ||||
CValidationState stateDummy; | CValidationState stateDummy; | ||||
if (setMisbehaving.count(fromPeer)) { | if (setMisbehaving.count(fromPeer)) { | ||||
continue; | continue; | ||||
} | } | ||||
if (AcceptToMemoryPool(config, mempool, stateDummy, | if (AcceptToMemoryPool(config, g_mempool, stateDummy, | ||||
porphanTx, true, &fMissingInputs2)) { | porphanTx, true, &fMissingInputs2)) { | ||||
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", | LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", | ||||
orphanId.ToString()); | orphanId.ToString()); | ||||
RelayTransaction(orphanTx, connman); | RelayTransaction(orphanTx, connman); | ||||
for (size_t i = 0; i < orphanTx.vout.size(); i++) { | for (size_t i = 0; i < orphanTx.vout.size(); i++) { | ||||
vWorkQueue.emplace_back(orphanId, i); | vWorkQueue.emplace_back(orphanId, i); | ||||
} | } | ||||
vEraseQueue.push_back(orphanId); | vEraseQueue.push_back(orphanId); | ||||
Show All 17 Lines | else if (strCommand == NetMsgType::TX) { | ||||
// transactions or witness-stripped transactions, as | // transactions or witness-stripped transactions, as | ||||
// they can have been malleated. See | // they can have been malleated. See | ||||
// https://github.com/bitcoin/bitcoin/issues/8279 | // https://github.com/bitcoin/bitcoin/issues/8279 | ||||
// for details. | // for details. | ||||
assert(recentRejects); | assert(recentRejects); | ||||
recentRejects->insert(orphanId); | recentRejects->insert(orphanId); | ||||
} | } | ||||
} | } | ||||
mempool.check(pcoinsTip.get()); | g_mempool.check(pcoinsTip.get()); | ||||
} | } | ||||
} | } | ||||
for (const uint256 &hash : vEraseQueue) { | for (const uint256 &hash : vEraseQueue) { | ||||
EraseOrphanTx(hash); | 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 | ||||
▲ Show 20 Lines • Show All 220 Lines • ▼ Show 20 Lines | else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
if (!MarkBlockAsInFlight(config, pfrom->GetId(), | if (!MarkBlockAsInFlight(config, pfrom->GetId(), | ||||
pindex->GetBlockHash(), | pindex->GetBlockHash(), | ||||
chainparams.GetConsensus(), pindex, | chainparams.GetConsensus(), pindex, | ||||
&queuedBlockIt)) { | &queuedBlockIt)) { | ||||
if (!(*queuedBlockIt)->partialBlock) { | if (!(*queuedBlockIt)->partialBlock) { | ||||
(*queuedBlockIt) | (*queuedBlockIt) | ||||
->partialBlock.reset( | ->partialBlock.reset( | ||||
new PartiallyDownloadedBlock(config, | new PartiallyDownloadedBlock(config, | ||||
&mempool)); | &g_mempool)); | ||||
} else { | } else { | ||||
// The block was already in flight using compact | // The block was already in flight using compact | ||||
// blocks from the same peer. | // blocks from the same peer. | ||||
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; | ||||
} | } | ||||
} | } | ||||
Show All 37 Lines | else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
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, &g_mempool); | ||||
ReadStatus status = | ReadStatus status = | ||||
tempBlock.InitData(cmpctblock, vExtraTxnForCompact); | tempBlock.InitData(cmpctblock, 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); | ||||
▲ Show 20 Lines • Show All 1,153 Lines • ▼ Show 20 Lines | std::vector<CInv> vInv; | ||||
LOCK(pto->cs_filter); | LOCK(pto->cs_filter); | ||||
if (!pto->fRelayTxes) { | if (!pto->fRelayTxes) { | ||||
pto->setInventoryTxToSend.clear(); | pto->setInventoryTxToSend.clear(); | ||||
} | } | ||||
} | } | ||||
// Respond to BIP35 mempool requests | // Respond to BIP35 mempool requests | ||||
if (fSendTrickle && pto->fSendMempool) { | if (fSendTrickle && pto->fSendMempool) { | ||||
auto vtxinfo = mempool.infoAll(); | auto vtxinfo = g_mempool.infoAll(); | ||||
pto->fSendMempool = false; | pto->fSendMempool = false; | ||||
Amount filterrate = Amount::zero(); | Amount filterrate = Amount::zero(); | ||||
{ | { | ||||
LOCK(pto->cs_feeFilter); | LOCK(pto->cs_feeFilter); | ||||
filterrate = pto->minFeeFilter; | filterrate = pto->minFeeFilter; | ||||
} | } | ||||
LOCK(pto->cs_filter); | LOCK(pto->cs_filter); | ||||
Show All 34 Lines | std::vector<CInv> vInv; | ||||
Amount filterrate = Amount::zero(); | Amount filterrate = Amount::zero(); | ||||
{ | { | ||||
LOCK(pto->cs_feeFilter); | LOCK(pto->cs_feeFilter); | ||||
filterrate = pto->minFeeFilter; | filterrate = pto->minFeeFilter; | ||||
} | } | ||||
// Topologically and fee-rate sort the inventory we send for privacy | // Topologically and fee-rate sort the inventory we send for privacy | ||||
// and priority reasons. A heap is used so that not all items need | // and priority reasons. A heap is used so that not all items need | ||||
// sorting if only a few are being sent. | // sorting if only a few are being sent. | ||||
CompareInvMempoolOrder compareInvMempoolOrder(&mempool); | CompareInvMempoolOrder compareInvMempoolOrder(&g_mempool); | ||||
std::make_heap(vInvTx.begin(), vInvTx.end(), | std::make_heap(vInvTx.begin(), vInvTx.end(), | ||||
compareInvMempoolOrder); | compareInvMempoolOrder); | ||||
// No reason to drain out at many times the network's capacity, | // No reason to drain out at many times the network's capacity, | ||||
// especially since we have many peers and some will draw much | // especially since we have many peers and some will draw much | ||||
// shorter delays. | // shorter delays. | ||||
unsigned int nRelayedTransactions = 0; | unsigned int nRelayedTransactions = 0; | ||||
LOCK(pto->cs_filter); | LOCK(pto->cs_filter); | ||||
while (!vInvTx.empty() && | while (!vInvTx.empty() && | ||||
nRelayedTransactions < INVENTORY_BROADCAST_MAX_PER_MB * | nRelayedTransactions < INVENTORY_BROADCAST_MAX_PER_MB * | ||||
config.GetMaxBlockSize() / | config.GetMaxBlockSize() / | ||||
1000000) { | 1000000) { | ||||
// Fetch the top element from the heap | // Fetch the top element from the heap | ||||
std::pop_heap(vInvTx.begin(), vInvTx.end(), | std::pop_heap(vInvTx.begin(), vInvTx.end(), | ||||
compareInvMempoolOrder); | compareInvMempoolOrder); | ||||
std::set<uint256>::iterator it = vInvTx.back(); | std::set<uint256>::iterator it = vInvTx.back(); | ||||
vInvTx.pop_back(); | vInvTx.pop_back(); | ||||
uint256 hash = *it; | uint256 hash = *it; | ||||
// Remove it from the to-be-sent set | // Remove it from the to-be-sent set | ||||
pto->setInventoryTxToSend.erase(it); | pto->setInventoryTxToSend.erase(it); | ||||
// Check if not in the filter already | // Check if not in the filter already | ||||
if (pto->filterInventoryKnown.contains(hash)) { | if (pto->filterInventoryKnown.contains(hash)) { | ||||
continue; | continue; | ||||
} | } | ||||
// Not in the mempool anymore? don't bother sending it. | // Not in the mempool anymore? don't bother sending it. | ||||
auto txinfo = mempool.info(hash); | auto txinfo = g_mempool.info(hash); | ||||
if (!txinfo.tx) { | if (!txinfo.tx) { | ||||
continue; | continue; | ||||
} | } | ||||
if (filterrate != Amount::zero() && | if (filterrate != Amount::zero() && | ||||
txinfo.feeRate.GetFeePerK() < filterrate) { | txinfo.feeRate.GetFeePerK() < filterrate) { | ||||
continue; | continue; | ||||
} | } | ||||
if (pto->pfilter && | if (pto->pfilter && | ||||
▲ Show 20 Lines • Show All 170 Lines • ▼ Show 20 Lines | bool PeerLogicValidation::SendMessages(const Config &config, CNode *pto, | ||||
// We don't want white listed peers to filter txs to us if we have | // We don't want white listed peers to filter txs to us if we have | ||||
// -whitelistforcerelay | // -whitelistforcerelay | ||||
if (pto->nVersion >= FEEFILTER_VERSION && | if (pto->nVersion >= FEEFILTER_VERSION && | ||||
gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && | gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && | ||||
!(pto->fWhitelisted && | !(pto->fWhitelisted && | ||||
gArgs.GetBoolArg("-whitelistforcerelay", | gArgs.GetBoolArg("-whitelistforcerelay", | ||||
DEFAULT_WHITELISTFORCERELAY))) { | DEFAULT_WHITELISTFORCERELAY))) { | ||||
Amount currentFilter = | Amount currentFilter = | ||||
mempool | g_mempool | ||||
.GetMinFee( | .GetMinFee( | ||||
gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | ||||
1000000) | 1000000) | ||||
.GetFeePerK(); | .GetFeePerK(); | ||||
int64_t timeNow = GetTimeMicros(); | int64_t timeNow = GetTimeMicros(); | ||||
if (timeNow > pto->nextSendTimeFeeFilter) { | if (timeNow > pto->nextSendTimeFeeFilter) { | ||||
static CFeeRate default_feerate = | static CFeeRate default_feerate = | ||||
CFeeRate(DEFAULT_MIN_RELAY_TX_FEE_PER_KB); | CFeeRate(DEFAULT_MIN_RELAY_TX_FEE_PER_KB); | ||||
Show All 40 Lines |