aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp259
1 files changed, 159 insertions, 100 deletions
diff --git a/src/main.cpp b/src/main.cpp
index da00b4b53..15c3916a6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -38,7 +38,7 @@ using namespace boost;
CCriticalSection cs_main;
-map<uint256, CBlockIndex*> mapBlockIndex;
+BlockMap mapBlockIndex;
CChain chainActive;
int64_t nTimeBestReceived = 0;
CWaitableCriticalSection csBestBlock;
@@ -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);
}
@@ -328,7 +334,7 @@ void ProcessBlockAvailability(NodeId nodeid) {
assert(state != NULL);
if (state->hashLastUnknownBlock != 0) {
- map<uint256, CBlockIndex*>::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock);
+ BlockMap::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock);
if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) {
if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork)
state->pindexBestKnownBlock = itOld->second;
@@ -344,7 +350,7 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
ProcessBlockAvailability(nodeid);
- map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hash);
+ BlockMap::iterator it = mapBlockIndex.find(hash);
if (it != mapBlockIndex.end() && it->second->nChainWork > 0) {
// An actually better block was announced.
if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork)
@@ -434,7 +440,7 @@ CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const {
// Find the first block the caller has in the main chain
BOOST_FOREACH(const uint256& hash, locator.vHave) {
- std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+ BlockMap::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
@@ -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,29 +487,50 @@ 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)
{
- if (!mapOrphanTransactions.count(hash))
+ map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
+ if (it == mapOrphanTransactions.end())
return;
- const CTransaction& tx = mapOrphanTransactions[hash];
- BOOST_FOREACH(const CTxIn& txin, tx.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);
+ }
+ mapOrphanTransactions.erase(it);
+}
+
+void EraseOrphansFor(NodeId peer)
+{
+ int nErased = 0;
+ map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();
+ while (iter != mapOrphanTransactions.end())
{
- mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash);
- if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty())
- mapOrphanTransactionsByPrev.erase(txin.prevout.hash);
+ map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
+ if (maybeErase->second.fromPeer == peer)
+ {
+ EraseOrphanTx(maybeErase->second.tx.GetHash());
+ ++nErased;
+ }
}
- mapOrphanTransactions.erase(hash);
+ 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;
@@ -511,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);
@@ -670,7 +697,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
// IsStandard() will have already returned false
// and this method isn't called.
vector<vector<unsigned char> > stack;
- if (!EvalScript(stack, tx.vin[i].scriptSig, tx, i, false, 0))
+ if (!EvalScript(stack, tx.vin[i].scriptSig, tx, i, false))
return false;
if (whichType == TX_SCRIPTHASH)
@@ -1017,9 +1044,9 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
int nHeight = -1;
{
CCoinsViewCache &view = *pcoinsTip;
- CCoins coins;
- if (view.GetCoins(hash, coins))
- nHeight = coins.nHeight;
+ const CCoins* coins = view.AccessCoins(hash);
+ if (coins)
+ nHeight = coins->nHeight;
}
if (nHeight > 0)
pindexSlow = chainActive[nHeight];
@@ -1324,12 +1351,13 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
bool ret;
// mark inputs spent
if (!tx.IsCoinBase()) {
- BOOST_FOREACH(const CTxIn &txin, tx.vin) {
+ txundo.vprevout.reserve(tx.vin.size());
+ for (unsigned int i = 0; i < tx.vin.size(); i++) {
+ const CTxIn &txin = tx.vin[i];
CCoins &coins = inputs.GetCoins(txin.prevout.hash);
- CTxInUndo undo;
- ret = coins.Spend(txin.prevout, undo);
+ txundo.vprevout.push_back(CTxInUndo());
+ ret = coins.Spend(txin.prevout, txundo.vprevout.back());
assert(ret);
- txundo.vprevout.push_back(undo);
}
}
@@ -1340,16 +1368,11 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
bool CScriptCheck::operator()() const {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
- if (!VerifyScript(scriptSig, scriptPubKey, *ptxTo, nIn, nFlags, nHashType))
+ if (!VerifyScript(scriptSig, scriptPubKey, *ptxTo, nIn, nFlags))
return error("CScriptCheck() : %s VerifySignature failed", ptxTo->GetHash().ToString());
return true;
}
-bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType)
-{
- return CScriptCheck(txFrom, txTo, nIn, flags, nHashType)();
-}
-
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
@@ -1371,19 +1394,20 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
const COutPoint &prevout = tx.vin[i].prevout;
- const CCoins &coins = inputs.GetCoins(prevout.hash);
+ const CCoins *coins = inputs.AccessCoins(prevout.hash);
+ assert(coins);
// If prev is coinbase, check that it's matured
- if (coins.IsCoinBase()) {
- if (nSpendHeight - coins.nHeight < COINBASE_MATURITY)
+ if (coins->IsCoinBase()) {
+ if (nSpendHeight - coins->nHeight < COINBASE_MATURITY)
return state.Invalid(
- error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins.nHeight),
+ error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
}
// Check for negative or overflow input values
- nValueIn += coins.vout[prevout.n].nValue;
- if (!MoneyRange(coins.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
+ nValueIn += coins->vout[prevout.n].nValue;
+ if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn))
return state.DoS(100, error("CheckInputs() : txin values out of range"),
REJECT_INVALID, "bad-txns-inputvalues-outofrange");
@@ -1413,10 +1437,11 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
if (fScriptChecks) {
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const COutPoint &prevout = tx.vin[i].prevout;
- const CCoins &coins = inputs.GetCoins(prevout.hash);
+ const CCoins* coins = inputs.AccessCoins(prevout.hash);
+ assert(coins);
// Verify signature
- CScriptCheck check(coins, tx, i, flags, 0);
+ CScriptCheck check(*coins, tx, i, flags);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@@ -1428,8 +1453,8 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// arguments; if so, don't trigger DoS protection to
// avoid splitting the network between upgraded and
// non-upgraded nodes.
- CScriptCheck check(coins, tx, i,
- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, 0);
+ CScriptCheck check(*coins, tx, i,
+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS);
if (check())
return state.Invalid(false, REJECT_NONSTANDARD, "non-mandatory-script-verify-flag");
}
@@ -1614,8 +1639,8 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
if (fEnforceBIP30) {
BOOST_FOREACH(const CTransaction& tx, block.vtx) {
- const uint256& hash = tx.GetHash();
- if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
+ const CCoins* coins = view.AccessCoins(tx.GetHash());
+ if (coins && !coins->IsPruned())
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"),
REJECT_INVALID, "bad-txns-BIP30");
}
@@ -1639,6 +1664,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
vPos.reserve(block.vtx.size());
+ blockundo.vtxundo.reserve(block.vtx.size() - 1);
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
const CTransaction &tx = block.vtx[i];
@@ -1674,10 +1700,11 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
control.Add(vChecks);
}
- CTxUndo txundo;
- UpdateCoins(tx, state, view, txundo, pindex->nHeight);
- if (!tx.IsCoinBase())
- blockundo.vtxundo.push_back(txundo);
+ CTxUndo undoDummy;
+ if (i > 0) {
+ blockundo.vtxundo.push_back(CTxUndo());
+ }
+ UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
vPos.push_back(std::make_pair(tx.GetHash(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
@@ -1773,11 +1800,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);
@@ -1790,7 +1812,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();
@@ -1907,6 +1929,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);
@@ -2068,7 +2095,7 @@ CBlockIndex* AddToBlockIndex(CBlockHeader& block)
{
// Check for duplicate
uint256 hash = block.GetHash();
- std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hash);
+ BlockMap::iterator it = mapBlockIndex.find(hash);
if (it != mapBlockIndex.end())
return it->second;
@@ -2079,9 +2106,9 @@ CBlockIndex* AddToBlockIndex(CBlockHeader& block)
LOCK(cs_nBlockSequenceId);
pindexNew->nSequenceId = nBlockSequenceId++;
}
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
+ BlockMap::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
- map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock);
+ BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock);
if (miPrev != mapBlockIndex.end())
{
pindexNew->pprev = (*miPrev).second;
@@ -2294,7 +2321,7 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex
AssertLockHeld(cs_main);
// Check for duplicate
uint256 hash = block.GetHash();
- std::map<uint256, CBlockIndex*>::iterator miSelf = mapBlockIndex.find(hash);
+ BlockMap::iterator miSelf = mapBlockIndex.find(hash);
CBlockIndex *pindex = NULL;
if (miSelf != mapBlockIndex.end()) {
pindex = miSelf->second;
@@ -2302,7 +2329,7 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex
return state.Invalid(error("AcceptBlock() : block is marked invalid"), 0, "duplicate");
}
- CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
+ CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint();
if (pcheckpoint && block.hashPrevBlock != (chainActive.Tip() ? chainActive.Tip()->GetBlockHash() : uint256(0)))
{
// Extra checks to prevent "fill up memory by spamming with bogus blocks"
@@ -2323,7 +2350,7 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex
CBlockIndex* pindexPrev = NULL;
int nHeight = 0;
if (hash != Params().HashGenesisBlock()) {
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
+ BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end())
return state.DoS(10, error("AcceptBlock() : prev block not found"), 0, "bad-prevblk");
pindexPrev = (*mi).second;
@@ -2345,7 +2372,7 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex
REJECT_CHECKPOINT, "checkpoint mismatch");
// Don't accept any forks from the main chain prior to last checkpoint
- CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
+ CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint();
if (pcheckpoint && nHeight < pcheckpoint->nHeight)
return state.DoS(100, error("AcceptBlock() : forked chain older than last checkpoint (height %d)", nHeight));
@@ -2517,7 +2544,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
return error("ProcessBlock() : CheckBlock FAILED");
// If we don't already have its previous block (with full data), shunt it off to holding area until we get it
- std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(pblock->hashPrevBlock);
+ BlockMap::iterator it = mapBlockIndex.find(pblock->hashPrevBlock);
if (pblock->hashPrevBlock != 0 && (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA)))
{
LogPrintf("ProcessBlock: ORPHAN BLOCK %lu, prev=%s\n", (unsigned long)mapOrphanBlocks.size(), pblock->hashPrevBlock.ToString());
@@ -2766,7 +2793,7 @@ FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly)
{
if (pos.IsNull())
return NULL;
- boost::filesystem::path path = GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile);
+ boost::filesystem::path path = GetBlockPosFilename(pos, prefix);
boost::filesystem::create_directories(path.parent_path());
FILE* file = fopen(path.string().c_str(), "rb+");
if (!file && !fReadOnly)
@@ -2793,13 +2820,18 @@ FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly) {
return OpenDiskFile(pos, "rev", fReadOnly);
}
+boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix)
+{
+ return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile);
+}
+
CBlockIndex * InsertBlockIndex(uint256 hash)
{
if (hash == 0)
return NULL;
// Return existing
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+ BlockMap::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
return (*mi).second;
@@ -2876,7 +2908,7 @@ bool static LoadBlockIndexDB()
LogPrintf("LoadBlockIndexDB(): transaction index %s\n", fTxIndex ? "enabled" : "disabled");
// Load pointer to end of best chain
- std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
+ BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
if (it == mapBlockIndex.end())
return true;
chainActive.SetTip(it->second);
@@ -2898,7 +2930,7 @@ CVerifyDB::~CVerifyDB()
uiInterface.ShowProgress("", 100);
}
-bool CVerifyDB::VerifyDB(int nCheckLevel, int nCheckDepth)
+bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth)
{
LOCK(cs_main);
if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL)
@@ -2911,7 +2943,7 @@ bool CVerifyDB::VerifyDB(int nCheckLevel, int nCheckDepth)
nCheckDepth = chainActive.Height();
nCheckLevel = std::max(0, std::min(4, nCheckLevel));
LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
- CCoinsViewCache coins(*pcoinsTip, true);
+ CCoinsViewCache coins(*coinsview, true);
CBlockIndex* pindexState = chainActive.Tip();
CBlockIndex* pindexFailure = NULL;
int nGoodTransactions = 0;
@@ -3034,7 +3066,7 @@ void PrintBlockTree()
AssertLockHeld(cs_main);
// pre-compute tree structure
map<CBlockIndex*, vector<CBlockIndex*> > mapNext;
- for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
+ for (BlockMap::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
{
CBlockIndex* pindex = (*mi).second;
mapNext[pindex->pprev].push_back(pindex);
@@ -3134,7 +3166,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;
}
@@ -3280,13 +3312,13 @@ void static ProcessGetData(CNode* pfrom)
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK)
{
bool send = false;
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(inv.hash);
+ BlockMap::iterator mi = mapBlockIndex.find(inv.hash);
if (mi != mapBlockIndex.end())
{
// If the requested block is at a height below our last
// checkpoint, only serve it if it's in the checkpointed chain
int nHeight = mi->second->nHeight;
- CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
+ CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint();
if (pcheckpoint && nHeight < pcheckpoint->nHeight) {
if (!chainActive.Contains(mi->second))
{
@@ -3638,6 +3670,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);
+ }
}
}
@@ -3711,7 +3748,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (locator.IsNull())
{
// If locator is null, return the hashStop block
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashStop);
+ BlockMap::iterator mi = mapBlockIndex.find(hashStop);
if (mi == mapBlockIndex.end())
return true;
pindex = (*mi).second;
@@ -3752,48 +3789,62 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
bool fMissingInputs = false;
CValidationState state;
+
+ mapAlreadyAskedFor.erase(inv);
+
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
{
mempool.check(pcoinsTip);
RelayTransaction(tx);
- mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
vEraseQueue.push_back(inv.hash);
-
LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s : accepted %s (poolsz %u)\n",
pfrom->id, pfrom->cleanSubVer,
tx.GetHash().ToString(),
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++)
{
- uint256 hashPrev = vWorkQueue[i];
- for (set<uint256>::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin();
- mi != mapOrphanTransactionsByPrev[hashPrev].end();
+ map<uint256, set<uint256> >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]);
+ if (itByPrev == mapOrphanTransactionsByPrev.end())
+ continue;
+ for (set<uint256>::iterator mi = itByPrev->second.begin();
+ mi != itByPrev->second.end();
++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);
@@ -3805,10 +3856,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) {
@@ -4057,21 +4109,25 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else if (strCommand == "reject")
{
- if (fDebug)
- {
- string strMsg; unsigned char ccode; string strReason;
- vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, 111);
+ if (fDebug) {
+ try {
+ string strMsg; unsigned char ccode; string strReason;
+ vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, 111);
- ostringstream ss;
- ss << strMsg << " code " << itostr(ccode) << ": " << strReason;
+ ostringstream ss;
+ ss << strMsg << " code " << itostr(ccode) << ": " << strReason;
- if (strMsg == "block" || strMsg == "tx")
- {
- uint256 hash;
- vRecv >> hash;
- ss << ": hash " << hash.ToString();
+ if (strMsg == "block" || strMsg == "tx")
+ {
+ uint256 hash;
+ vRecv >> hash;
+ ss << ": hash " << hash.ToString();
+ }
+ LogPrint("net", "Reject %s\n", SanitizeString(ss.str()));
+ } catch (std::ios_base::failure& e) {
+ // Avoid feedback loops by preventing reject messages from triggering a new reject message.
+ LogPrint("net", "Unparseable reject message received\n");
}
- LogPrint("net", "Reject %s\n", SanitizeString(ss.str()));
}
}
@@ -4136,7 +4192,7 @@ bool ProcessMessages(CNode* pfrom)
// Scan for message start
if (memcmp(msg.hdr.pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0) {
- LogPrintf("\n\nPROCESSMESSAGE: INVALID MESSAGESTART\n\n");
+ LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", msg.hdr.GetCommand(), pfrom->id);
fOk = false;
break;
}
@@ -4145,7 +4201,7 @@ bool ProcessMessages(CNode* pfrom)
CMessageHeader& hdr = msg.hdr;
if (!hdr.IsValid())
{
- LogPrintf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand());
+ LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", hdr.GetCommand(), pfrom->id);
continue;
}
string strCommand = hdr.GetCommand();
@@ -4312,7 +4368,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;
}
@@ -4392,7 +4450,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if (!pto->fDisconnect && state.nBlocksInFlight &&
state.nLastBlockReceive < state.nLastBlockProcess - BLOCK_DOWNLOAD_TIMEOUT*1000000 &&
state.vBlocksInFlight.front().nTime < state.nLastBlockProcess - 2*BLOCK_DOWNLOAD_TIMEOUT*1000000) {
- LogPrintf("Peer %s is stalling block download, disconnecting\n", state.name.c_str());
+ LogPrintf("Peer %s is stalling block download, disconnecting\n", state.name);
pto->fDisconnect = true;
}
@@ -4502,7 +4560,7 @@ bool CBlockUndo::ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock
}
std::string CBlockFileInfo::ToString() const {
- return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst).c_str(), DateTimeStrFormat("%Y-%m-%d", nTimeLast).c_str());
+ return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast));
}
@@ -4513,7 +4571,7 @@ public:
CMainCleanup() {}
~CMainCleanup() {
// block headers
- std::map<uint256, CBlockIndex*>::iterator it1 = mapBlockIndex.begin();
+ BlockMap::iterator it1 = mapBlockIndex.begin();
for (; it1 != mapBlockIndex.end(); it1++)
delete (*it1).second;
mapBlockIndex.clear();
@@ -4526,5 +4584,6 @@ public:
// orphan transactions
mapOrphanTransactions.clear();
+ mapOrphanTransactionsByPrev.clear();
}
} instance_of_cmaincleanup;