Skip to content

Commit ef19a19

Browse files
committed
Merge bitcoin/bitcoin#30356: refactor: add coinbase constraints to BlockAssembler::Options
c504b69 refactor: add coinbase constraints to BlockCreateOptions (Sjors Provoost) 6b4c817 refactor: pass BlockCreateOptions to createNewBlock (Sjors Provoost) 323cfed refactor: use CHECK_NONFATAL to avoid single-use symbol (Sjors Provoost) Pull request description: When generating a block template through e.g. getblocktemplate RPC, we reserve 4000 weight units and 400 sigops. Pools use this space for their coinbase outputs. At least one pool patched their Bitcoin Core node to adjust these hardcoded values. They eventually [produced an invalid block](https://bitcoin.stackexchange.com/questions/117837/how-many-sigops-are-in-the-invalid-block-783426) which exceeded the sigops limit. The existince of such patches suggests it may be useful to make this value configurable. This PR would make such a change easier. However, the main motivation is that in the Stratum v2 spec requires the pool to communicate the maximum bytes they intend to add to the coinbase outputs. Specifically the `CoinbaseOutputDataSize` message which is part of the [Template Distribution Protocol](https://github.com/stratum-mining/sv2-spec/blob/main/07-Template-Distribution-Protocol.md#71-coinbaseoutputdatasize-client---server) has a field `coinbase_output_max_additional_size`. A proposed change to the spec adds the max additional sigops as well: stratum-mining/sv2-spec#86. Whether that change makes it into the spec is not important though, as adding both to `BlockAssembler::Options` makes sense. The first commit is a test refactor followup for #30335, related to the code that's changed here, but not required. The second commit introduces BlockCreateOptions, with just `use_mempool`. The thirds commit adds `coinbase_max_additional_weight` and `coinbase_output_max_additional_sigops` to `BlockCreateOptions`. They use the originally hardcoded values, and no existing caller overrides these defaults. This changes in #29432. ACKs for top commit: itornaza: tested ACK c504b69 ryanofsky: Code review ACK c504b69 ismaelsadeeq: Code review ACK c504b69 Tree-SHA512: de2fa085f47048c91d95524e03f909f6f27f175c1fefa3d6106445e7eb5cf5b710eda6ea5b641cf3b4704a4e4e0181a0c829003b9fd35465f2a46167e5d64487
2 parents 9c8b36e + c504b69 commit ef19a19

File tree

6 files changed

+42
-19
lines changed

6 files changed

+42
-19
lines changed

src/interfaces/mining.h

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

8+
#include <node/types.h>
9+
#include <uint256.h>
10+
811
#include <memory>
912
#include <optional>
10-
#include <uint256.h>
1113

1214
namespace node {
1315
struct CBlockTemplate;
@@ -41,10 +43,10 @@ class Mining
4143
* Construct a new block template
4244
*
4345
* @param[in] script_pub_key the coinbase output
44-
* @param[in] use_mempool set false to omit mempool transactions
46+
* @param[in] options options for creating the block
4547
* @returns a block template
4648
*/
47-
virtual std::unique_ptr<node::CBlockTemplate> createNewBlock(const CScript& script_pub_key, bool use_mempool = true) = 0;
49+
virtual std::unique_ptr<node::CBlockTemplate> createNewBlock(const CScript& script_pub_key, const node::BlockCreateOptions& options={}) = 0;
4850

4951
/**
5052
* Processes new block. A valid new block is automatically relayed to peers.

src/node/interfaces.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -884,12 +884,11 @@ class MinerImpl : public Mining
884884
return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root);
885885
}
886886

887-
std::unique_ptr<CBlockTemplate> createNewBlock(const CScript& script_pub_key, bool use_mempool) override
887+
std::unique_ptr<CBlockTemplate> createNewBlock(const CScript& script_pub_key, const BlockCreateOptions& options) override
888888
{
889-
BlockAssembler::Options options;
890-
ApplyArgsManOptions(gArgs, options);
891-
892-
return BlockAssembler{chainman().ActiveChainstate(), use_mempool ? context()->mempool.get() : nullptr, options}.CreateNewBlock(script_pub_key);
889+
BlockAssembler::Options assemble_options{options};
890+
ApplyArgsManOptions(*Assert(m_node.args), assemble_options);
891+
return BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(script_pub_key);
893892
}
894893

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

src/node/miner.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,17 @@ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman)
5959

6060
static BlockAssembler::Options ClampOptions(BlockAssembler::Options options)
6161
{
62-
// Limit weight to between 4K and DEFAULT_BLOCK_MAX_WEIGHT for sanity:
63-
options.nBlockMaxWeight = std::clamp<size_t>(options.nBlockMaxWeight, 4000, DEFAULT_BLOCK_MAX_WEIGHT);
62+
Assert(options.coinbase_max_additional_weight <= DEFAULT_BLOCK_MAX_WEIGHT);
63+
Assert(options.coinbase_output_max_additional_sigops <= MAX_BLOCK_SIGOPS_COST);
64+
// Limit weight to between coinbase_max_additional_weight and DEFAULT_BLOCK_MAX_WEIGHT for sanity:
65+
// Coinbase (reserved) outputs can safely exceed -blockmaxweight, but the rest of the block template will be empty.
66+
options.nBlockMaxWeight = std::clamp<size_t>(options.nBlockMaxWeight, options.coinbase_max_additional_weight, DEFAULT_BLOCK_MAX_WEIGHT);
6467
return options;
6568
}
6669

6770
BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options)
6871
: chainparams{chainstate.m_chainman.GetParams()},
69-
m_mempool{mempool},
72+
m_mempool{options.use_mempool ? mempool : nullptr},
7073
m_chainstate{chainstate},
7174
m_options{ClampOptions(options)}
7275
{
@@ -87,8 +90,8 @@ void BlockAssembler::resetBlock()
8790
inBlock.clear();
8891

8992
// Reserve space for coinbase tx
90-
nBlockWeight = 4000;
91-
nBlockSigOpsCost = 400;
93+
nBlockWeight = m_options.coinbase_max_additional_weight;
94+
nBlockSigOpsCost = m_options.coinbase_output_max_additional_sigops;
9295

9396
// These counters do not include coinbase tx
9497
nBlockTx = 0;
@@ -379,7 +382,7 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele
379382
++nConsecutiveFailed;
380383

381384
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight >
382-
m_options.nBlockMaxWeight - 4000) {
385+
m_options.nBlockMaxWeight - m_options.coinbase_max_additional_weight) {
383386
// Give up if we're close to full and haven't succeeded in a while
384387
break;
385388
}

src/node/miner.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#ifndef BITCOIN_NODE_MINER_H
77
#define BITCOIN_NODE_MINER_H
88

9+
#include <node/types.h>
910
#include <policy/policy.h>
1011
#include <primitives/block.h>
1112
#include <txmempool.h>
@@ -153,7 +154,7 @@ class BlockAssembler
153154
Chainstate& m_chainstate;
154155

155156
public:
156-
struct Options {
157+
struct Options : BlockCreateOptions {
157158
// Configuration parameters for the block size
158159
size_t nBlockMaxWeight{DEFAULT_BLOCK_MAX_WEIGHT};
159160
CFeeRate blockMinFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};

src/node/types.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#ifndef BITCOIN_NODE_TYPES_H
1414
#define BITCOIN_NODE_TYPES_H
1515

16+
#include <cstddef>
17+
1618
namespace node {
1719
enum class TransactionError {
1820
OK, //!< No error
@@ -24,6 +26,24 @@ enum class TransactionError {
2426
MAX_BURN_EXCEEDED,
2527
INVALID_PACKAGE,
2628
};
29+
30+
struct BlockCreateOptions {
31+
/**
32+
* Set false to omit mempool transactions
33+
*/
34+
bool use_mempool{true};
35+
/**
36+
* The maximum additional weight which the pool will add to the coinbase
37+
* scriptSig, witness and outputs. This must include any additional
38+
* weight needed for larger CompactSize encoded lengths.
39+
*/
40+
size_t coinbase_max_additional_weight{4000};
41+
/**
42+
* The maximum additional sigops which the pool will add in coinbase
43+
* transaction outputs.
44+
*/
45+
size_t coinbase_output_max_additional_sigops{400};
46+
};
2747
} // namespace node
2848

2949
#endif // BITCOIN_NODE_TYPES_H

src/rpc/mining.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ static RPCHelpMan generateblock()
371371

372372
ChainstateManager& chainman = EnsureChainman(node);
373373
{
374-
std::unique_ptr<CBlockTemplate> blocktemplate{miner.createNewBlock(coinbase_script, /*use_mempool=*/false)};
374+
std::unique_ptr<CBlockTemplate> blocktemplate{miner.createNewBlock(coinbase_script, {.use_mempool = false})};
375375
if (!blocktemplate) {
376376
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
377377
}
@@ -778,9 +778,7 @@ static RPCHelpMan getblocktemplate()
778778
}
779779
ENTER_CRITICAL_SECTION(cs_main);
780780

781-
std::optional<uint256> maybe_tip{miner.getTipHash()};
782-
CHECK_NONFATAL(maybe_tip);
783-
tip = maybe_tip.value();
781+
tip = CHECK_NONFATAL(miner.getTipHash()).value();
784782

785783
if (!IsRPCRunning())
786784
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");

0 commit comments

Comments
 (0)