Bitcoin Core  31.0.0
P2P Digital Currency
txgraph.cpp
Go to the documentation of this file.
1 // Copyright (c) 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 <random.h>
7 #include <txgraph.h>
8 #include <util/feefrac.h>
9 
10 #include <cassert>
11 #include <cstdint>
12 
13 namespace {
14 
15 std::strong_ordering PointerComparator(const TxGraph::Ref& a, const TxGraph::Ref& b) noexcept
16 {
17  return (&a) <=> (&b);
18 }
19 
20 void BenchTxGraphTrim(benchmark::Bench& bench)
21 {
22  // The from-block transactions consist of 1000 fully linear clusters, each with 64
23  // transactions. The mempool contains 11 transactions that together merge all of these into
24  // a single cluster.
25  //
26  // (1000 chains of 64 transactions, 64000 T's total)
27  //
28  // T T T T T T T T
29  // | | | | | | | |
30  // T T T T T T T T
31  // | | | | | | | |
32  // T T T T T T T T
33  // | | | | | | | |
34  // T T T T T T T T
35  // (64 long) (64 long) (64 long) (64 long) (64 long) (64 long) (64 long) (64 long)
36  // | | | | | | | |
37  // | | / \ | / \ | | /
38  // \----------+--------/ \--------+--------/ \--------+-----+----+--------/
39  // | | |
40  // B B B
41  //
42  // (11 B's, each attaching to up to 100 chains of 64 T's)
43  //
45  static constexpr int MAX_CLUSTER_COUNT = 64;
47  static constexpr int NUM_TOP_CHAINS = 1000;
49  static constexpr int NUM_TX_PER_TOP_CHAIN = MAX_CLUSTER_COUNT;
51  static constexpr int NUM_DEPS_PER_BOTTOM_TX = 100;
53  static constexpr int32_t MAX_CLUSTER_SIZE = 100'000 * 100;
56  static constexpr uint64_t HIGH_ACCEPTABLE_COST = 100'000'000;
57 
59  std::vector<TxGraph::Ref> top_refs;
61  std::vector<TxGraph::Ref> bottom_refs;
65  std::vector<size_t> top_components;
66 
67  InsecureRandomContext rng(11);
68  auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, HIGH_ACCEPTABLE_COST, PointerComparator);
69 
70  // Construct the top chains.
71  for (int chain = 0; chain < NUM_TOP_CHAINS; ++chain) {
72  for (int chaintx = 0; chaintx < NUM_TX_PER_TOP_CHAIN; ++chaintx) {
73  int64_t fee = rng.randbits<27>() + 100;
74  FeePerWeight feerate{fee, 1};
75  graph->AddTransaction(top_refs.emplace_back(), feerate);
76  // Add internal dependencies linking the chain transactions together.
77  if (chaintx > 0) {
78  graph->AddDependency(*(top_refs.rbegin()), *(top_refs.rbegin() + 1));
79  }
80  }
81  // Remember the last transaction in each chain, to attach the bottom transactions to.
82  top_components.push_back(top_refs.size() - 1);
83  }
84 
85  // Make the graph linearize all clusters acceptably.
86  graph->GetBlockBuilder();
87 
88  // Construct the bottom transactions, and dependencies to the top chains.
89  while (top_components.size() > 1) {
90  // Construct the transaction.
91  int64_t fee = rng.randbits<27>() + 100;
92  FeePerWeight feerate{fee, 1};
93  TxGraph::Ref bottom_tx;
94  graph->AddTransaction(bottom_tx, feerate);
95  // Determine the number of dependencies this transaction will have.
96  int deps = std::min<int>(NUM_DEPS_PER_BOTTOM_TX, top_components.size());
97  for (int dep = 0; dep < deps; ++dep) {
98  // Pick an transaction in top_components to attach to.
99  auto idx = rng.randrange(top_components.size());
100  // Add dependency.
101  graph->AddDependency(/*parent=*/top_refs[top_components[idx]], /*child=*/bottom_tx);
102  // Unless this is the last dependency being added, remove from top_components, as
103  // the component will be merged with that one.
104  if (dep < deps - 1) {
105  // Move entry top the back.
106  if (idx != top_components.size() - 1) std::swap(top_components.back(), top_components[idx]);
107  // And pop it.
108  top_components.pop_back();
109  }
110  }
111  bottom_refs.push_back(std::move(bottom_tx));
112  }
113 
114  // Run the benchmark exactly once. Running it multiple times would require the setup to be
115  // redone, which takes a very non-negligible time compared to the trimming itself.
116  bench.epochIterations(1).epochs(1).run([&] {
117  // Call Trim() to remove transactions and bring the cluster back within limits.
118  graph->Trim();
119  // And relinearize everything that remains acceptably.
120  graph->GetBlockBuilder();
121  });
122 
123  assert(!graph->IsOversized(TxGraph::Level::TOP));
124  // At least 99% of chains must survive.
125  assert(graph->GetTransactionCount(TxGraph::Level::TOP) >= (NUM_TOP_CHAINS * NUM_TX_PER_TOP_CHAIN * 99) / 100);
126 }
127 
128 } // namespace
129 
130 static void TxGraphTrim(benchmark::Bench& bench) { BenchTxGraphTrim(bench); }
131 
132 BENCHMARK(TxGraphTrim);
Main entry point to nanobench&#39;s benchmarking facility.
Definition: nanobench.h:627