diff options
Diffstat (limited to 'src/node/miner.h')
-rw-r--r-- | src/node/miner.h | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/src/node/miner.h b/src/node/miner.h new file mode 100644 index 0000000000..0e8c02793a --- /dev/null +++ b/src/node/miner.h @@ -0,0 +1,208 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2020 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 <primitives/block.h> +#include <txmempool.h> + +#include <memory> +#include <optional> +#include <stdint.h> + +#include <boost/multi_index/ordered_index.hpp> +#include <boost/multi_index_container.hpp> + +class ChainstateManager; +class CBlockIndex; +class CChainParams; +class CScript; + +namespace Consensus { struct Params; }; + +static const bool DEFAULT_PRINTPRIORITY = false; + +struct CBlockTemplate +{ + CBlock block; + std::vector<CAmount> vTxFees; + std::vector<int64_t> vTxSigOpsCost; + std::vector<unsigned char> 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(); + } + + int64_t 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<ancestor_score>, + boost::multi_index::identity<CTxMemPoolModifiedEntry>, + CompareTxMemPoolEntryByAncestorFee + > + > +> indexed_modified_transaction_set; + +typedef indexed_modified_transaction_set::nth_index<0>::type::iterator modtxiter; +typedef indexed_modified_transaction_set::index<ancestor_score>::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->GetFee(); + 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<CBlockTemplate> pblocktemplate; + + // Configuration parameters for the block size + bool fIncludeWitness; + unsigned int nBlockMaxWeight; + CFeeRate blockMinFeeRate; + + // 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 nLockTimeCutoff; + const CChainParams& chainparams; + const CTxMemPool& m_mempool; + CChainState& m_chainstate; + +public: + struct Options { + Options(); + size_t nBlockMaxWeight; + CFeeRate blockMinFeeRate; + }; + + explicit BlockAssembler(CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params); + explicit BlockAssembler(CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params, const Options& options); + + /** Construct a new block template with coinbase to scriptPubKeyIn */ + std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn); + + inline static std::optional<int64_t> m_last_block_num_txs{}; + inline static std::optional<int64_t> 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(int& nPackagesSelected, int& nDescendantsUpdated) EXCLUSIVE_LOCKS_REQUIRED(m_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; + /** Return true if given transaction from mapTx has already been evaluated, + * or if the transaction's cached data in mapTx is incorrect. */ + bool SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set& mapModifiedTx, CTxMemPool::setEntries& failedTx) EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs); + /** Sort the package in an order that is valid to appear in a block */ + void SortForBlock(const CTxMemPool::setEntries& package, std::vector<CTxMemPool::txiter>& sortedEntries); + /** Add descendants of given transactions to mapModifiedTx with ancestor + * state updated assuming given transactions are inBlock. Returns number + * of updated descendants. */ + int UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set& mapModifiedTx) EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs); +}; + +/** Modify the extranonce in a block */ +void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce); +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); + +#endif // BITCOIN_NODE_MINER_H |