diff options
Diffstat (limited to 'src/main.cpp')
| -rw-r--r-- | src/main.cpp | 89 |
1 files changed, 68 insertions, 21 deletions
diff --git a/src/main.cpp b/src/main.cpp index bbe5bd87f..1b746a0b0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -63,8 +63,13 @@ struct COrphanBlock { map<uint256, COrphanBlock*> mapOrphanBlocks; multimap<uint256, COrphanBlock*> mapOrphanBlocksByPrev; -map<uint256, CTransaction> mapOrphanTransactions; +struct COrphanTx { + CTransaction tx; + NodeId fromPeer; +}; +map<uint256, COrphanTx> mapOrphanTransactions; map<uint256, set<uint256> > mapOrphanTransactionsByPrev; +void EraseOrphansFor(NodeId peer); // Constant stuff for coinbase transactions we create: CScript COINBASE_FLAGS; @@ -264,6 +269,7 @@ void FinalizeNode(NodeId nodeid) { mapBlocksInFlight.erase(entry.hash); BOOST_FOREACH(const uint256& hash, state->vBlocksToDownload) mapBlocksToDownload.erase(hash); + EraseOrphansFor(nodeid); mapNodeState.erase(nodeid); } @@ -461,7 +467,7 @@ CBlockTreeDB *pblocktree = NULL; // mapOrphanTransactions // -bool AddOrphanTx(const CTransaction& tx) +bool AddOrphanTx(const CTransaction& tx, NodeId peer) { uint256 hash = tx.GetHash(); if (mapOrphanTransactions.count(hash)) @@ -481,23 +487,26 @@ bool AddOrphanTx(const CTransaction& tx) return false; } - mapOrphanTransactions[hash] = tx; + mapOrphanTransactions[hash].tx = tx; + mapOrphanTransactions[hash].fromPeer = peer; BOOST_FOREACH(const CTxIn& txin, tx.vin) mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); - LogPrint("mempool", "stored orphan tx %s (mapsz %u)\n", hash.ToString(), - mapOrphanTransactions.size()); + LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(), + mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size()); return true; } void static EraseOrphanTx(uint256 hash) { - map<uint256, CTransaction>::iterator it = mapOrphanTransactions.find(hash); + map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash); if (it == mapOrphanTransactions.end()) return; - BOOST_FOREACH(const CTxIn& txin, it->second.vin) + BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin) { map<uint256, set<uint256> >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash); + if (itPrev == mapOrphanTransactionsByPrev.end()) + continue; itPrev->second.erase(hash); if (itPrev->second.empty()) mapOrphanTransactionsByPrev.erase(itPrev); @@ -505,6 +514,23 @@ void static EraseOrphanTx(uint256 hash) mapOrphanTransactions.erase(it); } +void EraseOrphansFor(NodeId peer) +{ + int nErased = 0; + map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin(); + while (iter != mapOrphanTransactions.end()) + { + map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid + if (maybeErase->second.fromPeer == peer) + { + EraseOrphanTx(maybeErase->second.tx.GetHash()); + ++nErased; + } + } + if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer %d\n", nErased, peer); +} + + unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) { unsigned int nEvicted = 0; @@ -512,7 +538,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) { // Evict a random orphan: uint256 randomhash = GetRandHash(); - map<uint256, CTransaction>::iterator it = mapOrphanTransactions.lower_bound(randomhash); + map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); EraseOrphanTx(it->first); @@ -1776,11 +1802,6 @@ bool static WriteChainState(CValidationState &state) { void static UpdateTip(CBlockIndex *pindexNew) { chainActive.SetTip(pindexNew); - // Update best block in wallet (so we can detect restored wallets) - bool fIsInitialDownload = IsInitialBlockDownload(); - if ((chainActive.Height() % 20160) == 0 || (!fIsInitialDownload && (chainActive.Height() % 144) == 0)) - g_signals.SetBestChain(chainActive.GetLocator()); - // New best block nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); @@ -1793,7 +1814,7 @@ void static UpdateTip(CBlockIndex *pindexNew) { cvBlockChange.notify_all(); // Check the version of the last 100 blocks to see if we need to upgrade: - if (!fIsInitialDownload) + if (!IsInitialBlockDownload()) { int nUpgraded = 0; const CBlockIndex* pindex = chainActive.Tip(); @@ -1910,6 +1931,11 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { SyncWithWallets(tx, pblock); } + // Update best block in wallet (so we can detect restored wallets) + // Emit this signal after the SyncWithWallets signals as the wallet relies on that everything up to this point has been synced + if ((chainActive.Height() % 20160) == 0 || ((chainActive.Height() % 144) == 0 && !IsInitialBlockDownload())) + g_signals.SetBestChain(chainActive.GetLocator()); + int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001); @@ -3137,7 +3163,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) blkdat >> nSize; if (nSize < 80 || nSize > MAX_BLOCK_SIZE) continue; - } catch (std::exception &e) { + } catch (const std::exception &) { // no valid block header found; don't complain break; } @@ -3641,6 +3667,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Track requests for our stuff g_signals.Inventory(inv.hash); + + if (pfrom->nSendSize > (SendBufferSize() * 2)) { + Misbehaving(pfrom->GetId(), 50); + return error("send buffer size() = %u", pfrom->nSendSize); + } } } @@ -3770,6 +3801,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, mempool.mapTx.size()); // Recursively process any orphan transactions that depended on this one + set<NodeId> setMisbehaving; for (unsigned int i = 0; i < vWorkQueue.size(); i++) { map<uint256, set<uint256> >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]); @@ -3780,25 +3812,36 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, ++mi) { const uint256& orphanHash = *mi; - const CTransaction& orphanTx = mapOrphanTransactions[orphanHash]; + const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx; + NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer; bool fMissingInputs2 = false; // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get // anyone relaying LegitTxX banned) CValidationState stateDummy; + vEraseQueue.push_back(orphanHash); + + if (setMisbehaving.count(fromPeer)) + continue; if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) { LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); RelayTransaction(orphanTx); mapAlreadyAskedFor.erase(CInv(MSG_TX, orphanHash)); vWorkQueue.push_back(orphanHash); - vEraseQueue.push_back(orphanHash); } else if (!fMissingInputs2) { - // invalid or too-little-fee orphan - vEraseQueue.push_back(orphanHash); + int nDos = 0; + if (stateDummy.IsInvalid(nDos) && nDos > 0) + { + // Punish peer that gave us an invalid orphan tx + Misbehaving(fromPeer, nDos); + setMisbehaving.insert(fromPeer); + LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString()); + } + // too-little-fee orphan LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString()); } mempool.check(pcoinsTip); @@ -3810,10 +3853,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } else if (fMissingInputs) { - AddOrphanTx(tx); + AddOrphanTx(tx, pfrom->GetId()); // DoS prevention: do not allow mapOrphanTransactions to grow unbounded - unsigned int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS); + unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); + unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx); if (nEvicted > 0) LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted); } else if (pfrom->fWhitelisted) { @@ -4317,7 +4361,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle) if (pto->addr.IsLocal()) LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString()); else + { CNode::Ban(pto->addr); + } } state.fShouldBan = false; } @@ -4531,5 +4577,6 @@ public: // orphan transactions mapOrphanTransactions.clear(); + mapOrphanTransactionsByPrev.clear(); } } instance_of_cmaincleanup; |