diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h index 974490561a4..cebe97edb7a 100644 --- a/src/interfaces/mining.h +++ b/src/interfaces/mining.h @@ -5,9 +5,11 @@ #ifndef BITCOIN_INTERFACES_MINING_H #define BITCOIN_INTERFACES_MINING_H +#include +#include + #include #include -#include namespace node { struct CBlockTemplate; @@ -41,10 +43,10 @@ public: * Construct a new block template * * @param[in] script_pub_key the coinbase output - * @param[in] use_mempool set false to omit mempool transactions + * @param[in] options options for creating the block * @returns a block template */ - virtual std::unique_ptr createNewBlock(const CScript& script_pub_key, bool use_mempool = true) = 0; + virtual std::unique_ptr createNewBlock(const CScript& script_pub_key, const node::BlockCreateOptions& options={}) = 0; /** * Processes new block. A valid new block is automatically relayed to peers. diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index ef12ffe34b0..46d36f83f84 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -884,12 +884,11 @@ public: return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root); } - std::unique_ptr createNewBlock(const CScript& script_pub_key, bool use_mempool) override + std::unique_ptr createNewBlock(const CScript& script_pub_key, const BlockCreateOptions& options) override { - BlockAssembler::Options options; - ApplyArgsManOptions(gArgs, options); - - return BlockAssembler{chainman().ActiveChainstate(), use_mempool ? context()->mempool.get() : nullptr, options}.CreateNewBlock(script_pub_key); + BlockAssembler::Options assemble_options{options}; + ApplyArgsManOptions(*Assert(m_node.args), assemble_options); + return BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(script_pub_key); } NodeContext* context() override { return &m_node; } diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 291f1d5fc7f..fa2d979b86a 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -59,14 +59,17 @@ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman) static BlockAssembler::Options ClampOptions(BlockAssembler::Options options) { - // Limit weight to between 4K and DEFAULT_BLOCK_MAX_WEIGHT for sanity: - options.nBlockMaxWeight = std::clamp(options.nBlockMaxWeight, 4000, DEFAULT_BLOCK_MAX_WEIGHT); + Assert(options.coinbase_max_additional_weight <= DEFAULT_BLOCK_MAX_WEIGHT); + Assert(options.coinbase_output_max_additional_sigops <= MAX_BLOCK_SIGOPS_COST); + // Limit weight to between coinbase_max_additional_weight and DEFAULT_BLOCK_MAX_WEIGHT for sanity: + // Coinbase (reserved) outputs can safely exceed -blockmaxweight, but the rest of the block template will be empty. + options.nBlockMaxWeight = std::clamp(options.nBlockMaxWeight, options.coinbase_max_additional_weight, DEFAULT_BLOCK_MAX_WEIGHT); return options; } BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options) : chainparams{chainstate.m_chainman.GetParams()}, - m_mempool{mempool}, + m_mempool{options.use_mempool ? mempool : nullptr}, m_chainstate{chainstate}, m_options{ClampOptions(options)} { @@ -87,8 +90,8 @@ void BlockAssembler::resetBlock() inBlock.clear(); // Reserve space for coinbase tx - nBlockWeight = 4000; - nBlockSigOpsCost = 400; + nBlockWeight = m_options.coinbase_max_additional_weight; + nBlockSigOpsCost = m_options.coinbase_output_max_additional_sigops; // These counters do not include coinbase tx nBlockTx = 0; @@ -379,7 +382,7 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele ++nConsecutiveFailed; if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight > - m_options.nBlockMaxWeight - 4000) { + m_options.nBlockMaxWeight - m_options.coinbase_max_additional_weight) { // Give up if we're close to full and haven't succeeded in a while break; } diff --git a/src/node/miner.h b/src/node/miner.h index 622ca16c8fd..efd773eb310 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_NODE_MINER_H #define BITCOIN_NODE_MINER_H +#include #include #include #include @@ -153,7 +154,7 @@ private: Chainstate& m_chainstate; public: - struct Options { + struct Options : BlockCreateOptions { // Configuration parameters for the block size size_t nBlockMaxWeight{DEFAULT_BLOCK_MAX_WEIGHT}; CFeeRate blockMinFeeRate{DEFAULT_BLOCK_MIN_TX_FEE}; diff --git a/src/node/types.h b/src/node/types.h index 0461e85f430..bb8d17ef43f 100644 --- a/src/node/types.h +++ b/src/node/types.h @@ -13,6 +13,8 @@ #ifndef BITCOIN_NODE_TYPES_H #define BITCOIN_NODE_TYPES_H +#include + namespace node { enum class TransactionError { OK, //!< No error @@ -24,6 +26,24 @@ enum class TransactionError { MAX_BURN_EXCEEDED, INVALID_PACKAGE, }; + +struct BlockCreateOptions { + /** + * Set false to omit mempool transactions + */ + bool use_mempool{true}; + /** + * The maximum additional weight which the pool will add to the coinbase + * scriptSig, witness and outputs. This must include any additional + * weight needed for larger CompactSize encoded lengths. + */ + size_t coinbase_max_additional_weight{4000}; + /** + * The maximum additional sigops which the pool will add in coinbase + * transaction outputs. + */ + size_t coinbase_output_max_additional_sigops{400}; +}; } // namespace node #endif // BITCOIN_NODE_TYPES_H diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 7e420dcd9b5..8482ce6eb2e 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -371,7 +371,7 @@ static RPCHelpMan generateblock() ChainstateManager& chainman = EnsureChainman(node); { - std::unique_ptr blocktemplate{miner.createNewBlock(coinbase_script, /*use_mempool=*/false)}; + std::unique_ptr blocktemplate{miner.createNewBlock(coinbase_script, {.use_mempool = false})}; if (!blocktemplate) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); } @@ -778,9 +778,7 @@ static RPCHelpMan getblocktemplate() } ENTER_CRITICAL_SECTION(cs_main); - std::optional maybe_tip{miner.getTipHash()}; - CHECK_NONFATAL(maybe_tip); - tip = maybe_tip.value(); + tip = CHECK_NONFATAL(miner.getTipHash()).value(); if (!IsRPCRunning()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");