aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp89
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;