/root/bitcoin/src/test/fuzz/addrman.cpp
Line | Count | Source |
1 | | // Copyright (c) 2020-present 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 <addrdb.h> |
6 | | #include <addrman.h> |
7 | | #include <addrman_impl.h> |
8 | | #include <chainparams.h> |
9 | | #include <common/args.h> |
10 | | #include <merkleblock.h> |
11 | | #include <random.h> |
12 | | #include <test/fuzz/FuzzedDataProvider.h> |
13 | | #include <test/fuzz/fuzz.h> |
14 | | #include <test/fuzz/util.h> |
15 | | #include <test/fuzz/util/net.h> |
16 | | #include <test/util/setup_common.h> |
17 | | #include <test/util/time.h> |
18 | | #include <util/asmap.h> |
19 | | #include <util/chaintype.h> |
20 | | |
21 | | #include <cassert> |
22 | | #include <cstdint> |
23 | | #include <ctime> |
24 | | #include <optional> |
25 | | #include <string> |
26 | | #include <vector> |
27 | | |
28 | | namespace { |
29 | | const BasicTestingSetup* g_setup; |
30 | | |
31 | | int32_t GetCheckRatio() |
32 | 0 | { |
33 | 0 | return std::clamp<int32_t>(g_setup->m_node.args->GetIntArg("-checkaddrman", 0), 0, 1000000); |
34 | 0 | } |
35 | | } // namespace |
36 | | |
37 | | void initialize_addrman() |
38 | 0 | { |
39 | 0 | static const auto testing_setup = MakeNoLogFileContext<>(ChainType::REGTEST); |
40 | 0 | g_setup = testing_setup.get(); |
41 | 0 | } |
42 | | |
43 | | FUZZ_TARGET(data_stream_addr_man, .init = initialize_addrman) |
44 | 0 | { |
45 | 0 | SeedRandomStateForTest(SeedRand::ZEROS); |
46 | 0 | FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; |
47 | 0 | DataStream data_stream = ConsumeDataStream(fuzzed_data_provider); |
48 | 0 | NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)}; |
49 | 0 | AddrMan addr_man(netgroupman, /*deterministic=*/false, GetCheckRatio()); |
50 | 0 | try { |
51 | 0 | ReadFromStream(addr_man, data_stream); |
52 | 0 | } catch (const std::exception&) { |
53 | 0 | } |
54 | 0 | } |
55 | | |
56 | | /** |
57 | | * Generate a random address. Always returns a valid address. |
58 | | */ |
59 | | CNetAddr RandAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext& fast_random_context) |
60 | 0 | { |
61 | 0 | CNetAddr addr; |
62 | 0 | assert(!addr.IsValid()); Branch (62:5): [True: 0, False: 0]
|
63 | 0 | for (size_t i = 0; i < 8 && !addr.IsValid(); ++i) { Branch (63:24): [True: 0, False: 0]
Branch (63:33): [True: 0, False: 0]
|
64 | 0 | if (fuzzed_data_provider.remaining_bytes() > 1 && fuzzed_data_provider.ConsumeBool()) { Branch (64:13): [True: 0, False: 0]
Branch (64:59): [True: 0, False: 0]
|
65 | 0 | addr = ConsumeNetAddr(fuzzed_data_provider); |
66 | 0 | } else { |
67 | 0 | addr = ConsumeNetAddr(fuzzed_data_provider, &fast_random_context); |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | | // Return a dummy IPv4 5.5.5.5 if we generated an invalid address. |
72 | 0 | if (!addr.IsValid()) { Branch (72:9): [True: 0, False: 0]
|
73 | 0 | in_addr v4_addr = {}; |
74 | 0 | v4_addr.s_addr = 0x05050505; |
75 | 0 | addr = CNetAddr{v4_addr}; |
76 | 0 | } |
77 | |
|
78 | 0 | return addr; |
79 | 0 | } |
80 | | |
81 | | /** Fill addrman with lots of addresses from lots of sources. */ |
82 | | void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider) |
83 | 0 | { |
84 | | // Add a fraction of the addresses to the "tried" table. |
85 | | // 0, 1, 2, 3 corresponding to 0%, 100%, 50%, 33% |
86 | 0 | const size_t n = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3); |
87 | |
|
88 | 0 | const size_t num_sources = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50); |
89 | 0 | CNetAddr prev_source; |
90 | | // Generate a FastRandomContext seed to use inside the loops instead of |
91 | | // fuzzed_data_provider. When fuzzed_data_provider is exhausted it |
92 | | // just returns 0. |
93 | 0 | FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)}; |
94 | 0 | for (size_t i = 0; i < num_sources; ++i) { Branch (94:24): [True: 0, False: 0]
|
95 | 0 | const auto source = RandAddr(fuzzed_data_provider, fast_random_context); |
96 | 0 | const size_t num_addresses = fast_random_context.randrange(500) + 1; // [1..500] |
97 | |
|
98 | 0 | for (size_t j = 0; j < num_addresses; ++j) { Branch (98:28): [True: 0, False: 0]
|
99 | 0 | const auto addr = CAddress{CService{RandAddr(fuzzed_data_provider, fast_random_context), 8333}, NODE_NETWORK}; |
100 | 0 | const std::chrono::seconds time_penalty{fast_random_context.randrange(100000001)}; |
101 | 0 | addrman.Add({addr}, source, time_penalty); |
102 | |
|
103 | 0 | if (n > 0 && addrman.Size() % n == 0) { Branch (103:17): [True: 0, False: 0]
Branch (103:26): [True: 0, False: 0]
|
104 | 0 | addrman.Good(addr, Now<NodeSeconds>()); |
105 | 0 | } |
106 | | |
107 | | // Add 10% of the addresses from more than one source. |
108 | 0 | if (fast_random_context.randrange(10) == 0 && prev_source.IsValid()) { Branch (108:17): [True: 0, False: 0]
Branch (108:59): [True: 0, False: 0]
|
109 | 0 | addrman.Add({addr}, prev_source, time_penalty); |
110 | 0 | } |
111 | 0 | } |
112 | 0 | prev_source = source; |
113 | 0 | } |
114 | 0 | } |
115 | | |
116 | | FUZZ_TARGET(addrman, .init = initialize_addrman) |
117 | 0 | { |
118 | 0 | SeedRandomStateForTest(SeedRand::ZEROS); |
119 | 0 | FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); |
120 | 0 | NodeClockContext clock_ctx{ConsumeTime(fuzzed_data_provider)}; |
121 | 0 | NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)}; |
122 | 0 | auto addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider, GetCheckRatio()); |
123 | 0 | if (fuzzed_data_provider.ConsumeBool()) { Branch (123:9): [True: 0, False: 0]
|
124 | 0 | const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; |
125 | 0 | DataStream ds{serialized_data}; |
126 | 0 | try { |
127 | 0 | ds >> *addr_man_ptr; |
128 | 0 | } catch (const std::ios_base::failure&) { |
129 | 0 | addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider, GetCheckRatio()); |
130 | 0 | } |
131 | 0 | } |
132 | 0 | AddrManDeterministic& addr_man = *addr_man_ptr; |
133 | 0 | LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) { |
134 | 0 | CallOneOf( |
135 | 0 | fuzzed_data_provider, |
136 | 0 | [&] { |
137 | 0 | addr_man.ResolveCollisions(); |
138 | 0 | }, |
139 | 0 | [&] { |
140 | 0 | (void)addr_man.SelectTriedCollision(); |
141 | 0 | }, |
142 | 0 | [&] { |
143 | 0 | std::vector<CAddress> addresses; |
144 | 0 | LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) { |
145 | 0 | addresses.push_back(ConsumeAddress(fuzzed_data_provider)); |
146 | 0 | } |
147 | 0 | auto net_addr = ConsumeNetAddr(fuzzed_data_provider); |
148 | 0 | auto time_penalty = ConsumeDuration<std::chrono::seconds>(fuzzed_data_provider, /*min=*/0s, /*max=*/100000000s); |
149 | 0 | addr_man.Add(addresses, net_addr, time_penalty); |
150 | 0 | }, |
151 | 0 | [&] { |
152 | 0 | auto addr = ConsumeService(fuzzed_data_provider); |
153 | 0 | auto time = ConsumeTime(fuzzed_data_provider); |
154 | 0 | addr_man.Good(addr, time); |
155 | 0 | }, |
156 | 0 | [&] { |
157 | 0 | auto addr = ConsumeService(fuzzed_data_provider); |
158 | 0 | auto count_failure = fuzzed_data_provider.ConsumeBool(); |
159 | 0 | auto time = ConsumeTime(fuzzed_data_provider); |
160 | 0 | addr_man.Attempt(addr, count_failure, time); |
161 | 0 | }, |
162 | 0 | [&] { |
163 | 0 | auto addr = ConsumeService(fuzzed_data_provider); |
164 | 0 | auto time = ConsumeTime(fuzzed_data_provider); |
165 | 0 | addr_man.Connected(addr, time); |
166 | 0 | }, |
167 | 0 | [&] { |
168 | 0 | auto addr = ConsumeService(fuzzed_data_provider); |
169 | 0 | auto n_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS); |
170 | 0 | addr_man.SetServices(addr, n_services); |
171 | 0 | }); |
172 | 0 | } |
173 | 0 | const AddrMan& const_addr_man{addr_man}; |
174 | 0 | std::optional<Network> network; |
175 | 0 | if (fuzzed_data_provider.ConsumeBool()) { Branch (175:9): [True: 0, False: 0]
|
176 | 0 | network = fuzzed_data_provider.PickValueInArray(ALL_NETWORKS); |
177 | 0 | } |
178 | 0 | auto max_addresses = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096); |
179 | 0 | auto max_pct = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 100); |
180 | 0 | auto filtered = fuzzed_data_provider.ConsumeBool(); |
181 | 0 | (void)const_addr_man.GetAddr(max_addresses, max_pct, network, filtered); |
182 | |
|
183 | 0 | std::unordered_set<Network> nets; |
184 | 0 | for (const auto& net : ALL_NETWORKS) { Branch (184:26): [True: 0, False: 0]
|
185 | 0 | if (fuzzed_data_provider.ConsumeBool()) { Branch (185:13): [True: 0, False: 0]
|
186 | 0 | nets.insert(net); |
187 | 0 | } |
188 | 0 | } |
189 | 0 | (void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool(), nets); |
190 | |
|
191 | 0 | std::optional<bool> in_new; |
192 | 0 | if (fuzzed_data_provider.ConsumeBool()) { Branch (192:9): [True: 0, False: 0]
|
193 | 0 | in_new = fuzzed_data_provider.ConsumeBool(); |
194 | 0 | } |
195 | 0 | (void)const_addr_man.Size(network, in_new); |
196 | 0 | DataStream data_stream{}; |
197 | 0 | data_stream << const_addr_man; |
198 | 0 | } |
199 | | |
200 | | // Check that serialize followed by unserialize produces the same addrman. |
201 | | FUZZ_TARGET(addrman_serdeser, .init = initialize_addrman) |
202 | 0 | { |
203 | 0 | SeedRandomStateForTest(SeedRand::ZEROS); |
204 | 0 | FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); |
205 | 0 | NodeClockContext clock_ctx{ConsumeTime(fuzzed_data_provider)}; |
206 | |
|
207 | 0 | NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)}; |
208 | 0 | AddrManDeterministic addr_man1{netgroupman, fuzzed_data_provider, GetCheckRatio()}; |
209 | 0 | AddrManDeterministic addr_man2{netgroupman, fuzzed_data_provider, GetCheckRatio()}; |
210 | |
|
211 | 0 | DataStream data_stream{}; |
212 | |
|
213 | 0 | FillAddrman(addr_man1, fuzzed_data_provider); |
214 | 0 | data_stream << addr_man1; |
215 | 0 | data_stream >> addr_man2; |
216 | | assert(addr_man1 == addr_man2); Branch (216:5): [True: 0, False: 0]
|
217 | 0 | } |