Changeset View
Changeset View
Standalone View
Standalone View
src/miner.cpp
Show First 20 Lines • Show All 247 Lines • ▼ Show 20 Lines | LogPrint(BCLog::BENCH, | ||||
nDescendantsUpdated, 0.001 * (nTime2 - nTime1), | nDescendantsUpdated, 0.001 * (nTime2 - nTime1), | ||||
0.001 * (nTime2 - nTimeStart)); | 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 : mempool->GetMemPoolParents(iter)) { | ||||
if (!inBlock.count(parent)) { | if (!inBlock.count(parent->GetTx().GetId())) { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries &testSet) { | void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries &testSet) { | ||||
for (CTxMemPool::setEntries::iterator iit = testSet.begin(); | for (CTxMemPool::setEntries::iterator iit = testSet.begin(); | ||||
iit != testSet.end();) { | iit != testSet.end();) { | ||||
// Only test txs not already in the block. | // Only test txs not already in the block. | ||||
if (inBlock.count(*iit)) { | if (inBlock.count((*iit)->GetTx().GetId())) { | ||||
testSet.erase(iit++); | testSet.erase(iit++); | ||||
} else { | } else { | ||||
iit++; | iit++; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
bool BlockAssembler::TestPackage(uint64_t packageSize, | bool BlockAssembler::TestPackage(uint64_t packageSize, | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) { | void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) { | ||||
pblocktemplate->entries.emplace_back(iter->GetSharedTx(), iter->GetFee(), | pblocktemplate->entries.emplace_back(iter->GetSharedTx(), iter->GetFee(), | ||||
iter->GetTxSize(), | iter->GetTxSize(), | ||||
iter->GetSigOpCount()); | iter->GetSigOpCount()); | ||||
nBlockSize += iter->GetTxSize(); | nBlockSize += iter->GetTxSize(); | ||||
++nBlockTx; | ++nBlockTx; | ||||
nBlockSigOps += iter->GetSigOpCount(); | nBlockSigOps += iter->GetSigOpCount(); | ||||
nFees += iter->GetFee(); | nFees += iter->GetFee(); | ||||
inBlock.insert(iter); | inBlock.insert(iter->GetTx().GetId()); | ||||
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); | 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()); | ||||
} | } | ||||
} | } | ||||
// TODO: Temporary adapter, delete this eventually. | |||||
int BlockAssembler::UpdatePackagesForAdded( | |||||
const TxIdSet &alreadyAdded, | |||||
indexed_modified_transaction_set &mapModifiedTx) { | |||||
CTxMemPool::setEntries entries; | |||||
for (const TxId &id : alreadyAdded) { | |||||
entries.insert(mempool->mapTx.find(id)); | |||||
} | |||||
return UpdatePackagesForAdded(entries, mapModifiedTx); | |||||
} | |||||
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); | 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. | ||||
Show All 25 Lines | |||||
// ancestor inclusion in the block). Also skip transactions that we've already | // ancestor inclusion in the block). Also skip transactions that we've already | ||||
// 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) { | const TxIdSet &failedTx) { | ||||
assert(it != mempool->mapTx.end()); | assert(it != mempool->mapTx.end()); | ||||
return mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it); | const TxId &txId = it->GetTx().GetId(); | ||||
return mapModifiedTx.count(it) || inBlock.count(txId) || | |||||
failedTx.count(txId); | |||||
} | } | ||||
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 | ||||
// sufficient to validly order the transactions for block inclusion. | // sufficient to validly order the transactions for block inclusion. | ||||
Show All 23 Lines | void BlockAssembler::addPackageTxs(int &nPackagesSelected, | ||||
// loop, we compare the best transaction in mapModifiedTxs with the next | // loop, we compare the best transaction in mapModifiedTxs with the next | ||||
// transaction in the mempool to decide what transaction package to work | // transaction in the mempool to decide what transaction package to work | ||||
// on next. | // on next. | ||||
// mapModifiedTx will store sorted packages after they are modified because | // mapModifiedTx will store sorted packages after they are modified because | ||||
// some of their txs are already in the block. | // some of their txs are already in the block. | ||||
indexed_modified_transaction_set mapModifiedTx; | indexed_modified_transaction_set mapModifiedTx; | ||||
// 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; | TxIdSet 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 = mempool->mapTx.get<ancestor_score>().begin(); | ||||
CTxMemPool::txiter iter; | CTxMemPool::txiter iter; | ||||
Show All 36 Lines | while (mi != mempool->mapTx.get<ancestor_score>().end() || | ||||
// Either no entry in mapModifiedTx, or it's worse than mapTx. | // Either no entry in mapModifiedTx, or it's worse than mapTx. | ||||
// Increment mi for the next loop iteration. | // Increment mi for the next loop iteration. | ||||
++mi; | ++mi; | ||||
} | } | ||||
} | } | ||||
// We skip mapTx entries that are inBlock, and mapModifiedTx shouldn't | // We skip mapTx entries that are inBlock, and mapModifiedTx shouldn't | ||||
// contain anything that is inBlock. | // contain anything that is inBlock. | ||||
assert(!inBlock.count(iter)); | assert(!inBlock.count(iter->GetTx().GetId())); | ||||
uint64_t packageSize = iter->GetSizeWithAncestors(); | uint64_t packageSize = iter->GetSizeWithAncestors(); | ||||
Amount packageFees = iter->GetModFeesWithAncestors(); | Amount packageFees = iter->GetModFeesWithAncestors(); | ||||
int64_t packageSigOps = iter->GetSigOpCountWithAncestors(); | int64_t packageSigOps = iter->GetSigOpCountWithAncestors(); | ||||
if (fUsingModified) { | if (fUsingModified) { | ||||
packageSize = modit->nSizeWithAncestors; | packageSize = modit->nSizeWithAncestors; | ||||
packageFees = modit->nModFeesWithAncestors; | packageFees = modit->nModFeesWithAncestors; | ||||
packageSigOps = modit->nSigOpCountWithAncestors; | packageSigOps = modit->nSigOpCountWithAncestors; | ||||
} | } | ||||
if (packageFees < blockMinFeeRate.GetFee(packageSize)) { | if (packageFees < blockMinFeeRate.GetFee(packageSize)) { | ||||
// Everything else we might consider has a lower fee rate | // Everything else we might consider has a lower fee rate | ||||
return; | return; | ||||
} | } | ||||
if (!TestPackage(packageSize, packageSigOps)) { | if (!TestPackage(packageSize, packageSigOps)) { | ||||
if (fUsingModified) { | if (fUsingModified) { | ||||
// Since we always look at the best entry in mapModifiedTx, we | // Since we always look at the best entry in mapModifiedTx, we | ||||
// must erase failed entries so that we can consider the next | // must erase failed entries so that we can consider the next | ||||
// best entry on the next loop iteration | // best entry on the next loop iteration | ||||
mapModifiedTx.get<ancestor_score>().erase(modit); | mapModifiedTx.get<ancestor_score>().erase(modit); | ||||
failedTx.insert(iter); | failedTx.insert(iter->GetTx().GetId()); | ||||
} | } | ||||
++nConsecutiveFailed; | ++nConsecutiveFailed; | ||||
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && | if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && | ||||
nBlockSize > nMaxGeneratedBlockSize - 1000) { | nBlockSize > nMaxGeneratedBlockSize - 1000) { | ||||
// Give up if we're close to full and haven't succeeded in a | // Give up if we're close to full and haven't succeeded in a | ||||
// while. | // while. | ||||
Show All 11 Lines | while (mi != mempool->mapTx.get<ancestor_score>().end() || | ||||
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); | ||||
failedTx.insert(iter); | failedTx.insert(iter->GetTx().GetId()); | ||||
} | } | ||||
continue; | continue; | ||||
} | } | ||||
// This transaction will make it in; reset the failed counter. | // This transaction will make it in; reset the failed counter. | ||||
nConsecutiveFailed = 0; | nConsecutiveFailed = 0; | ||||
// Package can be added. Sort the entries in a valid order. | // Package can be added. Sort the entries in a valid order. | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | void BlockAssembler::addPriorityTxs() { | ||||
// priority transactions. | // priority transactions. | ||||
while (!vecPriority.empty()) { | while (!vecPriority.empty()) { | ||||
iter = vecPriority.front().second; | iter = vecPriority.front().second; | ||||
actualPriority = vecPriority.front().first; | actualPriority = vecPriority.front().first; | ||||
std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer); | std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer); | ||||
vecPriority.pop_back(); | vecPriority.pop_back(); | ||||
// If tx already in block, skip. | // If tx already in block, skip. | ||||
if (inBlock.count(iter)) { | if (inBlock.count(iter->GetTx().GetId())) { | ||||
// Shouldn't happen for priority txs. | // Shouldn't happen for priority txs. | ||||
assert(false); | assert(false); | ||||
continue; | continue; | ||||
} | } | ||||
// If tx is dependent on other mempool txs which haven't yet been | // If tx is dependent on other mempool txs which haven't yet been | ||||
// included then put it in the waitSet. | // included then put it in the waitSet. | ||||
if (isStillDependent(iter)) { | if (isStillDependent(iter)) { | ||||
▲ Show 20 Lines • Show All 78 Lines • Show Last 20 Lines |