Merge #9959: Mining: Prevent slowdown in CreateNewBlock on large mempools

011124a Update benchmarking with package statistics (Suhas Daftuar)
42cd8c8 Add benchmarking for CreateNewBlock (Suhas Daftuar)
eed816a Mining: return early when block is almost full (Suhas Daftuar)

Tree-SHA512: c0d8f71e4e0441acf3f4ca12f8705e413b59b323659346a447145653def71710537fb4c6d80cad8e36d68b0aabf19c92e9eab7135a8897b053ed58720856cdda
pull/365/head
Wladimir J. van der Laan 8 years ago
commit cde9b1a864
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6

@ -126,6 +126,8 @@ void BlockAssembler::resetBlock()
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx) std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx)
{ {
int64_t nTimeStart = GetTimeMicros();
resetBlock(); resetBlock();
pblocktemplate.reset(new CBlockTemplate()); pblocktemplate.reset(new CBlockTemplate());
@ -164,7 +166,11 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
// transaction (which in most cases can be a no-op). // transaction (which in most cases can be a no-op).
fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()) && fMineWitnessTx; fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()) && fMineWitnessTx;
addPackageTxs(); int nPackagesSelected = 0;
int nDescendantsUpdated = 0;
addPackageTxs(nPackagesSelected, nDescendantsUpdated);
int64_t nTime1 = GetTimeMicros();
nLastBlockTx = nBlockTx; nLastBlockTx = nBlockTx;
nLastBlockSize = nBlockSize; nLastBlockSize = nBlockSize;
@ -196,6 +202,9 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
} }
int64_t nTime2 = GetTimeMicros();
LogPrint("bench", "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", 0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, 0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart));
return std::move(pblocktemplate); return std::move(pblocktemplate);
} }
@ -269,9 +278,10 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
} }
} }
void BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, int BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded,
indexed_modified_transaction_set &mapModifiedTx) indexed_modified_transaction_set &mapModifiedTx)
{ {
int nDescendantsUpdated = 0;
BOOST_FOREACH(const CTxMemPool::txiter it, alreadyAdded) { BOOST_FOREACH(const CTxMemPool::txiter it, alreadyAdded) {
CTxMemPool::setEntries descendants; CTxMemPool::setEntries descendants;
mempool.CalculateDescendants(it, descendants); mempool.CalculateDescendants(it, descendants);
@ -279,6 +289,7 @@ void BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alread
BOOST_FOREACH(CTxMemPool::txiter desc, descendants) { BOOST_FOREACH(CTxMemPool::txiter desc, descendants) {
if (alreadyAdded.count(desc)) if (alreadyAdded.count(desc))
continue; continue;
++nDescendantsUpdated;
modtxiter mit = mapModifiedTx.find(desc); modtxiter mit = mapModifiedTx.find(desc);
if (mit == mapModifiedTx.end()) { if (mit == mapModifiedTx.end()) {
CTxMemPoolModifiedEntry modEntry(desc); CTxMemPoolModifiedEntry modEntry(desc);
@ -291,6 +302,7 @@ void BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alread
} }
} }
} }
return nDescendantsUpdated;
} }
// Skip entries in mapTx that are already in a block or are present // Skip entries in mapTx that are already in a block or are present
@ -331,7 +343,7 @@ void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, CTxMemP
// Each time through the loop, we compare the best transaction in // Each time through the loop, we compare the best transaction in
// mapModifiedTxs with the next transaction in the mempool to decide what // mapModifiedTxs with the next transaction in the mempool to decide what
// transaction package to work on next. // transaction package to work on next.
void BlockAssembler::addPackageTxs() void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated)
{ {
// mapModifiedTx will store sorted packages after they are modified // mapModifiedTx will store sorted packages after they are modified
// because some of their txs are already in the block // because some of their txs are already in the block
@ -345,6 +357,13 @@ void BlockAssembler::addPackageTxs()
CTxMemPool::indexed_transaction_set::index<ancestor_score>::type::iterator mi = mempool.mapTx.get<ancestor_score>().begin(); CTxMemPool::indexed_transaction_set::index<ancestor_score>::type::iterator mi = mempool.mapTx.get<ancestor_score>().begin();
CTxMemPool::txiter iter; CTxMemPool::txiter iter;
// Limit the number of attempts to add transactions to the block when it is
// close to full; this is just a simple heuristic to finish quickly if the
// mempool has a lot of entries.
const int64_t MAX_CONSECUTIVE_FAILURES = 1000;
int64_t nConsecutiveFailed = 0;
while (mi != mempool.mapTx.get<ancestor_score>().end() || !mapModifiedTx.empty()) while (mi != mempool.mapTx.get<ancestor_score>().end() || !mapModifiedTx.empty())
{ {
// First try to find a new transaction in mapTx to evaluate. // First try to find a new transaction in mapTx to evaluate.
@ -406,6 +425,14 @@ void BlockAssembler::addPackageTxs()
mapModifiedTx.get<ancestor_score>().erase(modit); mapModifiedTx.get<ancestor_score>().erase(modit);
failedTx.insert(iter); failedTx.insert(iter);
} }
++nConsecutiveFailed;
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight >
nBlockMaxWeight - 4000) {
// Give up if we're close to full and haven't succeeded in a while
break;
}
continue; continue;
} }
@ -426,6 +453,9 @@ void BlockAssembler::addPackageTxs()
continue; continue;
} }
// This transaction will make it in; reset the failed counter.
nConsecutiveFailed = 0;
// Package can be added. Sort the entries in a valid order. // Package can be added. Sort the entries in a valid order.
std::vector<CTxMemPool::txiter> sortedEntries; std::vector<CTxMemPool::txiter> sortedEntries;
SortForBlock(ancestors, iter, sortedEntries); SortForBlock(ancestors, iter, sortedEntries);
@ -436,8 +466,10 @@ void BlockAssembler::addPackageTxs()
mapModifiedTx.erase(sortedEntries[i]); mapModifiedTx.erase(sortedEntries[i]);
} }
++nPackagesSelected;
// Update transactions that depend on each of these // Update transactions that depend on each of these
UpdatePackagesForAdded(ancestors, mapModifiedTx); nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx);
} }
} }

@ -180,8 +180,10 @@ private:
void AddToBlock(CTxMemPool::txiter iter); void AddToBlock(CTxMemPool::txiter iter);
// Methods for how to add transactions to a block. // Methods for how to add transactions to a block.
/** Add transactions based on feerate including unconfirmed ancestors */ /** Add transactions based on feerate including unconfirmed ancestors
void addPackageTxs(); * Increments nPackagesSelected / nDescendantsUpdated with corresponding
* statistics from the package selection (for logging statistics). */
void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated);
// helper functions for addPackageTxs() // helper functions for addPackageTxs()
/** Remove confirmed (inBlock) entries from given set */ /** Remove confirmed (inBlock) entries from given set */
@ -199,8 +201,9 @@ private:
/** Sort the package in an order that is valid to appear in a block */ /** Sort the package in an order that is valid to appear in a block */
void SortForBlock(const CTxMemPool::setEntries& package, CTxMemPool::txiter entry, std::vector<CTxMemPool::txiter>& sortedEntries); void SortForBlock(const CTxMemPool::setEntries& package, CTxMemPool::txiter entry, std::vector<CTxMemPool::txiter>& sortedEntries);
/** Add descendants of given transactions to mapModifiedTx with ancestor /** Add descendants of given transactions to mapModifiedTx with ancestor
* state updated assuming given transactions are inBlock. */ * state updated assuming given transactions are inBlock. Returns number
void UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set &mapModifiedTx); * of updated descendants. */
int UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set &mapModifiedTx);
}; };
/** Modify the extranonce in a block */ /** Modify the extranonce in a block */

Loading…
Cancel
Save