Changeset View
Changeset View
Standalone View
Standalone View
src/miner.cpp
Show First 20 Lines • Show All 75 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, const CTxMemPool &mpool) | BlockAssembler::BlockAssembler(const Config &config, const CTxMemPool &mpool) | ||||
: config(&_config), mempool(&mpool) { | : mempool(&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); | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
nMaxGeneratedBlockSize = | nMaxGeneratedBlockSize = | ||||
ComputeMaxGeneratedBlockSize(*config, chainActive.Tip()); | ComputeMaxGeneratedBlockSize(config, chainActive.Tip()); | ||||
} | } | ||||
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 9 Lines | |||||
getExcessiveBlockSizeSig(const Config &config) { | getExcessiveBlockSizeSig(const Config &config) { | ||||
std::string cbmsg = "/EB" + getSubVersionEB(config.GetMaxBlockSize()) + "/"; | std::string cbmsg = "/EB" + getSubVersionEB(config.GetMaxBlockSize()) + "/"; | ||||
const char *cbcstr = cbmsg.c_str(); | const char *cbcstr = cbmsg.c_str(); | ||||
std::vector<uint8_t> vec(cbcstr, cbcstr + cbmsg.size()); | std::vector<uint8_t> vec(cbcstr, cbcstr + cbmsg.size()); | ||||
return vec; | return vec; | ||||
} | } | ||||
std::unique_ptr<CBlockTemplate> | std::unique_ptr<CBlockTemplate> | ||||
BlockAssembler::CreateNewBlock(const CScript &scriptPubKeyIn) { | BlockAssembler::CreateNewBlock(const Config &config, | ||||
const CScript &scriptPubKeyIn) { | |||||
int64_t nTimeStart = GetTimeMicros(); | int64_t nTimeStart = GetTimeMicros(); | ||||
resetBlock(); | resetBlock(); | ||||
pblocktemplate.reset(new CBlockTemplate()); | pblocktemplate.reset(new CBlockTemplate()); | ||||
if (!pblocktemplate.get()) { | if (!pblocktemplate.get()) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
// 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, 0, -1); | pblocktemplate->entries.emplace_back(CTransactionRef(), -SATOSHI, 0, -1); | ||||
LOCK2(cs_main, mempool->cs); | LOCK2(cs_main, 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 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 | ||||
if (chainparams.MineBlocksOnDemand()) { | if (chainparams.MineBlocksOnDemand()) { | ||||
pblock->nVersion = gArgs.GetArg("-blockversion", pblock->nVersion); | pblock->nVersion = gArgs.GetArg("-blockversion", pblock->nVersion); | ||||
} | } | ||||
pblock->nTime = GetAdjustedTime(); | pblock->nTime = GetAdjustedTime(); | ||||
nMaxGeneratedBlockSize = ComputeMaxGeneratedBlockSize(*config, pindexPrev); | nMaxGeneratedBlockSize = ComputeMaxGeneratedBlockSize(config, pindexPrev); | ||||
nMedianTimePast = pindexPrev->GetMedianTimePast(); | nMedianTimePast = pindexPrev->GetMedianTimePast(); | ||||
nLockTimeCutoff = | nLockTimeCutoff = | ||||
(STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) | (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) | ||||
? nMedianTimePast | ? nMedianTimePast | ||||
: pblock->GetBlockTime(); | : pblock->GetBlockTime(); | ||||
addPriorityTxs(); | addPriorityTxs(config); | ||||
int nPackagesSelected = 0; | int nPackagesSelected = 0; | ||||
int nDescendantsUpdated = 0; | int nDescendantsUpdated = 0; | ||||
addPackageTxs(nPackagesSelected, nDescendantsUpdated); | addPackageTxs(config, nPackagesSelected, nDescendantsUpdated); | ||||
if (IsMagneticAnomalyEnabled(*config, pindexPrev)) { | if (IsMagneticAnomalyEnabled(config, pindexPrev)) { | ||||
// If magnetic anomaly is enabled, we make sure transaction are | // If magnetic anomaly is enabled, we make sure transaction are | ||||
// canonically ordered. | // canonically ordered. | ||||
// FIXME: Use a zipped list. See T479 | // FIXME: Use a zipped list. See T479 | ||||
std::sort(std::begin(pblocktemplate->entries) + 1, | std::sort(std::begin(pblocktemplate->entries) + 1, | ||||
std::end(pblocktemplate->entries), | std::end(pblocktemplate->entries), | ||||
[](const CBlockTemplateEntry &a, const CBlockTemplateEntry &b) | [](const CBlockTemplateEntry &a, const CBlockTemplateEntry &b) | ||||
-> bool { return a.tx->GetId() < b.tx->GetId(); }); | -> bool { return a.tx->GetId() < b.tx->GetId(); }); | ||||
} | } | ||||
Show All 31 Lines | BlockAssembler::CreateNewBlock(const Config &config, | ||||
uint64_t nSerializeSize = | uint64_t nSerializeSize = | ||||
GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION); | GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION); | ||||
LogPrintf("CreateNewBlock(): total size: %u txs: %u fees: %ld sigops %d\n", | LogPrintf("CreateNewBlock(): total size: %u txs: %u fees: %ld sigops %d\n", | ||||
nSerializeSize, nBlockTx, nFees, nBlockSigOps); | nSerializeSize, nBlockTx, nFees, nBlockSigOps); | ||||
// Fill in header. | // Fill in header. | ||||
pblock->hashPrevBlock = pindexPrev->GetBlockHash(); | pblock->hashPrevBlock = pindexPrev->GetBlockHash(); | ||||
UpdateTime(pblock, *config, pindexPrev); | UpdateTime(pblock, config, pindexPrev); | ||||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, *config); | pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, config); | ||||
pblock->nNonce = 0; | pblock->nNonce = 0; | ||||
pblocktemplate->entries[0].txSigOps = GetSigOpCountWithoutP2SH( | pblocktemplate->entries[0].txSigOps = GetSigOpCountWithoutP2SH( | ||||
*pblocktemplate->entries[0].tx, STANDARD_SCRIPT_VERIFY_FLAGS); | *pblocktemplate->entries[0].tx, STANDARD_SCRIPT_VERIFY_FLAGS); | ||||
// Copy all the transactions into the block | // Copy all the transactions into the block | ||||
// FIXME: This should be removed as it is significant overhead. | // FIXME: This should be removed as it is significant overhead. | ||||
// See T479 | // See T479 | ||||
for (const CBlockTemplateEntry &tx : pblocktemplate->entries) { | for (const CBlockTemplateEntry &tx : pblocktemplate->entries) { | ||||
pblock->vtx.push_back(tx.tx); | pblock->vtx.push_back(tx.tx); | ||||
} | } | ||||
CValidationState state; | CValidationState state; | ||||
BlockValidationOptions validationOptions(false, false); | BlockValidationOptions validationOptions(false, false); | ||||
if (!TestBlockValidity(*config, state, *pblock, pindexPrev, | if (!TestBlockValidity(config, state, *pblock, pindexPrev, | ||||
validationOptions)) { | validationOptions)) { | ||||
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", | throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", | ||||
__func__, | __func__, | ||||
FormatStateMessage(state))); | FormatStateMessage(state))); | ||||
} | } | ||||
int64_t nTime2 = GetTimeMicros(); | int64_t nTime2 = GetTimeMicros(); | ||||
LogPrint(BCLog::BENCH, | LogPrint(BCLog::BENCH, | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/** | /** | ||||
* Perform transaction-level checks before adding to block: | * Perform transaction-level checks before adding to block: | ||||
* - Transaction finality (locktime) | * - Transaction finality (locktime) | ||||
* - Serialized size (in case -blockmaxsize is in use) | * - Serialized size (in case -blockmaxsize is in use) | ||||
*/ | */ | ||||
bool BlockAssembler::TestPackageTransactions( | bool BlockAssembler::TestPackageTransactions( | ||||
const CTxMemPool::setEntries &package) { | const Config &config, const CTxMemPool::setEntries &package) { | ||||
uint64_t nPotentialBlockSize = nBlockSize; | uint64_t nPotentialBlockSize = nBlockSize; | ||||
for (const CTxMemPool::txiter it : package) { | for (const CTxMemPool::txiter it : package) { | ||||
CValidationState state; | CValidationState state; | ||||
if (!ContextualCheckTransaction(*config, it->GetTx(), state, nHeight, | if (!ContextualCheckTransaction(config, it->GetTx(), state, nHeight, | ||||
nLockTimeCutoff, nMedianTimePast)) { | nLockTimeCutoff, nMedianTimePast)) { | ||||
return false; | return false; | ||||
} | } | ||||
uint64_t nTxSize = | uint64_t nTxSize = | ||||
::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION); | ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION); | ||||
if (nPotentialBlockSize + nTxSize >= nMaxGeneratedBlockSize) { | if (nPotentialBlockSize + nTxSize >= nMaxGeneratedBlockSize) { | ||||
return false; | return false; | ||||
} | } | ||||
nPotentialBlockSize += nTxSize; | nPotentialBlockSize += nTxSize; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
BlockAssembler::TestForBlockResult | BlockAssembler::TestForBlockResult | ||||
BlockAssembler::TestForBlock(CTxMemPool::txiter it) { | BlockAssembler::TestForBlock(const Config &config, CTxMemPool::txiter it) { | ||||
auto blockSizeWithTx = | auto blockSizeWithTx = | ||||
nBlockSize + | nBlockSize + | ||||
::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION); | ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION); | ||||
if (blockSizeWithTx >= nMaxGeneratedBlockSize) { | if (blockSizeWithTx >= nMaxGeneratedBlockSize) { | ||||
if (nBlockSize > nMaxGeneratedBlockSize - 100 || lastFewTxs > 50) { | if (nBlockSize > nMaxGeneratedBlockSize - 100 || lastFewTxs > 50) { | ||||
return TestForBlockResult::BlockFinished; | return TestForBlockResult::BlockFinished; | ||||
} | } | ||||
Show All 17 Lines | if (nBlockSigOps + it->GetSigOpCount() >= maxBlockSigOps) { | ||||
// Otherwise attempt to find another tx with fewer sigops to put in the | // Otherwise attempt to find another tx with fewer sigops to put in the | ||||
// block. | // block. | ||||
return TestForBlockResult::TXCantFit; | return TestForBlockResult::TXCantFit; | ||||
} | } | ||||
// Must check that lock times are still valid. This can be removed once MTP | // Must check that lock times are still valid. This can be removed once MTP | ||||
// is always enforced as long as reorgs keep the mempool consistent. | // is always enforced as long as reorgs keep the mempool consistent. | ||||
CValidationState state; | CValidationState state; | ||||
if (!ContextualCheckTransaction(*config, it->GetTx(), state, nHeight, | if (!ContextualCheckTransaction(config, it->GetTx(), state, nHeight, | ||||
nLockTimeCutoff, nMedianTimePast)) { | nLockTimeCutoff, nMedianTimePast)) { | ||||
return TestForBlockResult::TXCantFit; | return TestForBlockResult::TXCantFit; | ||||
} | } | ||||
return TestForBlockResult::TXFits; | return TestForBlockResult::TXFits; | ||||
} | } | ||||
void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) { | void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) { | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* addPackageTx includes transactions paying a fee by ensuring that | * addPackageTx includes transactions paying a fee by ensuring that | ||||
* the partial ordering of transactions is maintained. That is to say | * the partial ordering of transactions is maintained. That is to say | ||||
* children come after parents, despite having a potentially larger fee. | * children come after parents, despite having a potentially larger fee. | ||||
* @param[out] nPackagesSelected How many packages were selected | * @param[out] nPackagesSelected How many packages were selected | ||||
* @param[out] nDescendantsUpdated Number of descendant transactions updated | * @param[out] nDescendantsUpdated Number of descendant transactions updated | ||||
*/ | */ | ||||
void BlockAssembler::addPackageTxs(int &nPackagesSelected, | void BlockAssembler::addPackageTxs(const Config &config, int &nPackagesSelected, | ||||
int &nDescendantsUpdated) { | int &nDescendantsUpdated) { | ||||
// selection algorithm orders the mempool based on feerate of a | // selection algorithm orders the mempool based on feerate of a | ||||
// transaction including all unconfirmed ancestors. Since we don't remove | // transaction including all unconfirmed ancestors. Since we don't remove | ||||
// transactions from the mempool as we select them for block inclusion, we | // transactions from the mempool as we select them for block inclusion, we | ||||
// need an alternate method of updating the feerate of a transaction with | // need an alternate method of updating the feerate of a transaction with | ||||
// its not-yet-selected ancestors as we go. This is accomplished by | // its not-yet-selected ancestors as we go. This is accomplished by | ||||
// walking the in-mempool descendants of selected transactions and storing | // walking the in-mempool descendants of selected transactions and storing | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | while (mi != mempool->mapTx.get<ancestor_score>().end() || | ||||
std::string dummy; | std::string dummy; | ||||
mempool->CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, nNoLimit, | mempool->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(config, ancestors)) { | ||||
if (fUsingModified) { | if (fUsingModified) { | ||||
mapModifiedTx.get<ancestor_score>().erase(modit); | mapModifiedTx.get<ancestor_score>().erase(modit); | ||||
failedTx.insert(iter); | failedTx.insert(iter); | ||||
} | } | ||||
continue; | continue; | ||||
} | } | ||||
// This transaction will make it in; reset the failed counter. | // This transaction will make it in; reset the failed counter. | ||||
Show All 11 Lines | while (mi != mempool->mapTx.get<ancestor_score>().end() || | ||||
++nPackagesSelected; | ++nPackagesSelected; | ||||
// Update transactions that depend on each of these | // Update transactions that depend on each of these | ||||
nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx); | nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx); | ||||
} | } | ||||
} | } | ||||
void BlockAssembler::addPriorityTxs() { | void BlockAssembler::addPriorityTxs(const Config &config) { | ||||
// How much of the block should be dedicated to high-priority transactions, | // How much of the block should be dedicated to high-priority transactions, | ||||
// included regardless of the fees they pay. | // included regardless of the fees they pay. | ||||
if (config->GetBlockPriorityPercentage() == 0) { | if (config.GetBlockPriorityPercentage() == 0) { | ||||
return; | return; | ||||
} | } | ||||
uint64_t nBlockPrioritySize = | uint64_t nBlockPrioritySize = | ||||
nMaxGeneratedBlockSize * config->GetBlockPriorityPercentage() / 100; | nMaxGeneratedBlockSize * config.GetBlockPriorityPercentage() / 100; | ||||
// This vector will be sorted into a priority queue: | // This vector will be sorted into a priority queue: | ||||
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; | ||||
Show All 29 Lines | while (!vecPriority.empty()) { | ||||
// 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)) { | ||||
waitPriMap.insert(std::make_pair(iter, actualPriority)); | waitPriMap.insert(std::make_pair(iter, actualPriority)); | ||||
continue; | continue; | ||||
} | } | ||||
TestForBlockResult testResult = TestForBlock(iter); | TestForBlockResult testResult = TestForBlock(config, iter); | ||||
// Break if the block is completed | // Break if the block is completed | ||||
if (testResult == TestForBlockResult::BlockFinished) { | if (testResult == TestForBlockResult::BlockFinished) { | ||||
break; | break; | ||||
} | } | ||||
// If this tx does not fit in the block, skip to next transaction. | // If this tx does not fit in the block, skip to next transaction. | ||||
if (testResult != TestForBlockResult::TXFits) { | if (testResult != TestForBlockResult::TXFits) { | ||||
continue; | continue; | ||||
▲ Show 20 Lines • Show All 65 Lines • Show Last 20 Lines |