#ifndef BITCOIN_NODE_MINER_H
#define BITCOIN_NODE_MINER_H
#include <interfaces/types.h>
#include <node/types.h>
#include <policy/policy.h>
#include <primitives/block.h>
#include <txmempool.h>
#include <util/feefrac.h>
#include <cstdint>
#include <memory>
#include <optional>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/tag.hpp>
#include <boost/multi_index_container.hpp>
class ArgsManager;
class CBlockIndex;
class CChainParams;
class CScript;
class Chainstate;
class ChainstateManager;
namespace Consensus { struct Params; };
using interfaces::BlockRef;
namespace node {
class KernelNotifications;
static const bool DEFAULT_PRINT_MODIFIED_FEE = false;
struct CBlockTemplate
{
CBlock block;
std::vector<CAmount> vTxFees;
std::vector<int64_t> vTxSigOpsCost;
std::vector<unsigned char> vchCoinbaseCommitment;
std::vector<FeeFrac> m_package_feerates;
};
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;
};
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;
}
};
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);
}
};
struct CTxMemPoolModifiedEntry_Indices final : boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
modifiedentry_iter,
CompareCTxMemPoolIter
>,
boost::multi_index::ordered_non_unique<
boost::multi_index::tag<ancestor_score>,
boost::multi_index::identity<CTxMemPoolModifiedEntry>,
CompareTxMemPoolEntryByAncestorFee
>
>
{};
typedef boost::multi_index_container<
CTxMemPoolModifiedEntry,
CTxMemPoolModifiedEntry_Indices
> 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->GetModifiedFee();
e.nSizeWithAncestors -= iter->GetTxSize();
e.nSigOpCostWithAncestors -= iter->GetSigOpCost();
}
CTxMemPool::txiter iter;
};
class BlockAssembler
{
private:
std::unique_ptr<CBlockTemplate> pblocktemplate;
uint64_t nBlockWeight;
uint64_t nBlockTx;
uint64_t nBlockSigOpsCost;
CAmount nFees;
std::unordered_set<Txid, SaltedTxidHasher> inBlock;
int nHeight;
int64_t m_lock_time_cutoff;
const CChainParams& chainparams;
const CTxMemPool* const m_mempool;
Chainstate& m_chainstate;
public:
struct Options : BlockCreateOptions {
size_t nBlockMaxWeight{DEFAULT_BLOCK_MAX_WEIGHT};
CFeeRate blockMinFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
bool test_block_validity{true};
bool print_modified_fee{DEFAULT_PRINT_MODIFIED_FEE};
};
explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options);
std::unique_ptr<CBlockTemplate> CreateNewBlock();
inline static std::optional<int64_t> m_last_block_num_txs{};
inline static std::optional<int64_t> m_last_block_weight{};
private:
const Options m_options;
void resetBlock();
void AddToBlock(CTxMemPool::txiter iter);
void addPackageTxs(int& nPackagesSelected, int& nDescendantsUpdated) EXCLUSIVE_LOCKS_REQUIRED(!m_mempool->cs);
void onlyUnconfirmed(CTxMemPool::setEntries& testSet);
bool TestPackage(uint64_t packageSize, int64_t packageSigOpsCost) const;
bool TestPackageTransactions(const CTxMemPool::setEntries& package) const;
void SortForBlock(const CTxMemPool::setEntries& package, std::vector<CTxMemPool::txiter>& sortedEntries);
};
int64_t GetMinimumTime(const CBlockIndex* pindexPrev, const int64_t difficulty_adjustment_interval);
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
void RegenerateCommitments(CBlock& block, ChainstateManager& chainman);
void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& options);
void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t version, uint32_t timestamp, uint32_t nonce);
std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman,
KernelNotifications& kernel_notifications,
CTxMemPool* mempool,
const std::unique_ptr<CBlockTemplate>& block_template,
const BlockWaitOptions& options,
const BlockAssembler::Options& assemble_options);
std::optional<BlockRef> GetTip(ChainstateManager& chainman);
std::optional<BlockRef> WaitTipChanged(ChainstateManager& chainman, KernelNotifications& kernel_notifications, const uint256& current_tip, MillisecondsDouble& timeout);
}
#endif