diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp index 4005701caea..00102aefe2c 100644 --- a/src/bench/block_assemble.cpp +++ b/src/bench/block_assemble.cpp @@ -20,19 +20,23 @@ #include <memory> #include <vector> +using node::BlockAssembler; + static void AssembleBlock(benchmark::Bench& bench) { const auto test_setup = MakeNoLogFileContext<const TestingSetup>(); CScriptWitness witness; witness.stack.push_back(WITNESS_STACK_ELEM_OP_TRUE); + BlockAssembler::Options options; + options.coinbase_output_script = P2WSH_OP_TRUE; // Collect some loose transactions that spend the coinbases of our mined blocks constexpr size_t NUM_BLOCKS{200}; std::array<CTransactionRef, NUM_BLOCKS - COINBASE_MATURITY + 1> txs; for (size_t b{0}; b < NUM_BLOCKS; ++b) { CMutableTransaction tx; - tx.vin.emplace_back(MineBlock(test_setup->m_node, P2WSH_OP_TRUE)); + tx.vin.emplace_back(MineBlock(test_setup->m_node, options)); tx.vin.back().scriptWitness = witness; tx.vout.emplace_back(1337, P2WSH_OP_TRUE); if (NUM_BLOCKS - b >= COINBASE_MATURITY) @@ -48,7 +52,7 @@ static void AssembleBlock(benchmark::Bench& bench) } bench.run([&] { - PrepareBlock(test_setup->m_node, P2WSH_OP_TRUE); + PrepareBlock(test_setup->m_node, options); }); } static void BlockAssemblerAddPackageTxns(benchmark::Bench& bench) @@ -56,11 +60,12 @@ static void BlockAssemblerAddPackageTxns(benchmark::Bench& bench) FastRandomContext det_rand{true}; auto testing_setup{MakeNoLogFileContext<TestChain100Setup>()}; testing_setup->PopulateMempool(det_rand, /*num_transactions=*/1000, /*submit=*/true); - node::BlockAssembler::Options assembler_options; + BlockAssembler::Options assembler_options; assembler_options.test_block_validity = false; + assembler_options.coinbase_output_script = P2WSH_OP_TRUE; bench.run([&] { - PrepareBlock(testing_setup->m_node, P2WSH_OP_TRUE, assembler_options); + PrepareBlock(testing_setup->m_node, assembler_options); }); } diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h index 6f23bf3bb55..9c32e999a5b 100644 --- a/src/interfaces/mining.h +++ b/src/interfaces/mining.h @@ -88,11 +88,10 @@ public: /** * Construct a new block template * - * @param[in] script_pub_key the coinbase output * @param[in] options options for creating the block * @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. diff --git a/src/ipc/capnp/mining.capnp b/src/ipc/capnp/mining.capnp index f8faaa0c424..5af37b725ab 100644 --- a/src/ipc/capnp/mining.capnp +++ b/src/ipc/capnp/mining.capnp @@ -17,7 +17,7 @@ interface Mining $Proxy.wrap("interfaces::Mining") { isInitialBlockDownload @1 (context :Proxy.Context) -> (result: Bool); getTip @2 (context :Proxy.Context) -> (result: Common.BlockRef, hasResult: Bool); 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); getTransactionsUpdated @6 (context :Proxy.Context) -> (result: UInt32); testBlockValidity @7 (context :Proxy.Context, block: Data, checkMerkleRoot: Bool) -> (state: BlockValidationState, result: Bool); diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index e4ae9400e37..45c9208727e 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -1004,11 +1004,11 @@ public: 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}; 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; } diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 790ee1c1466..5d7304b597e 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -106,7 +106,7 @@ void BlockAssembler::resetBlock() nFees = 0; } -std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) +std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock() { 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[0].prevout.SetNull(); 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.vin[0].scriptSig = CScript() << nHeight << OP_0; pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx)); diff --git a/src/node/miner.h b/src/node/miner.h index 25ce110b348..f6461a8d553 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -169,8 +169,8 @@ public: explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options); - /** Construct a new block template with coinbase to scriptPubKeyIn */ - std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn); + /** Construct a new block template */ + 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{}; diff --git a/src/node/types.h b/src/node/types.h index 1302f1b127f..2fc66b892b5 100644 --- a/src/node/types.h +++ b/src/node/types.h @@ -3,8 +3,8 @@ // 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 -//! that are used by internally by node code, but also used externally by wallet -//! or GUI code. +//! that are used by internally by node code, but also used externally by wallet, +//! mining or GUI code. //! //! This file is intended to define only simple types that do not have external //! dependencies. More complicated types should be defined in dedicated header @@ -14,6 +14,7 @@ #define BITCOIN_NODE_TYPES_H #include <cstddef> +#include <script/script.h> namespace node { enum class TransactionError { @@ -43,6 +44,22 @@ struct BlockCreateOptions { * transaction outputs. */ 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 diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 60828c17115..5516e1c0d99 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -158,11 +158,11 @@ static bool GenerateBlock(ChainstateManager& chainman, Mining& miner, CBlock&& b return true; } -static UniValue generateBlocks(ChainstateManager& chainman, Mining& miner, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries) +static UniValue generateBlocks(ChainstateManager& chainman, Mining& miner, const CScript& coinbase_output_script, int nGenerate, uint64_t nMaxTries) { UniValue blockHashes(UniValue::VARR); while (nGenerate > 0 && !chainman.m_interrupt) { - std::unique_ptr<BlockTemplate> block_template(miner.createNewBlock(coinbase_script)); + std::unique_ptr<BlockTemplate> block_template(miner.createNewBlock({ .coinbase_output_script = coinbase_output_script })); CHECK_NONFATAL(block_template); std::shared_ptr<const CBlock> block_out; @@ -236,9 +236,9 @@ static RPCHelpMan generatetodescriptor() const auto num_blocks{self.Arg<int>("num_blocks")}; const auto max_tries{self.Arg<uint64_t>("maxtries")}; - CScript coinbase_script; + CScript coinbase_output_script; std::string error; - if (!getScriptFromDescriptor(self.Arg<std::string>("descriptor"), coinbase_script, error)) { + if (!getScriptFromDescriptor(self.Arg<std::string>("descriptor"), coinbase_output_script, error)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error); } @@ -246,7 +246,7 @@ static RPCHelpMan generatetodescriptor() Mining& miner = EnsureMining(node); ChainstateManager& chainman = EnsureChainman(node); - return generateBlocks(chainman, miner, coinbase_script, num_blocks, max_tries); + return generateBlocks(chainman, miner, coinbase_output_script, num_blocks, max_tries); }, }; } @@ -292,9 +292,9 @@ static RPCHelpMan generatetoaddress() Mining& miner = EnsureMining(node); ChainstateManager& chainman = EnsureChainman(node); - CScript coinbase_script = GetScriptForDestination(destination); + CScript coinbase_output_script = GetScriptForDestination(destination); - return generateBlocks(chainman, miner, coinbase_script, num_blocks, max_tries); + return generateBlocks(chainman, miner, coinbase_output_script, num_blocks, max_tries); }, }; } @@ -328,16 +328,16 @@ static RPCHelpMan generateblock() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { const auto address_or_descriptor = request.params[0].get_str(); - CScript coinbase_script; + CScript coinbase_output_script; std::string error; - if (!getScriptFromDescriptor(address_or_descriptor, coinbase_script, error)) { + if (!getScriptFromDescriptor(address_or_descriptor, coinbase_output_script, error)) { const auto destination = DecodeDestination(address_or_descriptor); if (!IsValidDestination(destination)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address or descriptor"); } - coinbase_script = GetScriptForDestination(destination); + coinbase_output_script = GetScriptForDestination(destination); } NodeContext& node = EnsureAnyNodeContext(request.context); @@ -371,7 +371,7 @@ static RPCHelpMan generateblock() ChainstateManager& chainman = EnsureChainman(node); { - std::unique_ptr<BlockTemplate> block_template{miner.createNewBlock(coinbase_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); block = block_template->getBlock(); @@ -814,8 +814,7 @@ static RPCHelpMan getblocktemplate() time_start = GetTime(); // Create new block - CScript scriptDummy = CScript() << OP_TRUE; - block_template = miner.createNewBlock(scriptDummy); + block_template = miner.createNewBlock(); CHECK_NONFATAL(block_template); diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index 48ae874fcd8..4b576bb084f 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -67,8 +67,9 @@ CBlock BuildChainTestingSetup::CreateBlock(const CBlockIndex* prev, const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey) { - BlockAssembler::Options options; - std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock(scriptPubKey); + BlockAssembler::Options options; + options.coinbase_output_script = scriptPubKey; + std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock(); CBlock& block = pblocktemplate->block; block.hashPrevBlock = prev->GetBlockHash(); block.nTime = prev->nTime + 1; diff --git a/src/test/fuzz/mini_miner.cpp b/src/test/fuzz/mini_miner.cpp index d06594d5f8d..139fdcdab81 100644 --- a/src/test/fuzz/mini_miner.cpp +++ b/src/test/fuzz/mini_miner.cpp @@ -174,15 +174,15 @@ FUZZ_TARGET(mini_miner_selection, .init = initialize_miner) miner_options.blockMinFeeRate = target_feerate; miner_options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT; miner_options.test_block_validity = false; + miner_options.coinbase_output_script = CScript() << OP_0; node::BlockAssembler miner{g_setup->m_node.chainman->ActiveChainstate(), &pool, miner_options}; node::MiniMiner mini_miner{pool, outpoints}; assert(mini_miner.IsReadyToCalculate()); - CScript spk_placeholder = CScript() << OP_0; // Use BlockAssembler as oracle. BlockAssembler and MiniMiner should select the same // transactions, stopping once packages do not meet target_feerate. - const auto blocktemplate{miner.CreateNewBlock(spk_placeholder)}; + const auto blocktemplate{miner.CreateNewBlock()}; mini_miner.BuildMockTemplate(target_feerate); assert(!mini_miner.IsReadyToCalculate()); auto mock_template_txids = mini_miner.GetMockTemplateTxids(); diff --git a/src/test/fuzz/package_eval.cpp b/src/test/fuzz/package_eval.cpp index 0373d2493fa..2016e3e0522 100644 --- a/src/test/fuzz/package_eval.cpp +++ b/src/test/fuzz/package_eval.cpp @@ -21,6 +21,7 @@ #include <validation.h> #include <validationinterface.h> +using node::BlockAssembler; using node::NodeContext; namespace { @@ -42,8 +43,11 @@ void initialize_tx_pool() static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(); g_setup = testing_setup.get(); + BlockAssembler::Options options; + options.coinbase_output_script = P2WSH_EMPTY; + for (int i = 0; i < 2 * COINBASE_MATURITY; ++i) { - COutPoint prevout{MineBlock(g_setup->m_node, P2WSH_EMPTY)}; + COutPoint prevout{MineBlock(g_setup->m_node, options)}; if (i < COINBASE_MATURITY) { // Remember the txids to avoid expensive disk access later on g_outpoints_coinbase_init_mature.push_back(prevout); diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index 61723882080..a95c6e54dfb 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -45,7 +45,7 @@ void initialize_process_message() {.extra_args = {"-txreconciliation"}}); g_setup = testing_setup.get(); for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { - MineBlock(g_setup->m_node, CScript() << OP_TRUE); + MineBlock(g_setup->m_node, {}); } g_setup->m_node.validation_signals->SyncWithValidationInterfaceQueue(); } diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index 25bda09378e..9b8ce5b23a8 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -35,7 +35,7 @@ void initialize_process_messages() {.extra_args = {"-txreconciliation"}}); g_setup = testing_setup.get(); for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { - MineBlock(g_setup->m_node, CScript() << OP_TRUE); + MineBlock(g_setup->m_node, {}); } g_setup->m_node.validation_signals->SyncWithValidationInterfaceQueue(); } diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index 39aa404484e..0116b4c8dec 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -45,8 +45,11 @@ void initialize_tx_pool() static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(); g_setup = testing_setup.get(); + BlockAssembler::Options options; + options.coinbase_output_script = P2WSH_OP_TRUE; + for (int i = 0; i < 2 * COINBASE_MATURITY; ++i) { - COutPoint prevout{MineBlock(g_setup->m_node, P2WSH_OP_TRUE)}; + COutPoint prevout{MineBlock(g_setup->m_node, options)}; // Remember the txids to avoid expensive disk access later on auto& outpoints = i < COINBASE_MATURITY ? g_outpoints_coinbase_init_mature : @@ -98,7 +101,7 @@ void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, Cha options.nBlockMaxWeight = fuzzed_data_provider.ConsumeIntegralInRange(0U, MAX_BLOCK_WEIGHT); options.blockMinFeeRate = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)}; auto assembler = BlockAssembler{chainstate, &tx_pool, options}; - auto block_template = assembler.CreateNewBlock(CScript{} << OP_TRUE); + auto block_template = assembler.CreateNewBlock(); Assert(block_template->block.vtx.size() >= 1); } const auto info_all = tx_pool.infoAll(); diff --git a/src/test/fuzz/utxo_total_supply.cpp b/src/test/fuzz/utxo_total_supply.cpp index b0f1a1251a6..a09de41d7b9 100644 --- a/src/test/fuzz/utxo_total_supply.cpp +++ b/src/test/fuzz/utxo_total_supply.cpp @@ -17,6 +17,8 @@ #include <util/chaintype.h> #include <validation.h> +using node::BlockAssembler; + FUZZ_TARGET(utxo_total_supply) { /** The testing setup that creates a chainman only (no chainstate) */ @@ -36,9 +38,11 @@ FUZZ_TARGET(utxo_total_supply) LOCK(chainman.GetMutex()); return chainman.ActiveHeight(); }; + BlockAssembler::Options options; + options.coinbase_output_script = CScript() << OP_FALSE; const auto PrepareNextBlock = [&]() { // Use OP_FALSE to avoid BIP30 check from hitting early - auto block = PrepareBlock(node, CScript{} << OP_FALSE); + auto block = PrepareBlock(node, options); // Replace OP_FALSE with OP_TRUE { CMutableTransaction tx{*block->vtx.back()}; diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index c5ecf7022e1..8a264f3fd39 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -54,7 +54,7 @@ struct MinerTestingSetup : public TestingSetup { Assert(error.empty()); return *m_node.mempool; } - BlockAssembler AssemblerForTest(CTxMemPool& tx_mempool); + BlockAssembler AssemblerForTest(CTxMemPool& tx_mempool, BlockAssembler::Options options); }; } // namespace miner_tests @@ -62,10 +62,8 @@ BOOST_FIXTURE_TEST_SUITE(miner_tests, MinerTestingSetup) static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE); -BlockAssembler MinerTestingSetup::AssemblerForTest(CTxMemPool& tx_mempool) +BlockAssembler MinerTestingSetup::AssemblerForTest(CTxMemPool& tx_mempool, BlockAssembler::Options options) { - BlockAssembler::Options options; - options.nBlockMaxWeight = MAX_BLOCK_WEIGHT; options.blockMinFeeRate = blockMinFeeRate; return BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}; @@ -137,7 +135,9 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const Txid hashHighFeeTx = tx.GetHash(); AddToMempool(tx_mempool, entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)); - std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); + BlockAssembler::Options options; + options.coinbase_output_script = scriptPubKey; + std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(tx_mempool, options).CreateNewBlock(); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 4U); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx); BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx); @@ -158,7 +158,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse; Txid hashLowFeeTx = tx.GetHash(); AddToMempool(tx_mempool, entry.Fee(feeToUse).FromTx(tx)); - pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); + pblocktemplate = AssemblerForTest(tx_mempool, options).CreateNewBlock(); // Verify that the free tx and the low fee tx didn't get selected for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx); @@ -172,7 +172,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee hashLowFeeTx = tx.GetHash(); AddToMempool(tx_mempool, entry.Fee(feeToUse + 2).FromTx(tx)); - pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); + pblocktemplate = AssemblerForTest(tx_mempool, options).CreateNewBlock(); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U); BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx); @@ -194,7 +194,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse; Txid hashLowFeeTx2 = tx.GetHash(); AddToMempool(tx_mempool, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); - pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); + pblocktemplate = AssemblerForTest(tx_mempool, options).CreateNewBlock(); // Verify that this tx isn't selected. for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { @@ -207,7 +207,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const tx.vin[0].prevout.n = 1; tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee AddToMempool(tx_mempool, entry.Fee(10000).FromTx(tx)); - pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); + pblocktemplate = AssemblerForTest(tx_mempool, options).CreateNewBlock(); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 9U); BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2); } @@ -225,12 +225,15 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: const CAmount HIGHFEE = COIN; const CAmount HIGHERFEE = 4 * COIN; + BlockAssembler::Options options; + options.coinbase_output_script = scriptPubKey; + { CTxMemPool& tx_mempool{MakeMempool()}; LOCK(tx_mempool.cs); // Just to make sure we can still make simple blocks - auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); + auto pblocktemplate = AssemblerForTest(tx_mempool, options).CreateNewBlock(); BOOST_CHECK(pblocktemplate); // block sigops > limit: 1000 CHECKMULTISIG + 1 @@ -250,7 +253,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: tx.vin[0].prevout.hash = hash; } - BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool, options).CreateNewBlock(), std::runtime_error, HasReason("bad-blk-sigops")); } { @@ -267,7 +270,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: AddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(AssemblerForTest(tx_mempool, options).CreateNewBlock()); } { @@ -291,7 +294,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: AddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(AssemblerForTest(tx_mempool, options).CreateNewBlock()); } { @@ -301,7 +304,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: // orphan in tx_mempool, template creation fails hash = tx.GetHash(); AddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).FromTx(tx)); - BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool, options).CreateNewBlock(), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); } { @@ -322,7 +325,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE; // First txn output + fresh coinbase - new txn fee hash = tx.GetHash(); AddToMempool(tx_mempool, entry.Fee(HIGHERFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(AssemblerForTest(tx_mempool, options).CreateNewBlock()); } { @@ -338,7 +341,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: // give it a fee so it'll get mined AddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)); // Should throw bad-cb-multiple - BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool, options).CreateNewBlock(), std::runtime_error, HasReason("bad-cb-multiple")); } { @@ -355,7 +358,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); AddToMempool(tx_mempool, entry.Fee(HIGHFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool, options).CreateNewBlock(), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); } { @@ -375,7 +378,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: next->BuildSkip(); m_node.chainman->ActiveChain().SetTip(*next); } - BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(AssemblerForTest(tx_mempool, options).CreateNewBlock()); // Extend to a 210000-long block chain. while (m_node.chainman->ActiveChain().Tip()->nHeight < 210000) { CBlockIndex* prev = m_node.chainman->ActiveChain().Tip(); @@ -387,7 +390,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: next->BuildSkip(); m_node.chainman->ActiveChain().SetTip(*next); } - BOOST_CHECK(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(AssemblerForTest(tx_mempool, options).CreateNewBlock()); // invalid p2sh txn in tx_mempool, template creation fails tx.vin[0].prevout.hash = txFirst[0]->GetHash(); @@ -403,7 +406,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: tx.vout[0].nValue -= LOWFEE; hash = tx.GetHash(); AddToMempool(tx_mempool, entry.Fee(LOWFEE).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)); - BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("mandatory-script-verify-flag-failed")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(tx_mempool, options).CreateNewBlock(), std::runtime_error, HasReason("mandatory-script-verify-flag-failed")); // Delete the dummy blocks again. while (m_node.chainman->ActiveChain().Tip()->nHeight > nHeight) { @@ -505,7 +508,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1; BOOST_CHECK(!TestSequenceLocks(CTransaction{tx}, tx_mempool)); // Sequence locks fail - auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); + auto pblocktemplate = AssemblerForTest(tx_mempool, options).CreateNewBlock(); BOOST_CHECK(pblocktemplate); // None of the of the absolute height/time locked tx should have made @@ -521,12 +524,15 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: m_node.chainman->ActiveChain().Tip()->nHeight++; SetMockTime(m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1); - BOOST_CHECK(pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(tx_mempool, options).CreateNewBlock()); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U); } void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) { + BlockAssembler::Options options; + options.coinbase_output_script = scriptPubKey; + CTxMemPool& tx_mempool{MakeMempool()}; LOCK(tx_mempool.cs); @@ -588,7 +594,7 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const Txid hashFreeGrandchild = tx.GetHash(); AddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(false).FromTx(tx)); - auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey); + auto pblocktemplate = AssemblerForTest(tx_mempool, options).CreateNewBlock(); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashFreeParent); BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashFreePrioritisedTx); @@ -610,9 +616,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) CScript scriptPubKey = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex << OP_CHECKSIG; std::unique_ptr<CBlockTemplate> pblocktemplate; + BlockAssembler::Options options; + options.coinbase_output_script = scriptPubKey; + CTxMemPool& tx_mempool{*m_node.mempool}; // Simple block creation, nothing special yet: - BOOST_CHECK(pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(tx_mempool, options).CreateNewBlock()); // We can't make transactions until we have inputs // Therefore, load 110 blocks :) diff --git a/src/test/peerman_tests.cpp b/src/test/peerman_tests.cpp index 6de373eef23..64b13fa3cc1 100644 --- a/src/test/peerman_tests.cpp +++ b/src/test/peerman_tests.cpp @@ -20,8 +20,7 @@ static void mineBlock(const node::NodeContext& node, std::chrono::seconds block_ { auto curr_time = GetTime<std::chrono::seconds>(); SetMockTime(block_time); // update time so the block is created with it - node::BlockAssembler::Options options; - CBlock block = node::BlockAssembler{node.chainman->ActiveChainstate(), nullptr, options}.CreateNewBlock(CScript() << OP_TRUE)->block; + CBlock block = node::BlockAssembler{node.chainman->ActiveChainstate(), nullptr, {}}.CreateNewBlock()->block; while (!CheckProofOfWork(block.GetHash(), block.nBits, node.chainman->GetConsensus())) ++block.nNonce; block.fChecked = true; // little speedup SetMockTime(curr_time); // process block at current time diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp index ad7a38d3fea..bde634ec1cd 100644 --- a/src/test/util/mining.cpp +++ b/src/test/util/mining.cpp @@ -24,9 +24,10 @@ COutPoint generatetoaddress(const NodeContext& node, const std::string& address) { const auto dest = DecodeDestination(address); assert(IsValidDestination(dest)); - const auto coinbase_script = GetScriptForDestination(dest); + BlockAssembler::Options assembler_options; + assembler_options.coinbase_output_script = {GetScriptForDestination(dest)}; - return MineBlock(node, coinbase_script); + return MineBlock(node, assembler_options); } std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const CChainParams& params) @@ -60,9 +61,9 @@ std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const return ret; } -COutPoint MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) +COutPoint MineBlock(const NodeContext& node, const node::BlockAssembler::Options& assembler_options) { - auto block = PrepareBlock(node, coinbase_scriptPubKey); + auto block = PrepareBlock(node, assembler_options); auto valid = MineBlock(node, block); assert(!valid.IsNull()); return valid; @@ -108,12 +109,12 @@ COutPoint MineBlock(const NodeContext& node, std::shared_ptr<CBlock>& block) return {}; } -std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey, +std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const BlockAssembler::Options& assembler_options) { auto block = std::make_shared<CBlock>( BlockAssembler{Assert(node.chainman)->ActiveChainstate(), Assert(node.mempool.get()), assembler_options} - .CreateNewBlock(coinbase_scriptPubKey) + .CreateNewBlock() ->block); LOCK(cs_main); @@ -125,6 +126,7 @@ std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coi std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) { BlockAssembler::Options assembler_options; + assembler_options.coinbase_output_script = coinbase_scriptPubKey; ApplyArgsManOptions(*node.args, assembler_options); - return PrepareBlock(node, coinbase_scriptPubKey, assembler_options); + return PrepareBlock(node, assembler_options); } diff --git a/src/test/util/mining.h b/src/test/util/mining.h index 3f071257f1d..9c6e29b4d34 100644 --- a/src/test/util/mining.h +++ b/src/test/util/mining.h @@ -23,7 +23,8 @@ struct NodeContext; std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const CChainParams& params); /** Returns the generated coin */ -COutPoint MineBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey); +COutPoint MineBlock(const node::NodeContext&, + const node::BlockAssembler::Options& assembler_options); /** * Returns the generated coin (or Null if the block was invalid). @@ -32,8 +33,8 @@ COutPoint MineBlock(const node::NodeContext&, const CScript& coinbase_scriptPubK COutPoint MineBlock(const node::NodeContext&, std::shared_ptr<CBlock>& block); /** Prepare a block to be mined */ -std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey); -std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext& node, const CScript& coinbase_scriptPubKey, +std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext&); +std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext& node, const node::BlockAssembler::Options& assembler_options); /** RPC-like helper function, returns the generated coin */ diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 12feba09a54..68cf49681bc 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -377,7 +377,8 @@ CBlock TestChain100Setup::CreateBlock( Chainstate& chainstate) { BlockAssembler::Options options; - CBlock block = BlockAssembler{chainstate, nullptr, options}.CreateNewBlock(scriptPubKey)->block; + options.coinbase_output_script = scriptPubKey; + CBlock block = BlockAssembler{chainstate, nullptr, options}.CreateNewBlock()->block; Assert(block.vtx.size() == 1); for (const CMutableTransaction& tx : txns) { diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index f3bc8e71391..5c1f195868b 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -66,7 +66,8 @@ std::shared_ptr<CBlock> MinerTestingSetup::Block(const uint256& prev_hash) static uint64_t time = Params().GenesisBlock().nTime; BlockAssembler::Options options; - auto ptemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock(CScript{} << i++ << OP_TRUE); + options.coinbase_output_script = CScript{} << i++ << OP_TRUE; + auto ptemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock(); auto pblock = std::make_shared<CBlock>(ptemplate->block); pblock->hashPrevBlock = prev_hash; pblock->nTime = ++time; @@ -331,7 +332,8 @@ BOOST_AUTO_TEST_CASE(witness_commitment_index) CScript pubKey; pubKey << 1 << OP_TRUE; BlockAssembler::Options options; - auto ptemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock(pubKey); + options.coinbase_output_script = pubKey; + auto ptemplate = BlockAssembler{m_node.chainman->ActiveChainstate(), m_node.mempool.get(), options}.CreateNewBlock(); CBlock pblock = ptemplate->block; CTxOut witness;