Changeset View
Changeset View
Standalone View
Standalone View
src/miner.cpp
Show First 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | static uint64_t ComputeMaxGeneratedBlockSize(const Config &config, | ||||
// Limit size to between 1K and MaxBlockSize-1K for sanity: | // Limit size to between 1K and MaxBlockSize-1K for sanity: | ||||
nMaxGeneratedBlockSize = | nMaxGeneratedBlockSize = | ||||
std::max(uint64_t(1000), std::min(config.GetMaxBlockSize() - 1000, | std::max(uint64_t(1000), std::min(config.GetMaxBlockSize() - 1000, | ||||
nMaxGeneratedBlockSize)); | nMaxGeneratedBlockSize)); | ||||
return nMaxGeneratedBlockSize; | return nMaxGeneratedBlockSize; | ||||
} | } | ||||
BlockAssembler::BlockAssembler(const Config &_config) : config(&_config) { | BlockAssembler::BlockAssembler(const Config &_config, const CTxMemPool &mpool) | ||||
: config(&_config), mpool(&mpool) { | |||||
if (gArgs.IsArgSet("-blockmintxfee")) { | if (gArgs.IsArgSet("-blockmintxfee")) { | ||||
Amount n = Amount::zero(); | Amount n = Amount::zero(); | ||||
ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n); | ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n); | ||||
blockMinFeeRate = CFeeRate(n); | blockMinFeeRate = CFeeRate(n); | ||||
} else { | } else { | ||||
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB); | blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | BlockAssembler::CreateNewBlock(const CScript &scriptPubKeyIn) { | ||||
// Add dummy coinbase tx as first transaction. | // Add dummy coinbase tx as first transaction. | ||||
pblock->vtx.emplace_back(); | pblock->vtx.emplace_back(); | ||||
// updated at end | // updated at end | ||||
pblocktemplate->vTxFees.push_back(-SATOSHI); | pblocktemplate->vTxFees.push_back(-SATOSHI); | ||||
// updated at end | // updated at end | ||||
pblocktemplate->vTxSigOpsCount.push_back(-1); | pblocktemplate->vTxSigOpsCount.push_back(-1); | ||||
LOCK2(cs_main, mempool.cs); | LOCK2(cs_main, mpool->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 80 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 : mpool->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 102 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); | mpool->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); | mpool->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 != mpool->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 = mpool->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 != mpool->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 != mpool->mapTx.get<ancestor_score>().end() && | ||||
SkipMapTxEntry(mempool.mapTx.project<0>(mi), mapModifiedTx, | SkipMapTxEntry(mpool->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 == mpool->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 = mpool->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 != mpool->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, | mpool->CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, nNoLimit, | ||||
nNoLimit, nNoLimit, dummy, false); | 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(mpool->mapTx.size()); | ||||
for (CTxMemPool::indexed_transaction_set::iterator mi = | for (CTxMemPool::indexed_transaction_set::iterator mi = | ||||
mempool.mapTx.begin(); | mpool->mapTx.begin(); | ||||
mi != mempool.mapTx.end(); ++mi) { | mi != mpool->mapTx.end(); ++mi) { | ||||
double dPriority = mi->GetPriority(nHeight); | double dPriority = mi->GetPriority(nHeight); | ||||
Amount dummy; | Amount dummy; | ||||
mempool.ApplyDeltas(mi->GetTx().GetId(), dPriority, dummy); | mpool->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 : mpool->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 27 Lines |