refactor: add coinbase constraints to BlockCreateOptions

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 which exceeded the sigops limit.
https://bitcoin.stackexchange.com/questions/117837/how-many-sigops-are-in-the-invalid-block-783426

The existince of such patches suggests it may be useful to
make this value configurable. This commit would make such a
change easier.

The main motivation however is that the Stratum v2 spec
requires the pool to communicate the maximum bytes they intend
to add to the coinbase outputs. A proposed change to the spec
would also require them to communicate the maximum number of sigops.

This commit also documents what happens when
-blockmaxweight is lower than the coinbase
reserved value.

Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
This commit is contained in:
Sjors Provoost 2024-07-17 18:33:15 +02:00
parent 6b4c817d4b
commit c504b6997b
No known key found for this signature in database
GPG Key ID: 57FF9BDBCC301009
2 changed files with 19 additions and 5 deletions

View File

@ -59,8 +59,11 @@ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman)
static BlockAssembler::Options ClampOptions(BlockAssembler::Options options)
{
// Limit weight to between 4K and DEFAULT_BLOCK_MAX_WEIGHT for sanity:
options.nBlockMaxWeight = std::clamp<size_t>(options.nBlockMaxWeight, 4000, DEFAULT_BLOCK_MAX_WEIGHT);
Assert(options.coinbase_max_additional_weight <= 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;
}
@ -87,8 +90,8 @@ void BlockAssembler::resetBlock()
inBlock.clear();
// Reserve space for coinbase tx
nBlockWeight = 4000;
nBlockSigOpsCost = 400;
nBlockWeight = m_options.coinbase_max_additional_weight;
nBlockSigOpsCost = m_options.coinbase_output_max_additional_sigops;
// These counters do not include coinbase tx
nBlockTx = 0;
@ -379,7 +382,7 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele
++nConsecutiveFailed;
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
break;
}

View File

@ -32,6 +32,17 @@ 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