Changeset View
Changeset View
Standalone View
Standalone View
src/miner.cpp
Show First 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | BlockAssembler::CreateNewBlock(const CScript &scriptPubKeyIn) { | ||||
} | } | ||||
// Pointer for convenience. | // Pointer for convenience. | ||||
pblock = &pblocktemplate->block; | pblock = &pblocktemplate->block; | ||||
// Add dummy coinbase tx as first transaction. It is updated at the end. | // Add dummy coinbase tx as first transaction. It is updated at the end. | ||||
pblocktemplate->entries.emplace_back(CTransactionRef(), -SATOSHI, -1); | pblocktemplate->entries.emplace_back(CTransactionRef(), -SATOSHI, -1); | ||||
LOCK2(cs_main, mempool.cs); | LOCK2(cs_main, g_mempool.cs); | ||||
CBlockIndex *pindexPrev = chainActive.Tip(); | CBlockIndex *pindexPrev = chainActive.Tip(); | ||||
nHeight = pindexPrev->nHeight + 1; | nHeight = pindexPrev->nHeight + 1; | ||||
const CChainParams &chainparams = config->GetChainParams(); | const CChainParams &chainparams = config->GetChainParams(); | ||||
pblock->nVersion = | pblock->nVersion = | ||||
ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); | ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); | ||||
// -regtest only: allow overriding block.nVersion with | // -regtest only: allow overriding block.nVersion with | ||||
// -blockversion=N to test forking scenarios | // -blockversion=N to test forking scenarios | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | LogPrint( | ||||
"updated descendants), validity: %.2fms (total %.2fms)\n", | "updated descendants), validity: %.2fms (total %.2fms)\n", | ||||
0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, | 0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, | ||||
0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart)); | 0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart)); | ||||
return std::move(pblocktemplate); | return std::move(pblocktemplate); | ||||
} | } | ||||
bool BlockAssembler::isStillDependent(CTxMemPool::txiter iter) { | bool BlockAssembler::isStillDependent(CTxMemPool::txiter iter) { | ||||
for (CTxMemPool::txiter parent : mempool.GetMemPoolParents(iter)) { | for (CTxMemPool::txiter parent : g_mempool.GetMemPoolParents(iter)) { | ||||
if (!inBlock.count(parent)) { | if (!inBlock.count(parent)) { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries &testSet) { | void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries &testSet) { | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) { | ||||
nFees += iter->GetFee(); | nFees += iter->GetFee(); | ||||
inBlock.insert(iter); | inBlock.insert(iter); | ||||
bool fPrintPriority = | bool fPrintPriority = | ||||
gArgs.GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY); | gArgs.GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY); | ||||
if (fPrintPriority) { | if (fPrintPriority) { | ||||
double dPriority = iter->GetPriority(nHeight); | double dPriority = iter->GetPriority(nHeight); | ||||
Amount dummy; | Amount dummy; | ||||
mempool.ApplyDeltas(iter->GetTx().GetId(), dPriority, dummy); | g_mempool.ApplyDeltas(iter->GetTx().GetId(), dPriority, dummy); | ||||
LogPrintf( | LogPrintf( | ||||
"priority %.1f fee %s txid %s\n", dPriority, | "priority %.1f fee %s txid %s\n", dPriority, | ||||
CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(), | CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(), | ||||
iter->GetTx().GetId().ToString()); | iter->GetTx().GetId().ToString()); | ||||
} | } | ||||
} | } | ||||
int BlockAssembler::UpdatePackagesForAdded( | int BlockAssembler::UpdatePackagesForAdded( | ||||
const CTxMemPool::setEntries &alreadyAdded, | const CTxMemPool::setEntries &alreadyAdded, | ||||
indexed_modified_transaction_set &mapModifiedTx) { | indexed_modified_transaction_set &mapModifiedTx) { | ||||
int nDescendantsUpdated = 0; | int nDescendantsUpdated = 0; | ||||
for (const CTxMemPool::txiter it : alreadyAdded) { | for (const CTxMemPool::txiter it : alreadyAdded) { | ||||
CTxMemPool::setEntries descendants; | CTxMemPool::setEntries descendants; | ||||
mempool.CalculateDescendants(it, descendants); | g_mempool.CalculateDescendants(it, descendants); | ||||
// Insert all descendants (not yet in block) into the modified set. | // Insert all descendants (not yet in block) into the modified set. | ||||
for (CTxMemPool::txiter desc : descendants) { | for (CTxMemPool::txiter desc : descendants) { | ||||
if (alreadyAdded.count(desc)) { | if (alreadyAdded.count(desc)) { | ||||
continue; | continue; | ||||
} | } | ||||
++nDescendantsUpdated; | ++nDescendantsUpdated; | ||||
modtxiter mit = mapModifiedTx.find(desc); | modtxiter mit = mapModifiedTx.find(desc); | ||||
Show All 19 Lines | |||||
// failed to add. This can happen if we consider a transaction in mapModifiedTx | // failed to add. This can happen if we consider a transaction in mapModifiedTx | ||||
// and it fails: we can then potentially consider it again while walking mapTx. | // and it fails: we can then potentially consider it again while walking mapTx. | ||||
// It's currently guaranteed to fail again, but as a belt-and-suspenders check | // It's currently guaranteed to fail again, but as a belt-and-suspenders check | ||||
// we put it in failedTx and avoid re-evaluation, since the re-evaluation would | // we put it in failedTx and avoid re-evaluation, since the re-evaluation would | ||||
// be using cached size/sigops/fee values that are not actually correct. | // be using cached size/sigops/fee values that are not actually correct. | ||||
bool BlockAssembler::SkipMapTxEntry( | bool BlockAssembler::SkipMapTxEntry( | ||||
CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx, | CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx, | ||||
CTxMemPool::setEntries &failedTx) { | CTxMemPool::setEntries &failedTx) { | ||||
assert(it != mempool.mapTx.end()); | assert(it != g_mempool.mapTx.end()); | ||||
return mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it); | return mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it); | ||||
} | } | ||||
void BlockAssembler::SortForBlock( | void BlockAssembler::SortForBlock( | ||||
const CTxMemPool::setEntries &package, CTxMemPool::txiter entry, | const CTxMemPool::setEntries &package, CTxMemPool::txiter entry, | ||||
std::vector<CTxMemPool::txiter> &sortedEntries) { | std::vector<CTxMemPool::txiter> &sortedEntries) { | ||||
// Sort package by ancestor count. If a transaction A depends on transaction | // Sort package by ancestor count. If a transaction A depends on transaction | ||||
// B, then A's ancestor count must be greater than B's. So this is | // B, then A's ancestor count must be greater than B's. So this is | ||||
Show All 31 Lines | void BlockAssembler::addPackageTxs(int &nPackagesSelected, | ||||
// Keep track of entries that failed inclusion, to avoid duplicate work. | // Keep track of entries that failed inclusion, to avoid duplicate work. | ||||
CTxMemPool::setEntries failedTx; | CTxMemPool::setEntries failedTx; | ||||
// Start by adding all descendants of previously added txs to mapModifiedTx | // Start by adding all descendants of previously added txs to mapModifiedTx | ||||
// and modifying them for their already included ancestors. | // and modifying them for their already included ancestors. | ||||
UpdatePackagesForAdded(inBlock, mapModifiedTx); | UpdatePackagesForAdded(inBlock, mapModifiedTx); | ||||
CTxMemPool::indexed_transaction_set::index<ancestor_score>::type::iterator | CTxMemPool::indexed_transaction_set::index<ancestor_score>::type::iterator | ||||
mi = mempool.mapTx.get<ancestor_score>().begin(); | mi = g_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 | // 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 | // close to full; this is just a simple heuristic to finish quickly if the | ||||
// mempool has a lot of entries. | // mempool has a lot of entries. | ||||
const int64_t MAX_CONSECUTIVE_FAILURES = 1000; | const int64_t MAX_CONSECUTIVE_FAILURES = 1000; | ||||
int64_t nConsecutiveFailed = 0; | int64_t nConsecutiveFailed = 0; | ||||
while (mi != mempool.mapTx.get<ancestor_score>().end() || | while (mi != g_mempool.mapTx.get<ancestor_score>().end() || | ||||
!mapModifiedTx.empty()) { | !mapModifiedTx.empty()) { | ||||
// First try to find a new transaction in mapTx to evaluate. | // First try to find a new transaction in mapTx to evaluate. | ||||
if (mi != mempool.mapTx.get<ancestor_score>().end() && | if (mi != g_mempool.mapTx.get<ancestor_score>().end() && | ||||
SkipMapTxEntry(mempool.mapTx.project<0>(mi), mapModifiedTx, | SkipMapTxEntry(g_mempool.mapTx.project<0>(mi), mapModifiedTx, | ||||
failedTx)) { | failedTx)) { | ||||
++mi; | ++mi; | ||||
continue; | continue; | ||||
} | } | ||||
// Now that mi is not stale, determine which transaction to evaluate: | // Now that mi is not stale, determine which transaction to evaluate: | ||||
// the next entry from mapTx, or the best from mapModifiedTx? | // the next entry from mapTx, or the best from mapModifiedTx? | ||||
bool fUsingModified = false; | bool fUsingModified = false; | ||||
modtxscoreiter modit = mapModifiedTx.get<ancestor_score>().begin(); | modtxscoreiter modit = mapModifiedTx.get<ancestor_score>().begin(); | ||||
if (mi == mempool.mapTx.get<ancestor_score>().end()) { | if (mi == g_mempool.mapTx.get<ancestor_score>().end()) { | ||||
// We're out of entries in mapTx; use the entry from mapModifiedTx | // We're out of entries in mapTx; use the entry from mapModifiedTx | ||||
iter = modit->iter; | iter = modit->iter; | ||||
fUsingModified = true; | fUsingModified = true; | ||||
} else { | } else { | ||||
// Try to compare the mapTx entry to the mapModifiedTx entry. | // Try to compare the mapTx entry to the mapModifiedTx entry. | ||||
iter = mempool.mapTx.project<0>(mi); | iter = g_mempool.mapTx.project<0>(mi); | ||||
if (modit != mapModifiedTx.get<ancestor_score>().end() && | if (modit != mapModifiedTx.get<ancestor_score>().end() && | ||||
CompareModifiedEntry()(*modit, CTxMemPoolModifiedEntry(iter))) { | CompareModifiedEntry()(*modit, CTxMemPoolModifiedEntry(iter))) { | ||||
// The best entry in mapModifiedTx has higher score than the one | // The best entry in mapModifiedTx has higher score than the one | ||||
// from mapTx. Switch which transaction (package) to consider | // from mapTx. Switch which transaction (package) to consider | ||||
iter = modit->iter; | iter = modit->iter; | ||||
fUsingModified = true; | fUsingModified = true; | ||||
} else { | } else { | ||||
// Either no entry in mapModifiedTx, or it's worse than mapTx. | // Either no entry in mapModifiedTx, or it's worse than mapTx. | ||||
Show All 39 Lines | while (mi != g_mempool.mapTx.get<ancestor_score>().end() || | ||||
} | } | ||||
continue; | continue; | ||||
} | } | ||||
CTxMemPool::setEntries ancestors; | CTxMemPool::setEntries ancestors; | ||||
uint64_t nNoLimit = std::numeric_limits<uint64_t>::max(); | uint64_t nNoLimit = std::numeric_limits<uint64_t>::max(); | ||||
std::string dummy; | std::string dummy; | ||||
mempool.CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, nNoLimit, | g_mempool.CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, | ||||
nNoLimit, nNoLimit, dummy, false); | nNoLimit, nNoLimit, nNoLimit, dummy, | ||||
false); | |||||
onlyUnconfirmed(ancestors); | onlyUnconfirmed(ancestors); | ||||
ancestors.insert(iter); | ancestors.insert(iter); | ||||
// Test if all tx's are Final. | // Test if all tx's are Final. | ||||
if (!TestPackageTransactions(ancestors)) { | if (!TestPackageTransactions(ancestors)) { | ||||
if (fUsingModified) { | if (fUsingModified) { | ||||
mapModifiedTx.get<ancestor_score>().erase(modit); | mapModifiedTx.get<ancestor_score>().erase(modit); | ||||
Show All 36 Lines | void BlockAssembler::addPriorityTxs() { | ||||
std::vector<TxCoinAgePriority> vecPriority; | std::vector<TxCoinAgePriority> vecPriority; | ||||
TxCoinAgePriorityCompare pricomparer; | TxCoinAgePriorityCompare pricomparer; | ||||
std::map<CTxMemPool::txiter, double, CTxMemPool::CompareIteratorByHash> | std::map<CTxMemPool::txiter, double, CTxMemPool::CompareIteratorByHash> | ||||
waitPriMap; | waitPriMap; | ||||
typedef std::map<CTxMemPool::txiter, double, | typedef std::map<CTxMemPool::txiter, double, | ||||
CTxMemPool::CompareIteratorByHash>::iterator waitPriIter; | CTxMemPool::CompareIteratorByHash>::iterator waitPriIter; | ||||
double actualPriority = -1; | double actualPriority = -1; | ||||
vecPriority.reserve(mempool.mapTx.size()); | vecPriority.reserve(g_mempool.mapTx.size()); | ||||
for (CTxMemPool::indexed_transaction_set::iterator mi = | for (CTxMemPool::indexed_transaction_set::iterator mi = | ||||
mempool.mapTx.begin(); | g_mempool.mapTx.begin(); | ||||
mi != mempool.mapTx.end(); ++mi) { | mi != g_mempool.mapTx.end(); ++mi) { | ||||
double dPriority = mi->GetPriority(nHeight); | double dPriority = mi->GetPriority(nHeight); | ||||
Amount dummy; | Amount dummy; | ||||
mempool.ApplyDeltas(mi->GetTx().GetId(), dPriority, dummy); | g_mempool.ApplyDeltas(mi->GetTx().GetId(), dPriority, dummy); | ||||
vecPriority.push_back(TxCoinAgePriority(dPriority, mi)); | vecPriority.push_back(TxCoinAgePriority(dPriority, mi)); | ||||
} | } | ||||
std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer); | std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer); | ||||
CTxMemPool::txiter iter; | CTxMemPool::txiter iter; | ||||
// Add a tx from priority queue to fill the part of block reserved to | // Add a tx from priority queue to fill the part of block reserved to | ||||
// priority transactions. | // priority transactions. | ||||
Show All 39 Lines | while (!vecPriority.empty()) { | ||||
// if we have dropped below the AllowFreeThreshold, then we're done | // if we have dropped below the AllowFreeThreshold, then we're done | ||||
// adding priority transactions. | // adding priority transactions. | ||||
if (!AllowFree(actualPriority)) { | if (!AllowFree(actualPriority)) { | ||||
break; | break; | ||||
} | } | ||||
// This tx was successfully added, so add transactions that depend | // This tx was successfully added, so add transactions that depend | ||||
// on this one to the priority queue to try again. | // on this one to the priority queue to try again. | ||||
for (CTxMemPool::txiter child : mempool.GetMemPoolChildren(iter)) { | for (CTxMemPool::txiter child : g_mempool.GetMemPoolChildren(iter)) { | ||||
waitPriIter wpiter = waitPriMap.find(child); | waitPriIter wpiter = waitPriMap.find(child); | ||||
if (wpiter == waitPriMap.end()) { | if (wpiter == waitPriMap.end()) { | ||||
continue; | continue; | ||||
} | } | ||||
vecPriority.push_back(TxCoinAgePriority(wpiter->second, child)); | vecPriority.push_back(TxCoinAgePriority(wpiter->second, child)); | ||||
std::push_heap(vecPriority.begin(), vecPriority.end(), pricomparer); | std::push_heap(vecPriority.begin(), vecPriority.end(), pricomparer); | ||||
waitPriMap.erase(wpiter); | waitPriMap.erase(wpiter); | ||||
Show All 38 Lines |