Bitcoin Core  27.99.0
P2P Digital Currency
addrman.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020-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 <addrman.h>
6 #include <bench/bench.h>
7 #include <netbase.h>
8 #include <netgroup.h>
9 #include <random.h>
10 #include <util/check.h>
11 #include <util/time.h>
12 
13 #include <optional>
14 #include <vector>
15 
16 /* A "source" is a source address from which we have received a bunch of other addresses. */
17 
18 static constexpr size_t NUM_SOURCES = 64;
19 static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256;
20 
21 static NetGroupManager EMPTY_NETGROUPMAN{std::vector<bool>()};
22 static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO{0};
23 
24 static std::vector<CAddress> g_sources;
25 static std::vector<std::vector<CAddress>> g_addresses;
26 
27 static void CreateAddresses()
28 {
29  if (g_sources.size() > 0) { // already created
30  return;
31  }
32 
33  FastRandomContext rng(uint256(std::vector<unsigned char>(32, 123)));
34 
35  auto randAddr = [&rng]() {
36  in6_addr addr;
37  memcpy(&addr, rng.randbytes(sizeof(addr)).data(), sizeof(addr));
38 
39  uint16_t port;
40  memcpy(&port, rng.randbytes(sizeof(port)).data(), sizeof(port));
41  if (port == 0) {
42  port = 1;
43  }
44 
45  CAddress ret(CService(addr, port), NODE_NETWORK);
46 
47  ret.nTime = Now<NodeSeconds>();
48 
49  return ret;
50  };
51 
52  for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
53  g_sources.emplace_back(randAddr());
54  g_addresses.emplace_back();
55  for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
56  g_addresses[source_i].emplace_back(randAddr());
57  }
58  }
59 }
60 
61 static void AddAddressesToAddrMan(AddrMan& addrman)
62 {
63  for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
64  addrman.Add(g_addresses[source_i], g_sources[source_i]);
65  }
66 }
67 
68 static void FillAddrMan(AddrMan& addrman)
69 {
71 
72  AddAddressesToAddrMan(addrman);
73 }
74 
75 /* Benchmarks */
76 
77 static void AddrManAdd(benchmark::Bench& bench)
78 {
80 
81  bench.run([&] {
82  AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
83  AddAddressesToAddrMan(addrman);
84  });
85 }
86 
87 static void AddrManSelect(benchmark::Bench& bench)
88 {
89  AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
90 
91  FillAddrMan(addrman);
92 
93  bench.run([&] {
94  const auto& address = addrman.Select();
95  assert(address.first.GetPort() > 0);
96  });
97 }
98 
99 // The worst case performance of the Select() function is when there is only
100 // one address on the table, because it linearly searches every position of
101 // several buckets before identifying the correct bucket
103 {
104  AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
105 
106  // Add one address to the new table
107  CService addr = Lookup("250.3.1.1", 8333, false).value();
108  addrman.Add({CAddress(addr, NODE_NONE)}, addr);
109 
110  bench.run([&] {
111  (void)addrman.Select();
112  });
113 }
114 
116 {
117  AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
118 
119  // add single I2P address to new table
120  CService i2p_service;
121  i2p_service.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");
122  CAddress i2p_address(i2p_service, NODE_NONE);
123  i2p_address.nTime = Now<NodeSeconds>();
124  const CNetAddr source{LookupHost("252.2.2.2", false).value()};
125  addrman.Add({i2p_address}, source);
126 
127  FillAddrMan(addrman);
128 
129  bench.run([&] {
130  (void)addrman.Select(/*new_only=*/false, NET_I2P);
131  });
132 }
133 
134 static void AddrManGetAddr(benchmark::Bench& bench)
135 {
136  AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
137 
138  FillAddrMan(addrman);
139 
140  bench.run([&] {
141  const auto& addresses = addrman.GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt);
142  assert(addresses.size() > 0);
143  });
144 }
145 
147 {
148  auto markSomeAsGood = [](AddrMan& addrman) {
149  for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
150  for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
151  addrman.Good(g_addresses[source_i][addr_i]);
152  }
153  }
154  };
155 
156  CreateAddresses();
157 
158  bench.run([&] {
159  // To make the benchmark independent of the number of evaluations, we always prepare a new addrman.
160  // This is necessary because AddrMan::Good() method modifies the object, affecting the timing of subsequent calls
161  // to the same method and we want to do the same amount of work in every loop iteration.
162  //
163  // This has some overhead (exactly the result of AddrManAdd benchmark), but that overhead is constant so improvements in
164  // AddrMan::Good() will still be noticeable.
165  AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
166  AddAddressesToAddrMan(addrman);
167 
168  markSomeAsGood(addrman);
169  });
170 }
171 
static NetGroupManager EMPTY_NETGROUPMAN
Definition: addrman.cpp:21
static void AddrManSelectByNetwork(benchmark::Bench &bench)
Definition: addrman.cpp:115
static void AddrManSelectFromAlmostEmpty(benchmark::Bench &bench)
Definition: addrman.cpp:102
static void FillAddrMan(AddrMan &addrman)
Definition: addrman.cpp:68
static void AddrManSelect(benchmark::Bench &bench)
Definition: addrman.cpp:87
static void AddrManAddThenGood(benchmark::Bench &bench)
Definition: addrman.cpp:146
static constexpr size_t NUM_SOURCES
Definition: addrman.cpp:18
static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO
Definition: addrman.cpp:22
BENCHMARK(AddrManAdd, benchmark::PriorityLevel::HIGH)
static std::vector< CAddress > g_sources
Definition: addrman.cpp:24
static void AddrManGetAddr(benchmark::Bench &bench)
Definition: addrman.cpp:134
static constexpr size_t NUM_ADDRESSES_PER_SOURCE
Definition: addrman.cpp:19
static void CreateAddresses()
Definition: addrman.cpp:27
static void AddAddressesToAddrMan(AddrMan &addrman)
Definition: addrman.cpp:61
static void AddrManAdd(benchmark::Bench &bench)
Definition: addrman.cpp:77
static std::vector< std::vector< CAddress > > g_addresses
Definition: addrman.cpp:25
int ret
Stochastic address manager.
Definition: addrman.h:88
bool Add(const std::vector< CAddress > &vAddr, const CNetAddr &source, std::chrono::seconds time_penalty=0s)
Attempt to add one or more addresses to addrman's new table.
Definition: addrman.cpp:1293
A CService with information about it as peer.
Definition: protocol.h:367
NodeSeconds nTime
Always included in serialization. The behavior is unspecified if the value is not representable as ui...
Definition: protocol.h:457
Network address.
Definition: netaddress.h:112
bool SetSpecial(const std::string &addr)
Parse a Tor or I2P address and set this object to it.
Definition: netaddress.cpp:208
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:531
Fast randomness source.
Definition: random.h:145
std::vector< B > randbytes(size_t len)
Generate random bytes.
Definition: random.cpp:671
Netgroup manager.
Definition: netgroup.h:16
Main entry point to nanobench's benchmarking facility.
Definition: nanobench.h:627
Bench & run(char const *benchmarkName, Op &&op)
Repeatedly calls op() based on the configuration, and performs measurements.
Definition: nanobench.h:1234
256-bit opaque blob.
Definition: uint256.h:106
@ HIGH
Definition: bench.h:47
@ NET_I2P
I2P.
Definition: netaddress.h:46
std::vector< CService > Lookup(const std::string &name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
Resolve a service string to its corresponding service.
Definition: netbase.cpp:182
std::vector< CNetAddr > LookupHost(const std::string &name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
Resolve a host string to its corresponding network addresses.
Definition: netbase.cpp:164
@ NODE_NONE
Definition: protocol.h:312
@ NODE_NETWORK
Definition: protocol.h:315
const char * source
Definition: rpcconsole.cpp:58
assert(!tx.IsCoinBase())