diff --git a/src/miner.h b/src/miner.h --- a/src/miner.h +++ b/src/miner.h @@ -161,12 +161,13 @@ int64_t nMedianTimePast; const Config *config; + const CTxMemPool *mempool; // Variables used for addPriorityTxs int lastFewTxs; public: - BlockAssembler(const Config &_config); + BlockAssembler(const Config &_config, const CTxMemPool &mempool); /** Construct a new block template with coinbase to scriptPubKeyIn */ std::unique_ptr CreateNewBlock(const CScript &scriptPubKeyIn); diff --git a/src/miner.cpp b/src/miner.cpp --- a/src/miner.cpp +++ b/src/miner.cpp @@ -87,7 +87,8 @@ return nMaxGeneratedBlockSize; } -BlockAssembler::BlockAssembler(const Config &_config) : config(&_config) { +BlockAssembler::BlockAssembler(const Config &_config, const CTxMemPool &mempool) + : config(&_config), mempool(&mempool) { if (gArgs.IsArgSet("-blockmintxfee")) { Amount n = Amount::zero(); @@ -141,7 +142,7 @@ // Add dummy coinbase tx as first transaction. It is updated at the end. pblocktemplate->entries.emplace_back(CTransactionRef(), -SATOSHI, -1); - LOCK2(cs_main, g_mempool.cs); + LOCK2(cs_main, mempool->cs); CBlockIndex *pindexPrev = chainActive.Tip(); nHeight = pindexPrev->nHeight + 1; @@ -245,7 +246,7 @@ } bool BlockAssembler::isStillDependent(CTxMemPool::txiter iter) { - for (CTxMemPool::txiter parent : g_mempool.GetMemPoolParents(iter)) { + for (CTxMemPool::txiter parent : mempool->GetMemPoolParents(iter)) { if (!inBlock.count(parent)) { return true; } @@ -363,7 +364,7 @@ if (fPrintPriority) { double dPriority = iter->GetPriority(nHeight); Amount dummy; - g_mempool.ApplyDeltas(iter->GetTx().GetId(), dPriority, dummy); + mempool->ApplyDeltas(iter->GetTx().GetId(), dPriority, dummy); LogPrintf( "priority %.1f fee %s txid %s\n", dPriority, CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(), @@ -377,7 +378,7 @@ int nDescendantsUpdated = 0; for (const CTxMemPool::txiter it : alreadyAdded) { CTxMemPool::setEntries descendants; - g_mempool.CalculateDescendants(it, 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)) { @@ -413,7 +414,7 @@ bool BlockAssembler::SkipMapTxEntry( CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx, CTxMemPool::setEntries &failedTx) { - assert(it != g_mempool.mapTx.end()); + assert(it != mempool->mapTx.end()); return mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it); } @@ -461,7 +462,7 @@ UpdatePackagesForAdded(inBlock, mapModifiedTx); CTxMemPool::indexed_transaction_set::index::type::iterator - mi = g_mempool.mapTx.get().begin(); + mi = mempool->mapTx.get().begin(); CTxMemPool::txiter iter; // Limit the number of attempts to add transactions to the block when it is @@ -470,11 +471,11 @@ const int64_t MAX_CONSECUTIVE_FAILURES = 1000; int64_t nConsecutiveFailed = 0; - while (mi != g_mempool.mapTx.get().end() || + while (mi != mempool->mapTx.get().end() || !mapModifiedTx.empty()) { // First try to find a new transaction in mapTx to evaluate. - if (mi != g_mempool.mapTx.get().end() && - SkipMapTxEntry(g_mempool.mapTx.project<0>(mi), mapModifiedTx, + if (mi != mempool->mapTx.get().end() && + SkipMapTxEntry(mempool->mapTx.project<0>(mi), mapModifiedTx, failedTx)) { ++mi; continue; @@ -485,13 +486,13 @@ bool fUsingModified = false; modtxscoreiter modit = mapModifiedTx.get().begin(); - if (mi == g_mempool.mapTx.get().end()) { + if (mi == mempool->mapTx.get().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 = g_mempool.mapTx.project<0>(mi); + iter = mempool->mapTx.project<0>(mi); if (modit != mapModifiedTx.get().end() && CompareModifiedEntry()(*modit, CTxMemPoolModifiedEntry(iter))) { // The best entry in mapModifiedTx has higher score than the one @@ -547,9 +548,8 @@ CTxMemPool::setEntries ancestors; uint64_t nNoLimit = std::numeric_limits::max(); std::string dummy; - g_mempool.CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, - nNoLimit, nNoLimit, nNoLimit, dummy, - false); + mempool->CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, nNoLimit, + nNoLimit, nNoLimit, dummy, false); onlyUnconfirmed(ancestors); ancestors.insert(iter); @@ -602,13 +602,13 @@ CTxMemPool::CompareIteratorByHash>::iterator waitPriIter; double actualPriority = -1; - vecPriority.reserve(g_mempool.mapTx.size()); + vecPriority.reserve(mempool->mapTx.size()); for (CTxMemPool::indexed_transaction_set::iterator mi = - g_mempool.mapTx.begin(); - mi != g_mempool.mapTx.end(); ++mi) { + mempool->mapTx.begin(); + mi != mempool->mapTx.end(); ++mi) { double dPriority = mi->GetPriority(nHeight); Amount dummy; - g_mempool.ApplyDeltas(mi->GetTx().GetId(), dPriority, dummy); + mempool->ApplyDeltas(mi->GetTx().GetId(), dPriority, dummy); vecPriority.push_back(TxCoinAgePriority(dPriority, mi)); } std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer); @@ -664,7 +664,7 @@ // This tx was successfully added, so add transactions that depend // on this one to the priority queue to try again. - for (CTxMemPool::txiter child : g_mempool.GetMemPoolChildren(iter)) { + for (CTxMemPool::txiter child : mempool->GetMemPoolChildren(iter)) { waitPriIter wpiter = waitPriMap.find(child); if (wpiter == waitPriMap.end()) { continue; diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -131,8 +131,8 @@ UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd) { std::unique_ptr pblocktemplate( - BlockAssembler(config).CreateNewBlock( - coinbaseScript->reserveScript)); + BlockAssembler(config, g_mempool) + .CreateNewBlock(coinbaseScript->reserveScript)); if (!pblocktemplate.get()) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); @@ -585,7 +585,8 @@ // Create new block CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = BlockAssembler(config).CreateNewBlock(scriptDummy); + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptDummy); if (!pblocktemplate) { throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -128,7 +128,7 @@ .FromTx(tx)); std::unique_ptr pblocktemplate = - BlockAssembler(config).CreateNewBlock(scriptPubKey); + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == parentTxId); BOOST_CHECK(pblocktemplate->block.vtx[2]->GetId() == highFeeTxId); BOOST_CHECK(pblocktemplate->block.vtx[3]->GetId() == mediumFeeTxId); @@ -150,7 +150,8 @@ int64_t(5000000000LL - 1000 - 50000) * SATOSHI - feeToUse; TxId lowFeeTxId = tx.GetId(); g_mempool.addUnchecked(lowFeeTxId, entry.Fee(feeToUse).FromTx(tx)); - pblocktemplate = BlockAssembler(config).CreateNewBlock(scriptPubKey); + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); // Verify that the free tx and the low fee tx didn't get selected. for (const auto &txn : pblocktemplate->block.vtx) { BOOST_CHECK(txn->GetId() != freeTxId); @@ -166,7 +167,8 @@ lowFeeTxId = tx.GetId(); g_mempool.addUnchecked(lowFeeTxId, entry.Fee(feeToUse + 2 * SATOSHI).FromTx(tx)); - pblocktemplate = BlockAssembler(config).CreateNewBlock(scriptPubKey); + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[4]->GetId() == freeTxId); BOOST_CHECK(pblocktemplate->block.vtx[5]->GetId() == lowFeeTxId); @@ -190,7 +192,8 @@ TxId lowFeeTxId2 = tx.GetId(); g_mempool.addUnchecked( lowFeeTxId2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); - pblocktemplate = BlockAssembler(config).CreateNewBlock(scriptPubKey); + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); // Verify that this tx isn't selected. for (const auto &txn : pblocktemplate->block.vtx) { @@ -204,7 +207,8 @@ // 10k satoshi fee. tx.vout[0].nValue = (100000000 - 10000) * SATOSHI; g_mempool.addUnchecked(tx.GetId(), entry.Fee(10000 * SATOSHI).FromTx(tx)); - pblocktemplate = BlockAssembler(config).CreateNewBlock(scriptPubKey); + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[8]->GetId() == lowFeeTxId2); } @@ -219,7 +223,7 @@ << OP_CHECKSIG; std::unique_ptr pblocktemplate = - BlockAssembler(config).CreateNewBlock(scriptPubKey); + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); CBlock *pblock = &pblocktemplate->block; @@ -265,8 +269,9 @@ GlobalConfig config; // Simple block creation, nothing special yet: - BOOST_CHECK(pblocktemplate = - BlockAssembler(config).CreateNewBlock(scriptPubKey)); + BOOST_CHECK( + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); // We can't make transactions until we have inputs. Therefore, load 100 // blocks :) @@ -302,8 +307,9 @@ } // Just to make sure we can still make simple blocks. - BOOST_CHECK(pblocktemplate = - BlockAssembler(config).CreateNewBlock(scriptPubKey)); + BOOST_CHECK( + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); const Amount BLOCKSUBSIDY = 50 * COIN; const Amount LOWFEE = CENT; @@ -332,8 +338,9 @@ .FromTx(tx)); tx.vin[0].prevout = COutPoint(hash, 0); } - BOOST_CHECK_THROW(BlockAssembler(config).CreateNewBlock(scriptPubKey), - std::runtime_error); + BOOST_CHECK_THROW( + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), + std::runtime_error); g_mempool.clear(); tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0); @@ -353,8 +360,9 @@ .FromTx(tx)); tx.vin[0].prevout = COutPoint(hash, 0); } - BOOST_CHECK(pblocktemplate = - BlockAssembler(config).CreateNewBlock(scriptPubKey)); + BOOST_CHECK( + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); g_mempool.clear(); // block size > limit @@ -380,15 +388,17 @@ .FromTx(tx)); tx.vin[0].prevout = COutPoint(hash, 0); } - BOOST_CHECK(pblocktemplate = - BlockAssembler(config).CreateNewBlock(scriptPubKey)); + BOOST_CHECK( + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); g_mempool.clear(); // Orphan in mempool, template creation fails. hash = tx.GetId(); g_mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); - BOOST_CHECK_THROW(BlockAssembler(config).CreateNewBlock(scriptPubKey), - std::runtime_error); + BOOST_CHECK_THROW( + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), + std::runtime_error); g_mempool.clear(); // Child with higher priority than parent. @@ -409,8 +419,9 @@ g_mempool.addUnchecked( hash, entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK(pblocktemplate = - BlockAssembler(config).CreateNewBlock(scriptPubKey)); + BOOST_CHECK( + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); g_mempool.clear(); // Coinbase in mempool, template creation fails. @@ -423,8 +434,9 @@ g_mempool.addUnchecked( hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); - BOOST_CHECK_THROW(BlockAssembler(config).CreateNewBlock(scriptPubKey), - std::runtime_error); + BOOST_CHECK_THROW( + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), + std::runtime_error); g_mempool.clear(); // Invalid (pre-p2sh) txn in mempool, template creation fails. @@ -455,8 +467,9 @@ g_mempool.addUnchecked( hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); - BOOST_CHECK_THROW(BlockAssembler(config).CreateNewBlock(scriptPubKey), - std::runtime_error); + BOOST_CHECK_THROW( + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), + std::runtime_error); g_mempool.clear(); for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) { // Restore the MedianTimePast. @@ -478,8 +491,9 @@ g_mempool.addUnchecked( hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK_THROW(BlockAssembler(config).CreateNewBlock(scriptPubKey), - std::runtime_error); + BOOST_CHECK_THROW( + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), + std::runtime_error); g_mempool.clear(); // Subsidy changing. @@ -495,8 +509,9 @@ next->BuildSkip(); chainActive.SetTip(next); } - BOOST_CHECK(pblocktemplate = - BlockAssembler(config).CreateNewBlock(scriptPubKey)); + BOOST_CHECK( + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); // Extend to a 210000-long block chain. while (chainActive.Tip()->nHeight < 210000) { CBlockIndex *prev = chainActive.Tip(); @@ -508,8 +523,9 @@ next->BuildSkip(); chainActive.SetTip(next); } - BOOST_CHECK(pblocktemplate = - BlockAssembler(config).CreateNewBlock(scriptPubKey)); + BOOST_CHECK( + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); // Delete the dummy blocks again. while (chainActive.Tip()->nHeight > nHeight) { CBlockIndex *del = chainActive.Tip(); @@ -676,12 +692,13 @@ // Sequence locks fail. BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); - pblocktemplate = BlockAssembler(config).CreateNewBlock(scriptPubKey); + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate); // None of the of the absolute height/time locked tx should have made it // into the template because we still check IsFinalTx in CreateNewBlock, but - // relative locked txs will if inconsistently added to mempool. For now + // relative locked txs will if inconsistently added to g_mempool. For now // these will still generate a valid template until BIP68 soft fork. BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3UL); // However if we advance height by 1 and time by 512, all of them should be @@ -694,8 +711,9 @@ chainActive.Tip()->nHeight++; SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1); - BOOST_CHECK(pblocktemplate = - BlockAssembler(config).CreateNewBlock(scriptPubKey)); + BOOST_CHECK( + pblocktemplate = + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5UL); chainActive.Tip()->nHeight--; @@ -710,7 +728,7 @@ void CheckBlockMaxSize(const Config &config, uint64_t size, uint64_t expected) { gArgs.ForceSetArg("-blockmaxsize", std::to_string(size)); - BlockAssembler ba(config); + BlockAssembler ba(config, g_mempool); BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(), expected); } @@ -749,7 +767,7 @@ // DEFAULT_MAX_GENERATED_BLOCK_SIZE { gArgs.ClearArg("-blockmaxsize"); - BlockAssembler ba(config); + BlockAssembler ba(config, g_mempool); BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(), DEFAULT_MAX_GENERATED_BLOCK_SIZE); } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -156,7 +156,7 @@ const std::vector &txns, const CScript &scriptPubKey) { const Config &config = GetConfig(); std::unique_ptr pblocktemplate = - BlockAssembler(config).CreateNewBlock(scriptPubKey); + BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); CBlock &block = pblocktemplate->block; // Replace mempool-selected txns with just coinbase plus passed-in txns: diff --git a/src/txmempool.h b/src/txmempool.h --- a/src/txmempool.h +++ b/src/txmempool.h @@ -682,7 +682,7 @@ * Assumes that setDescendants includes all in-mempool descendants of * anything already in it. */ - void CalculateDescendants(txiter it, setEntries &setDescendants); + void CalculateDescendants(txiter it, setEntries &setDescendants) const; /** * The minimum fee to get into the mempool, which may itself not be enough diff --git a/src/txmempool.cpp b/src/txmempool.cpp --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -528,7 +528,7 @@ // it are already in setDescendants as well, so that we can save time by not // iterating over those entries. void CTxMemPool::CalculateDescendants(txiter entryit, - setEntries &setDescendants) { + setEntries &setDescendants) const { setEntries stage; if (setDescendants.count(entryit) == 0) { stage.insert(entryit);