Skip to content

Commit c059732

Browse files
committed
Benchmark Chainstate::ConnectBlock duration
Measure ConnectBlock performance for - blocks containing only schnorr sigs - blocks containing both schnorr and ecdsa sigs - blocks containing only ecdsa sigs This will allow testing and measurement of performance improvement for features like batch verification of schnorr signatures
1 parent 89720b7 commit c059732

File tree

2 files changed

+181
-0
lines changed

2 files changed

+181
-0
lines changed

src/bench/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ add_executable(bench_bitcoin
2020
chacha20.cpp
2121
checkblock.cpp
2222
checkblockindex.cpp
23+
check_connectblock.cpp
2324
checkqueue.cpp
2425
cluster_linearize.cpp
2526
crypto_hash.cpp

src/bench/check_connectblock.cpp

+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// Copyright (c) 2016-2022 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <bench/bench.h>
6+
7+
#include <addresstype.h>
8+
#include <interfaces/chain.h>
9+
#include <kernel/cs_main.h>
10+
#include <script/interpreter.h>
11+
#include <sync.h>
12+
#include <test/util/setup_common.h>
13+
#include <validation.h>
14+
15+
#include <cassert>
16+
#include <utility>
17+
#include <vector>
18+
19+
CBlock CreateTestBlock(TestChain100Setup* test_setup, std::vector<CKey>& keys, std::vector<CScript>& scriptpubkeys)
20+
{
21+
Chainstate& chainstate{test_setup->m_node.chainman->ActiveChainstate()};
22+
23+
const int num_txs = 500;
24+
25+
std::vector<CMutableTransaction> txs;
26+
txs.reserve(num_txs);
27+
28+
auto input_tx{test_setup->m_coinbase_txns[0]};
29+
30+
std::vector<COutPoint> inputs{COutPoint(input_tx->GetHash(), 0)};
31+
inputs.reserve(scriptpubkeys.size());
32+
33+
std::vector<CTxOut> outputs;
34+
// Each transaction will create outputs for each scriptpubkey that are spent in the next transaction
35+
outputs.reserve(scriptpubkeys.size());
36+
37+
for (int i{0}; i < num_txs; i++) {
38+
Txid txid = input_tx->GetHash();
39+
40+
for (size_t j{0}; j < outputs.size(); j++) {
41+
inputs.emplace_back(txid, j);
42+
}
43+
44+
outputs.clear();
45+
for (size_t j{0}; j < scriptpubkeys.size(); j++) {
46+
outputs.emplace_back(COIN, scriptpubkeys[j]);
47+
}
48+
const auto taproot_tx{test_setup->CreateValidTransaction(
49+
std::vector{input_tx}, inputs, chainstate.m_chain.Height() + 1, keys, outputs, std::nullopt, std::nullopt)};
50+
txs.push_back(taproot_tx.first);
51+
input_tx = MakeTransactionRef(taproot_tx.first);
52+
53+
inputs.clear();
54+
}
55+
56+
const WitnessV1Taproot taproot{XOnlyPubKey(test_setup->coinbaseKey.GetPubKey())};
57+
const CScript coinbase_spk{GetScriptForDestination(taproot)};
58+
return test_setup->CreateBlock(txs, coinbase_spk, chainstate);
59+
}
60+
61+
static void ConnectBlockAllSchnorr(benchmark::Bench& bench)
62+
{
63+
const auto test_setup{MakeNoLogFileContext<TestChain100Setup>()};
64+
65+
size_t num_keys{4};
66+
std::vector<CKey> keys{test_setup->coinbaseKey};
67+
keys.reserve(num_keys + 1);
68+
69+
std::vector<CScript> taproot_spks;
70+
taproot_spks.reserve(num_keys);
71+
72+
for (size_t i{0}; i < num_keys; i++) {
73+
const CKey key{GenerateRandomKey()};
74+
keys.push_back(key);
75+
const CScript scriptpubkey{GetScriptForDestination(WitnessV1Taproot{XOnlyPubKey(key.GetPubKey())})};
76+
taproot_spks.push_back(scriptpubkey);
77+
}
78+
79+
const auto test_block{CreateTestBlock(test_setup.get(), keys, taproot_spks)};
80+
auto pindex{std::make_unique<CBlockIndex>(test_block)};
81+
auto test_blockhash{std::make_unique<uint256>(test_block.GetHash())};
82+
83+
Chainstate& chainstate{test_setup->m_node.chainman->ActiveChainstate()};
84+
85+
pindex->nHeight = chainstate.m_chain.Height() + 1;
86+
pindex->phashBlock = test_blockhash.get();
87+
pindex->pprev = chainstate.m_chain.Tip();
88+
89+
BlockValidationState test_block_state;
90+
bench.unit("block").run([&] {
91+
LOCK(cs_main);
92+
CCoinsViewCache viewNew{&chainstate.CoinsTip()};
93+
assert(chainstate.ConnectBlock(test_block, test_block_state, pindex.get(), viewNew, false));
94+
});
95+
}
96+
97+
static void ConnectBlockMixed(benchmark::Bench& bench)
98+
{
99+
const auto test_setup{MakeNoLogFileContext<TestChain100Setup>()};
100+
101+
size_t num_taproot{2};
102+
size_t num_nontaproot{2};
103+
104+
std::vector<CKey> keys{test_setup->coinbaseKey};
105+
keys.reserve(num_taproot + num_nontaproot + 1);
106+
107+
std::vector<CScript> spks;
108+
spks.reserve(num_taproot + num_nontaproot);
109+
110+
for (size_t i{0}; i < num_nontaproot; i++) {
111+
const CKey key{GenerateRandomKey()};
112+
keys.push_back(key);
113+
const CScript scriptpubkey{GetScriptForDestination(WitnessV0KeyHash{key.GetPubKey()})};
114+
spks.push_back(scriptpubkey);
115+
}
116+
117+
for (size_t i{0}; i < num_taproot; i++) {
118+
const CKey key{GenerateRandomKey()};
119+
keys.push_back(key);
120+
const CScript scriptpubkey{GetScriptForDestination(WitnessV1Taproot{XOnlyPubKey(key.GetPubKey())})};
121+
spks.push_back(scriptpubkey);
122+
}
123+
124+
const auto test_block{CreateTestBlock(test_setup.get(), keys, spks)};
125+
auto pindex{std::make_unique<CBlockIndex>(test_block)};
126+
auto test_blockhash{std::make_unique<uint256>(test_block.GetHash())};
127+
128+
Chainstate& chainstate{test_setup->m_node.chainman->ActiveChainstate()};
129+
130+
pindex->nHeight = chainstate.m_chain.Height() + 1;
131+
pindex->phashBlock = test_blockhash.get();
132+
pindex->pprev = chainstate.m_chain.Tip();
133+
134+
BlockValidationState test_block_state;
135+
bench.unit("block").run([&] {
136+
LOCK(cs_main);
137+
CCoinsViewCache viewNew{&chainstate.CoinsTip()};
138+
assert(chainstate.ConnectBlock(test_block, test_block_state, pindex.get(), viewNew, false));
139+
});
140+
}
141+
142+
static void ConnectBlockNoSchnorr(benchmark::Bench& bench)
143+
{
144+
const auto test_setup{MakeNoLogFileContext<TestChain100Setup>()};
145+
146+
size_t num_keys{4};
147+
std::vector<CKey> keys{test_setup->coinbaseKey};
148+
keys.reserve(num_keys + 1);
149+
150+
std::vector<CScript> spks;
151+
spks.reserve(num_keys);
152+
153+
for (size_t i{0}; i < num_keys; i++) {
154+
const CKey key{GenerateRandomKey()};
155+
keys.push_back(key);
156+
const CScript scriptpubkey{GetScriptForDestination(WitnessV0KeyHash{key.GetPubKey()})};
157+
spks.push_back(scriptpubkey);
158+
}
159+
160+
const auto test_block{CreateTestBlock(test_setup.get(), keys, spks)};
161+
auto pindex{std::make_unique<CBlockIndex>(test_block)};
162+
auto test_blockhash{std::make_unique<uint256>(test_block.GetHash())};
163+
164+
Chainstate& chainstate{test_setup->m_node.chainman->ActiveChainstate()};
165+
166+
pindex->nHeight = chainstate.m_chain.Height() + 1;
167+
pindex->phashBlock = test_blockhash.get();
168+
pindex->pprev = chainstate.m_chain.Tip();
169+
170+
BlockValidationState test_block_state;
171+
bench.unit("block").run([&] {
172+
LOCK(cs_main);
173+
CCoinsViewCache viewNew{&chainstate.CoinsTip()};
174+
assert(chainstate.ConnectBlock(test_block, test_block_state, pindex.get(), viewNew, false));
175+
});
176+
}
177+
178+
BENCHMARK(ConnectBlockAllSchnorr, benchmark::PriorityLevel::HIGH);
179+
BENCHMARK(ConnectBlockMixed, benchmark::PriorityLevel::HIGH);
180+
BENCHMARK(ConnectBlockNoSchnorr, benchmark::PriorityLevel::HIGH);

0 commit comments

Comments
 (0)