From 56895dd26608c8d58963ce5854dd09da33311296 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 f4cc3991..800fd81f 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 ed01e44a..85cff64d 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 af33dde8..0fbdfdaa 100644 --- a/src/sv2/template_provider.cpp +++ b/src/sv2/template_provider.cpp @@ -587,7 +587,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 674343b1..f35459d9 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 57f1275a..237df7c8 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 ee016be5ad5ad46f7d0ceb96b929ab0fb4d87ca3 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 800fd81f..ed3e2c1c 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::CoinbaseTx 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 7d006254..eea4678f 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 85cff64d..76cf6673 100644 --- a/src/ipc/capnp/mining.capnp +++ b/src/ipc/capnp/mining.capnp @@ -28,6 +28,7 @@ interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") { getTxFees @3 (context: Proxy.Context) -> (result: List(Int64)); getTxSigops @4 (context: Proxy.Context) -> (result: List(Int64)); getCoinbaseRawTx @5 (context: Proxy.Context) -> (result: Data); + getCoinbaseTx @12 (context: Proxy.Context) -> (result: CoinbaseTx); getCoinbaseCommitment @6 (context: Proxy.Context) -> (result: Data); getWitnessCommitmentIndex @7 (context: Proxy.Context) -> (result: Int32); getCoinbaseMerklePath @8 (context: Proxy.Context) -> (result: List(Data)); @@ -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 CoinbaseTx $Proxy.wrap("node::CoinbaseTx") { + 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 00000000..aeb25fa5 --- /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