Skip to content

Commit 2f6a8e5

Browse files
committed
Merge bitcoin/bitcoin#26695: bench: BlockAssembler on a mempool with packages
0452805 [bench] BlockAssembler with mempool packages (glozow) 6ce265a [test util] lock cs_main before pool.cs in PopulateMempool (glozow) 8791410 [test util] randomize fee in PopulateMempool (glozow) cba5934 [miner] allow bypassing TestBlockValidity (glozow) c058852 [refactor] parameterize BlockAssembler::Options in PrepareBlock (glozow) a2de971 [refactor] add helper to apply ArgsManager to BlockAssembler::Options (glozow) Pull request description: Performance of block template building matters as miners likely want to be able to start mining on a block with transactions asap after a block is found. We would want to know if a mempool PR accidentally caused, for example, a 100x slowdown. An `AssembleBlock()` bench exists, but it operates on a mempool with 101 transactions, each with 0 ancestors or descendants and with the same fee. Adding a bench with a more complex mempool is useful because (1) it's more realistic (2) updating packages can potentially cause the algorithm to take a long time. ACKs for top commit: kevkevinpal: Tested ACK [0452805](bitcoin/bitcoin@0452805) achow101: ACK 0452805 stickies-v: ACK 0452805 Tree-SHA512: 38c138d6a75616651f9b1faf4e3a1cd833437a486f4e84308fbee958e8462bb570582c88f7ba7ab99d80191e97855ac2cf27c43cc21585d3e4b0e227effe2fb5
2 parents 9082125 + 0452805 commit 2f6a8e5

File tree

6 files changed

+54
-13
lines changed

6 files changed

+54
-13
lines changed

src/bench/block_assemble.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <bench/bench.h>
66
#include <consensus/validation.h>
77
#include <crypto/sha256.h>
8+
#include <node/miner.h>
89
#include <test/util/mining.h>
910
#include <test/util/script.h>
1011
#include <test/util/setup_common.h>
@@ -45,5 +46,18 @@ static void AssembleBlock(benchmark::Bench& bench)
4546
PrepareBlock(test_setup->m_node, P2WSH_OP_TRUE);
4647
});
4748
}
49+
static void BlockAssemblerAddPackageTxns(benchmark::Bench& bench)
50+
{
51+
FastRandomContext det_rand{true};
52+
auto testing_setup{MakeNoLogFileContext<TestChain100Setup>()};
53+
testing_setup->PopulateMempool(det_rand, /*num_transactions=*/1000, /*submit=*/true);
54+
node::BlockAssembler::Options assembler_options;
55+
assembler_options.test_block_validity = false;
56+
57+
bench.run([&] {
58+
PrepareBlock(testing_setup->m_node, P2WSH_OP_TRUE, assembler_options);
59+
});
60+
}
4861

4962
BENCHMARK(AssembleBlock, benchmark::PriorityLevel::HIGH);
63+
BENCHMARK(BlockAssemblerAddPackageTxns, benchmark::PriorityLevel::LOW);

src/node/miner.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,12 @@ BlockAssembler::Options::Options()
6060
{
6161
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
6262
nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
63+
test_block_validity = true;
6364
}
6465

6566
BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options)
66-
: chainparams{chainstate.m_chainman.GetParams()},
67+
: test_block_validity{options.test_block_validity},
68+
chainparams{chainstate.m_chainman.GetParams()},
6769
m_mempool(mempool),
6870
m_chainstate(chainstate)
6971
{
@@ -72,23 +74,27 @@ BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool
7274
nBlockMaxWeight = std::max<size_t>(4000, std::min<size_t>(MAX_BLOCK_WEIGHT - 4000, options.nBlockMaxWeight));
7375
}
7476

75-
static BlockAssembler::Options DefaultOptions()
77+
void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& options)
7678
{
7779
// Block resource limits
7880
// If -blockmaxweight is not given, limit to DEFAULT_BLOCK_MAX_WEIGHT
79-
BlockAssembler::Options options;
8081
options.nBlockMaxWeight = gArgs.GetIntArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
8182
if (gArgs.IsArgSet("-blockmintxfee")) {
8283
std::optional<CAmount> parsed = ParseMoney(gArgs.GetArg("-blockmintxfee", ""));
8384
options.blockMinFeeRate = CFeeRate{parsed.value_or(DEFAULT_BLOCK_MIN_TX_FEE)};
8485
} else {
8586
options.blockMinFeeRate = CFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
8687
}
88+
}
89+
static BlockAssembler::Options ConfiguredOptions()
90+
{
91+
BlockAssembler::Options options;
92+
ApplyArgsManOptions(gArgs, options);
8793
return options;
8894
}
8995

9096
BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool)
91-
: BlockAssembler(chainstate, mempool, DefaultOptions()) {}
97+
: BlockAssembler(chainstate, mempool, ConfiguredOptions()) {}
9298

9399
void BlockAssembler::resetBlock()
94100
{
@@ -170,7 +176,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
170176
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
171177

172178
BlockValidationState state;
173-
if (!TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev, GetAdjustedTime, false, false)) {
179+
if (test_block_validity && !TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev,
180+
GetAdjustedTime, /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/false)) {
174181
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString()));
175182
}
176183
const auto time_2{SteadyClock::now()};

src/node/miner.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <boost/multi_index/ordered_index.hpp>
1717
#include <boost/multi_index_container.hpp>
1818

19+
class ArgsManager;
1920
class ChainstateManager;
2021
class CBlockIndex;
2122
class CChainParams;
@@ -135,6 +136,9 @@ class BlockAssembler
135136
unsigned int nBlockMaxWeight;
136137
CFeeRate blockMinFeeRate;
137138

139+
// Whether to call TestBlockValidity() at the end of CreateNewBlock().
140+
const bool test_block_validity;
141+
138142
// Information on the current status of the block
139143
uint64_t nBlockWeight;
140144
uint64_t nBlockTx;
@@ -155,6 +159,7 @@ class BlockAssembler
155159
Options();
156160
size_t nBlockMaxWeight;
157161
CFeeRate blockMinFeeRate;
162+
bool test_block_validity;
158163
};
159164

160165
explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool);
@@ -197,6 +202,9 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
197202

198203
/** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */
199204
void RegenerateCommitments(CBlock& block, ChainstateManager& chainman);
205+
206+
/** Apply -blockmintxfee and -blockmaxweight options from ArgsManager to BlockAssembler options. */
207+
void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& options);
200208
} // namespace node
201209

202210
#endif // BITCOIN_NODE_MINER_H

src/test/util/mining.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include <consensus/merkle.h>
99
#include <key_io.h>
1010
#include <node/context.h>
11-
#include <node/miner.h>
1211
#include <pow.h>
1312
#include <script/standard.h>
1413
#include <test/util/script.h>
@@ -74,10 +73,11 @@ CTxIn MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey)
7473
return CTxIn{block->vtx[0]->GetHash(), 0};
7574
}
7675

77-
std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey)
76+
std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey,
77+
const BlockAssembler::Options& assembler_options)
7878
{
7979
auto block = std::make_shared<CBlock>(
80-
BlockAssembler{Assert(node.chainman)->ActiveChainstate(), Assert(node.mempool.get())}
80+
BlockAssembler{Assert(node.chainman)->ActiveChainstate(), Assert(node.mempool.get()), assembler_options}
8181
.CreateNewBlock(coinbase_scriptPubKey)
8282
->block);
8383

@@ -87,3 +87,9 @@ std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coi
8787

8888
return block;
8989
}
90+
std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey)
91+
{
92+
BlockAssembler::Options assembler_options;
93+
ApplyArgsManOptions(*node.args, assembler_options);
94+
return PrepareBlock(node, coinbase_scriptPubKey, assembler_options);
95+
}

src/test/util/mining.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#ifndef BITCOIN_TEST_UTIL_MINING_H
66
#define BITCOIN_TEST_UTIL_MINING_H
77

8+
#include <node/miner.h>
9+
810
#include <memory>
911
#include <string>
1012
#include <vector>
@@ -25,6 +27,8 @@ CTxIn MineBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey);
2527

2628
/** Prepare a block to be mined */
2729
std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey);
30+
std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext& node, const CScript& coinbase_scriptPubKey,
31+
const node::BlockAssembler::Options& assembler_options);
2832

2933
/** RPC-like helper function, returns the generated coin */
3034
CTxIn generatetoaddress(const node::NodeContext&, const std::string& address);

src/test/util/setup_common.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -397,15 +397,15 @@ std::vector<CTransactionRef> TestChain100Setup::PopulateMempool(FastRandomContex
397397
unspent_prevouts.pop_front();
398398
}
399399
const size_t num_outputs = det_rand.randrange(24) + 1;
400-
// Approximately 1000sat "fee," equal output amounts.
401-
const CAmount amount_per_output = (total_in - 1000) / num_outputs;
400+
const CAmount fee = 100 * det_rand.randrange(30);
401+
const CAmount amount_per_output = (total_in - fee) / num_outputs;
402402
for (size_t n{0}; n < num_outputs; ++n) {
403403
CScript spk = CScript() << CScriptNum(num_transactions + n);
404404
mtx.vout.push_back(CTxOut(amount_per_output, spk));
405405
}
406406
CTransactionRef ptx = MakeTransactionRef(mtx);
407407
mempool_transactions.push_back(ptx);
408-
if (amount_per_output > 2000) {
408+
if (amount_per_output > 3000) {
409409
// If the value is high enough to fund another transaction + fees, keep track of it so
410410
// it can be used to build a more complex transaction graph. Insert randomly into
411411
// unspent_prevouts for extra randomness in the resulting structures.
@@ -415,9 +415,11 @@ std::vector<CTransactionRef> TestChain100Setup::PopulateMempool(FastRandomContex
415415
}
416416
}
417417
if (submit) {
418-
LOCK2(m_node.mempool->cs, cs_main);
418+
LOCK2(cs_main, m_node.mempool->cs);
419419
LockPoints lp;
420-
m_node.mempool->addUnchecked(CTxMemPoolEntry(ptx, 1000, 0, 1, false, 4, lp));
420+
m_node.mempool->addUnchecked(CTxMemPoolEntry(ptx, /*fee=*/(total_in - num_outputs * amount_per_output),
421+
/*time=*/0, /*entry_height=*/1,
422+
/*spends_coinbase=*/false, /*sigops_cost=*/4, lp));
421423
}
422424
--num_transactions;
423425
}

0 commit comments

Comments
 (0)