Bitcoin Core  29.1.0
P2P Digital Currency
disconnected_transactions.cpp
Go to the documentation of this file.
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>
7 #include <primitives/block.h>
9 #include <script/script.h>
10 #include <test/util/setup_common.h>
11 
12 #include <algorithm>
13 #include <cassert>
14 #include <cstddef>
15 #include <cstdint>
16 #include <iterator>
17 #include <memory>
18 #include <vector>
19 
20 constexpr size_t BLOCK_VTX_COUNT{4000};
21 constexpr size_t BLOCK_VTX_COUNT_10PERCENT{400};
22 
23 using BlockTxns = decltype(CBlock::vtx);
24 
26 struct ReorgTxns {
34  size_t num_shared;
35 };
36 
37 static BlockTxns CreateRandomTransactions(size_t num_txns)
38 {
39  // Ensure every transaction has a different txid by having each one spend the previous one.
40  static Txid prevout_hash{};
41 
42  BlockTxns txns;
43  txns.reserve(num_txns);
44  // Simplest spk for every tx
45  CScript spk = CScript() << OP_TRUE;
46  for (uint32_t i = 0; i < num_txns; ++i) {
48  tx.vin.emplace_back(COutPoint{prevout_hash, 0});
49  tx.vout.emplace_back(CENT, spk);
50  auto ptx{MakeTransactionRef(tx)};
51  txns.emplace_back(ptx);
52  prevout_hash = ptx->GetHash();
53  }
54  return txns;
55 }
56 
62 static ReorgTxns CreateBlocks(size_t num_not_shared)
63 {
64  auto num_shared{BLOCK_VTX_COUNT - num_not_shared};
65  const auto shared_txns{CreateRandomTransactions(/*num_txns=*/num_shared)};
66 
67  // Create different sets of transactions...
68  auto disconnected_block_txns{CreateRandomTransactions(/*num_txns=*/num_not_shared)};
69  std::copy(shared_txns.begin(), shared_txns.end(), std::back_inserter(disconnected_block_txns));
70 
71  auto connected_block_txns{CreateRandomTransactions(/*num_txns=*/num_not_shared)};
72  std::copy(shared_txns.begin(), shared_txns.end(), std::back_inserter(connected_block_txns));
73 
74  assert(disconnected_block_txns.size() == BLOCK_VTX_COUNT);
75  assert(connected_block_txns.size() == BLOCK_VTX_COUNT);
76 
77  return ReorgTxns{/*disconnected_txns=*/disconnected_block_txns,
78  /*connected_txns_1=*/connected_block_txns,
79  /*connected_txns_2=*/CreateRandomTransactions(BLOCK_VTX_COUNT),
80  /*num_shared=*/num_shared};
81 }
82 
83 static void Reorg(const ReorgTxns& reorg)
84 {
86  // Disconnect block
87  const auto evicted = disconnectpool.AddTransactionsFromBlock(reorg.disconnected_txns);
88  assert(evicted.empty());
89 
90  // Connect first block
91  disconnectpool.removeForBlock(reorg.connected_txns_1);
92  // Connect new tip
93  disconnectpool.removeForBlock(reorg.connected_txns_2);
94 
95  // Sanity Check
96  assert(disconnectpool.size() == BLOCK_VTX_COUNT - reorg.num_shared);
97 
98  disconnectpool.clear();
99 }
100 
106 {
107  const auto chains{CreateBlocks(/*num_not_shared=*/1)};
108  assert(chains.num_shared == BLOCK_VTX_COUNT - 1);
109 
110  bench.minEpochIterations(10).run([&]() {
111  Reorg(chains);
112  });
113 }
114 
117 {
118  const auto chains{CreateBlocks(/*num_not_shared=*/BLOCK_VTX_COUNT_10PERCENT)};
119  assert(chains.num_shared == BLOCK_VTX_COUNT - BLOCK_VTX_COUNT_10PERCENT);
120 
121  bench.minEpochIterations(10).run([&]() {
122  Reorg(chains);
123  });
124 }
125 
128 {
129  const auto chains{CreateBlocks(/*num_not_shared=*/BLOCK_VTX_COUNT - BLOCK_VTX_COUNT_10PERCENT)};
130  assert(chains.num_shared == BLOCK_VTX_COUNT_10PERCENT);
131 
132  bench.minEpochIterations(10).run([&]() {
133  Reorg(chains);
134  });
135 }
136 
BlockTxns connected_txns_2
Second connected block, new chain tip.
assert(!tx.IsCoinBase())
static void AddAndRemoveDisconnectedBlockTransactions90(benchmark::Bench &bench)
Add transactions from DisconnectedBlockTransactions, remove 90% of them, and then pop from the front ...
decltype(CBlock::vtx) BlockTxns
std::vector< CTxIn > vin
Definition: transaction.h:379
static void AddAndRemoveDisconnectedBlockTransactionsAll(benchmark::Bench &bench)
Add transactions from DisconnectedBlockTransactions, remove all but one (the disconnected block&#39;s coi...
BlockTxns connected_txns_1
First connected block.
BENCHMARK(AddAndRemoveDisconnectedBlockTransactionsAll, benchmark::PriorityLevel::HIGH)
static void Reorg(const ReorgTxns &reorg)
static const unsigned int MAX_DISCONNECTED_TX_POOL_BYTES
Maximum bytes for transactions to store for processing during reorg.
size_t num_shared
Transactions shared between disconnected_txns and connected_txns_1.
ANKERL_NANOBENCH(NODISCARD) std Bench & minEpochIterations(uint64_t numIters) noexcept
Sets the minimum number of iterations each epoch should take.
constexpr size_t BLOCK_VTX_COUNT_10PERCENT
constexpr size_t BLOCK_VTX_COUNT
Bench & run(char const *benchmarkName, Op &&op)
Repeatedly calls op() based on the configuration, and performs measurements.
Definition: nanobench.h:1234
Definition: script.h:84
static ReorgTxns CreateBlocks(size_t num_not_shared)
Creates blocks for a Reorg, each with BLOCK_VTX_COUNT transactions.
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:28
std::vector< CTxOut > vout
Definition: transaction.h:380
DisconnectedBlockTransactions.
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:424
std::vector< CTransactionRef > vtx
Definition: block.h:72
Reorg where 1 block is disconnected and 2 blocks are connected.
BlockTxns disconnected_txns
Disconnected block.
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:414
A mutable version of CTransaction.
Definition: transaction.h:377
Main entry point to nanobench&#39;s benchmarking facility.
Definition: nanobench.h:627
static constexpr CAmount CENT
Definition: setup_common.h:47
static BlockTxns CreateRandomTransactions(size_t num_txns)
static void AddAndRemoveDisconnectedBlockTransactions10(benchmark::Bench &bench)
Add transactions from DisconnectedBlockTransactions, remove 10% of them, and then pop from the front ...