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