Changeset View
Changeset View
Standalone View
Standalone View
src/miner.cpp
Show First 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
BlockAssembler::Options::Options() | BlockAssembler::Options::Options() | ||||
: nExcessiveBlockSize(DEFAULT_MAX_BLOCK_SIZE), | : nExcessiveBlockSize(DEFAULT_MAX_BLOCK_SIZE), | ||||
nMaxGeneratedBlockSize(DEFAULT_MAX_GENERATED_BLOCK_SIZE), | nMaxGeneratedBlockSize(DEFAULT_MAX_GENERATED_BLOCK_SIZE), | ||||
blockMinFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB) {} | blockMinFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB) {} | ||||
BlockAssembler::BlockAssembler(const CChainParams ¶ms, | BlockAssembler::BlockAssembler(const CChainParams ¶ms, | ||||
const CTxMemPool &_mempool, | const CTxMemPool &mempool, | ||||
const Options &options) | const Options &options) | ||||
: chainParams(params), mempool(&_mempool) { | : chainParams(params), m_mempool(mempool) { | ||||
blockMinFeeRate = options.blockMinFeeRate; | blockMinFeeRate = options.blockMinFeeRate; | ||||
// Limit size to between 1K and options.nExcessiveBlockSize -1K for sanity: | // Limit size to between 1K and options.nExcessiveBlockSize -1K for sanity: | ||||
nMaxGeneratedBlockSize = std::max<uint64_t>( | nMaxGeneratedBlockSize = std::max<uint64_t>( | ||||
1000, std::min<uint64_t>(options.nExcessiveBlockSize - 1000, | 1000, std::min<uint64_t>(options.nExcessiveBlockSize - 1000, | ||||
options.nMaxGeneratedBlockSize)); | options.nMaxGeneratedBlockSize)); | ||||
// Calculate the max consensus sigchecks for this block. | // Calculate the max consensus sigchecks for this block. | ||||
auto nMaxBlockSigChecks = | auto nMaxBlockSigChecks = | ||||
GetMaxBlockSigChecksCount(options.nExcessiveBlockSize); | GetMaxBlockSigChecksCount(options.nExcessiveBlockSize); | ||||
Show All 22 Lines | static BlockAssembler::Options DefaultOptions(const Config &config) { | ||||
if (gArgs.IsArgSet("-blockmintxfee") && | if (gArgs.IsArgSet("-blockmintxfee") && | ||||
ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) { | ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) { | ||||
options.blockMinFeeRate = CFeeRate(n); | options.blockMinFeeRate = CFeeRate(n); | ||||
} | } | ||||
return options; | return options; | ||||
} | } | ||||
BlockAssembler::BlockAssembler(const Config &config, const CTxMemPool &_mempool) | BlockAssembler::BlockAssembler(const Config &config, const CTxMemPool &mempool) | ||||
: BlockAssembler(config.GetChainParams(), _mempool, | : BlockAssembler(config.GetChainParams(), mempool, DefaultOptions(config)) { | ||||
DefaultOptions(config)) {} | } | ||||
void BlockAssembler::resetBlock() { | void BlockAssembler::resetBlock() { | ||||
inBlock.clear(); | inBlock.clear(); | ||||
// Reserve space for coinbase tx. | // Reserve space for coinbase tx. | ||||
nBlockSize = 1000; | nBlockSize = 1000; | ||||
nBlockSigOps = 100; | nBlockSigOps = 100; | ||||
Show All 17 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, m_mempool.cs); | ||||
CBlockIndex *pindexPrev = ::ChainActive().Tip(); | CBlockIndex *pindexPrev = ::ChainActive().Tip(); | ||||
assert(pindexPrev != nullptr); | assert(pindexPrev != nullptr); | ||||
nHeight = pindexPrev->nHeight + 1; | nHeight = pindexPrev->nHeight + 1; | ||||
const Consensus::Params &consensusParams = chainParams.GetConsensus(); | const Consensus::Params &consensusParams = chainParams.GetConsensus(); | ||||
pblock->nVersion = ComputeBlockVersion(pindexPrev, consensusParams); | pblock->nVersion = ComputeBlockVersion(pindexPrev, consensusParams); | ||||
// -regtest only: allow overriding block.nVersion with | // -regtest only: allow overriding block.nVersion with | ||||
▲ Show 20 Lines • Show All 169 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
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 (CTxMemPool::txiter it : alreadyAdded) { | for (CTxMemPool::txiter it : alreadyAdded) { | ||||
CTxMemPool::setEntries descendants; | CTxMemPool::setEntries descendants; | ||||
mempool->CalculateDescendants(it, descendants); | m_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 18 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 != m_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, | const CTxMemPool::setEntries &package, | ||||
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 30 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 = m_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 != m_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 != m_mempool.mapTx.get<ancestor_score>().end() && | ||||
SkipMapTxEntry(mempool->mapTx.project<0>(mi), mapModifiedTx, | SkipMapTxEntry(m_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 == m_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 = m_mempool.mapTx.project<0>(mi); | ||||
if (modit != mapModifiedTx.get<ancestor_score>().end() && | if (modit != mapModifiedTx.get<ancestor_score>().end() && | ||||
CompareTxMemPoolEntryByAncestorFee()( | CompareTxMemPoolEntryByAncestorFee()( | ||||
*modit, CTxMemPoolModifiedEntry(iter))) { | *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 { | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | while (mi != m_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, | m_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 20 Lines • Show All 64 Lines • Show Last 20 Lines |