diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2017-03-30 20:53:31 +0200 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2017-03-30 20:55:29 +0200 |
commit | cde9b1a864c1743b0a20f914028e53df12a70906 (patch) | |
tree | d8fdd5f99df3050518b8d59f1ab7258b50107964 /src/miner.cpp | |
parent | 8ac80412867118172dc4172494304e19969e9489 (diff) | |
parent | 011124a2b278c5a60bad5f1b0b4abbf7ebc95aa0 (diff) |
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
Diffstat (limited to 'src/miner.cpp')
-rw-r--r-- | src/miner.cpp | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/src/miner.cpp b/src/miner.cpp index 4fd99c5282..e155df015a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -126,6 +126,8 @@ void BlockAssembler::resetBlock() std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx) { + int64_t nTimeStart = GetTimeMicros(); + resetBlock(); 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). fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()) && fMineWitnessTx; - addPackageTxs(); + int nPackagesSelected = 0; + int nDescendantsUpdated = 0; + addPackageTxs(nPackagesSelected, nDescendantsUpdated); + + int64_t nTime1 = GetTimeMicros(); nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; @@ -196,6 +202,9 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { 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); } @@ -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) { + int nDescendantsUpdated = 0; BOOST_FOREACH(const CTxMemPool::txiter it, alreadyAdded) { CTxMemPool::setEntries descendants; mempool.CalculateDescendants(it, descendants); @@ -279,6 +289,7 @@ void BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alread BOOST_FOREACH(CTxMemPool::txiter desc, descendants) { if (alreadyAdded.count(desc)) continue; + ++nDescendantsUpdated; modtxiter mit = mapModifiedTx.find(desc); if (mit == mapModifiedTx.end()) { 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 @@ -331,7 +343,7 @@ void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, CTxMemP // Each time through the loop, we compare the best transaction in // mapModifiedTxs with the next transaction in the mempool to decide what // 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 // 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::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()) { // First try to find a new transaction in mapTx to evaluate. @@ -406,6 +425,14 @@ void BlockAssembler::addPackageTxs() mapModifiedTx.get<ancestor_score>().erase(modit); 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; } @@ -426,6 +453,9 @@ void BlockAssembler::addPackageTxs() continue; } + // This transaction will make it in; reset the failed counter. + nConsecutiveFailed = 0; + // Package can be added. Sort the entries in a valid order. std::vector<CTxMemPool::txiter> sortedEntries; SortForBlock(ancestors, iter, sortedEntries); @@ -436,8 +466,10 @@ void BlockAssembler::addPackageTxs() mapModifiedTx.erase(sortedEntries[i]); } + ++nPackagesSelected; + // Update transactions that depend on each of these - UpdatePackagesForAdded(ancestors, mapModifiedTx); + nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx); } } |