Skip to content

Commit 3f66642

Browse files
committed
Merge bitcoin/bitcoin#30440: Have createNewBlock() return a BlockTemplate interface
a93c171 Drop unneeded nullptr check from CreateNewBlock() (Sjors Provoost) dd87b6d Have createNewBlock return BlockTemplate interface (Sjors Provoost) Pull request description: Suggested in bitcoin/bitcoin#29432 (comment) An external program that uses the Mining interface may need quick access to some information in the block template, while it can wait a bit longer for the full raw transaction data. This would be the case for a Stratum v2 Template Provider which needs to send a [NewTemplate](https://github.com/stratum-mining/sv2-spec/blob/main/07-Template-Distribution-Protocol.md#72-newtemplate-server---client) message message (which doesn't include transactions) as quickly as possible. It does not include the serialized block transactions. ACKs for top commit: achow101: ACK a93c171 ryanofsky: Code review ACK a93c171. Since last review, just rebased with no changes or conflicts itornaza: Code review ACK a93c171 TheCharlatan: Re-ACK a93c171 Tree-SHA512: 17cb61eb5548e9d4a69e34dd732f68a06cde2ad3d82c8339efee704c7860d5de144d93b23d6ecd6ee4ec205844e5560ad0f6d3917822fa75bb8e640c5f51af9a
2 parents 2bf721e + a93c171 commit 3f66642

File tree

4 files changed

+112
-50
lines changed

4 files changed

+112
-50
lines changed

src/interfaces/mining.h

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,45 @@
55
#ifndef BITCOIN_INTERFACES_MINING_H
66
#define BITCOIN_INTERFACES_MINING_H
77

8-
#include <node/types.h>
9-
#include <uint256.h>
8+
#include <consensus/amount.h> // for CAmount
9+
#include <node/types.h> // for BlockCreateOptions
10+
#include <primitives/block.h> // for CBlock, CBlockHeader
11+
#include <primitives/transaction.h> // for CTransactionRef
12+
#include <stdint.h> // for int64_t
13+
#include <uint256.h> // for uint256
1014

11-
#include <memory>
12-
#include <optional>
15+
#include <memory> // for unique_ptr, shared_ptr
16+
#include <optional> // for optional
17+
#include <vector> // for vector
1318

1419
namespace node {
15-
struct CBlockTemplate;
1620
struct NodeContext;
1721
} // namespace node
1822

1923
class BlockValidationState;
20-
class CBlock;
2124
class CScript;
2225

2326
namespace interfaces {
2427

28+
//! Block template interface
29+
class BlockTemplate
30+
{
31+
public:
32+
virtual ~BlockTemplate() = default;
33+
34+
virtual CBlockHeader getBlockHeader() = 0;
35+
virtual CBlock getBlock() = 0;
36+
37+
virtual std::vector<CAmount> getTxFees() = 0;
38+
virtual std::vector<int64_t> getTxSigops() = 0;
39+
40+
virtual CTransactionRef getCoinbaseTx() = 0;
41+
virtual std::vector<unsigned char> getCoinbaseCommitment() = 0;
42+
virtual int getWitnessCommitmentIndex() = 0;
43+
};
44+
2545
//! Interface giving clients (RPC, Stratum v2 Template Provider in the future)
2646
//! ability to create block templates.
27-
2847
class Mining
2948
{
3049
public:
@@ -39,14 +58,14 @@ class Mining
3958
//! Returns the hash for the tip of this chain
4059
virtual std::optional<uint256> getTipHash() = 0;
4160

42-
/**
61+
/**
4362
* Construct a new block template
4463
*
4564
* @param[in] script_pub_key the coinbase output
4665
* @param[in] options options for creating the block
4766
* @returns a block template
4867
*/
49-
virtual std::unique_ptr<node::CBlockTemplate> createNewBlock(const CScript& script_pub_key, const node::BlockCreateOptions& options={}) = 0;
68+
virtual std::unique_ptr<BlockTemplate> createNewBlock(const CScript& script_pub_key, const node::BlockCreateOptions& options = {}) = 0;
5069

5170
/**
5271
* Processes new block. A valid new block is automatically relayed to peers.

src/node/interfaces.cpp

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767

6868
#include <boost/signals2/signal.hpp>
6969

70+
using interfaces::BlockTemplate;
7071
using interfaces::BlockTip;
7172
using interfaces::Chain;
7273
using interfaces::FoundBlock;
@@ -863,6 +864,52 @@ class ChainImpl : public Chain
863864
NodeContext& m_node;
864865
};
865866

867+
class BlockTemplateImpl : public BlockTemplate
868+
{
869+
public:
870+
explicit BlockTemplateImpl(std::unique_ptr<CBlockTemplate> block_template) : m_block_template(std::move(block_template))
871+
{
872+
assert(m_block_template);
873+
}
874+
875+
CBlockHeader getBlockHeader() override
876+
{
877+
return m_block_template->block;
878+
}
879+
880+
CBlock getBlock() override
881+
{
882+
return m_block_template->block;
883+
}
884+
885+
std::vector<CAmount> getTxFees() override
886+
{
887+
return m_block_template->vTxFees;
888+
}
889+
890+
std::vector<int64_t> getTxSigops() override
891+
{
892+
return m_block_template->vTxSigOpsCost;
893+
}
894+
895+
CTransactionRef getCoinbaseTx() override
896+
{
897+
return m_block_template->block.vtx[0];
898+
}
899+
900+
std::vector<unsigned char> getCoinbaseCommitment() override
901+
{
902+
return m_block_template->vchCoinbaseCommitment;
903+
}
904+
905+
int getWitnessCommitmentIndex() override
906+
{
907+
return GetWitnessCommitmentIndex(m_block_template->block);
908+
}
909+
910+
const std::unique_ptr<CBlockTemplate> m_block_template;
911+
};
912+
866913
class MinerImpl : public Mining
867914
{
868915
public:
@@ -909,11 +956,11 @@ class MinerImpl : public Mining
909956
return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root);
910957
}
911958

912-
std::unique_ptr<CBlockTemplate> createNewBlock(const CScript& script_pub_key, const BlockCreateOptions& options) override
959+
std::unique_ptr<BlockTemplate> createNewBlock(const CScript& script_pub_key, const BlockCreateOptions& options) override
913960
{
914961
BlockAssembler::Options assemble_options{options};
915962
ApplyArgsManOptions(*Assert(m_node.args), assemble_options);
916-
return BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(script_pub_key);
963+
return std::make_unique<BlockTemplateImpl>(BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(script_pub_key));
917964
}
918965

919966
NodeContext* context() override { return &m_node; }

src/node/miner.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
113113
resetBlock();
114114

115115
pblocktemplate.reset(new CBlockTemplate());
116-
117-
if (!pblocktemplate.get()) {
118-
return nullptr;
119-
}
120116
CBlock* const pblock = &pblocktemplate->block; // pointer for convenience
121117

122118
// Add dummy coinbase tx as first transaction

src/rpc/mining.cpp

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@
4545
#include <memory>
4646
#include <stdint.h>
4747

48-
using node::BlockAssembler;
49-
using node::CBlockTemplate;
48+
using interfaces::BlockTemplate;
5049
using interfaces::Mining;
50+
using node::BlockAssembler;
5151
using node::NodeContext;
5252
using node::RegenerateCommitments;
5353
using node::UpdateTime;
@@ -130,7 +130,7 @@ static RPCHelpMan getnetworkhashps()
130130
};
131131
}
132132

133-
static bool GenerateBlock(ChainstateManager& chainman, Mining& miner, CBlock& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block)
133+
static bool GenerateBlock(ChainstateManager& chainman, Mining& miner, CBlock&& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block)
134134
{
135135
block_out.reset();
136136
block.hashMerkleRoot = BlockMerkleRoot(block);
@@ -146,7 +146,7 @@ static bool GenerateBlock(ChainstateManager& chainman, Mining& miner, CBlock& bl
146146
return true;
147147
}
148148

149-
block_out = std::make_shared<const CBlock>(block);
149+
block_out = std::make_shared<const CBlock>(std::move(block));
150150

151151
if (!process_new_block) return true;
152152

@@ -161,12 +161,11 @@ static UniValue generateBlocks(ChainstateManager& chainman, Mining& miner, const
161161
{
162162
UniValue blockHashes(UniValue::VARR);
163163
while (nGenerate > 0 && !chainman.m_interrupt) {
164-
std::unique_ptr<CBlockTemplate> pblocktemplate(miner.createNewBlock(coinbase_script));
165-
if (!pblocktemplate.get())
166-
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
164+
std::unique_ptr<BlockTemplate> block_template(miner.createNewBlock(coinbase_script));
165+
CHECK_NONFATAL(block_template);
167166

168167
std::shared_ptr<const CBlock> block_out;
169-
if (!GenerateBlock(chainman, miner, pblocktemplate->block, nMaxTries, block_out, /*process_new_block=*/true)) {
168+
if (!GenerateBlock(chainman, miner, block_template->getBlock(), nMaxTries, block_out, /*process_new_block=*/true)) {
170169
break;
171170
}
172171

@@ -371,11 +370,10 @@ static RPCHelpMan generateblock()
371370

372371
ChainstateManager& chainman = EnsureChainman(node);
373372
{
374-
std::unique_ptr<CBlockTemplate> blocktemplate{miner.createNewBlock(coinbase_script, {.use_mempool = false})};
375-
if (!blocktemplate) {
376-
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
377-
}
378-
block = blocktemplate->block;
373+
std::unique_ptr<BlockTemplate> block_template{miner.createNewBlock(coinbase_script, {.use_mempool = false})};
374+
CHECK_NONFATAL(block_template);
375+
376+
block = block_template->getBlock();
379377
}
380378

381379
CHECK_NONFATAL(block.vtx.size() == 1);
@@ -394,7 +392,7 @@ static RPCHelpMan generateblock()
394392
std::shared_ptr<const CBlock> block_out;
395393
uint64_t max_tries{DEFAULT_MAX_TRIES};
396394

397-
if (!GenerateBlock(chainman, miner, block, max_tries, block_out, process_new_block) || !block_out) {
395+
if (!GenerateBlock(chainman, miner, std::move(block), max_tries, block_out, process_new_block) || !block_out) {
398396
throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
399397
}
400398

@@ -800,7 +798,7 @@ static RPCHelpMan getblocktemplate()
800798
// Update block
801799
static CBlockIndex* pindexPrev;
802800
static int64_t time_start;
803-
static std::unique_ptr<CBlockTemplate> pblocktemplate;
801+
static std::unique_ptr<BlockTemplate> block_template;
804802
if (!pindexPrev || pindexPrev->GetBlockHash() != tip ||
805803
(miner.getTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5))
806804
{
@@ -814,20 +812,19 @@ static RPCHelpMan getblocktemplate()
814812

815813
// Create new block
816814
CScript scriptDummy = CScript() << OP_TRUE;
817-
pblocktemplate = miner.createNewBlock(scriptDummy);
818-
if (!pblocktemplate) {
819-
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
820-
}
815+
block_template = miner.createNewBlock(scriptDummy);
816+
CHECK_NONFATAL(block_template);
817+
821818

822819
// Need to update only after we know createNewBlock succeeded
823820
pindexPrev = pindexPrevNew;
824821
}
825822
CHECK_NONFATAL(pindexPrev);
826-
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
823+
CBlock block{block_template->getBlock()};
827824

828825
// Update nTime
829-
UpdateTime(pblock, consensusParams, pindexPrev);
830-
pblock->nNonce = 0;
826+
UpdateTime(&block, consensusParams, pindexPrev);
827+
block.nNonce = 0;
831828

832829
// NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration
833830
const bool fPreSegWit = !DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_SEGWIT);
@@ -836,8 +833,11 @@ static RPCHelpMan getblocktemplate()
836833

837834
UniValue transactions(UniValue::VARR);
838835
std::map<uint256, int64_t> setTxIndex;
836+
std::vector<CAmount> tx_fees{block_template->getTxFees()};
837+
std::vector<CAmount> tx_sigops{block_template->getTxSigops()};
838+
839839
int i = 0;
840-
for (const auto& it : pblock->vtx) {
840+
for (const auto& it : block.vtx) {
841841
const CTransaction& tx = *it;
842842
uint256 txHash = tx.GetHash();
843843
setTxIndex[txHash] = i++;
@@ -860,8 +860,8 @@ static RPCHelpMan getblocktemplate()
860860
entry.pushKV("depends", std::move(deps));
861861

862862
int index_in_template = i - 1;
863-
entry.pushKV("fee", pblocktemplate->vTxFees[index_in_template]);
864-
int64_t nTxSigOps = pblocktemplate->vTxSigOpsCost[index_in_template];
863+
entry.pushKV("fee", tx_fees.at(index_in_template));
864+
int64_t nTxSigOps{tx_sigops.at(index_in_template)};
865865
if (fPreSegWit) {
866866
CHECK_NONFATAL(nTxSigOps % WITNESS_SCALE_FACTOR == 0);
867867
nTxSigOps /= WITNESS_SCALE_FACTOR;
@@ -874,7 +874,7 @@ static RPCHelpMan getblocktemplate()
874874

875875
UniValue aux(UniValue::VOBJ);
876876

877-
arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
877+
arith_uint256 hashTarget = arith_uint256().SetCompact(block.nBits);
878878

879879
UniValue aMutable(UniValue::VARR);
880880
aMutable.push_back("time");
@@ -904,7 +904,7 @@ static RPCHelpMan getblocktemplate()
904904
break;
905905
case ThresholdState::LOCKED_IN:
906906
// Ensure bit is set in block version
907-
pblock->nVersion |= chainman.m_versionbitscache.Mask(consensusParams, pos);
907+
block.nVersion |= chainman.m_versionbitscache.Mask(consensusParams, pos);
908908
[[fallthrough]];
909909
case ThresholdState::STARTED:
910910
{
@@ -913,7 +913,7 @@ static RPCHelpMan getblocktemplate()
913913
if (setClientRules.find(vbinfo.name) == setClientRules.end()) {
914914
if (!vbinfo.gbt_force) {
915915
// If the client doesn't support this, don't indicate it in the [default] version
916-
pblock->nVersion &= ~chainman.m_versionbitscache.Mask(consensusParams, pos);
916+
block.nVersion &= ~chainman.m_versionbitscache.Mask(consensusParams, pos);
917917
}
918918
}
919919
break;
@@ -933,15 +933,15 @@ static RPCHelpMan getblocktemplate()
933933
}
934934
}
935935
}
936-
result.pushKV("version", pblock->nVersion);
936+
result.pushKV("version", block.nVersion);
937937
result.pushKV("rules", std::move(aRules));
938938
result.pushKV("vbavailable", std::move(vbavailable));
939939
result.pushKV("vbrequired", int(0));
940940

941-
result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex());
941+
result.pushKV("previousblockhash", block.hashPrevBlock.GetHex());
942942
result.pushKV("transactions", std::move(transactions));
943943
result.pushKV("coinbaseaux", std::move(aux));
944-
result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue);
944+
result.pushKV("coinbasevalue", (int64_t)block.vtx[0]->vout[0].nValue);
945945
result.pushKV("longpollid", tip.GetHex() + ToString(nTransactionsUpdatedLast));
946946
result.pushKV("target", hashTarget.GetHex());
947947
result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1);
@@ -960,16 +960,16 @@ static RPCHelpMan getblocktemplate()
960960
if (!fPreSegWit) {
961961
result.pushKV("weightlimit", (int64_t)MAX_BLOCK_WEIGHT);
962962
}
963-
result.pushKV("curtime", pblock->GetBlockTime());
964-
result.pushKV("bits", strprintf("%08x", pblock->nBits));
963+
result.pushKV("curtime", block.GetBlockTime());
964+
result.pushKV("bits", strprintf("%08x", block.nBits));
965965
result.pushKV("height", (int64_t)(pindexPrev->nHeight+1));
966966

967967
if (consensusParams.signet_blocks) {
968968
result.pushKV("signet_challenge", HexStr(consensusParams.signet_challenge));
969969
}
970970

971-
if (!pblocktemplate->vchCoinbaseCommitment.empty()) {
972-
result.pushKV("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment));
971+
if (!block_template->getCoinbaseCommitment().empty()) {
972+
result.pushKV("default_witness_commitment", HexStr(block_template->getCoinbaseCommitment()));
973973
}
974974

975975
return result;

0 commit comments

Comments
 (0)