Drop script_pub_key arg from createNewBlock

Providing a script for the coinbase transaction is only done in test code
and for CPU solo mining.

Production miners use the getblocktemplate RPC which omits the coinbase
transaction entirely from its block template, leaving it to external (pool)
software to construct it.

A coinbase script can still be passed via BlockCreateOptions instead.

A temporary overload is added so that the test can be modified in the
next commit.
This commit is contained in:
Sjors Provoost 2024-11-21 10:48:26 +01:00
parent 7ab733ede4
commit ff41b9e296
No known key found for this signature in database
GPG key ID: 57FF9BDBCC301009
7 changed files with 39 additions and 16 deletions

View file

@ -88,11 +88,10 @@ public:
/** /**
* Construct a new block template * Construct a new block template
* *
* @param[in] script_pub_key the coinbase output
* @param[in] options options for creating the block * @param[in] options options for creating the block
* @returns a block template * @returns a block template
*/ */
virtual std::unique_ptr<BlockTemplate> createNewBlock(const CScript& script_pub_key, const node::BlockCreateOptions& options = {}) = 0; virtual std::unique_ptr<BlockTemplate> createNewBlock(const node::BlockCreateOptions& options = {}) = 0;
/** /**
* Processes new block. A valid new block is automatically relayed to peers. * Processes new block. A valid new block is automatically relayed to peers.

View file

@ -17,7 +17,7 @@ interface Mining $Proxy.wrap("interfaces::Mining") {
isInitialBlockDownload @1 (context :Proxy.Context) -> (result: Bool); isInitialBlockDownload @1 (context :Proxy.Context) -> (result: Bool);
getTip @2 (context :Proxy.Context) -> (result: Common.BlockRef, hasResult: Bool); getTip @2 (context :Proxy.Context) -> (result: Common.BlockRef, hasResult: Bool);
waitTipChanged @3 (context :Proxy.Context, currentTip: Data, timeout: Float64) -> (result: Common.BlockRef); waitTipChanged @3 (context :Proxy.Context, currentTip: Data, timeout: Float64) -> (result: Common.BlockRef);
createNewBlock @4 (scriptPubKey: Data, options: BlockCreateOptions) -> (result: BlockTemplate); createNewBlock @4 (options: BlockCreateOptions) -> (result: BlockTemplate);
processNewBlock @5 (context :Proxy.Context, block: Data) -> (newBlock: Bool, result: Bool); processNewBlock @5 (context :Proxy.Context, block: Data) -> (newBlock: Bool, result: Bool);
getTransactionsUpdated @6 (context :Proxy.Context) -> (result: UInt32); getTransactionsUpdated @6 (context :Proxy.Context) -> (result: UInt32);
testBlockValidity @7 (context :Proxy.Context, block: Data, checkMerkleRoot: Bool) -> (state: BlockValidationState, result: Bool); testBlockValidity @7 (context :Proxy.Context, block: Data, checkMerkleRoot: Bool) -> (state: BlockValidationState, result: Bool);

View file

@ -1004,11 +1004,11 @@ public:
return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root); return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root);
} }
std::unique_ptr<BlockTemplate> createNewBlock(const CScript& script_pub_key, const BlockCreateOptions& options) override std::unique_ptr<BlockTemplate> createNewBlock(const BlockCreateOptions& options) override
{ {
BlockAssembler::Options assemble_options{options}; BlockAssembler::Options assemble_options{options};
ApplyArgsManOptions(*Assert(m_node.args), assemble_options); ApplyArgsManOptions(*Assert(m_node.args), assemble_options);
return std::make_unique<BlockTemplateImpl>(BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(script_pub_key), m_node); return std::make_unique<BlockTemplateImpl>(BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(), m_node);
} }
NodeContext* context() override { return &m_node; } NodeContext* context() override { return &m_node; }

View file

@ -106,7 +106,7 @@ void BlockAssembler::resetBlock()
nFees = 0; nFees = 0;
} }
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock()
{ {
const auto time_start{SteadyClock::now()}; const auto time_start{SteadyClock::now()};
@ -151,7 +151,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
coinbaseTx.vin.resize(1); coinbaseTx.vin.resize(1);
coinbaseTx.vin[0].prevout.SetNull(); coinbaseTx.vin[0].prevout.SetNull();
coinbaseTx.vout.resize(1); coinbaseTx.vout.resize(1);
coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn; coinbaseTx.vout[0].scriptPubKey = m_options.coinbase_output_script;
coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus()); coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0; coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx)); pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));

View file

@ -169,14 +169,22 @@ public:
explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options); explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options);
/** Construct a new block template with coinbase to scriptPubKeyIn */ /** Construct a new block template */
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn); std::unique_ptr<CBlockTemplate> CreateNewBlock();
/** Temporary overload for tests */
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn)
{
m_options.coinbase_output_script = scriptPubKeyIn;
return CreateNewBlock();
};
inline static std::optional<int64_t> m_last_block_num_txs{}; inline static std::optional<int64_t> m_last_block_num_txs{};
inline static std::optional<int64_t> m_last_block_weight{}; inline static std::optional<int64_t> m_last_block_weight{};
private: private:
const Options m_options; // TODO: make const again
Options m_options;
// utility functions // utility functions
/** Clear the block's state and prepare for assembling a new block */ /** Clear the block's state and prepare for assembling a new block */

View file

@ -3,8 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
//! @file node/types.h is a home for public enum and struct type definitions //! @file node/types.h is a home for public enum and struct type definitions
//! that are used by internally by node code, but also used externally by wallet //! that are used by internally by node code, but also used externally by wallet,
//! or GUI code. //! mining or GUI code.
//! //!
//! This file is intended to define only simple types that do not have external //! This file is intended to define only simple types that do not have external
//! dependencies. More complicated types should be defined in dedicated header //! dependencies. More complicated types should be defined in dedicated header
@ -14,6 +14,7 @@
#define BITCOIN_NODE_TYPES_H #define BITCOIN_NODE_TYPES_H
#include <cstddef> #include <cstddef>
#include <script/script.h>
namespace node { namespace node {
enum class TransactionError { enum class TransactionError {
@ -43,6 +44,22 @@ struct BlockCreateOptions {
* transaction outputs. * transaction outputs.
*/ */
size_t coinbase_output_max_additional_sigops{400}; size_t coinbase_output_max_additional_sigops{400};
/**
* Script to put in the coinbase transaction. The default is an
* anyone-can-spend dummy.
*
* Should only be used for tests, when the default doesn't suffice.
*
* Note that higher level code like the getblocktemplate RPC may omit the
* coinbase transaction entirely. It's instead constructed by pool software
* using fields like coinbasevalue, coinbaseaux and default_witness_commitment.
* This software typically also controls the payout outputs, even for solo
* mining.
*
* The size and sigops are not checked against
* coinbase_max_additional_weight and coinbase_output_max_additional_sigops.
*/
CScript coinbase_output_script{CScript() << OP_TRUE};
}; };
} // namespace node } // namespace node

View file

@ -162,7 +162,7 @@ static UniValue generateBlocks(ChainstateManager& chainman, Mining& miner, const
{ {
UniValue blockHashes(UniValue::VARR); UniValue blockHashes(UniValue::VARR);
while (nGenerate > 0 && !chainman.m_interrupt) { while (nGenerate > 0 && !chainman.m_interrupt) {
std::unique_ptr<BlockTemplate> block_template(miner.createNewBlock(coinbase_output_script)); std::unique_ptr<BlockTemplate> block_template(miner.createNewBlock({ .coinbase_output_script = coinbase_output_script }));
CHECK_NONFATAL(block_template); CHECK_NONFATAL(block_template);
std::shared_ptr<const CBlock> block_out; std::shared_ptr<const CBlock> block_out;
@ -371,7 +371,7 @@ static RPCHelpMan generateblock()
ChainstateManager& chainman = EnsureChainman(node); ChainstateManager& chainman = EnsureChainman(node);
{ {
std::unique_ptr<BlockTemplate> block_template{miner.createNewBlock(coinbase_output_script, {.use_mempool = false})}; std::unique_ptr<BlockTemplate> block_template{miner.createNewBlock({.use_mempool = false, .coinbase_output_script = coinbase_output_script})};
CHECK_NONFATAL(block_template); CHECK_NONFATAL(block_template);
block = block_template->getBlock(); block = block_template->getBlock();
@ -814,8 +814,7 @@ static RPCHelpMan getblocktemplate()
time_start = GetTime(); time_start = GetTime();
// Create new block // Create new block
CScript scriptDummy = CScript() << OP_TRUE; block_template = miner.createNewBlock();
block_template = miner.createNewBlock(scriptDummy);
CHECK_NONFATAL(block_template); CHECK_NONFATAL(block_template);