From a62cb707dba6ca7d1c757e1b3ed02008e7e3d0af Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Wed, 3 Dec 2025 13:01:27 +0100 Subject: [PATCH 1/2] mining: rename getCoinbaseTx() to ..RawTx() This frees up the name getCoinbaseTx() for the next commit. Changing a function name does not impact IPC clients, as they only consider the function signature and sequence number. --- src/interfaces/mining.h | 13 ++++++++++++- src/ipc/capnp/mining.capnp | 2 +- src/sv2/template_provider.cpp | 2 +- src/test/sv2_mock_mining.cpp | 2 +- src/test/sv2_mock_mining.h | 2 +- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h index f4cc399..800fd81 100644 --- a/src/interfaces/mining.h +++ b/src/interfaces/mining.h @@ -38,8 +38,19 @@ class BlockTemplate // Sigop cost per transaction, not including coinbase transaction. virtual std::vector getTxSigops() = 0; - virtual CTransactionRef getCoinbaseTx() = 0; + /** + * Return serialized dummy coinbase transaction. + */ + virtual CTransactionRef getCoinbaseRawTx() = 0; + + /** + * Return scriptPubKey with SegWit OP_RETURN. + */ virtual std::vector getCoinbaseCommitment() = 0; + + /** + * Return which output in the dummy coinbase contains the SegWit OP_RETURN. + */ virtual int getWitnessCommitmentIndex() = 0; /** diff --git a/src/ipc/capnp/mining.capnp b/src/ipc/capnp/mining.capnp index ed01e44..85cff64 100644 --- a/src/ipc/capnp/mining.capnp +++ b/src/ipc/capnp/mining.capnp @@ -27,7 +27,7 @@ interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") { getBlock @2 (context: Proxy.Context) -> (result: Data); getTxFees @3 (context: Proxy.Context) -> (result: List(Int64)); getTxSigops @4 (context: Proxy.Context) -> (result: List(Int64)); - getCoinbaseTx @5 (context: Proxy.Context) -> (result: Data); + getCoinbaseRawTx @5 (context: Proxy.Context) -> (result: Data); getCoinbaseCommitment @6 (context: Proxy.Context) -> (result: Data); getWitnessCommitmentIndex @7 (context: Proxy.Context) -> (result: Int32); getCoinbaseMerklePath @8 (context: Proxy.Context) -> (result: List(Data)); diff --git a/src/sv2/template_provider.cpp b/src/sv2/template_provider.cpp index d308cc6..30d9557 100644 --- a/src/sv2/template_provider.cpp +++ b/src/sv2/template_provider.cpp @@ -576,7 +576,7 @@ bool Sv2TemplateProvider::SendWork(Sv2Client& client, uint64_t template_id, Bloc } node::Sv2NewTemplateMsg new_template{header, - block_template.getCoinbaseTx(), + block_template.getCoinbaseRawTx(), block_template.getCoinbaseMerklePath(), template_id, future_template}; diff --git a/src/test/sv2_mock_mining.cpp b/src/test/sv2_mock_mining.cpp index 674343b..f35459d 100644 --- a/src/test/sv2_mock_mining.cpp +++ b/src/test/sv2_mock_mining.cpp @@ -56,7 +56,7 @@ CBlockHeader MockBlockTemplate::getBlockHeader() { return block.GetBlockHeader() CBlock MockBlockTemplate::getBlock() { return block; } std::vector MockBlockTemplate::getTxFees() { return {}; } std::vector MockBlockTemplate::getTxSigops() { return {}; } -CTransactionRef MockBlockTemplate::getCoinbaseTx() { return block.vtx[0]; } +CTransactionRef MockBlockTemplate::getCoinbaseRawTx() { return block.vtx[0]; } std::vector MockBlockTemplate::getCoinbaseCommitment() { return {}; } int MockBlockTemplate::getWitnessCommitmentIndex() { return -1; } std::vector MockBlockTemplate::getCoinbaseMerklePath() { return {}; } diff --git a/src/test/sv2_mock_mining.h b/src/test/sv2_mock_mining.h index 57f1275..237df7c 100644 --- a/src/test/sv2_mock_mining.h +++ b/src/test/sv2_mock_mining.h @@ -58,7 +58,7 @@ class MockBlockTemplate : public interfaces::BlockTemplate { CBlock getBlock() override; std::vector getTxFees() override; std::vector getTxSigops() override; - CTransactionRef getCoinbaseTx() override; + CTransactionRef getCoinbaseRawTx() override; std::vector getCoinbaseCommitment() override; int getWitnessCommitmentIndex() override; std::vector getCoinbaseMerklePath() override; From 3f6838428bc694b33befecfd05ca56dc58fa21b3 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Wed, 3 Dec 2025 15:24:14 +0100 Subject: [PATCH 2/2] Use CoinbaseTemplate if available Avoid the brittle process of constructing the template coinbase fields from Bitcoin Core's dummy coinbase transaction. This uses the new getCoinbaseTx() interface method. Fall back to the old approach if that method is not available. --- src/interfaces/mining.h | 11 ++++++ src/ipc/capnp/mining-types.h | 1 + src/ipc/capnp/mining.capnp | 11 ++++++ src/sv2/coinbase_template.h | 63 ++++++++++++++++++++++++++++++++ src/sv2/messages.cpp | 67 +++++++++++++++++++++++++++++------ src/sv2/messages.h | 14 +++++++- src/sv2/template_provider.cpp | 25 ++++++++++--- src/test/sv2_mock_mining.cpp | 2 ++ src/test/sv2_mock_mining.h | 1 + 9 files changed, 178 insertions(+), 17 deletions(-) create mode 100644 src/sv2/coinbase_template.h diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h index 800fd81..00dcf78 100644 --- a/src/interfaces/mining.h +++ b/src/interfaces/mining.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -38,18 +39,28 @@ class BlockTemplate // Sigop cost per transaction, not including coinbase transaction. virtual std::vector getTxSigops() = 0; + /** Return fields needed to construct a coinbase transaction */ + virtual node::CoinbaseTxTemplate getCoinbaseTx() = 0; + /** * Return serialized dummy coinbase transaction. + * + * @note deprecated: use getCoinbaseTx() */ virtual CTransactionRef getCoinbaseRawTx() = 0; /** * Return scriptPubKey with SegWit OP_RETURN. + * + * @note deprecated: use getCoinbaseRawTx() */ virtual std::vector getCoinbaseCommitment() = 0; /** * Return which output in the dummy coinbase contains the SegWit OP_RETURN. + * + * @note deprecated. Scan outputs from getCoinbaseRawTx() outputs field for the + * SegWit marker. */ virtual int getWitnessCommitmentIndex() = 0; diff --git a/src/ipc/capnp/mining-types.h b/src/ipc/capnp/mining-types.h index 7d00625..eea4678 100644 --- a/src/ipc/capnp/mining-types.h +++ b/src/ipc/capnp/mining-types.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace mp { // Custom serializations diff --git a/src/ipc/capnp/mining.capnp b/src/ipc/capnp/mining.capnp index 85cff64..28da7d9 100644 --- a/src/ipc/capnp/mining.capnp +++ b/src/ipc/capnp/mining.capnp @@ -27,6 +27,7 @@ interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") { getBlock @2 (context: Proxy.Context) -> (result: Data); getTxFees @3 (context: Proxy.Context) -> (result: List(Int64)); getTxSigops @4 (context: Proxy.Context) -> (result: List(Int64)); + getCoinbaseTx @12 (context: Proxy.Context) -> (result: CoinbaseTxTemplate); getCoinbaseRawTx @5 (context: Proxy.Context) -> (result: Data); getCoinbaseCommitment @6 (context: Proxy.Context) -> (result: Data); getWitnessCommitmentIndex @7 (context: Proxy.Context) -> (result: Int32); @@ -51,3 +52,13 @@ struct BlockCheckOptions $Proxy.wrap("node::BlockCheckOptions") { checkMerkleRoot @0 :Bool $Proxy.name("check_merkle_root"); checkPow @1 :Bool $Proxy.name("check_pow"); } + +struct CoinbaseTxTemplate $Proxy.wrap("node::CoinbaseTxTemplate") { + version @0 :UInt32 $Proxy.name("version"); + sequence @1 :UInt32 $Proxy.name("sequence"); + scriptSigPrefix @2 :Data $Proxy.name("script_sig_prefix"); + witness @3 :Data $Proxy.name("witness"); + blockRewardRemaining @4 :Int64 $Proxy.name("block_reward_remaining"); + requiredOutputs @5 :List(Data) $Proxy.name("required_outputs"); + lockTime @6 :UInt32 $Proxy.name("lock_time"); +} diff --git a/src/sv2/coinbase_template.h b/src/sv2/coinbase_template.h new file mode 100644 index 0000000..d6b48b4 --- /dev/null +++ b/src/sv2/coinbase_template.h @@ -0,0 +1,63 @@ +// Copyright (c) 2025 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_SV2_COINBASE_TEMPLATE_H +#define BITCOIN_SV2_COINBASE_TEMPLATE_H + +#include +#include +#include +#include +#include