LCOV - code coverage report
Current view: top level - src/node - miner.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 298 366 81.4 %
Date: 2026-06-25 07:23:51 Functions: 17 18 94.4 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2021 The Bitcoin Core developers
       3             : // Copyright (c) 2014-2025 The Dash Core developers
       4             : // Distributed under the MIT software license, see the accompanying
       5             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       6             : 
       7             : #include <node/miner.h>
       8             : 
       9             : #include <chain.h>
      10             : #include <chainparams.h>
      11             : #include <consensus/amount.h>
      12             : #include <consensus/consensus.h>
      13             : #include <consensus/merkle.h>
      14             : #include <consensus/tx_verify.h>
      15             : #include <consensus/validation.h>
      16             : #include <deploymentstatus.h>
      17             : #include <node/context.h>
      18             : #include <policy/feerate.h>
      19             : #include <policy/policy.h>
      20             : #include <pow.h>
      21             : #include <primitives/transaction.h>
      22             : #include <timedata.h>
      23             : #include <util/moneystr.h>
      24             : #include <util/system.h>
      25             : #include <validation.h>
      26             : 
      27             : #include <chainlock/chainlock.h>
      28             : #include <chainlock/handler.h>
      29             : #include <evo/specialtx.h>
      30             : #include <evo/cbtx.h>
      31             : #include <evo/chainhelper.h>
      32             : #include <evo/creditpool.h>
      33             : #include <evo/mnhftx.h>
      34             : #include <evo/deterministicmns.h>
      35             : #include <evo/simplifiedmns.h>
      36             : #include <evo/specialtxman.h>
      37             : #include <governance/governance.h>
      38             : #include <instantsend/instantsend.h>
      39             : #include <llmq/blockprocessor.h>
      40             : #include <llmq/context.h>
      41             : #include <llmq/options.h>
      42             : #include <llmq/snapshot.h>
      43             : #include <masternode/payments.h>
      44             : 
      45             : #include <algorithm>
      46             : #include <utility>
      47             : 
      48             : namespace node {
      49       24517 : int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
      50             : {
      51       24517 :     int64_t nOldTime = pblock->nTime;
      52       24517 :     int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast() + 1, GetAdjustedTime());
      53             : 
      54       24517 :     if (nOldTime < nNewTime) {
      55       12241 :         pblock->nTime = nNewTime;
      56       12241 :     }
      57             : 
      58             :     // Updating time can change work required on testnet:
      59       24517 :     if (consensusParams.fPowAllowMinDifficultyBlocks) {
      60       24499 :         pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
      61       24499 :     }
      62             : 
      63       24517 :     return nNewTime - nOldTime;
      64             : }
      65             : 
      66       49034 : BlockAssembler::Options::Options()
      67       24517 : {
      68       24517 :     blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
      69       24517 :     nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
      70       49034 : }
      71             : 
      72       49034 : BlockAssembler::BlockAssembler(CChainState& chainstate, const NodeContext& node, const CTxMemPool* mempool, const CChainParams& params, const Options& options) :
      73       24517 :       m_blockman(chainstate.m_blockman),
      74       24517 :       m_chain_helper(chainstate.ChainHelper()),
      75       24517 :       m_chainstate(chainstate),
      76       24517 :       m_evoDb(*Assert(node.evodb)),
      77       24517 :       m_chainlocks(*Assert(node.chainlocks)),
      78       24517 :       m_clhandler(*Assert(node.clhandler)),
      79       24517 :       m_isman(*Assert(Assert(node.llmq_ctx)->isman)),
      80       24517 :       chainparams(params),
      81       24517 :       m_mempool(mempool),
      82       24517 :       m_quorum_block_processor(*Assert(Assert(node.llmq_ctx)->quorum_block_processor)),
      83       24517 :       m_qman(*Assert(Assert(node.llmq_ctx)->qman))
      84       24517 : {
      85       24517 :     blockMinFeeRate = options.blockMinFeeRate;
      86       24517 :     nBlockMaxSize = options.nBlockMaxSize;
      87       49034 : }
      88             : 
      89       24499 : static BlockAssembler::Options DefaultOptions()
      90             : {
      91             :     // Block resource limits
      92       24499 :     BlockAssembler::Options options;
      93       24499 :     options.nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
      94       24499 :     if (gArgs.IsArgSet("-blockmaxsize")) {
      95           0 :         options.nBlockMaxSize = gArgs.GetIntArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
      96           0 :     }
      97       24499 :     if (gArgs.IsArgSet("-blockmintxfee")) {
      98           0 :         std::optional<CAmount> parsed = ParseMoney(gArgs.GetArg("-blockmintxfee", ""));
      99           0 :         options.blockMinFeeRate = CFeeRate{parsed.value_or(DEFAULT_BLOCK_MIN_TX_FEE)};
     100           0 :     } else {
     101       24499 :         options.blockMinFeeRate = CFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
     102             :     }
     103       24499 :     return options;
     104           0 : }
     105             : 
     106       24499 : BlockAssembler::BlockAssembler(CChainState& chainstate, const NodeContext& node, const CTxMemPool* mempool, const CChainParams& params)
     107       24499 :     : BlockAssembler(chainstate, node, mempool, params, DefaultOptions()) {}
     108             : 
     109       24517 : void BlockAssembler::resetBlock()
     110             : {
     111       24517 :     inBlock.clear();
     112             : 
     113             :     // Reserve space for coinbase tx
     114       24517 :     nBlockSize = 1000;
     115       24517 :     nBlockSigOps = 100;
     116             : 
     117             :     // These counters do not include coinbase tx
     118       24517 :     nBlockTx = 0;
     119       24517 :     nFees = 0;
     120       24517 : }
     121             : 
     122             : // Helper to calculate best chainlock
     123        7631 : static bool CalcCbTxBestChainlock(const chainlock::Chainlocks& chainlocks, const CBlockIndex* pindexPrev,
     124             :                                   uint32_t& bestCLHeightDiff, CBLSSignature& bestCLSignature)
     125             : {
     126        7631 :     auto best_clsig = chainlocks.GetBestChainLock();
     127        7631 :     if (best_clsig.getHeight() < Params().GetConsensus().DeploymentHeight(Consensus::DEPLOYMENT_V19)) {
     128             :         // We don't want legacy BLS ChainLocks in CbTx (can happen on regtest/devenets)
     129        7631 :         best_clsig = chainlock::ChainLockSig{};
     130        7631 :     }
     131        7631 :     if (best_clsig.getHeight() == pindexPrev->nHeight) {
     132             :         // Our best CL is the newest one possible
     133           0 :         bestCLHeightDiff = 0;
     134           0 :         bestCLSignature = best_clsig.getSig();
     135           0 :         return true;
     136             :     }
     137             : 
     138        7631 :     auto prevBlockCoinbaseChainlock = GetNonNullCoinbaseChainlock(pindexPrev);
     139        7631 :     if (prevBlockCoinbaseChainlock.has_value()) {
     140             :         // Previous block Coinbase contains a non-null CL: We must insert the same sig or a better (newest) one
     141           0 :         if (best_clsig.IsNull()) {
     142             :             // We don't know any CL, therefore inserting the CL of the previous block
     143           0 :             bestCLHeightDiff = prevBlockCoinbaseChainlock->second + 1;
     144           0 :             bestCLSignature = prevBlockCoinbaseChainlock->first;
     145           0 :             return true;
     146             :         }
     147             : 
     148             :         // We check if our best CL is newer than the one from previous block Coinbase
     149           0 :         int curCLHeight = best_clsig.getHeight();
     150           0 :         int prevCLHeight = pindexPrev->nHeight - static_cast<int>(prevBlockCoinbaseChainlock->second) - 1;
     151           0 :         if (curCLHeight < prevCLHeight) {
     152             :             // Our best CL isn't newer: inserting CL from previous block
     153           0 :             bestCLHeightDiff = prevBlockCoinbaseChainlock->second + 1;
     154           0 :             bestCLSignature = prevBlockCoinbaseChainlock->first;
     155           0 :         }
     156             :         else {
     157             :             // Our best CL is newer
     158           0 :             bestCLHeightDiff = pindexPrev->nHeight - best_clsig.getHeight();
     159           0 :             bestCLSignature = best_clsig.getSig();
     160             :         }
     161             : 
     162           0 :         return true;
     163             :     }
     164             :     else {
     165             :         // Previous block Coinbase has no CL. We can either insert null or any valid CL
     166        7631 :         if (best_clsig.IsNull()) {
     167             :             // We don't know any CL, therefore inserting a null CL
     168        7631 :             bestCLHeightDiff = 0;
     169        7631 :             bestCLSignature.Reset();
     170        7631 :             return false;
     171             :         }
     172             : 
     173             :         // Inserting our best CL
     174           0 :         bestCLHeightDiff = pindexPrev->nHeight - best_clsig.getHeight();
     175           0 :         bestCLSignature = best_clsig.getSig();
     176             : 
     177           0 :         return true;
     178             :     }
     179        7631 : }
     180             : 
     181             : 
     182       24517 : std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
     183             : {
     184       24517 :     int64_t nTimeStart = GetTimeMicros();
     185             : 
     186       24517 :     resetBlock();
     187             : 
     188       24522 :     pblocktemplate.reset(new CBlockTemplate());
     189             : 
     190       24517 :     if (!pblocktemplate.get()) {
     191           0 :         return nullptr;
     192             :     }
     193       24517 :     CBlock* const pblock = &pblocktemplate->block; // pointer for convenience
     194             : 
     195             :     // Add dummy coinbase tx as first transaction
     196       24517 :     pblock->vtx.emplace_back();
     197       24517 :     pblocktemplate->vTxFees.push_back(-1); // updated at end
     198       24517 :     pblocktemplate->vTxSigOps.push_back(-1); // updated at end
     199             : 
     200       24517 :     LOCK(::cs_main);
     201       24517 :     CBlockIndex* pindexPrev = m_chainstate.m_chain.Tip();
     202       24517 :     assert(pindexPrev != nullptr);
     203       24517 :     nHeight = pindexPrev->nHeight + 1;
     204             : 
     205       24517 :     const bool fDIP0001Active_context{DeploymentActiveAfter(pindexPrev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_DIP0001)};
     206       24517 :     const bool fDIP0003Active_context{DeploymentActiveAfter(pindexPrev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_DIP0003)};
     207       24517 :     const bool fDIP0008Active_context{DeploymentActiveAfter(pindexPrev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_DIP0008)};
     208       24517 :     const bool fV20Active_context{DeploymentActiveAfter(pindexPrev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_V20)};
     209             : 
     210             :     // Limit size to between 1K and MaxBlockSize()-1K for sanity:
     211       24517 :     nBlockMaxSize = std::max<unsigned int>(1000, std::min<unsigned int>(MaxBlockSize(fDIP0001Active_context) - 1000, nBlockMaxSize));
     212       24517 :     nBlockMaxSigOps = MaxBlockSigOps(fDIP0001Active_context);
     213             : 
     214       24517 :     pblock->nVersion = m_chainstate.m_chainman.m_versionbitscache.ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
     215             :     // Non-mainnet only: allow overriding block.nVersion with
     216             :     // -blockversion=N to test forking scenarios
     217       24517 :     if (Params().NetworkIDString() != CBaseChainParams::MAIN) {
     218       24499 :         pblock->nVersion = gArgs.GetIntArg("-blockversion", pblock->nVersion);
     219       24499 :     }
     220             : 
     221       24517 :     pblock->nTime = GetAdjustedTime();
     222       24517 :     m_lock_time_cutoff = pindexPrev->GetMedianTimePast();
     223             : 
     224       24517 :     if (fDIP0003Active_context) {
     225       39115 :         for (const Consensus::LLMQParams& params : llmq::GetEnabledQuorumParams(m_chainstate.m_chainman, pindexPrev)) {
     226       29962 :             std::vector<CTransactionRef> vqcTx;
     227       59924 :             if (m_quorum_block_processor.GetMineableCommitmentsTx(params,
     228       29962 :                                                                   nHeight,
     229             :                                                                   vqcTx)) {
     230       25762 :                 for (const auto& qcTx : vqcTx) {
     231       14585 :                     pblock->vtx.emplace_back(qcTx);
     232       14585 :                     pblocktemplate->vTxFees.emplace_back(0);
     233       14585 :                     pblocktemplate->vTxSigOps.emplace_back(0);
     234       14585 :                     nBlockSize += qcTx->GetTotalSize();
     235       14585 :                     ++nBlockTx;
     236             :                 }
     237       11177 :             }
     238       29962 :         }
     239        9153 :     }
     240             : 
     241       24517 :     int nPackagesSelected = 0;
     242       24517 :     int nDescendantsUpdated = 0;
     243       24517 :     if (m_mempool) {
     244       24517 :         LOCK(m_mempool->cs);
     245       24517 :         addPackageTxs(*m_mempool, nPackagesSelected, nDescendantsUpdated, pindexPrev);
     246       24517 :     }
     247             : 
     248       24517 :     int64_t nTime1 = GetTimeMicros();
     249             : 
     250       24517 :     m_last_block_num_txs = nBlockTx;
     251       24517 :     m_last_block_size = nBlockSize;
     252       24517 :     LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps);
     253             : 
     254             :     // Create coinbase transaction.
     255       24517 :     CMutableTransaction coinbaseTx;
     256       24517 :     coinbaseTx.vin.resize(1);
     257       24517 :     coinbaseTx.vin[0].prevout.SetNull();
     258       24517 :     coinbaseTx.vout.resize(1);
     259       24517 :     coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
     260             : 
     261             :     // NOTE: unlike in bitcoin, we need to pass PREVIOUS block height here
     262       24517 :     CAmount blockSubsidy = GetBlockSubsidyInner(pindexPrev->nBits, pindexPrev->nHeight, Params().GetConsensus(), fV20Active_context);
     263       24517 :     CAmount blockReward = blockSubsidy + nFees;
     264             : 
     265             :     // Compute regular coinbase transaction.
     266       24517 :     coinbaseTx.vout[0].nValue = blockReward;
     267             : 
     268       24517 :     if (!fDIP0003Active_context) {
     269       15364 :         coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
     270       15364 :     } else {
     271        9153 :         coinbaseTx.vin[0].scriptSig = CScript() << OP_RETURN;
     272             : 
     273        9153 :         coinbaseTx.nVersion = 3;
     274        9153 :         coinbaseTx.nType = TRANSACTION_COINBASE;
     275             : 
     276        9153 :         CCbTx cbTx;
     277             : 
     278        9153 :         if (fV20Active_context) {
     279        7631 :             cbTx.nVersion = CCbTx::Version::CLSIG_AND_BALANCE;
     280        9153 :         } else if (fDIP0008Active_context) {
     281        1522 :             cbTx.nVersion = CCbTx::Version::MERKLE_ROOT_QUORUMS;
     282        1522 :         } else {
     283           0 :             cbTx.nVersion = CCbTx::Version::MERKLE_ROOT_MNLIST;
     284             :         }
     285             : 
     286        9153 :         cbTx.nHeight = nHeight;
     287             : 
     288        9153 :         BlockValidationState state;
     289        9153 :         CDeterministicMNList mn_list;
     290        9153 :         if (!m_chain_helper.special_tx->BuildNewListFromBlock(*pblock, pindexPrev, m_chainstate.CoinsTip(), true, state, mn_list)) {
     291           0 :             throw std::runtime_error(strprintf("%s: BuildNewListFromBlock failed: %s", __func__, state.ToString()));
     292             :         }
     293        9153 :         if (!CalcCbTxMerkleRootMNList(cbTx.merkleRootMNList, mn_list.to_sml(), state)) {
     294           0 :             throw std::runtime_error(strprintf("%s: CalcCbTxMerkleRootMNList failed: %s", __func__, state.ToString()));
     295             :         }
     296        9153 :         if (fDIP0008Active_context) {
     297        9153 :             if (!CalcCbTxMerkleRootQuorums(*pblock, pindexPrev, m_quorum_block_processor, cbTx.merkleRootQuorums, state)) {
     298           0 :                 throw std::runtime_error(strprintf("%s: CalcCbTxMerkleRootQuorums failed: %s", __func__, state.ToString()));
     299             :             }
     300        9153 :             if (fV20Active_context) {
     301        7631 :                 if (CalcCbTxBestChainlock(m_chainlocks, pindexPrev, cbTx.bestCLHeightDiff, cbTx.bestCLSignature)) {
     302           0 :                     LogPrintf("CreateNewBlock() h[%d] CbTx bestCLHeightDiff[%d] CLSig[%s]\n", nHeight, cbTx.bestCLHeightDiff, cbTx.bestCLSignature.ToString());
     303           0 :                 } else {
     304             :                     // not an error
     305        7631 :                     LogPrintf("CreateNewBlock() h[%d] CbTx failed to find best CL. Inserting null CL\n", nHeight);
     306             :                 }
     307        7631 :                 BlockValidationState state;
     308        7631 :                 const auto creditPoolDiff = GetCreditPoolDiffForBlock(*m_chain_helper.credit_pool_manager, *pblock, pindexPrev, chainparams.GetConsensus(), blockSubsidy, state);
     309        7631 :                 if (creditPoolDiff == std::nullopt) {
     310           0 :                     throw std::runtime_error(strprintf("%s: GetCreditPoolDiffForBlock failed: %s", __func__, state.ToString()));
     311             :                 }
     312             : 
     313        7631 :                 cbTx.creditPoolBalance = creditPoolDiff->GetTotalLocked();
     314        7631 :             }
     315        9153 :         }
     316             : 
     317        9153 :         SetTxPayload(coinbaseTx, cbTx);
     318        9153 :     }
     319             : 
     320             :     // Update coinbase transaction with additional info about masternode and governance payments,
     321             :     // get some info back to pass to getblocktemplate
     322       24517 :     m_chain_helper.mn_payments->FillBlockPayments(coinbaseTx, pindexPrev, blockSubsidy, nFees, pblocktemplate->voutMasternodePayments, pblocktemplate->voutSuperblockPayments);
     323             : 
     324       24517 :     pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
     325       24517 :     pblocktemplate->vTxFees[0] = -nFees;
     326             : 
     327             :     // Fill in header
     328       24517 :     pblock->hashPrevBlock  = pindexPrev->GetBlockHash();
     329       24517 :     UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
     330       24517 :     pblock->nBits          = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus());
     331       24517 :     pblock->nNonce         = 0;
     332       24517 :     pblocktemplate->nPrevBits = pindexPrev->nBits;
     333       24517 :     pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]);
     334             : 
     335       24517 :     BlockValidationState state;
     336       24517 :     if (!TestBlockValidity(state, m_chainlocks, m_evoDb, chainparams, m_chainstate, *pblock, pindexPrev, false, false)) {
     337           5 :         throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString()));
     338             :     }
     339       24512 :     int64_t nTime2 = GetTimeMicros();
     340             : 
     341       24512 :     LogPrint(BCLog::BENCHMARK, "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));
     342             : 
     343       24512 :     return std::move(pblocktemplate);
     344       24522 : }
     345             : 
     346         153 : void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet)
     347             : {
     348       17015 :     for (CTxMemPool::setEntries::iterator iit = testSet.begin(); iit != testSet.end(); ) {
     349             :         // Only test txs not already in the block
     350       16862 :         if (inBlock.count(*iit)) {
     351        9409 :             testSet.erase(iit++);
     352        9409 :         } else {
     353        7453 :             iit++;
     354             :         }
     355             :     }
     356         153 : }
     357             : 
     358         184 : bool BlockAssembler::TestPackage(uint64_t packageSize, unsigned int packageSigOps) const
     359             : {
     360         184 :     if (nBlockSize + packageSize >= nBlockMaxSize) {
     361          23 :         return false;
     362             :     }
     363             : 
     364         161 :     if (nBlockSigOps + packageSigOps >= nBlockMaxSigOps) {
     365           8 :         return false;
     366             :     }
     367         153 :     return true;
     368         184 : }
     369             : 
     370             : // Perform transaction-level checks before adding to block:
     371             : // - transaction finality (locktime)
     372             : // - safe TXs in regard to ChainLocks
     373         153 : bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package) const
     374             : {
     375        2188 :     for (CTxMemPool::txiter it : package) {
     376        2145 :         if (!IsFinalTx(it->GetTx(), nHeight, m_lock_time_cutoff)) {
     377           2 :             return false;
     378             :         }
     379             : 
     380        2143 :         const auto& txid = it->GetTx().GetHash();
     381        2143 :         if (!m_isman.IsInstantSendEnabled() || m_isman.IsLocked(txid)) {
     382           0 :             continue;
     383             :         }
     384             : 
     385        2143 :         if (!it->GetTx().vin.empty() && !m_clhandler.IsTxSafeForMining(txid)) {
     386         108 :             return false;
     387             :         }
     388             :     }
     389          43 :     return true;
     390         153 : }
     391             : 
     392        2035 : void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
     393             : {
     394        2035 :     pblocktemplate->block.vtx.emplace_back(iter->GetSharedTx());
     395        2035 :     pblocktemplate->vTxFees.push_back(iter->GetFee());
     396        2035 :     pblocktemplate->vTxSigOps.push_back(iter->GetSigOpCount());
     397        2035 :     nBlockSize += iter->GetTxSize();
     398        2035 :     ++nBlockTx;
     399        2035 :     nBlockSigOps += iter->GetSigOpCount();
     400        2035 :     nFees += iter->GetFee();
     401        2035 :     inBlock.insert(iter);
     402             : 
     403        2035 :     bool fPrintPriority = gArgs.GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
     404        2035 :     if (fPrintPriority) {
     405           0 :         LogPrintf("fee rate %s txid %s\n",
     406             :                   CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
     407             :                   iter->GetTx().GetHash().ToString());
     408           0 :     }
     409        2035 : }
     410             : 
     411             : /** Add descendants of given transactions to mapModifiedTx with ancestor
     412             :  * state updated assuming given transactions are inBlock. Returns number
     413             :  * of updated descendants. */
     414          43 : static int UpdatePackagesForAdded(const CTxMemPool& mempool,
     415             :                                   const CTxMemPool::setEntries& alreadyAdded,
     416             :                                   indexed_modified_transaction_set& mapModifiedTx) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs)
     417             : {
     418          43 :     AssertLockHeld(mempool.cs);
     419             : 
     420          43 :     int nDescendantsUpdated = 0;
     421        2078 :     for (CTxMemPool::txiter it : alreadyAdded) {
     422        2035 :         CTxMemPool::setEntries descendants;
     423        2035 :         mempool.CalculateDescendants(it, descendants);
     424             :         // Insert all descendants (not yet in block) into the modified set
     425     1005080 :         for (CTxMemPool::txiter desc : descendants) {
     426     1003045 :             if (alreadyAdded.count(desc)) {
     427      271728 :                 continue;
     428             :             }
     429      731317 :             ++nDescendantsUpdated;
     430      731317 :             modtxiter mit = mapModifiedTx.find(desc);
     431      731317 :             if (mit == mapModifiedTx.end()) {
     432        1162 :                 CTxMemPoolModifiedEntry modEntry(desc);
     433        1162 :                 mit = mapModifiedTx.insert(modEntry).first;
     434        1162 :             }
     435      731317 :             mapModifiedTx.modify(mit, update_for_parent_inclusion(it));
     436             :         }
     437        2035 :     }
     438          43 :     return nDescendantsUpdated;
     439           0 : }
     440             : 
     441          43 : void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, std::vector<CTxMemPool::txiter>& sortedEntries)
     442             : {
     443             :     // Sort package by ancestor count
     444             :     // If a transaction A depends on transaction B, then A's ancestor count
     445             :     // must be greater than B's.  So this is sufficient to validly order the
     446             :     // transactions for block inclusion.
     447          43 :     sortedEntries.clear();
     448          43 :     sortedEntries.insert(sortedEntries.begin(), package.begin(), package.end());
     449          43 :     std::sort(sortedEntries.begin(), sortedEntries.end(), CompareTxIterByAncestorCount());
     450          43 : }
     451             : 
     452             : // This transaction selection algorithm orders the mempool based
     453             : // on feerate of a transaction including all unconfirmed ancestors.
     454             : // Since we don't remove transactions from the mempool as we select them
     455             : // for block inclusion, we need an alternate method of updating the feerate
     456             : // of a transaction with its not-yet-selected ancestors as we go.
     457             : // This is accomplished by walking the in-mempool descendants of selected
     458             : // transactions and storing a temporary modified state in mapModifiedTxs.
     459             : // Each time through the loop, we compare the best transaction in
     460             : // mapModifiedTxs with the next transaction in the mempool to decide what
     461             : // transaction package to work on next.
     462       24517 : void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSelected, int& nDescendantsUpdated, const CBlockIndex* const pindexPrev)
     463             : {
     464       24517 :     AssertLockHeld(mempool.cs);
     465             : 
     466             :     // This credit pool is used only to check withdrawal limits and to find
     467             :     // duplicates of indexes. There's used `BlockSubsidy` equaled to 0
     468       24517 :     std::optional<CCreditPoolDiff> creditPoolDiff;
     469       24517 :     if (DeploymentActiveAfter(pindexPrev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_V20)) {
     470        7631 :         CCreditPool creditPool = m_chain_helper.GetCreditPool(pindexPrev);
     471        7631 :         creditPoolDiff.emplace(std::move(creditPool), pindexPrev, chainparams.GetConsensus(), 0);
     472        7631 :     }
     473             : 
     474             :     // This map with signals is used only to find duplicates
     475       24517 :     std::unordered_map<uint8_t, int> signals = m_chain_helper.ehf_manager->GetSignalsStage(pindexPrev);
     476             : 
     477             :     // mapModifiedTx will store sorted packages after they are modified
     478             :     // because some of their txs are already in the block
     479       24517 :     indexed_modified_transaction_set mapModifiedTx;
     480             :     // Keep track of entries that failed inclusion, to avoid duplicate work
     481       24517 :     CTxMemPool::setEntries failedTx;
     482             : 
     483       24517 :     CTxMemPool::indexed_transaction_set::index<ancestor_score>::type::iterator mi = mempool.mapTx.get<ancestor_score>().begin();
     484       24517 :     CTxMemPool::txiter iter;
     485             : 
     486             :     // Limit the number of attempts to add transactions to the block when it is
     487             :     // close to full; this is just a simple heuristic to finish quickly if the
     488             :     // mempool has a lot of entries.
     489       24517 :     const int64_t MAX_CONSECUTIVE_FAILURES = 1000;
     490       24517 :     int64_t nConsecutiveFailed = 0;
     491             : 
     492       26719 :     while (mi != mempool.mapTx.get<ancestor_score>().end() || !mapModifiedTx.empty()) {
     493             :         // First try to find a new transaction in mapTx to evaluate.
     494             :         //
     495             :         // Skip entries in mapTx that are already in a block or are present
     496             :         // in mapModifiedTx (which implies that the mapTx ancestor state is
     497             :         // stale due to ancestor inclusion in the block)
     498             :         // Also skip transactions that we've already failed to add. This can happen if
     499             :         // we consider a transaction in mapModifiedTx and it fails: we can then
     500             :         // potentially consider it again while walking mapTx.  It's currently
     501             :         // guaranteed to fail again, but as a belt-and-suspenders check we put it in
     502             :         // failedTx and avoid re-evaluation, since the re-evaluation would be using
     503             :         // cached size/sigops/fee values that are not actually correct.
     504             :         /** Return true if given transaction from mapTx has already been evaluated,
     505             :          * or if the transaction's cached data in mapTx is incorrect. */
     506        2205 :         if (mi != mempool.mapTx.get<ancestor_score>().end()) {
     507        2181 :             auto it = mempool.mapTx.project<0>(mi);
     508        2181 :             assert(it != mempool.mapTx.end());
     509        2181 :             if (mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it)) {
     510        2018 :                 ++mi;
     511        2018 :                 continue;
     512             :             }
     513         163 :         }
     514             : 
     515             :         // Now that mi is not stale, determine which transaction to evaluate:
     516             :         // the next entry from mapTx, or the best from mapModifiedTx?
     517         187 :         bool fUsingModified = false;
     518             : 
     519         187 :         modtxscoreiter modit = mapModifiedTx.get<ancestor_score>().begin();
     520         187 :         if (mi == mempool.mapTx.get<ancestor_score>().end()) {
     521             :             // We're out of entries in mapTx; use the entry from mapModifiedTx
     522          24 :             iter = modit->iter;
     523          24 :             fUsingModified = true;
     524          24 :         } else {
     525             :             // Try to compare the mapTx entry to the mapModifiedTx entry
     526         163 :             iter = mempool.mapTx.project<0>(mi);
     527         173 :             if (modit != mapModifiedTx.get<ancestor_score>().end() &&
     528          10 :                     CompareTxMemPoolEntryByAncestorFee()(*modit, CTxMemPoolModifiedEntry(iter))) {
     529             :                 // The best entry in mapModifiedTx has higher score
     530             :                 // than the one from mapTx.
     531             :                 // Switch which transaction (package) to consider
     532           3 :                 iter = modit->iter;
     533           3 :                 fUsingModified = true;
     534           3 :             } else {
     535             :                 // Either no entry in mapModifiedTx, or it's worse than mapTx.
     536             :                 // Increment mi for the next loop iteration.
     537         160 :                 ++mi;
     538             :             }
     539             :         }
     540             : 
     541         187 :         if (creditPoolDiff != std::nullopt) {
     542             :             // If one transaction is skipped due to limits, it is not a reason to interrupt
     543             :             // whole process of adding transactions.
     544             :             // `state` is local here because used only to log info about this specific tx
     545           0 :             TxValidationState state;
     546             : 
     547           0 :             if (iter->GetTx().IsSpecialTxVersion() && iter->GetTx().nType == TRANSACTION_ASSET_UNLOCK) {
     548             :                 // ASSET_UNLOCK transactions may expire after being added to mempool
     549             :                 // They should not be included to the block
     550           0 :                 if (!CheckAssetUnlockTx(m_blockman, m_qman, iter->GetTx(), pindexPrev, creditPoolDiff->pool.indexes, state)) {
     551           0 :                     if (fUsingModified) {
     552           0 :                         mapModifiedTx.get<ancestor_score>().erase(modit);
     553           0 :                         failedTx.insert(iter);
     554           0 :                     }
     555           0 :                     LogPrintf("%s: asset unlock tx %s is skipped due %s\n",
     556             :                               __func__, iter->GetTx().GetHash().ToString(), state.ToString());
     557           0 :                     continue;
     558             :                 }
     559           0 :             }
     560           0 :             if (!creditPoolDiff->ProcessLockUnlockTransaction(iter->GetTx(), state)) {
     561           0 :                 if (fUsingModified) {
     562           0 :                     mapModifiedTx.get<ancestor_score>().erase(modit);
     563           0 :                     failedTx.insert(iter);
     564           0 :                 }
     565           0 :                 LogPrintf("%s: asset-locks tx %s skipped due %s\n",
     566             :                           __func__, iter->GetTx().GetHash().ToString(), state.ToString());
     567           0 :                 continue;
     568             :             }
     569           0 :         }
     570         187 :         if (std::optional<uint8_t> signal = extractEHFSignal(iter->GetTx()); signal != std::nullopt) {
     571           0 :             if (signals.find(*signal) != signals.end()) {
     572           0 :                 if (fUsingModified) {
     573           0 :                     mapModifiedTx.get<ancestor_score>().erase(modit);
     574           0 :                     failedTx.insert(iter);
     575           0 :                 }
     576           0 :                 LogPrintf("%s: ehf signal tx %s skipped due to duplicate %d\n",
     577             :                           __func__, iter->GetTx().GetHash().ToString(), *signal);
     578           0 :                 continue;
     579             :             }
     580           0 :             signals.insert({*signal, 0});
     581           0 :         }
     582             : 
     583             :         // We skip mapTx entries that are inBlock, and mapModifiedTx shouldn't
     584             :         // contain anything that is inBlock.
     585         187 :         assert(!inBlock.count(iter));
     586             : 
     587         187 :         uint64_t packageSize = iter->GetSizeWithAncestors();
     588         187 :         CAmount packageFees = iter->GetModFeesWithAncestors();
     589         187 :         unsigned int packageSigOps = iter->GetSigOpCountWithAncestors();
     590         187 :         if (fUsingModified) {
     591          27 :             packageSize = modit->nSizeWithAncestors;
     592          27 :             packageFees = modit->nModFeesWithAncestors;
     593          27 :             packageSigOps = modit->nSigOpCountWithAncestors;
     594          27 :         }
     595             : 
     596         187 :         if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
     597             :             // Everything else we might consider has a lower fee rate
     598           3 :             return;
     599             :         }
     600             : 
     601         184 :         if (!TestPackage(packageSize, packageSigOps)) {
     602          31 :             if (fUsingModified) {
     603             :                 // Since we always look at the best entry in mapModifiedTx,
     604             :                 // we must erase failed entries so that we can consider the
     605             :                 // next best entry on the next loop iteration
     606           8 :                 mapModifiedTx.get<ancestor_score>().erase(modit);
     607           8 :                 failedTx.insert(iter);
     608           8 :             }
     609             : 
     610          31 :             ++nConsecutiveFailed;
     611             : 
     612          31 :             if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockSize > nBlockMaxSize - 1000) {
     613             :                 // Give up if we're close to full and haven't succeeded in a while
     614           0 :                 break;
     615             :             }
     616          31 :             continue;
     617             :         }
     618             : 
     619         153 :         CTxMemPool::setEntries ancestors;
     620         153 :         uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
     621         153 :         std::string dummy;
     622         153 :         mempool.CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
     623             : 
     624         153 :         onlyUnconfirmed(ancestors);
     625         153 :         ancestors.insert(iter);
     626             : 
     627             :         // Test if all tx's are Final and safe
     628         153 :         if (!TestPackageTransactions(ancestors)) {
     629         110 :             if (fUsingModified) {
     630           0 :                 mapModifiedTx.get<ancestor_score>().erase(modit);
     631           0 :                 failedTx.insert(iter);
     632           0 :             }
     633         110 :             continue;
     634             :         }
     635             : 
     636             :         // This transaction will make it in; reset the failed counter.
     637          43 :         nConsecutiveFailed = 0;
     638             : 
     639             :         // Package can be added. Sort the entries in a valid order.
     640          43 :         std::vector<CTxMemPool::txiter> sortedEntries;
     641          43 :         SortForBlock(ancestors, sortedEntries);
     642             : 
     643        2078 :         for (size_t i = 0; i < sortedEntries.size(); ++i) {
     644        2035 :             AddToBlock(sortedEntries[i]);
     645             :             // Erase from the modified set, if present
     646        2035 :             mapModifiedTx.erase(sortedEntries[i]);
     647        2035 :         }
     648             : 
     649          43 :         ++nPackagesSelected;
     650             : 
     651             :         // Update transactions that depend on each of these
     652          43 :         nDescendantsUpdated += UpdatePackagesForAdded(mempool, ancestors, mapModifiedTx);
     653         153 :     }
     654       24517 : }
     655             : } // namespace node

Generated by: LCOV version 1.16