mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-05-29 05:22:30 +02:00
Merge bitcoin/bitcoin#30356: refactor: add coinbase constraints to BlockAssembler::Options
c504b6997b
refactor: add coinbase constraints to BlockCreateOptions (Sjors Provoost)6b4c817d4b
refactor: pass BlockCreateOptions to createNewBlock (Sjors Provoost)323cfed595
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: https://github.com/stratum-mining/sv2-spec/pull/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 ACKc504b6997b
ryanofsky: Code review ACKc504b6997b
ismaelsadeeq: Code review ACKc504b6997b
Tree-SHA512: de2fa085f47048c91d95524e03f909f6f27f175c1fefa3d6106445e7eb5cf5b710eda6ea5b641cf3b4704a4e4e0181a0c829003b9fd35465f2a46167e5d64487
This commit is contained in:
commit
ef19a193fc
@ -5,9 +5,11 @@
|
|||||||
#ifndef BITCOIN_INTERFACES_MINING_H
|
#ifndef BITCOIN_INTERFACES_MINING_H
|
||||||
#define BITCOIN_INTERFACES_MINING_H
|
#define BITCOIN_INTERFACES_MINING_H
|
||||||
|
|
||||||
|
#include <node/types.h>
|
||||||
|
#include <uint256.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <uint256.h>
|
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
struct CBlockTemplate;
|
struct CBlockTemplate;
|
||||||
@ -41,10 +43,10 @@ public:
|
|||||||
* Construct a new block template
|
* Construct a new block template
|
||||||
*
|
*
|
||||||
* @param[in] script_pub_key the coinbase output
|
* @param[in] script_pub_key the coinbase output
|
||||||
* @param[in] use_mempool set false to omit mempool transactions
|
* @param[in] options options for creating the block
|
||||||
* @returns a block template
|
* @returns a block template
|
||||||
*/
|
*/
|
||||||
virtual std::unique_ptr<node::CBlockTemplate> createNewBlock(const CScript& script_pub_key, bool use_mempool = true) = 0;
|
virtual std::unique_ptr<node::CBlockTemplate> createNewBlock(const CScript& script_pub_key, const node::BlockCreateOptions& options={}) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes new block. A valid new block is automatically relayed to peers.
|
* Processes new block. A valid new block is automatically relayed to peers.
|
||||||
|
@ -884,12 +884,11 @@ public:
|
|||||||
return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root);
|
return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CBlockTemplate> createNewBlock(const CScript& script_pub_key, bool use_mempool) override
|
std::unique_ptr<CBlockTemplate> createNewBlock(const CScript& script_pub_key, const BlockCreateOptions& options) override
|
||||||
{
|
{
|
||||||
BlockAssembler::Options options;
|
BlockAssembler::Options assemble_options{options};
|
||||||
ApplyArgsManOptions(gArgs, options);
|
ApplyArgsManOptions(*Assert(m_node.args), assemble_options);
|
||||||
|
return BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(script_pub_key);
|
||||||
return BlockAssembler{chainman().ActiveChainstate(), use_mempool ? context()->mempool.get() : nullptr, options}.CreateNewBlock(script_pub_key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeContext* context() override { return &m_node; }
|
NodeContext* context() override { return &m_node; }
|
||||||
|
@ -59,14 +59,17 @@ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman)
|
|||||||
|
|
||||||
static BlockAssembler::Options ClampOptions(BlockAssembler::Options options)
|
static BlockAssembler::Options ClampOptions(BlockAssembler::Options options)
|
||||||
{
|
{
|
||||||
// Limit weight to between 4K and DEFAULT_BLOCK_MAX_WEIGHT for sanity:
|
Assert(options.coinbase_max_additional_weight <= DEFAULT_BLOCK_MAX_WEIGHT);
|
||||||
options.nBlockMaxWeight = std::clamp<size_t>(options.nBlockMaxWeight, 4000, DEFAULT_BLOCK_MAX_WEIGHT);
|
Assert(options.coinbase_output_max_additional_sigops <= MAX_BLOCK_SIGOPS_COST);
|
||||||
|
// Limit weight to between coinbase_max_additional_weight and DEFAULT_BLOCK_MAX_WEIGHT for sanity:
|
||||||
|
// Coinbase (reserved) outputs can safely exceed -blockmaxweight, but the rest of the block template will be empty.
|
||||||
|
options.nBlockMaxWeight = std::clamp<size_t>(options.nBlockMaxWeight, options.coinbase_max_additional_weight, DEFAULT_BLOCK_MAX_WEIGHT);
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options)
|
BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options)
|
||||||
: chainparams{chainstate.m_chainman.GetParams()},
|
: chainparams{chainstate.m_chainman.GetParams()},
|
||||||
m_mempool{mempool},
|
m_mempool{options.use_mempool ? mempool : nullptr},
|
||||||
m_chainstate{chainstate},
|
m_chainstate{chainstate},
|
||||||
m_options{ClampOptions(options)}
|
m_options{ClampOptions(options)}
|
||||||
{
|
{
|
||||||
@ -87,8 +90,8 @@ void BlockAssembler::resetBlock()
|
|||||||
inBlock.clear();
|
inBlock.clear();
|
||||||
|
|
||||||
// Reserve space for coinbase tx
|
// Reserve space for coinbase tx
|
||||||
nBlockWeight = 4000;
|
nBlockWeight = m_options.coinbase_max_additional_weight;
|
||||||
nBlockSigOpsCost = 400;
|
nBlockSigOpsCost = m_options.coinbase_output_max_additional_sigops;
|
||||||
|
|
||||||
// These counters do not include coinbase tx
|
// These counters do not include coinbase tx
|
||||||
nBlockTx = 0;
|
nBlockTx = 0;
|
||||||
@ -379,7 +382,7 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele
|
|||||||
++nConsecutiveFailed;
|
++nConsecutiveFailed;
|
||||||
|
|
||||||
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight >
|
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight >
|
||||||
m_options.nBlockMaxWeight - 4000) {
|
m_options.nBlockMaxWeight - m_options.coinbase_max_additional_weight) {
|
||||||
// Give up if we're close to full and haven't succeeded in a while
|
// Give up if we're close to full and haven't succeeded in a while
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#ifndef BITCOIN_NODE_MINER_H
|
#ifndef BITCOIN_NODE_MINER_H
|
||||||
#define BITCOIN_NODE_MINER_H
|
#define BITCOIN_NODE_MINER_H
|
||||||
|
|
||||||
|
#include <node/types.h>
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
#include <primitives/block.h>
|
#include <primitives/block.h>
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
@ -153,7 +154,7 @@ private:
|
|||||||
Chainstate& m_chainstate;
|
Chainstate& m_chainstate;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Options {
|
struct Options : BlockCreateOptions {
|
||||||
// Configuration parameters for the block size
|
// Configuration parameters for the block size
|
||||||
size_t nBlockMaxWeight{DEFAULT_BLOCK_MAX_WEIGHT};
|
size_t nBlockMaxWeight{DEFAULT_BLOCK_MAX_WEIGHT};
|
||||||
CFeeRate blockMinFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
|
CFeeRate blockMinFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#ifndef BITCOIN_NODE_TYPES_H
|
#ifndef BITCOIN_NODE_TYPES_H
|
||||||
#define BITCOIN_NODE_TYPES_H
|
#define BITCOIN_NODE_TYPES_H
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
enum class TransactionError {
|
enum class TransactionError {
|
||||||
OK, //!< No error
|
OK, //!< No error
|
||||||
@ -24,6 +26,24 @@ enum class TransactionError {
|
|||||||
MAX_BURN_EXCEEDED,
|
MAX_BURN_EXCEEDED,
|
||||||
INVALID_PACKAGE,
|
INVALID_PACKAGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BlockCreateOptions {
|
||||||
|
/**
|
||||||
|
* Set false to omit mempool transactions
|
||||||
|
*/
|
||||||
|
bool use_mempool{true};
|
||||||
|
/**
|
||||||
|
* The maximum additional weight which the pool will add to the coinbase
|
||||||
|
* scriptSig, witness and outputs. This must include any additional
|
||||||
|
* weight needed for larger CompactSize encoded lengths.
|
||||||
|
*/
|
||||||
|
size_t coinbase_max_additional_weight{4000};
|
||||||
|
/**
|
||||||
|
* The maximum additional sigops which the pool will add in coinbase
|
||||||
|
* transaction outputs.
|
||||||
|
*/
|
||||||
|
size_t coinbase_output_max_additional_sigops{400};
|
||||||
|
};
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
|
||||||
#endif // BITCOIN_NODE_TYPES_H
|
#endif // BITCOIN_NODE_TYPES_H
|
||||||
|
@ -371,7 +371,7 @@ static RPCHelpMan generateblock()
|
|||||||
|
|
||||||
ChainstateManager& chainman = EnsureChainman(node);
|
ChainstateManager& chainman = EnsureChainman(node);
|
||||||
{
|
{
|
||||||
std::unique_ptr<CBlockTemplate> blocktemplate{miner.createNewBlock(coinbase_script, /*use_mempool=*/false)};
|
std::unique_ptr<CBlockTemplate> blocktemplate{miner.createNewBlock(coinbase_script, {.use_mempool = false})};
|
||||||
if (!blocktemplate) {
|
if (!blocktemplate) {
|
||||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
|
||||||
}
|
}
|
||||||
@ -778,9 +778,7 @@ static RPCHelpMan getblocktemplate()
|
|||||||
}
|
}
|
||||||
ENTER_CRITICAL_SECTION(cs_main);
|
ENTER_CRITICAL_SECTION(cs_main);
|
||||||
|
|
||||||
std::optional<uint256> maybe_tip{miner.getTipHash()};
|
tip = CHECK_NONFATAL(miner.getTipHash()).value();
|
||||||
CHECK_NONFATAL(maybe_tip);
|
|
||||||
tip = maybe_tip.value();
|
|
||||||
|
|
||||||
if (!IsRPCRunning())
|
if (!IsRPCRunning())
|
||||||
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
|
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
|
||||||
|
Loading…
Reference in New Issue
Block a user