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
This commit is contained in:
parent
42d3060568
commit
06c8714572
@ -110,6 +110,8 @@ void BlockAssembler::resetBlock()
|
|||||||
|
|
||||||
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
|
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||||
{
|
{
|
||||||
|
int64_t nTimeStart = GetTimeMicros();
|
||||||
|
|
||||||
resetBlock();
|
resetBlock();
|
||||||
|
|
||||||
pblocktemplate.reset(new CBlockTemplate());
|
pblocktemplate.reset(new CBlockTemplate());
|
||||||
@ -141,7 +143,12 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
|
|||||||
: pblock->GetBlockTime();
|
: pblock->GetBlockTime();
|
||||||
|
|
||||||
addPriorityTxs();
|
addPriorityTxs();
|
||||||
addPackageTxs();
|
|
||||||
|
int nPackagesSelected = 0;
|
||||||
|
int nDescendantsUpdated = 0;
|
||||||
|
addPackageTxs(nPackagesSelected, nDescendantsUpdated);
|
||||||
|
|
||||||
|
int64_t nTime1 = GetTimeMicros();
|
||||||
|
|
||||||
nLastBlockTx = nBlockTx;
|
nLastBlockTx = nBlockTx;
|
||||||
nLastBlockSize = nBlockSize;
|
nLastBlockSize = nBlockSize;
|
||||||
@ -181,6 +188,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);
|
||||||
}
|
}
|
||||||
@ -292,9 +302,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);
|
||||||
@ -302,6 +313,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);
|
||||||
@ -314,6 +326,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
|
||||||
@ -354,7 +367,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
|
||||||
@ -368,6 +381,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.
|
||||||
@ -429,6 +449,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,6 +477,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);
|
||||||
@ -459,8 +490,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
src/miner.h
11
src/miner.h
@ -174,8 +174,10 @@ private:
|
|||||||
// Methods for how to add transactions to a block.
|
// Methods for how to add transactions to a block.
|
||||||
/** Add transactions based on tx "priority" */
|
/** Add transactions based on tx "priority" */
|
||||||
void addPriorityTxs();
|
void addPriorityTxs();
|
||||||
/** 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 function for addPriorityTxs
|
// helper function for addPriorityTxs
|
||||||
/** Test if tx will still "fit" in the block */
|
/** Test if tx will still "fit" in the block */
|
||||||
@ -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…
Reference in New Issue
Block a user