diff --git a/src/miner.h b/src/miner.h --- a/src/miner.h +++ b/src/miner.h @@ -168,7 +168,16 @@ int lastFewTxs; public: - BlockAssembler(const Config &_config, const CTxMemPool &mempool); + struct Options { + Options(); + size_t nBlockMaxSize; + CFeeRate blockMinFeeRate; + }; + + BlockAssembler(const Config &config, const CTxMemPool &mempool); + BlockAssembler(const Config &config, const CTxMemPool &mempool, + const Options &options); + /** Construct a new block template with coinbase to scriptPubKeyIn */ std::unique_ptr CreateNewBlock(const CScript &scriptPubKeyIn); diff --git a/src/miner.cpp b/src/miner.cpp --- a/src/miner.cpp +++ b/src/miner.cpp @@ -61,42 +61,43 @@ return nNewTime - nOldTime; } -static uint64_t ComputeMaxGeneratedBlockSize(const Config &config, - const CBlockIndex *pindexPrev) { - // Block resource limits - // If -blockmaxsize is not given, limit to DEFAULT_MAX_GENERATED_BLOCK_SIZE - // If only one is given, only restrict the specified resource. - // If both are given, restrict both. - uint64_t nMaxGeneratedBlockSize = DEFAULT_MAX_GENERATED_BLOCK_SIZE; - if (gArgs.IsArgSet("-blockmaxsize")) { - nMaxGeneratedBlockSize = - gArgs.GetArg("-blockmaxsize", DEFAULT_MAX_GENERATED_BLOCK_SIZE); - } +BlockAssembler::Options::Options() { + blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB); + nBlockMaxSize = DEFAULT_MAX_GENERATED_BLOCK_SIZE; +} - // Limit size to between 1K and MaxBlockSize-1K for sanity: +BlockAssembler::BlockAssembler(const Config &_config, + const CTxMemPool &_mempool, + const Options &options) + : config(&_config), mempool(&_mempool) { + blockMinFeeRate = options.blockMinFeeRate; + // Limit size to between 1K and max block size-1K for sanity: nMaxGeneratedBlockSize = - std::max(uint64_t(1000), std::min(config.GetMaxBlockSize() - 1000, - nMaxGeneratedBlockSize)); - - return nMaxGeneratedBlockSize; + std::max(uint64_t(1000), std::min(config->GetMaxBlockSize() - 1000, + options.nBlockMaxSize)); } -BlockAssembler::BlockAssembler(const Config &_config, const CTxMemPool &mpool) - : config(&_config), mempool(&mpool) { - +static BlockAssembler::Options DefaultOptions() { + BlockAssembler::Options options; + options.nBlockMaxSize = DEFAULT_MAX_GENERATED_BLOCK_SIZE; + if (gArgs.IsArgSet("-blockmaxsize")) { + options.nBlockMaxSize = + gArgs.GetArg("-blockmaxsize", DEFAULT_MAX_GENERATED_BLOCK_SIZE); + } if (gArgs.IsArgSet("-blockmintxfee")) { Amount n = Amount::zero(); ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n); - blockMinFeeRate = CFeeRate(n); + options.blockMinFeeRate = CFeeRate(n); } else { - blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB); + options.blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB); } - - LOCK(cs_main); - nMaxGeneratedBlockSize = - ComputeMaxGeneratedBlockSize(*config, chainActive.Tip()); + return options; } +BlockAssembler::BlockAssembler(const Config &_config, + const CTxMemPool &_mempool) + : BlockAssembler(_config, _mempool, DefaultOptions()) {} + void BlockAssembler::resetBlock() { inBlock.clear(); @@ -151,9 +152,8 @@ } pblock->nTime = GetAdjustedTime(); - nMaxGeneratedBlockSize = ComputeMaxGeneratedBlockSize(*config, pindexPrev); - nMedianTimePast = pindexPrev->GetMedianTimePast(); + nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) ? nMedianTimePast diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -32,6 +32,15 @@ static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB); +static BlockAssembler AssemblerForTest(const Config &config, + const CTxMemPool &mempool) { + BlockAssembler::Options options; + + options.nBlockMaxSize = DEFAULT_MAX_BLOCK_SIZE; + options.blockMinFeeRate = blockMinFeeRate; + return BlockAssembler(config, mempool, options); +} + static struct { uint8_t extranonce; uint32_t nonce; @@ -126,7 +135,7 @@ .FromTx(tx)); std::unique_ptr pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == parentTxId); BOOST_CHECK(pblocktemplate->block.vtx[2]->GetId() == highFeeTxId); BOOST_CHECK(pblocktemplate->block.vtx[3]->GetId() == mediumFeeTxId); @@ -149,7 +158,7 @@ TxId lowFeeTxId = tx.GetId(); g_mempool.addUnchecked(lowFeeTxId, entry.Fee(feeToUse).FromTx(tx)); pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey); // Verify that the free tx and the low fee tx didn't get selected. for (const auto &txn : pblocktemplate->block.vtx) { BOOST_CHECK(txn->GetId() != freeTxId); @@ -166,7 +175,7 @@ g_mempool.addUnchecked(lowFeeTxId, entry.Fee(feeToUse + 2 * SATOSHI).FromTx(tx)); pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[4]->GetId() == freeTxId); BOOST_CHECK(pblocktemplate->block.vtx[5]->GetId() == lowFeeTxId); @@ -191,7 +200,7 @@ g_mempool.addUnchecked( lowFeeTxId2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey); // Verify that this tx isn't selected. for (const auto &txn : pblocktemplate->block.vtx) { @@ -206,7 +215,7 @@ tx.vout[0].nValue = (100000000 - 10000) * SATOSHI; g_mempool.addUnchecked(tx.GetId(), entry.Fee(10000 * SATOSHI).FromTx(tx)); pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[8]->GetId() == lowFeeTxId2); } @@ -221,7 +230,7 @@ << OP_CHECKSIG; std::unique_ptr pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey); CBlock *pblock = &pblocktemplate->block; @@ -267,7 +276,7 @@ // Simple block creation, nothing special yet: BOOST_CHECK( pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey)); // We can't make transactions until we have inputs. Therefore, load 100 // blocks :) @@ -308,7 +317,7 @@ // Just to make sure we can still make simple blocks. BOOST_CHECK( pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey)); const Amount BLOCKSUBSIDY = 50 * COIN; const Amount LOWFEE = CENT; @@ -337,7 +346,7 @@ tx.vin[0].prevout = COutPoint(txid, 0); } BOOST_CHECK_THROW( - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey), std::runtime_error); g_mempool.clear(); @@ -359,7 +368,7 @@ } BOOST_CHECK( pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey)); g_mempool.clear(); // block size > limit @@ -386,14 +395,14 @@ } BOOST_CHECK( pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey)); g_mempool.clear(); // Orphan in mempool, template creation fails. TxId txid = tx.GetId(); g_mempool.addUnchecked(txid, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); BOOST_CHECK_THROW( - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey), std::runtime_error); g_mempool.clear(); @@ -417,7 +426,7 @@ entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK( pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey)); g_mempool.clear(); // Coinbase in mempool, template creation fails. @@ -431,7 +440,7 @@ txid, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); BOOST_CHECK_THROW( - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey), std::runtime_error); g_mempool.clear(); @@ -450,7 +459,7 @@ txid, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK_THROW( - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey), std::runtime_error); g_mempool.clear(); @@ -469,7 +478,7 @@ } BOOST_CHECK( pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey)); // Extend to a 210000-long block chain. while (chainActive.Tip()->nHeight < 210000) { CBlockIndex *prev = chainActive.Tip(); @@ -483,7 +492,7 @@ } BOOST_CHECK( pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey)); // Invalid p2sh txn in mempool, template creation fails tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0); @@ -504,7 +513,7 @@ txid, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); BOOST_CHECK_THROW( - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey), std::runtime_error); g_mempool.clear(); @@ -675,7 +684,7 @@ BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate); // None of the of the absolute height/time locked tx should have made it @@ -695,7 +704,7 @@ BOOST_CHECK( pblocktemplate = - BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); + AssemblerForTest(config, g_mempool).CreateNewBlock(scriptPubKey)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5UL); chainActive.Tip()->nHeight--; @@ -712,6 +721,13 @@ BlockAssembler ba(config, g_mempool); BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(), expected); + + // BlockAssembler with options gives the same result + BlockAssembler::Options options; + options.nBlockMaxSize = size; + options.blockMinFeeRate = blockMinFeeRate; + BlockAssembler baWithOptions(config, g_mempool, options); + BOOST_CHECK_EQUAL(baWithOptions.GetMaxGeneratedBlockSize(), expected); } BOOST_AUTO_TEST_CASE(BlockAssembler_construction) {