Merge restore_blockmaxsize

This commit is contained in:
Luke Dashjr 2024-03-25 17:26:53 +00:00
commit 02b941a9e2
7 changed files with 61 additions and 2 deletions

View File

@ -637,6 +637,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-whitelistrelay", strprintf("Add 'relay' permission to whitelisted peers with default permissions. This will accept relayed transactions even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-whitelistrelay", strprintf("Add 'relay' permission to whitelisted peers with default permissions. This will accept relayed transactions even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-blockmaxsize=<n>", strprintf("Set maximum block size in bytes (default: %d)", DEFAULT_BLOCK_MAX_SIZE), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
argsman.AddArg("-blockmaxweight=<n>", strprintf("Set maximum BIP141 block weight (default: %d)", DEFAULT_BLOCK_MAX_WEIGHT), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); argsman.AddArg("-blockmaxweight=<n>", strprintf("Set maximum BIP141 block weight (default: %d)", DEFAULT_BLOCK_MAX_WEIGHT), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
argsman.AddArg("-blockmintxfee=<amt>", strprintf("Set lowest fee rate (in %s/kvB) for transactions to be included in block creation. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); argsman.AddArg("-blockmintxfee=<amt>", strprintf("Set lowest fee rate (in %s/kvB) for transactions to be included in block creation. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
argsman.AddArg("-blockversion=<n>", "Override block version to test forking scenarios", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::BLOCK_CREATION); argsman.AddArg("-blockversion=<n>", "Override block version to test forking scenarios", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::BLOCK_CREATION);

View File

@ -61,6 +61,9 @@ static BlockAssembler::Options ClampOptions(BlockAssembler::Options options)
{ {
// Limit weight to between 4K and DEFAULT_BLOCK_MAX_WEIGHT for sanity: // 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); options.nBlockMaxWeight = std::clamp<size_t>(options.nBlockMaxWeight, 4000, DEFAULT_BLOCK_MAX_WEIGHT);
// Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity:
options.nBlockMaxSize = std::clamp<size_t>(options.nBlockMaxSize, 1000, MAX_BLOCK_SERIALIZED_SIZE - 1000);
// Whether we need to account for byte usage (in addition to weight usage)
return options; return options;
} }
@ -70,12 +73,27 @@ BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool
m_chainstate{chainstate}, m_chainstate{chainstate},
m_options{ClampOptions(options)} m_options{ClampOptions(options)}
{ {
fNeedSizeAccounting = (options.nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE - 1000);
} }
void ApplyArgsManOptions(const ArgsManager& args, BlockAssembler::Options& options) void ApplyArgsManOptions(const ArgsManager& args, BlockAssembler::Options& options)
{ {
// Block resource limits // Block resource limits
options.nBlockMaxWeight = args.GetIntArg("-blockmaxweight", options.nBlockMaxWeight); // If neither -blockmaxsize or -blockmaxweight is given, limit to DEFAULT_BLOCK_MAX_*
// If only one is given, only restrict the specified resource.
// If both are given, restrict both.
bool fWeightSet = false;
if (args.IsArgSet("-blockmaxweight")) {
options.nBlockMaxWeight = args.GetIntArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
fWeightSet = true;
}
if (args.IsArgSet("-blockmaxsize")) {
options.nBlockMaxSize = args.GetIntArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
if (!fWeightSet) {
options.nBlockMaxWeight = options.nBlockMaxSize * WITNESS_SCALE_FACTOR;
}
}
if (const auto blockmintxfee{args.GetArg("-blockmintxfee")}) { if (const auto blockmintxfee{args.GetArg("-blockmintxfee")}) {
if (const auto parsed{ParseMoney(*blockmintxfee)}) options.blockMinFeeRate = CFeeRate{*parsed}; if (const auto parsed{ParseMoney(*blockmintxfee)}) options.blockMinFeeRate = CFeeRate{*parsed};
} }
@ -95,6 +113,7 @@ void BlockAssembler::resetBlock()
inBlock.clear(); inBlock.clear();
// Reserve space for coinbase tx // Reserve space for coinbase tx
nBlockSize = 1000;
nBlockWeight = 4000; nBlockWeight = 4000;
nBlockSigOpsCost = 400; nBlockSigOpsCost = 400;
@ -147,6 +166,11 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
m_last_block_num_txs = nBlockTx; m_last_block_num_txs = nBlockTx;
m_last_block_weight = nBlockWeight; m_last_block_weight = nBlockWeight;
if (fNeedSizeAccounting) {
m_last_block_size = nBlockSize;
} else {
m_last_block_size = std::nullopt;
}
// Create coinbase transaction. // Create coinbase transaction.
CMutableTransaction coinbaseTx; CMutableTransaction coinbaseTx;
@ -160,7 +184,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vchCoinbaseCommitment = m_chainstate.m_chainman.GenerateCoinbaseCommitment(*pblock, pindexPrev); pblocktemplate->vchCoinbaseCommitment = m_chainstate.m_chainman.GenerateCoinbaseCommitment(*pblock, pindexPrev);
pblocktemplate->vTxFees[0] = -nFees; pblocktemplate->vTxFees[0] = -nFees;
LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops %d\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost); uint64_t nSerializeSize = GetSerializeSize(*pblock, PROTOCOL_VERSION);
LogPrintf("CreateNewBlock(): total size: %u block weight: %u txs: %u fees: %ld sigops %d\n", nSerializeSize, GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);
// Fill in header // Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash(); pblock->hashPrevBlock = pindexPrev->GetBlockHash();
@ -210,12 +235,21 @@ bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost
// Perform transaction-level checks before adding to block: // Perform transaction-level checks before adding to block:
// - transaction finality (locktime) // - transaction finality (locktime)
// - serialized size (in case -blockmaxsize is in use)
bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package) const bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package) const
{ {
uint64_t nPotentialBlockSize = nBlockSize; // only used with fNeedSizeAccounting
for (CTxMemPool::txiter it : package) { for (CTxMemPool::txiter it : package) {
if (!IsFinalTx(it->GetTx(), nHeight, m_lock_time_cutoff)) { if (!IsFinalTx(it->GetTx(), nHeight, m_lock_time_cutoff)) {
return false; return false;
} }
if (fNeedSizeAccounting) {
uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), PROTOCOL_VERSION);
if (nPotentialBlockSize + nTxSize >= m_options.nBlockMaxSize) {
return false;
}
nPotentialBlockSize += nTxSize;
}
} }
return true; return true;
} }
@ -225,6 +259,9 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
pblocktemplate->block.vtx.emplace_back(iter->GetSharedTx()); pblocktemplate->block.vtx.emplace_back(iter->GetSharedTx());
pblocktemplate->vTxFees.push_back(iter->GetFee()); pblocktemplate->vTxFees.push_back(iter->GetFee());
pblocktemplate->vTxSigOpsCost.push_back(iter->GetSigOpCost()); pblocktemplate->vTxSigOpsCost.push_back(iter->GetSigOpCost());
if (fNeedSizeAccounting) {
nBlockSize += ::GetSerializeSize(iter->GetTx(), PROTOCOL_VERSION);
}
nBlockWeight += iter->GetTxWeight(); nBlockWeight += iter->GetTxWeight();
++nBlockTx; ++nBlockTx;
nBlockSigOpsCost += iter->GetSigOpCost(); nBlockSigOpsCost += iter->GetSigOpCost();
@ -406,6 +443,15 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele
mapModifiedTx.get<ancestor_score>().erase(modit); mapModifiedTx.get<ancestor_score>().erase(modit);
failedTx.insert(iter); failedTx.insert(iter);
} }
if (fNeedSizeAccounting) {
++nConsecutiveFailed;
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockSize > m_options.nBlockMaxSize - 1000) {
// Give up if we're close to full and haven't succeeded in a while
break;
}
}
continue; continue;
} }

View File

@ -137,8 +137,11 @@ private:
// The constructed block template // The constructed block template
std::unique_ptr<CBlockTemplate> pblocktemplate; std::unique_ptr<CBlockTemplate> pblocktemplate;
bool fNeedSizeAccounting;
// Information on the current status of the block // Information on the current status of the block
uint64_t nBlockWeight; uint64_t nBlockWeight;
uint64_t nBlockSize;
uint64_t nBlockTx; uint64_t nBlockTx;
uint64_t nBlockSigOpsCost; uint64_t nBlockSigOpsCost;
CAmount nFees; CAmount nFees;
@ -156,6 +159,7 @@ public:
struct Options { struct Options {
// 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};
size_t nBlockMaxSize{DEFAULT_BLOCK_MAX_SIZE};
CFeeRate blockMinFeeRate{DEFAULT_BLOCK_MIN_TX_FEE}; CFeeRate blockMinFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
// Whether to call TestBlockValidity() at the end of CreateNewBlock(). // Whether to call TestBlockValidity() at the end of CreateNewBlock().
bool test_block_validity{true}; bool test_block_validity{true};
@ -169,6 +173,7 @@ public:
inline static std::optional<int64_t> m_last_block_num_txs{}; inline static std::optional<int64_t> m_last_block_num_txs{};
inline static std::optional<int64_t> m_last_block_weight{}; inline static std::optional<int64_t> m_last_block_weight{};
inline static std::optional<int64_t> m_last_block_size{};
private: private:
const Options m_options; const Options m_options;

View File

@ -19,6 +19,8 @@ class CCoinsViewCache;
class CFeeRate; class CFeeRate;
class CScript; class CScript;
/** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/
static const unsigned int DEFAULT_BLOCK_MAX_SIZE = MAX_BLOCK_SERIALIZED_SIZE;
/** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/ /** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/
static constexpr unsigned int DEFAULT_BLOCK_MAX_WEIGHT{MAX_BLOCK_WEIGHT - 4000}; static constexpr unsigned int DEFAULT_BLOCK_MAX_WEIGHT{MAX_BLOCK_WEIGHT - 4000};
/** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/ /** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/

View File

@ -416,6 +416,7 @@ static RPCHelpMan getmininginfo()
RPCResult::Type::OBJ, "", "", RPCResult::Type::OBJ, "", "",
{ {
{RPCResult::Type::NUM, "blocks", "The current block"}, {RPCResult::Type::NUM, "blocks", "The current block"},
{RPCResult::Type::NUM, "currentblocksize", /*optional=*/true, "The block size of the last assembled block (only present if a block was ever assembled, and blockmaxsize is configured)"},
{RPCResult::Type::NUM, "currentblockweight", /*optional=*/true, "The block weight of the last assembled block (only present if a block was ever assembled)"}, {RPCResult::Type::NUM, "currentblockweight", /*optional=*/true, "The block weight of the last assembled block (only present if a block was ever assembled)"},
{RPCResult::Type::NUM, "currentblocktx", /*optional=*/true, "The number of block transactions of the last assembled block (only present if a block was ever assembled)"}, {RPCResult::Type::NUM, "currentblocktx", /*optional=*/true, "The number of block transactions of the last assembled block (only present if a block was ever assembled)"},
{RPCResult::Type::NUM, "difficulty", "The current difficulty"}, {RPCResult::Type::NUM, "difficulty", "The current difficulty"},
@ -438,6 +439,7 @@ static RPCHelpMan getmininginfo()
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.pushKV("blocks", active_chain.Height()); obj.pushKV("blocks", active_chain.Height());
if (BlockAssembler::m_last_block_size) obj.pushKV("currentblocksize", *BlockAssembler::m_last_block_size);
if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight); if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs); if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
obj.pushKV("difficulty", (double)GetDifficulty(active_chain.Tip())); obj.pushKV("difficulty", (double)GetDifficulty(active_chain.Tip()));

View File

@ -63,6 +63,7 @@ BlockAssembler MinerTestingSetup::AssemblerForTest(CTxMemPool& tx_mempool)
BlockAssembler::Options options; BlockAssembler::Options options;
options.nBlockMaxWeight = MAX_BLOCK_WEIGHT; options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
options.blockMinFeeRate = blockMinFeeRate; options.blockMinFeeRate = blockMinFeeRate;
return BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}; return BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options};
} }

View File

@ -65,6 +65,7 @@ class MiningTest(BitcoinTestFramework):
assert_equal(mining_info['blocks'], 200) assert_equal(mining_info['blocks'], 200)
assert_equal(mining_info['currentblocktx'], 0) assert_equal(mining_info['currentblocktx'], 0)
assert_equal(mining_info['currentblockweight'], 4000) assert_equal(mining_info['currentblockweight'], 4000)
assert 'currentblocksize' not in mining_info
self.log.info('test blockversion') self.log.info('test blockversion')
self.restart_node(0, extra_args=[f'-mocktime={t}', '-blockversion=1337']) self.restart_node(0, extra_args=[f'-mocktime={t}', '-blockversion=1337'])
@ -132,6 +133,7 @@ class MiningTest(BitcoinTestFramework):
assert_equal(mining_info['chain'], self.chain) assert_equal(mining_info['chain'], self.chain)
assert 'currentblocktx' not in mining_info assert 'currentblocktx' not in mining_info
assert 'currentblockweight' not in mining_info assert 'currentblockweight' not in mining_info
assert 'currentblocksize' not in mining_info
assert_equal(mining_info['difficulty'], Decimal('4.656542373906925E-10')) assert_equal(mining_info['difficulty'], Decimal('4.656542373906925E-10'))
assert_equal(mining_info['networkhashps'], Decimal('0.003333333333333334')) assert_equal(mining_info['networkhashps'], Decimal('0.003333333333333334'))
assert_equal(mining_info['pooledtx'], 0) assert_equal(mining_info['pooledtx'], 0)