Bitcoin Core 28.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
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
18static constexpr size_t NUM_SOURCES = 64;
19static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256;
20
21static NetGroupManager EMPTY_NETGROUPMAN{std::vector<bool>()};
22static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO{0};
23
24static std::vector<CAddress> g_sources;
25static std::vector<std::vector<CAddress>> g_addresses;
26
27static 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
61static 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
68static void FillAddrMan(AddrMan& addrman)
69{
71
72 AddAddressesToAddrMan(addrman);
73}
74
75/* Benchmarks */
76
77static 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
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
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
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
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
#define BENCHMARK(n, priority_level)
Definition bench.h:79
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.
A combination of a network address (CNetAddr) and a (TCP) port.
Definition netaddress.h:531
Fast randomness source.
Definition random.h:377
Netgroup manager.
Definition netgroup.h:16
std::vector< B > randbytes(size_t len) noexcept
Generate random bytes.
Definition random.h:297
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:178
@ HIGH
Definition bench.h:47
@ NET_I2P
I2P.
Definition netaddress.h:46
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:177
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:195
@ NODE_NONE
Definition protocol.h:312
@ NODE_NETWORK
Definition protocol.h:315
const char * source
T Now()
Return the current time point cast to the given precision.
Definition time.h:91
assert(!tx.IsCoinBase())