Skip to content

Commit 59a35a7

Browse files
committed
[bench] DisconnectedBlockTransactions
1 parent 925bb72 commit 59a35a7

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

src/Makefile.bench.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ bench_bench_bitcoin_SOURCES = \
2828
bench/data.cpp \
2929
bench/data.h \
3030
bench/descriptors.cpp \
31+
bench/disconnected_transactions.cpp \
3132
bench/duplicate_inputs.cpp \
3233
bench/ellswift.cpp \
3334
bench/examples.cpp \
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright (c) 2023 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+
#include <test/util/random.h>
7+
#include <test/util/setup_common.h>
8+
#include <validation.h>
9+
10+
constexpr size_t BLOCK_VTX_COUNT{4000};
11+
constexpr size_t BLOCK_VTX_COUNT_10PERCENT{400};
12+
13+
using BlockTxns = decltype(CBlock::vtx);
14+
15+
/** Reorg where 1 block is disconnected and 2 blocks are connected. */
16+
struct ReorgTxns {
17+
/** Disconnected block. */
18+
BlockTxns disconnected_txns;
19+
/** First connected block. */
20+
BlockTxns connected_txns_1;
21+
/** Second connected block, new chain tip. Has no overlap with disconnected_txns. */
22+
BlockTxns connected_txns_2;
23+
/** Transactions shared between disconnected_txns and connected_txns_1. */
24+
size_t num_shared;
25+
};
26+
27+
static BlockTxns CreateRandomTransactions(size_t num_txns)
28+
{
29+
// Ensure every transaction has a different txid by having each one spend the previous one.
30+
static uint256 prevout_hash{uint256::ZERO};
31+
32+
BlockTxns txns;
33+
txns.reserve(num_txns);
34+
// Simplest spk for every tx
35+
CScript spk = CScript() << OP_TRUE;
36+
for (uint32_t i = 0; i < num_txns; ++i) {
37+
CMutableTransaction tx;
38+
tx.vin.emplace_back(CTxIn{COutPoint{prevout_hash, 0}});
39+
tx.vout.emplace_back(CTxOut{CENT, spk});
40+
auto ptx{MakeTransactionRef(tx)};
41+
txns.emplace_back(ptx);
42+
prevout_hash = ptx->GetHash();
43+
}
44+
return txns;
45+
}
46+
47+
/** Creates blocks for a Reorg, each with BLOCK_VTX_COUNT transactions. Between the disconnected
48+
* block and the first connected block, there will be num_not_shared transactions that are
49+
* different, and all other transactions the exact same. The second connected block has all unique
50+
* transactions. This is to simulate a reorg in which all but num_not_shared transactions are
51+
* confirmed in the new chain. */
52+
static ReorgTxns CreateBlocks(size_t num_not_shared)
53+
{
54+
auto num_shared{BLOCK_VTX_COUNT - num_not_shared};
55+
const auto shared_txns{CreateRandomTransactions(/*num_txns=*/num_shared)};
56+
57+
// Create different sets of transactions...
58+
auto disconnected_block_txns{CreateRandomTransactions(/*num_txns=*/num_not_shared)};
59+
std::copy(shared_txns.begin(), shared_txns.end(), std::back_inserter(disconnected_block_txns));
60+
61+
auto connected_block_txns{CreateRandomTransactions(/*num_txns=*/num_not_shared)};
62+
std::copy(shared_txns.begin(), shared_txns.end(), std::back_inserter(connected_block_txns));
63+
64+
assert(disconnected_block_txns.size() == BLOCK_VTX_COUNT);
65+
assert(connected_block_txns.size() == BLOCK_VTX_COUNT);
66+
67+
return ReorgTxns{/*disconnected_txns=*/disconnected_block_txns,
68+
/*connected_txns_1=*/connected_block_txns,
69+
/*connected_txns_2=*/CreateRandomTransactions(BLOCK_VTX_COUNT),
70+
/*num_shared=*/num_shared};
71+
}
72+
73+
static void Reorg(const ReorgTxns& reorg)
74+
{
75+
DisconnectedBlockTransactions disconnectpool;
76+
// Disconnect block
77+
disconnectpool.AddTransactionsFromBlock(reorg.disconnected_txns);
78+
79+
// Connect first block
80+
disconnectpool.removeForBlock(reorg.connected_txns_1);
81+
// Connect new tip
82+
disconnectpool.removeForBlock(reorg.connected_txns_2);
83+
84+
// Sanity Check
85+
assert(disconnectpool.queuedTx.size() == BLOCK_VTX_COUNT - reorg.num_shared);
86+
87+
disconnectpool.clear();
88+
}
89+
90+
/** Add transactions from DisconnectedBlockTransactions, remove all but one (the disconnected
91+
* block's coinbase transaction) of them, and then pop from the front until empty. This is a reorg
92+
* in which all of the non-coinbase transactions in the disconnected chain also exist in the new
93+
* chain. */
94+
static void AddAndRemoveDisconnectedBlockTransactionsAll(benchmark::Bench& bench)
95+
{
96+
const auto chains{CreateBlocks(/*num_not_shared=*/1)};
97+
assert(chains.num_shared == BLOCK_VTX_COUNT - 1);
98+
99+
bench.minEpochIterations(10).run([&]() NO_THREAD_SAFETY_ANALYSIS {
100+
Reorg(chains);
101+
});
102+
}
103+
104+
/** Add transactions from DisconnectedBlockTransactions, remove 90% of them, and then pop from the front until empty. */
105+
static void AddAndRemoveDisconnectedBlockTransactions90(benchmark::Bench& bench)
106+
{
107+
const auto chains{CreateBlocks(/*num_not_shared=*/BLOCK_VTX_COUNT_10PERCENT)};
108+
assert(chains.num_shared == BLOCK_VTX_COUNT - BLOCK_VTX_COUNT_10PERCENT);
109+
110+
bench.minEpochIterations(10).run([&]() NO_THREAD_SAFETY_ANALYSIS {
111+
Reorg(chains);
112+
});
113+
}
114+
115+
/** Add transactions from DisconnectedBlockTransactions, remove 10% of them, and then pop from the front until empty. */
116+
static void AddAndRemoveDisconnectedBlockTransactions10(benchmark::Bench& bench)
117+
{
118+
const auto chains{CreateBlocks(/*num_not_shared=*/BLOCK_VTX_COUNT - BLOCK_VTX_COUNT_10PERCENT)};
119+
assert(chains.num_shared == BLOCK_VTX_COUNT_10PERCENT);
120+
121+
bench.minEpochIterations(10).run([&]() NO_THREAD_SAFETY_ANALYSIS {
122+
Reorg(chains);
123+
});
124+
}
125+
126+
BENCHMARK(AddAndRemoveDisconnectedBlockTransactionsAll, benchmark::PriorityLevel::HIGH);
127+
BENCHMARK(AddAndRemoveDisconnectedBlockTransactions90, benchmark::PriorityLevel::HIGH);
128+
BENCHMARK(AddAndRemoveDisconnectedBlockTransactions10, benchmark::PriorityLevel::HIGH);

0 commit comments

Comments
 (0)