Skip to content
Permalink
Browse files

Restore blockmaxsize option, allowing to limit mined blocks by byte size

  • Loading branch information...
luke-jr committed Nov 5, 2018
1 parent 37f236a commit 1b7958070dd2a131e802e12f92483332e576f04c
Showing with 65 additions and 3 deletions.
  1. +1 −0 src/init.cpp
  2. +52 −3 src/miner.cpp
  3. +5 −0 src/miner.h
  4. +2 −0 src/policy/policy.h
  5. +2 −0 src/rpc/mining.cpp
  6. +1 −0 src/test/miner_tests.cpp
  7. +2 −0 test/functional/mining_basic.py
@@ -522,6 +522,7 @@ void SetupServerArgs()
gArgs.AddArg("-whitelistrelay", strprintf("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), false, OptionsCategory::NODE_RELAY);


gArgs.AddArg("-blockmaxsize=<n>", strprintf("Set maximum block size in bytes (default: %d)", DEFAULT_BLOCK_MAX_SIZE), false, OptionsCategory::BLOCK_CREATION);
gArgs.AddArg("-blockmaxweight=<n>", strprintf("Set maximum BIP141 block weight (default: %d)", DEFAULT_BLOCK_MAX_WEIGHT), false, OptionsCategory::BLOCK_CREATION);
gArgs.AddArg("-blockmintxfee=<amt>", strprintf("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)), false, OptionsCategory::BLOCK_CREATION);
gArgs.AddArg("-blockversion=<n>", "Override block version to test forking scenarios", true, OptionsCategory::BLOCK_CREATION);
@@ -47,21 +47,41 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
BlockAssembler::Options::Options() {
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
}

BlockAssembler::BlockAssembler(const CChainParams& params, const Options& options) : chainparams(params)
{
blockMinFeeRate = options.blockMinFeeRate;
// Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity:
nBlockMaxWeight = std::max<size_t>(4000, std::min<size_t>(MAX_BLOCK_WEIGHT - 4000, options.nBlockMaxWeight));
// Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity:
nBlockMaxSize = std::max<size_t>(1000, std::min<size_t>(MAX_BLOCK_SERIALIZED_SIZE - 1000, options.nBlockMaxSize));
// Whether we need to account for byte usage (in addition to weight usage)
fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE - 1000);
}

static BlockAssembler::Options DefaultOptions()
{
// Block resource limits
// If -blockmaxweight is not given, limit to DEFAULT_BLOCK_MAX_WEIGHT
// 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.
BlockAssembler::Options options;
options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
options.nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
bool fWeightSet = false;
if (gArgs.IsArgSet("-blockmaxweight")) {
options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
fWeightSet = true;
}
if (gArgs.IsArgSet("-blockmaxsize")) {
options.nBlockMaxSize = gArgs.GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
if (!fWeightSet) {
options.nBlockMaxWeight = options.nBlockMaxSize * WITNESS_SCALE_FACTOR;
}
}
CAmount n = 0;
if (gArgs.IsArgSet("-blockmintxfee") && ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) {
options.blockMinFeeRate = CFeeRate(n);
@@ -78,6 +98,7 @@ void BlockAssembler::resetBlock()
inBlock.clear();

// Reserve space for coinbase tx
nBlockSize = 1000;
nBlockWeight = 4000;
nBlockSigOpsCost = 400;
fIncludeWitness = false;
@@ -89,6 +110,7 @@ void BlockAssembler::resetBlock()

Optional<int64_t> BlockAssembler::m_last_block_num_txs{nullopt};
Optional<int64_t> BlockAssembler::m_last_block_weight{nullopt};
Optional<int64_t> BlockAssembler::m_last_block_size{nullopt};

std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
{
@@ -144,6 +166,11 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc

m_last_block_num_txs = nBlockTx;
m_last_block_weight = nBlockWeight;
if (fNeedSizeAccounting) {
m_last_block_size = nBlockSize;
} else {
m_last_block_size = boost::none;
}

// Create coinbase transaction.
CMutableTransaction coinbaseTx;
@@ -157,7 +184,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
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
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
@@ -204,13 +232,22 @@ bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost
// - transaction finality (locktime)
// - premature witness (in case segwit transactions are added to mempool before
// segwit activation)
// - serialized size (in case -blockmaxsize is in use)
bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package)
{
uint64_t nPotentialBlockSize = nBlockSize; // only used with fNeedSizeAccounting
for (CTxMemPool::txiter it : package) {
if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff))
return false;
if (!fIncludeWitness && it->GetTx().HasWitness())
return false;
if (fNeedSizeAccounting) {
uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), PROTOCOL_VERSION);
if (nPotentialBlockSize + nTxSize >= nBlockMaxSize) {
return false;
}
nPotentialBlockSize += nTxSize;
}
}
return true;
}
@@ -220,6 +257,9 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
pblock->vtx.emplace_back(iter->GetSharedTx());
pblocktemplate->vTxFees.push_back(iter->GetFee());
pblocktemplate->vTxSigOpsCost.push_back(iter->GetSigOpCost());
if (fNeedSizeAccounting) {
nBlockSize += ::GetSerializeSize(iter->GetTx(), PROTOCOL_VERSION);
}
nBlockWeight += iter->GetTxWeight();
++nBlockTx;
nBlockSigOpsCost += iter->GetSigOpCost();
@@ -404,6 +444,15 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
mapModifiedTx.get<ancestor_score>().erase(modit);
failedTx.insert(iter);
}

if (fNeedSizeAccounting) {
++nConsecutiveFailed;

if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockSize > nBlockMaxSize - 1000) {
// Give up if we're close to full and haven't succeeded in a while
break;
}
}
continue;
}

@@ -134,10 +134,13 @@ class BlockAssembler
// Configuration parameters for the block size
bool fIncludeWitness;
unsigned int nBlockMaxWeight;
uint64_t nBlockMaxSize;
bool fNeedSizeAccounting;
CFeeRate blockMinFeeRate;

// Information on the current status of the block
uint64_t nBlockWeight;
uint64_t nBlockSize;
uint64_t nBlockTx;
uint64_t nBlockSigOpsCost;
CAmount nFees;
@@ -152,6 +155,7 @@ class BlockAssembler
struct Options {
Options();
size_t nBlockMaxWeight;
size_t nBlockMaxSize;
CFeeRate blockMinFeeRate;
};

@@ -163,6 +167,7 @@ class BlockAssembler

static Optional<int64_t> m_last_block_num_txs;
static Optional<int64_t> m_last_block_weight;
static Optional<int64_t> m_last_block_size;

private:
// utility functions
@@ -16,6 +16,8 @@
class CCoinsViewCache;
class CTxOut;

/** 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 **/
static const 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 **/
@@ -195,6 +195,7 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
RPCResult{
"{\n"
" \"blocks\": nnn, (numeric) The current block\n"
" \"currentblocksize\": nnn, (numeric, optional) The block size of the last assembled block (only present if a block was ever assembled, and blockmaxsize is configured)\n"
" \"currentblockweight\": nnn, (numeric, optional) The block weight of the last assembled block (only present if a block was ever assembled)\n"
" \"currentblocktx\": nnn, (numeric, optional) The number of block transactions of the last assembled block (only present if a block was ever assembled)\n"
" \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n"
@@ -215,6 +216,7 @@ static UniValue getmininginfo(const JSONRPCRequest& request)

UniValue obj(UniValue::VOBJ);
obj.pushKV("blocks", (int)chainActive.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_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
obj.pushKV("difficulty", (double)GetDifficulty(chainActive.Tip()));
@@ -43,6 +43,7 @@ static BlockAssembler AssemblerForTest(const CChainParams& params) {
BlockAssembler::Options options;

options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
options.blockMinFeeRate = blockMinFeeRate;
return BlockAssembler(params, options);
}
@@ -54,6 +54,7 @@ def mine_chain(self):
assert_equal(mining_info['blocks'], 200)
assert_equal(mining_info['currentblocktx'], 0)
assert_equal(mining_info['currentblockweight'], 4000)
assert 'currentblocksize' not in mining_info
self.restart_node(0)
connect_nodes_bi(self.nodes, 0, 1)

@@ -73,6 +74,7 @@ def assert_submitblock(block, result_str_1, result_str_2=None):
assert_equal(mining_info['chain'], 'regtest')
assert 'currentblocktx' 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['networkhashps'], Decimal('0.003333333333333334'))
assert_equal(mining_info['pooledtx'], 0)

0 comments on commit 1b79580

Please sign in to comment.
You can’t perform that action at this time.