Page MenuHomePhabricator

miner.cpp
No OneTemporary

miner.cpp

// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <miner.h>
#include <amount.h>
#include <chain.h>
#include <chainparams.h>
#include <coins.h>
#include <config.h>
#include <consensus/activation.h>
#include <consensus/consensus.h>
#include <consensus/merkle.h>
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
#include <hash.h>
#include <net.h>
#include <policy/policy.h>
#include <pow.h>
#include <primitives/transaction.h>
#include <script/standard.h>
#include <timedata.h>
#include <txmempool.h>
#include <util.h>
#include <utilmoneystr.h>
#include <validation.h>
#include <validationinterface.h>
#include <algorithm>
#include <queue>
#include <utility>
// Unconfirmed transactions in the memory pool often depend on other
// transactions in the memory pool. When we select transactions from the
// pool, we select by highest priority or fee rate, so we might consider
// transactions that depend on transactions that aren't yet in the block.
uint64_t nLastBlockTx = 0;
uint64_t nLastBlockSize = 0;
int64_t UpdateTime(CBlockHeader *pblock, const Config &config,
const CBlockIndex *pindexPrev) {
int64_t nOldTime = pblock->nTime;
int64_t nNewTime =
std::max(pindexPrev->GetMedianTimePast() + 1, GetAdjustedTime());
if (nOldTime < nNewTime) {
pblock->nTime = nNewTime;
}
const Consensus::Params &consensusParams =
config.GetChainParams().GetConsensus();
// Updating time can change work required on testnet:
if (consensusParams.fPowAllowMinDifficultyBlocks) {
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, config);
}
return nNewTime - nOldTime;
}
static uint64_t ComputeMaxGeneratedBlockSize(const Config &config,
const CBlockIndex *pindexPrev) {
// Block resource limits
// If -blockmaxsize is not given, limit to DEFAULT_MAX_GENERATED_BLOCK_SIZE
// If only one is given, only restrict the specified resource.
// If both are given, restrict both.
uint64_t nMaxGeneratedBlockSize = DEFAULT_MAX_GENERATED_BLOCK_SIZE;
if (gArgs.IsArgSet("-blockmaxsize")) {
nMaxGeneratedBlockSize =
gArgs.GetArg("-blockmaxsize", DEFAULT_MAX_GENERATED_BLOCK_SIZE);
}
// Limit size to between 1K and MaxBlockSize-1K for sanity:
nMaxGeneratedBlockSize =
std::max(uint64_t(1000), std::min(config.GetMaxBlockSize() - 1000,
nMaxGeneratedBlockSize));
return nMaxGeneratedBlockSize;
}
BlockAssembler::BlockAssembler(const Config &_config, const CTxMemPool &mpool)
: config(&_config), mempool(&mpool) {
if (gArgs.IsArgSet("-blockmintxfee")) {
Amount n = Amount::zero();
ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n);
blockMinFeeRate = CFeeRate(n);
} else {
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB);
}
LOCK(cs_main);
nMaxGeneratedBlockSize =
ComputeMaxGeneratedBlockSize(*config, chainActive.Tip());
}
void BlockAssembler::resetBlock() {
inBlock.clear();
// Reserve space for coinbase tx.
nBlockSize = 1000;
nBlockSigOps = 100;
// These counters do not include coinbase tx.
nBlockTx = 0;
nFees = Amount::zero();
lastFewTxs = 0;
}
static const std::vector<uint8_t>
getExcessiveBlockSizeSig(const Config &config) {
std::string cbmsg = "/EB" + getSubVersionEB(config.GetMaxBlockSize()) + "/";
const char *cbcstr = cbmsg.c_str();
std::vector<uint8_t> vec(cbcstr, cbcstr + cbmsg.size());
return vec;
}
std::unique_ptr<CBlockTemplate>
BlockAssembler::CreateNewBlock(const CScript &scriptPubKeyIn) {
int64_t nTimeStart = GetTimeMicros();
resetBlock();
pblocktemplate.reset(new CBlockTemplate());
if (!pblocktemplate.get()) {
return nullptr;
}
// Pointer for convenience.
pblock = &pblocktemplate->block;
// Add dummy coinbase tx as first transaction. It is updated at the end.
pblocktemplate->entries.emplace_back(CTransactionRef(), -SATOSHI, 0, -1);
LOCK2(cs_main, mempool->cs);
CBlockIndex *pindexPrev = chainActive.Tip();
assert(pindexPrev != nullptr);
nHeight = pindexPrev->nHeight + 1;
const CChainParams &chainparams = config->GetChainParams();
pblock->nVersion =
ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
// -regtest only: allow overriding block.nVersion with
// -blockversion=N to test forking scenarios
if (chainparams.MineBlocksOnDemand()) {
pblock->nVersion = gArgs.GetArg("-blockversion", pblock->nVersion);
}
pblock->nTime = GetAdjustedTime();
nMaxGeneratedBlockSize = ComputeMaxGeneratedBlockSize(*config, pindexPrev);
nMedianTimePast = pindexPrev->GetMedianTimePast();
nLockTimeCutoff =
(STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
? nMedianTimePast
: pblock->GetBlockTime();
addPriorityTxs();
int nPackagesSelected = 0;
int nDescendantsUpdated = 0;
addPackageTxs(nPackagesSelected, nDescendantsUpdated);
if (IsMagneticAnomalyEnabled(*config, pindexPrev)) {
// If magnetic anomaly is enabled, we make sure transaction are
// canonically ordered.
// FIXME: Use a zipped list. See T479
std::sort(std::begin(pblocktemplate->entries) + 1,
std::end(pblocktemplate->entries),
[](const CBlockTemplateEntry &a, const CBlockTemplateEntry &b)
-> bool { return a.tx->GetId() < b.tx->GetId(); });
}
int64_t nTime1 = GetTimeMicros();
nLastBlockTx = nBlockTx;
nLastBlockSize = nBlockSize;
// Create coinbase transaction.
CMutableTransaction coinbaseTx;
coinbaseTx.vin.resize(1);
coinbaseTx.vin[0].prevout = COutPoint();
coinbaseTx.vout.resize(1);
coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
coinbaseTx.vout[0].nValue =
nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
// Make sure the coinbase is big enough.
uint64_t coinbaseSize =
::GetSerializeSize(coinbaseTx, SER_NETWORK, PROTOCOL_VERSION);
if (coinbaseSize < MIN_TX_SIZE) {
coinbaseTx.vin[0].scriptSig
<< std::vector<uint8_t>(MIN_TX_SIZE - coinbaseSize - 1);
}
pblocktemplate->entries[0].tx = MakeTransactionRef(coinbaseTx);
// Note: For the Coinbase, the template entry fields aside from the `tx` are
// not used anywhere at the time of writing. The mining rpc throws out the
// entire transaction in fact. The tx itself is only used during regtest
// mode.
pblocktemplate->entries[0].txFee = -1 * nFees;
uint64_t nSerializeSize =
GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION);
LogPrintf("CreateNewBlock(): total size: %u txs: %u fees: %ld sigops %d\n",
nSerializeSize, nBlockTx, nFees, nBlockSigOps);
// Fill in header.
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
UpdateTime(pblock, *config, pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, *config);
pblock->nNonce = 0;
pblocktemplate->entries[0].txSigOps = GetSigOpCountWithoutP2SH(
*pblocktemplate->entries[0].tx, STANDARD_SCRIPT_VERIFY_FLAGS);
// Copy all the transactions into the block
// FIXME: This should be removed as it is significant overhead.
// See T479
for (const CBlockTemplateEntry &tx : pblocktemplate->entries) {
pblock->vtx.push_back(tx.tx);
}
CValidationState state;
BlockValidationOptions validationOptions(false, false);
if (!TestBlockValidity(*config, state, *pblock, pindexPrev,
validationOptions)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s",
__func__,
FormatStateMessage(state)));
}
int64_t nTime2 = GetTimeMicros();
LogPrint(BCLog::BENCH,
"CreateNewBlock() packages: %.2fms (%d packages, %d updated "
"descendants), validity: %.2fms (total %.2fms)\n",
0.001 * (nTime1 - nTimeStart), nPackagesSelected,
nDescendantsUpdated, 0.001 * (nTime2 - nTime1),
0.001 * (nTime2 - nTimeStart));
return std::move(pblocktemplate);
}
bool BlockAssembler::isStillDependent(CTxMemPool::txiter iter) {
for (CTxMemPool::txiter parent : mempool->GetMemPoolParents(iter)) {
if (!inBlock.count(parent)) {
return true;
}
}
return false;
}
void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries &testSet) {
for (CTxMemPool::setEntries::iterator iit = testSet.begin();
iit != testSet.end();) {
// Only test txs not already in the block.
if (inBlock.count(*iit)) {
testSet.erase(iit++);
} else {
iit++;
}
}
}
bool BlockAssembler::TestPackage(uint64_t packageSize,
int64_t packageSigOps) const {
auto blockSizeWithPackage = nBlockSize + packageSize;
if (blockSizeWithPackage >= nMaxGeneratedBlockSize) {
return false;
}
if (nBlockSigOps + packageSigOps >=
GetMaxBlockSigOpsCount(blockSizeWithPackage)) {
return false;
}
return true;
}
/**
* Perform transaction-level checks before adding to block:
* - Transaction finality (locktime)
* - Serialized size (in case -blockmaxsize is in use)
*/
bool BlockAssembler::TestPackageTransactions(
const CTxMemPool::setEntries &package) {
uint64_t nPotentialBlockSize = nBlockSize;
for (const CTxMemPool::txiter it : package) {
CValidationState state;
if (!ContextualCheckTransaction(*config, it->GetTx(), state, nHeight,
nLockTimeCutoff, nMedianTimePast)) {
return false;
}
uint64_t nTxSize =
::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION);
if (nPotentialBlockSize + nTxSize >= nMaxGeneratedBlockSize) {
return false;
}
nPotentialBlockSize += nTxSize;
}
return true;
}
BlockAssembler::TestForBlockResult
BlockAssembler::TestForBlock(CTxMemPool::txiter it) {
auto blockSizeWithTx =
nBlockSize +
::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION);
if (blockSizeWithTx >= nMaxGeneratedBlockSize) {
if (nBlockSize > nMaxGeneratedBlockSize - 100 || lastFewTxs > 50) {
return TestForBlockResult::BlockFinished;
}
if (nBlockSize > nMaxGeneratedBlockSize - 1000) {
lastFewTxs++;
}
return TestForBlockResult::TXCantFit;
}
auto maxBlockSigOps = GetMaxBlockSigOpsCount(blockSizeWithTx);
if (nBlockSigOps + it->GetSigOpCount() >= maxBlockSigOps) {
// If the block has room for no more sig ops then flag that the block is
// finished.
// TODO: We should consider adding another transaction that isn't very
// dense in sigops instead of bailing out so easily.
if (nBlockSigOps > maxBlockSigOps - 2) {
return TestForBlockResult::BlockFinished;
}
// Otherwise attempt to find another tx with fewer sigops to put in the
// block.
return TestForBlockResult::TXCantFit;
}
// 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.
CValidationState state;
if (!ContextualCheckTransaction(*config, it->GetTx(), state, nHeight,
nLockTimeCutoff, nMedianTimePast)) {
return TestForBlockResult::TXCantFit;
}
return TestForBlockResult::TXFits;
}
void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) {
pblocktemplate->entries.emplace_back(iter->GetSharedTx(), iter->GetFee(),
iter->GetTxSize(),
iter->GetSigOpCount());
nBlockSize += iter->GetTxSize();
++nBlockTx;
nBlockSigOps += iter->GetSigOpCount();
nFees += iter->GetFee();
inBlock.insert(iter);
bool fPrintPriority =
gArgs.GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
if (fPrintPriority) {
double dPriority = iter->GetPriority(nHeight);
Amount dummy;
mempool->ApplyDeltas(iter->GetTx().GetId(), dPriority, dummy);
LogPrintf(
"priority %.1f fee %s txid %s\n", dPriority,
CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
iter->GetTx().GetId().ToString());
}
}
int BlockAssembler::UpdatePackagesForAdded(
const CTxMemPool::setEntries &alreadyAdded,
indexed_modified_transaction_set &mapModifiedTx) {
int nDescendantsUpdated = 0;
for (const CTxMemPool::txiter it : alreadyAdded) {
CTxMemPool::setEntries descendants;
mempool->CalculateDescendants(it, descendants);
// Insert all descendants (not yet in block) into the modified set.
for (CTxMemPool::txiter desc : descendants) {
if (alreadyAdded.count(desc)) {
continue;
}
++nDescendantsUpdated;
modtxiter mit = mapModifiedTx.find(desc);
if (mit == mapModifiedTx.end()) {
CTxMemPoolModifiedEntry modEntry(desc);
modEntry.nSizeWithAncestors -= it->GetTxSize();
modEntry.nModFeesWithAncestors -= it->GetModifiedFee();
modEntry.nSigOpCountWithAncestors -= it->GetSigOpCount();
mapModifiedTx.insert(modEntry);
} else {
mapModifiedTx.modify(mit, update_for_parent_inclusion(it));
}
}
}
return nDescendantsUpdated;
}
// Skip entries in mapTx that are already in a block or are present in
// mapModifiedTx (which implies that the mapTx ancestor state is stale due to
// 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
// 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
// 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.
bool BlockAssembler::SkipMapTxEntry(
CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx,
CTxMemPool::setEntries &failedTx) {
assert(it != mempool->mapTx.end());
return mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it);
}
void BlockAssembler::SortForBlock(
const CTxMemPool::setEntries &package, CTxMemPool::txiter entry,
std::vector<CTxMemPool::txiter> &sortedEntries) {
// 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
// sufficient to validly order the transactions for block inclusion.
sortedEntries.clear();
sortedEntries.insert(sortedEntries.begin(), package.begin(), package.end());
std::sort(sortedEntries.begin(), sortedEntries.end(),
CompareTxIterByAncestorCount());
}
/**
* addPackageTx includes transactions paying a fee by ensuring that
* the partial ordering of transactions is maintained. That is to say
* children come after parents, despite having a potentially larger fee.
* @param[out] nPackagesSelected How many packages were selected
* @param[out] nDescendantsUpdated Number of descendant transactions updated
*/
void BlockAssembler::addPackageTxs(int &nPackagesSelected,
int &nDescendantsUpdated) {
// selection algorithm orders the mempool based on feerate of a
// transaction including all unconfirmed ancestors. Since we don't remove
// transactions from the mempool as we select them for block inclusion, we
// need an alternate method of updating the feerate of a transaction with
// its not-yet-selected ancestors as we go. This is accomplished by
// walking the in-mempool descendants of selected transactions and storing
// a temporary modified state in mapModifiedTxs. Each time through the
// loop, we compare the best transaction in mapModifiedTxs with the next
// transaction in the mempool to decide what transaction package to work
// on next.
// mapModifiedTx will store sorted packages after they are modified because
// some of their txs are already in the block.
indexed_modified_transaction_set mapModifiedTx;
// Keep track of entries that failed inclusion, to avoid duplicate work.
CTxMemPool::setEntries failedTx;
// Start by adding all descendants of previously added txs to mapModifiedTx
// and modifying them for their already included ancestors.
UpdatePackagesForAdded(inBlock, mapModifiedTx);
CTxMemPool::indexed_transaction_set::index<ancestor_score>::type::iterator
mi = mempool->mapTx.get<ancestor_score>().begin();
CTxMemPool::txiter iter;
// 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
// mempool has a lot of entries.
const int64_t MAX_CONSECUTIVE_FAILURES = 1000;
int64_t nConsecutiveFailed = 0;
while (mi != mempool->mapTx.get<ancestor_score>().end() ||
!mapModifiedTx.empty()) {
// First try to find a new transaction in mapTx to evaluate.
if (mi != mempool->mapTx.get<ancestor_score>().end() &&
SkipMapTxEntry(mempool->mapTx.project<0>(mi), mapModifiedTx,
failedTx)) {
++mi;
continue;
}
// Now that mi is not stale, determine which transaction to evaluate:
// the next entry from mapTx, or the best from mapModifiedTx?
bool fUsingModified = false;
modtxscoreiter modit = mapModifiedTx.get<ancestor_score>().begin();
if (mi == mempool->mapTx.get<ancestor_score>().end()) {
// We're out of entries in mapTx; use the entry from mapModifiedTx
iter = modit->iter;
fUsingModified = true;
} else {
// Try to compare the mapTx entry to the mapModifiedTx entry.
iter = mempool->mapTx.project<0>(mi);
if (modit != mapModifiedTx.get<ancestor_score>().end() &&
CompareModifiedEntry()(*modit, CTxMemPoolModifiedEntry(iter))) {
// The best entry in mapModifiedTx has higher score than the one
// from mapTx. Switch which transaction (package) to consider
iter = modit->iter;
fUsingModified = true;
} else {
// Either no entry in mapModifiedTx, or it's worse than mapTx.
// Increment mi for the next loop iteration.
++mi;
}
}
// We skip mapTx entries that are inBlock, and mapModifiedTx shouldn't
// contain anything that is inBlock.
assert(!inBlock.count(iter));
uint64_t packageSize = iter->GetSizeWithAncestors();
Amount packageFees = iter->GetModFeesWithAncestors();
int64_t packageSigOps = iter->GetSigOpCountWithAncestors();
if (fUsingModified) {
packageSize = modit->nSizeWithAncestors;
packageFees = modit->nModFeesWithAncestors;
packageSigOps = modit->nSigOpCountWithAncestors;
}
if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
// Everything else we might consider has a lower fee rate
return;
}
if (!TestPackage(packageSize, packageSigOps)) {
if (fUsingModified) {
// Since we always look at the best entry in mapModifiedTx, we
// must erase failed entries so that we can consider the next
// best entry on the next loop iteration
mapModifiedTx.get<ancestor_score>().erase(modit);
failedTx.insert(iter);
}
++nConsecutiveFailed;
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES &&
nBlockSize > nMaxGeneratedBlockSize - 1000) {
// Give up if we're close to full and haven't succeeded in a
// while.
break;
}
continue;
}
CTxMemPool::setEntries ancestors;
uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
std::string dummy;
mempool->CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, nNoLimit,
nNoLimit, nNoLimit, dummy, false);
onlyUnconfirmed(ancestors);
ancestors.insert(iter);
// Test if all tx's are Final.
if (!TestPackageTransactions(ancestors)) {
if (fUsingModified) {
mapModifiedTx.get<ancestor_score>().erase(modit);
failedTx.insert(iter);
}
continue;
}
// This transaction will make it in; reset the failed counter.
nConsecutiveFailed = 0;
// Package can be added. Sort the entries in a valid order.
std::vector<CTxMemPool::txiter> sortedEntries;
SortForBlock(ancestors, iter, sortedEntries);
for (auto &entry : sortedEntries) {
AddToBlock(entry);
// Erase from the modified set, if present
mapModifiedTx.erase(entry);
}
++nPackagesSelected;
// Update transactions that depend on each of these
nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx);
}
}
void BlockAssembler::addPriorityTxs() {
// How much of the block should be dedicated to high-priority transactions,
// included regardless of the fees they pay.
if (config->GetBlockPriorityPercentage() == 0) {
return;
}
uint64_t nBlockPrioritySize =
nMaxGeneratedBlockSize * config->GetBlockPriorityPercentage() / 100;
// This vector will be sorted into a priority queue:
std::vector<TxCoinAgePriority> vecPriority;
TxCoinAgePriorityCompare pricomparer;
std::map<CTxMemPool::txiter, double, CTxMemPool::CompareIteratorByHash>
waitPriMap;
typedef std::map<CTxMemPool::txiter, double,
CTxMemPool::CompareIteratorByHash>::iterator waitPriIter;
double actualPriority = -1;
vecPriority.reserve(mempool->mapTx.size());
for (CTxMemPool::indexed_transaction_set::iterator mi =
mempool->mapTx.begin();
mi != mempool->mapTx.end(); ++mi) {
double dPriority = mi->GetPriority(nHeight);
Amount dummy;
mempool->ApplyDeltas(mi->GetTx().GetId(), dPriority, dummy);
vecPriority.push_back(TxCoinAgePriority(dPriority, mi));
}
std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
CTxMemPool::txiter iter;
// Add a tx from priority queue to fill the part of block reserved to
// priority transactions.
while (!vecPriority.empty()) {
iter = vecPriority.front().second;
actualPriority = vecPriority.front().first;
std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
vecPriority.pop_back();
// If tx already in block, skip.
if (inBlock.count(iter)) {
// Shouldn't happen for priority txs.
assert(false);
continue;
}
// If tx is dependent on other mempool txs which haven't yet been
// included then put it in the waitSet.
if (isStillDependent(iter)) {
waitPriMap.insert(std::make_pair(iter, actualPriority));
continue;
}
TestForBlockResult testResult = TestForBlock(iter);
// Break if the block is completed
if (testResult == TestForBlockResult::BlockFinished) {
break;
}
// If this tx does not fit in the block, skip to next transaction.
if (testResult != TestForBlockResult::TXFits) {
continue;
}
AddToBlock(iter);
// If now that this txs is added we've surpassed our desired priority
// size, then we're done adding priority transactions.
if (nBlockSize >= nBlockPrioritySize) {
break;
}
// if we have dropped below the AllowFreeThreshold, then we're done
// adding priority transactions.
if (!AllowFree(actualPriority)) {
break;
}
// This tx was successfully added, so add transactions that depend
// on this one to the priority queue to try again.
for (CTxMemPool::txiter child : mempool->GetMemPoolChildren(iter)) {
waitPriIter wpiter = waitPriMap.find(child);
if (wpiter == waitPriMap.end()) {
continue;
}
vecPriority.push_back(TxCoinAgePriority(wpiter->second, child));
std::push_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
waitPriMap.erase(wpiter);
}
}
}
void IncrementExtraNonce(const Config &config, CBlock *pblock,
const CBlockIndex *pindexPrev,
unsigned int &nExtraNonce) {
// Update nExtraNonce
static uint256 hashPrevBlock;
if (hashPrevBlock != pblock->hashPrevBlock) {
nExtraNonce = 0;
hashPrevBlock = pblock->hashPrevBlock;
}
++nExtraNonce;
// Height first in coinbase required for block.version=2
unsigned int nHeight = pindexPrev->nHeight + 1;
CMutableTransaction txCoinbase(*pblock->vtx[0]);
txCoinbase.vin[0].scriptSig =
(CScript() << nHeight << CScriptNum(nExtraNonce)
<< getExcessiveBlockSizeSig(config)) +
COINBASE_FLAGS;
// Make sure the coinbase is big enough.
uint64_t coinbaseSize =
::GetSerializeSize(txCoinbase, SER_NETWORK, PROTOCOL_VERSION);
if (coinbaseSize < MIN_TX_SIZE) {
txCoinbase.vin[0].scriptSig
<< std::vector<uint8_t>(MIN_TX_SIZE - coinbaseSize - 1);
}
assert(txCoinbase.vin[0].scriptSig.size() <= MAX_COINBASE_SCRIPTSIG_SIZE);
assert(::GetSerializeSize(txCoinbase, SER_NETWORK, PROTOCOL_VERSION) >=
MIN_TX_SIZE);
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
}

File Metadata

Mime Type
text/x-c
Expires
Fri, Feb 7, 15:57 (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5082651
Default Alt Text
miner.cpp (26 KB)

Event Timeline