// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_NODE_MINER_H #define BITCOIN_NODE_MINER_H #include #include #include #include #include #include #include class ArgsManager; class ChainstateManager; class CBlockIndex; class CChainParams; class CScript; namespace Consensus { struct Params; }; namespace node { static const bool DEFAULT_PRINTPRIORITY = false; struct CBlockTemplate { CBlock block; std::vector vTxFees; std::vector vTxSigOpsCost; std::vector vchCoinbaseCommitment; }; // Container for tracking updates to ancestor feerate as we include (parent) // transactions in a block struct CTxMemPoolModifiedEntry { explicit CTxMemPoolModifiedEntry(CTxMemPool::txiter entry) { iter = entry; nSizeWithAncestors = entry->GetSizeWithAncestors(); nModFeesWithAncestors = entry->GetModFeesWithAncestors(); nSigOpCostWithAncestors = entry->GetSigOpCostWithAncestors(); } CAmount GetModifiedFee() const { return iter->GetModifiedFee(); } uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; } CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; } size_t GetTxSize() const { return iter->GetTxSize(); } const CTransaction& GetTx() const { return iter->GetTx(); } CTxMemPool::txiter iter; uint64_t nSizeWithAncestors; CAmount nModFeesWithAncestors; int64_t nSigOpCostWithAncestors; }; /** Comparator for CTxMemPool::txiter objects. * It simply compares the internal memory address of the CTxMemPoolEntry object * pointed to. This means it has no meaning, and is only useful for using them * as key in other indexes. */ struct CompareCTxMemPoolIter { bool operator()(const CTxMemPool::txiter& a, const CTxMemPool::txiter& b) const { return &(*a) < &(*b); } }; struct modifiedentry_iter { typedef CTxMemPool::txiter result_type; result_type operator() (const CTxMemPoolModifiedEntry &entry) const { return entry.iter; } }; // A comparator that sorts transactions based on number of ancestors. // This is sufficient to sort an ancestor package in an order that is valid // to appear in a block. struct CompareTxIterByAncestorCount { bool operator()(const CTxMemPool::txiter& a, const CTxMemPool::txiter& b) const { if (a->GetCountWithAncestors() != b->GetCountWithAncestors()) { return a->GetCountWithAncestors() < b->GetCountWithAncestors(); } return CompareIteratorByHash()(a, b); } }; typedef boost::multi_index_container< CTxMemPoolModifiedEntry, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< modifiedentry_iter, CompareCTxMemPoolIter >, // sorted by modified ancestor fee rate boost::multi_index::ordered_non_unique< // Reuse same tag from CTxMemPool's similar index boost::multi_index::tag, boost::multi_index::identity, CompareTxMemPoolEntryByAncestorFee > > > indexed_modified_transaction_set; typedef indexed_modified_transaction_set::nth_index<0>::type::iterator modtxiter; typedef indexed_modified_transaction_set::index::type::iterator modtxscoreiter; struct update_for_parent_inclusion { explicit update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {} void operator() (CTxMemPoolModifiedEntry &e) { e.nModFeesWithAncestors -= iter->GetModifiedFee(); e.nSizeWithAncestors -= iter->GetTxSize(); e.nSigOpCostWithAncestors -= iter->GetSigOpCost(); } CTxMemPool::txiter iter; }; /** Generate a new block, without valid proof-of-work */ class BlockAssembler { private: // The constructed block template std::unique_ptr pblocktemplate; // Configuration parameters for the block size unsigned int nBlockMaxWeight; CFeeRate blockMinFeeRate; // Whether to call TestBlockValidity() at the end of CreateNewBlock(). const bool test_block_validity; // Information on the current status of the block uint64_t nBlockWeight; uint64_t nBlockTx; uint64_t nBlockSigOpsCost; CAmount nFees; CTxMemPool::setEntries inBlock; // Chain context for the block int nHeight; int64_t m_lock_time_cutoff; const CChainParams& chainparams; const CTxMemPool* const m_mempool; Chainstate& m_chainstate; public: struct Options { Options(); size_t nBlockMaxWeight; CFeeRate blockMinFeeRate; bool test_block_validity; }; explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool); explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options); /** Construct a new block template with coinbase to scriptPubKeyIn */ std::unique_ptr CreateNewBlock(const CScript& scriptPubKeyIn); inline static std::optional m_last_block_num_txs{}; inline static std::optional m_last_block_weight{}; private: // utility functions /** Clear the block's state and prepare for assembling a new block */ void resetBlock(); /** Add a tx to the block */ void AddToBlock(CTxMemPool::txiter iter); // Methods for how to add transactions to a block. /** Add transactions based on feerate including unconfirmed ancestors * Increments nPackagesSelected / nDescendantsUpdated with corresponding * statistics from the package selection (for logging statistics). */ void addPackageTxs(const CTxMemPool& mempool, int& nPackagesSelected, int& nDescendantsUpdated) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs); // helper functions for addPackageTxs() /** Remove confirmed (inBlock) entries from given set */ void onlyUnconfirmed(CTxMemPool::setEntries& testSet); /** Test if a new package would "fit" in the block */ bool TestPackage(uint64_t packageSize, int64_t packageSigOpsCost) const; /** Perform checks on each transaction in a package: * locktime, premature-witness, serialized size (if necessary) * These checks should always succeed, and they're here * only as an extra check in case of suboptimal node configuration */ bool TestPackageTransactions(const CTxMemPool::setEntries& package) const; /** Sort the package in an order that is valid to appear in a block */ void SortForBlock(const CTxMemPool::setEntries& package, std::vector& sortedEntries); }; int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); /** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman); /** Apply -blockmintxfee and -blockmaxweight options from ArgsManager to BlockAssembler options. */ void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& options); } // namespace node #endif // BITCOIN_NODE_MINER_H