aboutsummaryrefslogtreecommitdiff
path: root/src/miner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/miner.cpp')
-rw-r--r--src/miner.cpp999
1 files changed, 529 insertions, 470 deletions
diff --git a/src/miner.cpp b/src/miner.cpp
index 9552cf7cc..55a90b86f 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -1,32 +1,36 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// 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 "consensus/consensus.h"
+#include "consensus/merkle.h"
#include "consensus/validation.h"
-#include "crypto/scrypt.h"
#include "dogecoin.h"
#include "hash.h"
-#include "main.h"
+#include "validation.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"
-#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
-#endif
+#include "validationinterface.h"
+#include <algorithm>
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
-
-using namespace std;
+#include <queue>
+#include <utility>
//////////////////////////////////////////////////////////////////////////////
//
@@ -38,557 +42,612 @@ using namespace std;
// 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.
-// The COrphan class keeps track of these 'temporary orphans' while
-// CreateBlock is figuring out which transactions to include.
-//
-class COrphan
-{
-public:
- const CTransaction* ptx;
- set<uint256> setDependsOn;
- CFeeRate feeRate;
- double dPriority;
-
- COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0)
- {
- }
-};
uint64_t nLastBlockTx = 0;
uint64_t nLastBlockSize = 0;
+uint64_t nLastBlockWeight = 0;
-// We want to sort transactions by priority and fee rate, so:
-typedef boost::tuple<double, CFeeRate, const CTransaction*> TxPriority;
-class TxPriorityCompare
+class ScoreCompare
{
- bool byFee;
-
public:
- TxPriorityCompare(bool _byFee) : byFee(_byFee) { }
+ ScoreCompare() {}
- bool operator()(const TxPriority& a, const TxPriority& b)
+ bool operator()(const CTxMemPool::txiter a, const CTxMemPool::txiter b)
{
- if (byFee)
- {
- if (a.get<1>() == b.get<1>())
- return a.get<0>() < b.get<0>();
- return a.get<1>() < b.get<1>();
- }
- else
- {
- if (a.get<0>() == b.get<0>())
- return a.get<1>() < b.get<1>();
- return a.get<0>() < b.get<0>();
- }
+ return CompareTxMemPoolEntryByScore()(*b,*a); // Convert to less than
}
};
-void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
+int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
- pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+ int64_t nOldTime = pblock->nTime;
+ int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+
+ if (nOldTime < nNewTime)
+ pblock->nTime = nNewTime;
// Updating time can change work required on testnet:
if (consensusParams.fPowAllowMinDifficultyBlocks)
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
+
+ return nNewTime - nOldTime;
}
-CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
+BlockAssembler::BlockAssembler(const CChainParams& _chainparams)
+ : chainparams(_chainparams)
{
- const CChainParams& chainparams = Params();
- // Create new block
- auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
- if(!pblocktemplate.get())
- return NULL;
- CBlock *pblock = &pblocktemplate->block; // pointer for convenience
+ // Block resource limits
+ // If neither -blockmaxsize or -blockmaxweight is given, limit to DEFAULT_BLOCK_MAX_*
+ // If only one is given, only restrict the specified resource.
+ // If both are given, restrict both.
+ nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
+ nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
+ bool fWeightSet = false;
+ if (IsArgSet("-blockmaxweight")) {
+ nBlockMaxWeight = GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
+ nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
+ fWeightSet = true;
+ }
+ if (IsArgSet("-blockmaxsize")) {
+ nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
+ if (!fWeightSet) {
+ nBlockMaxWeight = nBlockMaxSize * WITNESS_SCALE_FACTOR;
+ }
+ }
+ if (IsArgSet("-blockmintxfee")) {
+ CAmount n = 0;
+ ParseMoney(GetArg("-blockmintxfee", ""), n);
+ blockMinFeeRate = CFeeRate(n);
+ } else {
+ blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
+ }
- /* Initialise the block version. */
- pblock->nVersion = CBlockHeader::CURRENT_VERSION;
- pblock->nVersion.SetChainId(chainparams.GetConsensus(0).nAuxpowChainId);
+ // Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity:
+ nBlockMaxWeight = std::max((unsigned int)4000, std::min((unsigned int)(MAX_BLOCK_WEIGHT-4000), nBlockMaxWeight));
+ // Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity:
+ nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SERIALIZED_SIZE-1000), nBlockMaxSize));
+ // Whether we need to account for byte usage (in addition to weight usage)
+ fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE-1000);
+}
- // -regtest only: allow overriding block.nVersion with
- // -blockversion=N to test forking scenarios
- if (Params().MineBlocksOnDemand())
- pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
+void BlockAssembler::resetBlock()
+{
+ inBlock.clear();
- // Create coinbase tx
- CMutableTransaction txNew;
- txNew.vin.resize(1);
- txNew.vin[0].prevout.SetNull();
- txNew.vout.resize(1);
- txNew.vout[0].scriptPubKey = scriptPubKeyIn;
+ // Reserve space for coinbase tx
+ nBlockSize = 1000;
+ nBlockWeight = 4000;
+ nBlockSigOpsCost = 400;
+ fIncludeWitness = false;
- // Add dummy coinbase tx as first transaction
- pblock->vtx.push_back(CTransaction());
- pblocktemplate->vTxFees.push_back(-1); // updated at end
- pblocktemplate->vTxSigOps.push_back(-1); // updated at end
+ // These counters do not include coinbase tx
+ nBlockTx = 0;
+ nFees = 0;
- // Largest block you're willing to create:
- unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
- // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity:
- nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize));
+ lastFewTxs = 0;
+ blockFinished = false;
+}
- // How much of the block should be dedicated to high-priority transactions,
- // included regardless of the fees they pay
- unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE);
- nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize);
+std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx)
+{
+ int64_t nTimeStart = GetTimeMicros();
- // Minimum block size you want to create; block will be filled with free transactions
- // until there are no more or the block reaches this size:
- unsigned int nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE);
- nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize);
+ resetBlock();
- // Collect memory pool transactions into the block
- CAmount nFees = 0;
+ pblocktemplate.reset(new CBlockTemplate());
- {
- LOCK2(cs_main, mempool.cs);
- CBlockIndex* pindexPrev = chainActive.Tip();
- const int nHeight = pindexPrev->nHeight + 1;
- pblock->nTime = GetAdjustedTime();
- CCoinsViewCache view(pcoinsTip);
-
- // Priority order to process transactions
- list<COrphan> vOrphan; // list memory doesn't move
- map<uint256, vector<COrphan*> > mapDependers;
- bool fPrintPriority = GetBoolArg("-printpriority", false);
-
- // This vector will be sorted into a priority queue:
- vector<TxPriority> vecPriority;
- vecPriority.reserve(mempool.mapTx.size());
- for (map<uint256, CTxMemPoolEntry>::iterator mi = mempool.mapTx.begin();
- mi != mempool.mapTx.end(); ++mi)
- {
- const CTransaction& tx = mi->second.GetTx();
- if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, pblock->nTime))
- continue;
+ if(!pblocktemplate.get())
+ return nullptr;
+ pblock = &pblocktemplate->block; // pointer for convenience
- COrphan* porphan = NULL;
- double dPriority = 0;
- CAmount nTotalIn = 0;
- bool fMissingInputs = false;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- // Read prev transaction
- if (!view.HaveCoins(txin.prevout.hash))
- {
- // This should never happen; all transactions in the memory
- // pool should connect to either transactions in the chain
- // or other transactions in the memory pool.
- if (!mempool.mapTx.count(txin.prevout.hash))
- {
- LogPrintf("ERROR: mempool transaction missing input\n");
- if (fDebug) assert("mempool transaction missing input" == 0);
- fMissingInputs = true;
- if (porphan)
- vOrphan.pop_back();
- break;
- }
-
- // Has to wait for dependencies
- if (!porphan)
- {
- // Use list for automatic deletion
- vOrphan.push_back(COrphan(&tx));
- porphan = &vOrphan.back();
- }
- mapDependers[txin.prevout.hash].push_back(porphan);
- porphan->setDependsOn.insert(txin.prevout.hash);
- nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue;
- continue;
- }
- const CCoins* coins = view.AccessCoins(txin.prevout.hash);
- assert(coins);
+ // Add dummy coinbase tx as first transaction
+ pblock->vtx.emplace_back();
+ pblocktemplate->vTxFees.push_back(-1); // updated at end
+ pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end
+
+ LOCK2(cs_main, mempool.cs);
+ CBlockIndex* pindexPrev = chainActive.Tip();
+ nHeight = pindexPrev->nHeight + 1;
+
+ const Consensus::Params& consensus = chainparams.GetConsensus(nHeight);
+ const int32_t nChainId = consensus.nAuxpowChainId;
+ // FIXME: Active version bits after the always-auxpow fork!
+ // const int32_t nVersion = ComputeBlockVersion(pindexPrev, consensus);
+ const int32_t nVersion = VERSIONBITS_LAST_OLD_BLOCK_VERSION;
+ pblock->SetBaseVersion(nVersion, nChainId);
+ // -regtest only: allow overriding block.nVersion with
+ // -blockversion=N to test forking scenarios
+ if (chainparams.MineBlocksOnDemand())
+ pblock->SetBaseVersion(GetArg("-blockversion", pblock->GetBaseVersion()), nChainId);
+
+ pblock->nTime = GetAdjustedTime();
+ const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
+
+ nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
+ ? nMedianTimePast
+ : pblock->GetBlockTime();
+
+ // Decide whether to include witness transactions
+ // This is only needed in case the witness softfork activation is reverted
+ // (which would require a very deep reorganization) or when
+ // -promiscuousmempoolflags is used.
+ // TODO: replace this with a call to main to assess validity of a mempool
+ // transaction (which in most cases can be a no-op).
+ fIncludeWitness = IsWitnessEnabled(pindexPrev, consensus) && fMineWitnessTx;
+
+ addPriorityTxs();
+ int nPackagesSelected = 0;
+ int nDescendantsUpdated = 0;
+ addPackageTxs(nPackagesSelected, nDescendantsUpdated);
+
+ int64_t nTime1 = GetTimeMicros();
+
+ nLastBlockTx = nBlockTx;
+ nLastBlockSize = nBlockSize;
+ nLastBlockWeight = nBlockWeight;
+
+ // Create coinbase transaction.
+ CMutableTransaction coinbaseTx;
+ coinbaseTx.vin.resize(1);
+ coinbaseTx.vin[0].prevout.SetNull();
+ coinbaseTx.vout.resize(1);
+ coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
+ coinbaseTx.vout[0].nValue = nFees + GetDogecoinBlockSubsidy(nHeight, consensus, pindexPrev->GetBlockHash(
+));
+ coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
+ pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
+ pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, consensus);
+ pblocktemplate->vTxFees[0] = -nFees;
+
+ uint64_t nSerializeSize = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION);
+ LogPrintf("CreateNewBlock(): total size: %u block weight: %u txs: %u fees: %ld sigops %d\n", nSerializeSize, GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);
+
+ // Fill in header
+ pblock->hashPrevBlock = pindexPrev->GetBlockHash();
+ UpdateTime(pblock, consensus, pindexPrev);
+ pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensus);
+ pblock->nNonce = 0;
+ pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
- CAmount nValueIn = coins->vout[txin.prevout.n].nValue;
- nTotalIn += nValueIn;
+ CValidationState state;
+ if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) {
+ throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
+ }
+ int64_t nTime2 = GetTimeMicros();
- int nConf = nHeight - coins->nHeight;
+ LogPrint("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));
- dPriority += (double)nValueIn * nConf;
- }
- if (fMissingInputs) continue;
+ return std::move(pblocktemplate);
+}
- // Priority is sum(valuein * age) / modified_txsize
- unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
- dPriority = tx.ComputePriority(dPriority, nTxSize);
+bool BlockAssembler::isStillDependent(CTxMemPool::txiter iter)
+{
+ BOOST_FOREACH(CTxMemPool::txiter parent, mempool.GetMemPoolParents(iter))
+ {
+ if (!inBlock.count(parent)) {
+ return true;
+ }
+ }
+ return false;
+}
- uint256 hash = tx.GetHash();
- mempool.ApplyDeltas(hash, dPriority, nTotalIn);
+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++;
+ }
+ }
+}
- CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize);
+bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost)
+{
+ // TODO: switch to weight-based accounting for packages instead of vsize-based accounting.
+ if (nBlockWeight + WITNESS_SCALE_FACTOR * packageSize >= nBlockMaxWeight)
+ return false;
+ if (nBlockSigOpsCost + packageSigOpsCost >= MAX_BLOCK_SIGOPS_COST)
+ return false;
+ return true;
+}
- if (porphan)
- {
- porphan->dPriority = dPriority;
- porphan->feeRate = feeRate;
+// Perform transaction-level checks before adding to block:
+// - transaction finality (locktime)
+// - premature witness (in case segwit transactions are added to mempool before
+// segwit activation)
+// - serialized size (in case -blockmaxsize is in use)
+bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package)
+{
+ uint64_t nPotentialBlockSize = nBlockSize; // only used with fNeedSizeAccounting
+ BOOST_FOREACH (const CTxMemPool::txiter it, package) {
+ if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff))
+ return false;
+ if (!fIncludeWitness && it->GetTx().HasWitness())
+ return false;
+ if (fNeedSizeAccounting) {
+ uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION);
+ if (nPotentialBlockSize + nTxSize >= nBlockMaxSize) {
+ return false;
}
- else
- vecPriority.push_back(TxPriority(dPriority, feeRate, &mi->second.GetTx()));
+ nPotentialBlockSize += nTxSize;
}
+ }
+ return true;
+}
- // Collect transactions into block
- uint64_t nBlockSize = 1000;
- uint64_t nBlockTx = 0;
- int nBlockSigOps = 100;
- bool fSortedByFee = (nBlockPrioritySize <= 0);
+bool BlockAssembler::TestForBlock(CTxMemPool::txiter iter)
+{
+ if (nBlockWeight + iter->GetTxWeight() >= nBlockMaxWeight) {
+ // If the block is so close to full that no more txs will fit
+ // or if we've tried more than 50 times to fill remaining space
+ // then flag that the block is finished
+ if (nBlockWeight > nBlockMaxWeight - 400 || lastFewTxs > 50) {
+ blockFinished = true;
+ return false;
+ }
+ // Once we're within 4000 weight of a full block, only look at 50 more txs
+ // to try to fill the remaining space.
+ if (nBlockWeight > nBlockMaxWeight - 4000) {
+ lastFewTxs++;
+ }
+ return false;
+ }
- TxPriorityCompare comparer(fSortedByFee);
- std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
+ if (fNeedSizeAccounting) {
+ if (nBlockSize + ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION) >= nBlockMaxSize) {
+ if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) {
+ blockFinished = true;
+ return false;
+ }
+ if (nBlockSize > nBlockMaxSize - 1000) {
+ lastFewTxs++;
+ }
+ return false;
+ }
+ }
- while (!vecPriority.empty())
- {
- // Take highest priority transaction off the priority queue:
- double dPriority = vecPriority.front().get<0>();
- CFeeRate feeRate = vecPriority.front().get<1>();
- const CTransaction& tx = *(vecPriority.front().get<2>());
+ if (nBlockSigOpsCost + iter->GetSigOpCost() >= MAX_BLOCK_SIGOPS_COST) {
+ // If the block has room for no more sig ops then
+ // flag that the block is finished
+ if (nBlockSigOpsCost > MAX_BLOCK_SIGOPS_COST - 8) {
+ blockFinished = true;
+ return false;
+ }
+ // Otherwise attempt to find another tx with fewer sigops
+ // to put in the block.
+ return false;
+ }
- std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
- vecPriority.pop_back();
+ // 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.
+ if (!IsFinalTx(iter->GetTx(), nHeight, nLockTimeCutoff))
+ return false;
- // Size limits
- unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
- if (nBlockSize + nTxSize >= nBlockMaxSize)
- continue;
+ return true;
+}
- // Legacy limits on sigOps:
- unsigned int nTxSigOps = GetLegacySigOpCount(tx);
- if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
- continue;
+void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
+{
+ pblock->vtx.emplace_back(iter->GetSharedTx());
+ pblocktemplate->vTxFees.push_back(iter->GetFee());
+ pblocktemplate->vTxSigOpsCost.push_back(iter->GetSigOpCost());
+ if (fNeedSizeAccounting) {
+ nBlockSize += ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION);
+ }
+ nBlockWeight += iter->GetTxWeight();
+ ++nBlockTx;
+ nBlockSigOpsCost += iter->GetSigOpCost();
+ nFees += iter->GetFee();
+ inBlock.insert(iter);
+
+ bool fPrintPriority = GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
+ if (fPrintPriority) {
+ double dPriority = iter->GetPriority(nHeight);
+ CAmount dummy;
+ mempool.ApplyDeltas(iter->GetTx().GetHash(), dPriority, dummy);
+ LogPrintf("priority %.1f fee %s txid %s\n",
+ dPriority,
+ CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
+ iter->GetTx().GetHash().ToString());
+ }
+}
- // Skip free transactions if we're past the minimum block size:
- const uint256& hash = tx.GetHash();
- double dPriorityDelta = 0;
- CAmount nFeeDelta = 0;
- mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
- if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
+int BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded,
+ indexed_modified_transaction_set &mapModifiedTx)
+{
+ int nDescendantsUpdated = 0;
+ BOOST_FOREACH(const CTxMemPool::txiter it, alreadyAdded) {
+ CTxMemPool::setEntries descendants;
+ mempool.CalculateDescendants(it, descendants);
+ // Insert all descendants (not yet in block) into the modified set
+ BOOST_FOREACH(CTxMemPool::txiter desc, descendants) {
+ if (alreadyAdded.count(desc))
continue;
-
- // Prioritise by fee once past the priority size or we run out of high-priority
- // transactions:
- if (!fSortedByFee &&
- ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority)))
- {
- fSortedByFee = true;
- comparer = TxPriorityCompare(fSortedByFee);
- std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
+ ++nDescendantsUpdated;
+ modtxiter mit = mapModifiedTx.find(desc);
+ if (mit == mapModifiedTx.end()) {
+ CTxMemPoolModifiedEntry modEntry(desc);
+ modEntry.nSizeWithAncestors -= it->GetTxSize();
+ modEntry.nModFeesWithAncestors -= it->GetModifiedFee();
+ modEntry.nSigOpCostWithAncestors -= it->GetSigOpCost();
+ mapModifiedTx.insert(modEntry);
+ } else {
+ mapModifiedTx.modify(mit, update_for_parent_inclusion(it));
}
+ }
+ }
+ return nDescendantsUpdated;
+}
- if (!view.HaveInputs(tx))
- continue;
+// 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());
+ if (mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it))
+ return true;
+ return false;
+}
- CAmount nTxFees = view.GetValueIn(tx)-tx.GetValueOut();
+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());
+}
- nTxSigOps += GetP2SHSigOpCount(tx, view);
- if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
- continue;
+// This transaction 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.
+void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated)
+{
+ // 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;
+ }
- // Note that flags: we don't want to set mempool/IsStandard()
- // policy here, but we still have to ensure that the block we
- // create only contains transactions that are valid in new blocks.
- CValidationState state;
- if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true))
- 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;
+ }
+ }
- UpdateCoins(tx, state, view, nHeight);
+ // 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();
+ CAmount packageFees = iter->GetModFeesWithAncestors();
+ int64_t packageSigOpsCost = iter->GetSigOpCostWithAncestors();
+ if (fUsingModified) {
+ packageSize = modit->nSizeWithAncestors;
+ packageFees = modit->nModFeesWithAncestors;
+ packageSigOpsCost = modit->nSigOpCostWithAncestors;
+ }
- // Added
- pblock->vtx.push_back(tx);
- pblocktemplate->vTxFees.push_back(nTxFees);
- pblocktemplate->vTxSigOps.push_back(nTxSigOps);
- nBlockSize += nTxSize;
- ++nBlockTx;
- nBlockSigOps += nTxSigOps;
- nFees += nTxFees;
+ if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
+ // Everything else we might consider has a lower fee rate
+ return;
+ }
- if (fPrintPriority)
- {
- LogPrintf("priority %.1f fee %s txid %s\n",
- dPriority, feeRate.ToString(), tx.GetHash().ToString());
+ if (!TestPackage(packageSize, packageSigOpsCost)) {
+ 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);
}
- // Add transactions that depend on this one to the priority queue
- if (mapDependers.count(hash))
- {
- BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
- {
- if (!porphan->setDependsOn.empty())
- {
- porphan->setDependsOn.erase(hash);
- if (porphan->setDependsOn.empty())
- {
- vecPriority.push_back(TxPriority(porphan->dPriority, porphan->feeRate, porphan->ptx));
- std::push_heap(vecPriority.begin(), vecPriority.end(), comparer);
- }
- }
- }
+ ++nConsecutiveFailed;
+
+ if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight >
+ nBlockMaxWeight - 4000) {
+ // Give up if we're close to full and haven't succeeded in a while
+ break;
}
+ continue;
}
- nLastBlockTx = nBlockTx;
- nLastBlockSize = nBlockSize;
- LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize);
-
- // Compute final coinbase transaction.
- const Consensus::Params &consensus = chainparams.GetConsensus(nHeight);
- txNew.vout[0].nValue = nFees + GetDogecoinBlockSubsidy(nHeight, consensus, pindexPrev->GetBlockHash());
- txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
- pblock->vtx[0] = txNew;
- pblocktemplate->vTxFees[0] = -nFees;
-
- // Fill in header
- pblock->hashPrevBlock = pindexPrev->GetBlockHash();
- UpdateTime(pblock, consensus, pindexPrev);
- pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensus);
- pblock->nNonce = 0;
- pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
-
- CValidationState state;
- if (!TestBlockValidity(state, *pblock, pindexPrev, false, false))
- throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed");
- }
+ 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);
- return pblocktemplate.release();
-}
+ onlyUnconfirmed(ancestors);
+ ancestors.insert(iter);
-void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
-{
- // Update nExtraNonce
- static uint256 hashPrevBlock;
- if (hashPrevBlock != pblock->hashPrevBlock)
- {
- nExtraNonce = 0;
- hashPrevBlock = pblock->hashPrevBlock;
- }
- ++nExtraNonce;
- unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
- CMutableTransaction txCoinbase(pblock->vtx[0]);
- txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
- assert(txCoinbase.vin[0].scriptSig.size() <= 100);
+ // Test if all tx's are Final
+ if (!TestPackageTransactions(ancestors)) {
+ if (fUsingModified) {
+ mapModifiedTx.get<ancestor_score>().erase(modit);
+ failedTx.insert(iter);
+ }
+ continue;
+ }
- pblock->vtx[0] = txCoinbase;
- pblock->hashMerkleRoot = pblock->BuildMerkleTree();
-}
+ // This transaction will make it in; reset the failed counter.
+ nConsecutiveFailed = 0;
-#ifdef ENABLE_WALLET
-//////////////////////////////////////////////////////////////////////////////
-//
-// Internal miner
-//
-
-//
-// ScanHash scans nonces looking for a hash with at least some zero bits.
-// The nonce is usually preserved between calls, but periodically or if the
-// nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at
-// zero.
-//
-bool static ScanHash(CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash, char *pscratchpad)
-{
- // Write the first 76 bytes of the block header to a double-SHA256 state.
- //CHash256 hasher;
- //CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
- //ss << *pblock;
- //assert(ss.size() == 80);
- //hasher.Write((unsigned char*)&ss[0], 76);
-
- while (true) {
- nNonce++;
-
- // Write the last 4 bytes of the block header (the nonce) to a copy of
- // the double-SHA256 state, and compute the result.
- pblock->nNonce = nNonce;
- scrypt_1024_1_1_256_sp(BEGIN(pblock->nVersion), (char*)phash, pscratchpad);
-
- // Return the nonce if the hash has at least some zero bits,
- // caller will check if it has enough to reach the target
- // TODO: I don't like having this hard-coded, it's too coarse for regtest, too fine for main
- if (((uint8_t*)phash)[31] == 0)
- return true;
+ // Package can be added. Sort the entries in a valid order.
+ std::vector<CTxMemPool::txiter> sortedEntries;
+ SortForBlock(ancestors, iter, sortedEntries);
- // If nothing found after trying for a while, return -1
- if ((nNonce & 0x1fff) == 0)
- return false;
- if ((nNonce & 0x01ff) == 0)
- boost::this_thread::interruption_point();
- }
-}
+ for (size_t i=0; i<sortedEntries.size(); ++i) {
+ AddToBlock(sortedEntries[i]);
+ // Erase from the modified set, if present
+ mapModifiedTx.erase(sortedEntries[i]);
+ }
-CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey)
-{
- CPubKey pubkey;
- if (!reservekey.GetReservedKey(pubkey))
- return NULL;
+ ++nPackagesSelected;
- CScript scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
- return CreateNewBlock(scriptPubKey);
+ // Update transactions that depend on each of these
+ nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx);
+ }
}
-static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
+void BlockAssembler::addPriorityTxs()
{
- LogPrintf("%s\n", pblock->ToString());
- LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue));
+ // How much of the block should be dedicated to high-priority transactions,
+ // included regardless of the fees they pay
+ unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE);
+ nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize);
- // Found a solution
- {
- LOCK(cs_main);
- if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash())
- return error("DogecoinMiner: generated block is stale");
+ if (nBlockPrioritySize == 0) {
+ return;
}
- // Remove key from key pool
- reservekey.KeepKey();
+ bool fSizeAccounting = fNeedSizeAccounting;
+ fNeedSizeAccounting = true;
+
+ // 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;
- // Track how many getdata requests this block gets
+ vecPriority.reserve(mempool.mapTx.size());
+ for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
+ mi != mempool.mapTx.end(); ++mi)
{
- LOCK(wallet.cs_wallet);
- wallet.mapRequestCount[pblock->GetHash()] = 0;
+ double dPriority = mi->GetPriority(nHeight);
+ CAmount dummy;
+ mempool.ApplyDeltas(mi->GetTx().GetHash(), dPriority, dummy);
+ vecPriority.push_back(TxCoinAgePriority(dPriority, mi));
}
+ std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
+
+ CTxMemPool::txiter iter;
+ while (!vecPriority.empty() && !blockFinished) { // add a tx from priority queue to fill the blockprioritysize
+ 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)) {
+ assert(false); // shouldn't happen for priority txs
+ continue;
+ }
- // Process this block the same as if we had received it from another node
- CValidationState state;
- if (!ProcessNewBlock(state, NULL, pblock, true, NULL))
- return error("DogecoinMiner: ProcessNewBlock, block not accepted");
+ // cannot accept witness transactions into a non-witness block
+ if (!fIncludeWitness && iter->GetTx().HasWitness())
+ continue;
- return true;
-}
-
-void static BitcoinMiner(CWallet *pwallet)
-{
- LogPrintf("DogecoinMiner started\n");
- SetThreadPriority(THREAD_PRIORITY_LOWEST);
- RenameThread("dogecoin-miner");
- const CChainParams& chainparams = Params();
-
- // Each thread has its own key and counter
- CReserveKey reservekey(pwallet);
- unsigned int nExtraNonce = 0;
-
- try {
- while (true) {
- if (chainparams.MiningRequiresPeers()) {
- // Busy-wait for the network to come online so we don't waste time mining
- // on an obsolete chain. In regtest mode we expect to fly solo.
- do {
- bool fvNodesEmpty;
- {
- LOCK(cs_vNodes);
- fvNodesEmpty = vNodes.empty();
- }
- if (!fvNodesEmpty && !IsInitialBlockDownload())
- break;
- MilliSleep(1000);
- } while (true);
- }
+ // 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;
+ }
- //
- // Create new block
- //
- unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
- CBlockIndex* pindexPrev = chainActive.Tip();
- const Consensus::Params &consensus = Params().GetConsensus(pindexPrev -> nHeight + 1);
+ // If this tx fits in the block add it, otherwise keep looping
+ if (TestForBlock(iter)) {
+ AddToBlock(iter);
- auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
- if (!pblocktemplate.get())
- {
- LogPrintf("Error in DogecoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
- return;
+ // If now that this txs is added we've surpassed our desired priority size
+ // or have dropped below the AllowFreeThreshold, then we're done adding priority txs
+ if (nBlockSize >= nBlockPrioritySize || !AllowFree(actualPriority)) {
+ break;
}
- CBlock *pblock = &pblocktemplate->block;
- IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
-
- LogPrintf("Running DogecoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
- ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
-
- //
- // Search
- //
- int64_t nStart = GetTime();
- arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
- uint256 hash;
- uint32_t nNonce = 0;
- char scratchpad[SCRYPT_SCRATCHPAD_SIZE];
- while (true) {
- // Check if something found
- if (ScanHash(pblock, nNonce, &hash, scratchpad))
- {
- if (UintToArith256(hash) <= hashTarget)
- {
- // Found a solution
- pblock->nNonce = nNonce;
- assert(hash == pblock->GetPoWHash());
-
- SetThreadPriority(THREAD_PRIORITY_NORMAL);
- LogPrintf("DogecoinMiner:\n");
- LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex());
- ProcessBlockFound(pblock, *pwallet, reservekey);
- SetThreadPriority(THREAD_PRIORITY_LOWEST);
-
- // In regression test mode, stop mining after a block is found.
- if (chainparams.MineBlocksOnDemand())
- throw boost::thread_interrupted();
-
- break;
- }
- }
- // Check for stop or if block needs to be rebuilt
- boost::this_thread::interruption_point();
- // Regtest mode doesn't require peers
- if (vNodes.empty() && chainparams.MiningRequiresPeers())
- break;
- if (nNonce >= 0xffff0000)
- break;
- if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
- break;
- if (pindexPrev != chainActive.Tip())
- break;
-
- // Update nTime every few seconds
- UpdateTime(pblock, consensus, pindexPrev);
- if (consensus.fPowAllowMinDifficultyBlocks)
- {
- // Changing pblock->nTime can change work required on testnet:
- hashTarget.SetCompact(pblock->nBits);
+ // This tx was successfully added, so
+ // add transactions that depend on this one to the priority queue to try again
+ BOOST_FOREACH(CTxMemPool::txiter child, mempool.GetMemPoolChildren(iter))
+ {
+ waitPriIter wpiter = waitPriMap.find(child);
+ if (wpiter != waitPriMap.end()) {
+ vecPriority.push_back(TxCoinAgePriority(wpiter->second,child));
+ std::push_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
+ waitPriMap.erase(wpiter);
}
}
}
}
- catch (const boost::thread_interrupted&)
- {
- LogPrintf("DogecoinMiner terminated\n");
- throw;
- }
- catch (const std::runtime_error &e)
- {
- LogPrintf("DogecoinMiner runtime error: %s\n", e.what());
- return;
- }
+ fNeedSizeAccounting = fSizeAccounting;
}
-void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
+void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
{
- static boost::thread_group* minerThreads = NULL;
-
- if (nThreads < 0) {
- // In regtest threads defaults to 1
- if (Params().DefaultMinerThreads())
- nThreads = Params().DefaultMinerThreads();
- else
- nThreads = boost::thread::hardware_concurrency();
- }
-
- if (minerThreads != NULL)
+ // Update nExtraNonce
+ static uint256 hashPrevBlock;
+ if (hashPrevBlock != pblock->hashPrevBlock)
{
- minerThreads->interrupt_all();
- delete minerThreads;
- minerThreads = NULL;
+ nExtraNonce = 0;
+ hashPrevBlock = pblock->hashPrevBlock;
}
+ ++nExtraNonce;
+ unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
+ CMutableTransaction txCoinbase(*pblock->vtx[0]);
+ txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
+ assert(txCoinbase.vin[0].scriptSig.size() <= 100);
- if (nThreads == 0 || !fGenerate)
- return;
-
- minerThreads = new boost::thread_group();
- for (int i = 0; i < nThreads; i++)
- minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet));
+ pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
+ pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
}
-
-#endif // ENABLE_WALLET