From 271dd0003ce482a20d119ae437ccd47436bd94b9 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 2 Sep 2025 10:35:09 +0200 Subject: [PATCH] Sv2NewTemplate: add coinbase_witness Adding coinbase_witness to the Sv2NewTemplate message so that it is automatically propagated to other roles in the Stratum v2 ecosystem, rather than assumed to be 0x00...00. This ensures that if this value ever gets consensus meaning, miners only need to upgrade their node software, not the rest of the mining stack. This is a breaking change requiring an updated Stratum v2 spec as well as support on the SRI side. --- src/sv2/messages.cpp | 7 +++++++ src/sv2/messages.h | 13 +++++++++++++ src/test/sv2_messages_tests.cpp | 5 ++++- src/test/sv2_template_provider_tests.cpp | 3 ++- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/sv2/messages.cpp b/src/sv2/messages.cpp index b4c28fc6..b553d451 100644 --- a/src/sv2/messages.cpp +++ b/src/sv2/messages.cpp @@ -12,6 +12,13 @@ node::Sv2NewTemplateMsg::Sv2NewTemplateMsg(const CBlockHeader& header, const CTr m_coinbase_tx_version = coinbase_tx->CURRENT_VERSION; m_coinbase_prefix = coinbase_tx->vin[0].scriptSig; + if (coinbase_tx->HasWitness()) { + const auto& witness_stack{coinbase_tx->vin[0].scriptWitness.stack}; + Assert(witness_stack.size() == 1 || witness_stack[0].size() == 32); + m_coinbase_witness = uint256(witness_stack[0]); + } else { + m_coinbase_witness = uint256(0); + } m_coinbase_tx_input_sequence = coinbase_tx->vin[0].nSequence; // The coinbase nValue already contains the nFee + the Block Subsidy when built using CreateBlock(). diff --git a/src/sv2/messages.h b/src/sv2/messages.h index 1a35dcc9..4c3eb766 100644 --- a/src/sv2/messages.h +++ b/src/sv2/messages.h @@ -282,6 +282,18 @@ struct Sv2NewTemplateMsg */ CScript m_coinbase_prefix; + /** + * 32 byte array of the first (and only) witness stack element of the coinbase. + * + * If there is no segwit commitment in m_coinbase_tx_outputs this value + * must be ignored. + * + * This is the BIP 141 witness reserved value. A future soft fork may move + * the witness reserved value elsewhere. In that case this field still + * represents the coinbase witness, for backward compatibility. + */ + uint256 m_coinbase_witness; + /** * The coinbase transaction input’s nSequence field. */ @@ -324,6 +336,7 @@ struct Sv2NewTemplateMsg << m_version << m_coinbase_tx_version << m_coinbase_prefix + << m_coinbase_witness << m_coinbase_tx_input_sequence << m_coinbase_tx_value_remaining << m_coinbase_tx_outputs_count; diff --git a/src/test/sv2_messages_tests.cpp b/src/test/sv2_messages_tests.cpp index f51fb6ba..7f96ffb3 100644 --- a/src/test/sv2_messages_tests.cpp +++ b/src/test/sv2_messages_tests.cpp @@ -110,6 +110,7 @@ BOOST_AUTO_TEST_CASE(Sv2NewTemplate_test) // U32 02000000 coinbase tx version // B0_255 04 coinbase_prefix len // 03012100 coinbase prefix + // U256 0000000000000000000000000000000000000000000000000000000000000000 - witness // U32 ffffffff coinbase tx input sequence // U64 0040075af0750700 coinbase tx value remaining // U32 01000000 coinbase tx outputs count @@ -119,7 +120,7 @@ BOOST_AUTO_TEST_CASE(Sv2NewTemplate_test) // U32 dbc80d00 coinbase lock time (height 903,387) // SEQ0_255[U256] 01 merkle path length // 1a6240823de4c8d6aaf826851bdf2b0e8d5acf7c31e8578cff4c394b5a32bd4e - merkle path - std::string expected{"01000000000000000000000030020000000403012100ffffffff0040075af0750700010000000c000100000000000000036a012adbc80d00011a6240823de4c8d6aaf826851bdf2b0e8d5acf7c31e8578cff4c394b5a32bd4e"}; + std::string expected{"010000000000000000000000300200000004030121000000000000000000000000000000000000000000000000000000000000000000ffffffff0040075af0750700010000000c000100000000000000036a012adbc80d00011a6240823de4c8d6aaf826851bdf2b0e8d5acf7c31e8578cff4c394b5a32bd4e"}; node::Sv2NewTemplateMsg new_template; new_template.m_template_id = 1; @@ -131,6 +132,8 @@ BOOST_AUTO_TEST_CASE(Sv2NewTemplate_test) CScript prefix(coinbase_prefix.begin(), coinbase_prefix.end()); new_template.m_coinbase_prefix = prefix; + new_template.m_coinbase_witness = uint256(0); + new_template.m_coinbase_tx_input_sequence = 4294967295; new_template.m_coinbase_tx_value_remaining = MAX_MONEY; diff --git a/src/test/sv2_template_provider_tests.cpp b/src/test/sv2_template_provider_tests.cpp index d32402bf..75a487e8 100644 --- a/src/test/sv2_template_provider_tests.cpp +++ b/src/test/sv2_template_provider_tests.cpp @@ -61,7 +61,8 @@ BOOST_AUTO_TEST_CASE(client_tests) 1 + // future_template 4 + // version 4 + // coinbase_tx_version - 2 + // coinbase_prefix (CompactSize(1) + 1-byte OP_0) + 2 + // coinbase_prefix (CompactSize(1) + 1-byte OP_0) + 32 + // coinbase_witness (fixed-size reserved value) 4 + // coinbase_tx_input_sequence 8 + // coinbase_tx_value_remaining 4 + // coinbase_tx_outputs_count (0)