aboutsummaryrefslogtreecommitdiff
path: root/src/test/fuzz
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/fuzz')
-rw-r--r--src/test/fuzz/FuzzedDataProvider.h1
-rw-r--r--src/test/fuzz/addrman.cpp140
-rw-r--r--src/test/fuzz/asmap_direct.cpp3
-rw-r--r--src/test/fuzz/autofile.cpp71
-rw-r--r--src/test/fuzz/banman.cpp87
-rw-r--r--src/test/fuzz/bech32.cpp32
-rw-r--r--src/test/fuzz/bloom_filter.cpp80
-rw-r--r--src/test/fuzz/buffered_file.cpp68
-rw-r--r--src/test/fuzz/coins_view.cpp341
-rw-r--r--src/test/fuzz/connman.cpp192
-rw-r--r--src/test/fuzz/crypto.cpp165
-rw-r--r--src/test/fuzz/crypto_chacha20.cpp49
-rw-r--r--src/test/fuzz/crypto_chacha20_poly1305_aead.cpp79
-rw-r--r--src/test/fuzz/cuckoocache.cpp2
-rw-r--r--src/test/fuzz/data_stream.cpp5
-rw-r--r--src/test/fuzz/descriptor_parse.cpp1
-rw-r--r--src/test/fuzz/deserialize.cpp8
-rw-r--r--src/test/fuzz/eval_script.cpp1
-rw-r--r--src/test/fuzz/fuzz.cpp20
-rw-r--r--src/test/fuzz/fuzz.h39
-rw-r--r--src/test/fuzz/i2p.cpp57
-rw-r--r--src/test/fuzz/integer.cpp6
-rw-r--r--src/test/fuzz/key.cpp1
-rw-r--r--src/test/fuzz/kitchen_sink.cpp10
-rw-r--r--src/test/fuzz/load_external_block_file.cpp6
-rw-r--r--src/test/fuzz/merkleblock.cpp50
-rw-r--r--src/test/fuzz/muhash.cpp63
-rw-r--r--src/test/fuzz/net.cpp158
-rw-r--r--src/test/fuzz/net_permissions.cpp13
-rw-r--r--src/test/fuzz/netaddress.cpp3
-rw-r--r--src/test/fuzz/netbase_dns_lookup.cpp71
-rw-r--r--src/test/fuzz/node_eviction.cpp26
-rw-r--r--src/test/fuzz/p2p_transport_deserializer.cpp3
-rw-r--r--src/test/fuzz/parse_numbers.cpp6
-rw-r--r--src/test/fuzz/parse_univalue.cpp1
-rw-r--r--src/test/fuzz/policy_estimator.cpp77
-rw-r--r--src/test/fuzz/policy_estimator_io.cpp5
-rw-r--r--src/test/fuzz/pow.cpp15
-rw-r--r--src/test/fuzz/process_message.cpp119
-rw-r--r--src/test/fuzz/process_messages.cpp42
-rw-r--r--src/test/fuzz/psbt.cpp28
-rw-r--r--src/test/fuzz/rolling_bloom_filter.cpp48
-rw-r--r--src/test/fuzz/rpc.cpp378
-rw-r--r--src/test/fuzz/script.cpp13
-rw-r--r--src/test/fuzz/script_assets_test_minimizer.cpp14
-rw-r--r--src/test/fuzz/script_descriptor_cache.cpp2
-rw-r--r--src/test/fuzz/script_flags.cpp18
-rw-r--r--src/test/fuzz/script_ops.cpp101
-rw-r--r--src/test/fuzz/scriptnum_ops.cpp194
-rw-r--r--src/test/fuzz/signature_checker.cpp20
-rw-r--r--src/test/fuzz/signet.cpp5
-rw-r--r--src/test/fuzz/socks5.cpp45
-rw-r--r--src/test/fuzz/string.cpp8
-rw-r--r--src/test/fuzz/strprintf.cpp123
-rw-r--r--src/test/fuzz/system.cpp120
-rw-r--r--src/test/fuzz/torcontrol.cpp80
-rw-r--r--src/test/fuzz/transaction.cpp17
-rw-r--r--src/test/fuzz/tx_pool.cpp285
-rw-r--r--src/test/fuzz/util.cpp292
-rw-r--r--src/test/fuzz/util.h330
-rw-r--r--src/test/fuzz/validation_load_mempool.cpp34
-rw-r--r--src/test/fuzz/versionbits.cpp350
62 files changed, 3128 insertions, 1493 deletions
diff --git a/src/test/fuzz/FuzzedDataProvider.h b/src/test/fuzz/FuzzedDataProvider.h
index 744a9d78ce..6cbfc39bc2 100644
--- a/src/test/fuzz/FuzzedDataProvider.h
+++ b/src/test/fuzz/FuzzedDataProvider.h
@@ -20,6 +20,7 @@
#include <cstdint>
#include <cstring>
#include <initializer_list>
+#include <limits>
#include <string>
#include <type_traits>
#include <utility>
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index af9080b5e9..0baf30aef6 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -45,83 +45,71 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
}
}
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 11)) {
- case 0: {
- addr_man.Clear();
- break;
- }
- case 1: {
- addr_man.ResolveCollisions();
- break;
- }
- case 2: {
- (void)addr_man.SelectTriedCollision();
- break;
- }
- case 3: {
- (void)addr_man.Select(fuzzed_data_provider.ConsumeBool());
- break;
- }
- case 4: {
- (void)addr_man.GetAddr(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- break;
- }
- case 5: {
- const std::optional<CAddress> opt_address = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider);
- if (opt_address && opt_net_addr) {
- addr_man.Add(*opt_address, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000));
- }
- break;
- }
- case 6: {
- std::vector<CAddress> addresses;
- while (fuzzed_data_provider.ConsumeBool()) {
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ addr_man.Clear();
+ },
+ [&] {
+ addr_man.ResolveCollisions();
+ },
+ [&] {
+ (void)addr_man.SelectTriedCollision();
+ },
+ [&] {
+ (void)addr_man.Select(fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ (void)addr_man.GetAddr(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ },
+ [&] {
const std::optional<CAddress> opt_address = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- if (!opt_address) {
- break;
+ const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider);
+ if (opt_address && opt_net_addr) {
+ addr_man.Add(*opt_address, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000));
}
- addresses.push_back(*opt_address);
- }
- const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider);
- if (opt_net_addr) {
- addr_man.Add(addresses, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000));
- }
- break;
- }
- case 7: {
- const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (opt_service) {
- addr_man.Good(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider));
- }
- break;
- }
- case 8: {
- const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (opt_service) {
- addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider));
- }
- break;
- }
- case 9: {
- const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (opt_service) {
- addr_man.Connected(*opt_service, ConsumeTime(fuzzed_data_provider));
- }
- break;
- }
- case 10: {
- const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (opt_service) {
- addr_man.SetServices(*opt_service, ServiceFlags{fuzzed_data_provider.ConsumeIntegral<uint64_t>()});
- }
- break;
- }
- case 11: {
- (void)addr_man.Check();
- break;
- }
- }
+ },
+ [&] {
+ std::vector<CAddress> addresses;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ const std::optional<CAddress> opt_address = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
+ if (!opt_address) {
+ break;
+ }
+ addresses.push_back(*opt_address);
+ }
+ const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider);
+ if (opt_net_addr) {
+ addr_man.Add(addresses, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000));
+ }
+ },
+ [&] {
+ const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
+ if (opt_service) {
+ addr_man.Good(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider));
+ }
+ },
+ [&] {
+ const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
+ if (opt_service) {
+ addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider));
+ }
+ },
+ [&] {
+ const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
+ if (opt_service) {
+ addr_man.Connected(*opt_service, ConsumeTime(fuzzed_data_provider));
+ }
+ },
+ [&] {
+ const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
+ if (opt_service) {
+ addr_man.SetServices(*opt_service, ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS));
+ }
+ },
+ [&] {
+ (void)addr_man.Check();
+ });
}
(void)addr_man.size();
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION);
diff --git a/src/test/fuzz/asmap_direct.cpp b/src/test/fuzz/asmap_direct.cpp
index 8b7822dc16..8ca4de3919 100644
--- a/src/test/fuzz/asmap_direct.cpp
+++ b/src/test/fuzz/asmap_direct.cpp
@@ -2,8 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <test/fuzz/fuzz.h>
+#include <netaddress.h>
#include <util/asmap.h>
+#include <test/fuzz/fuzz.h>
#include <cstdint>
#include <optional>
diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp
index eb3424ef28..479342e4be 100644
--- a/src/test/fuzz/autofile.cpp
+++ b/src/test/fuzz/autofile.cpp
@@ -1,8 +1,7 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <optional.h>
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -21,43 +20,37 @@ FUZZ_TARGET(autofile)
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
CAutoFile auto_file = fuzzed_auto_file_provider.open();
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
- case 0: {
- std::array<uint8_t, 4096> arr{};
- try {
- auto_file.read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- } catch (const std::ios_base::failure&) {
- }
- break;
- }
- case 1: {
- const std::array<uint8_t, 4096> arr{};
- try {
- auto_file.write((const char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- } catch (const std::ios_base::failure&) {
- }
- break;
- }
- case 2: {
- try {
- auto_file.ignore(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- } catch (const std::ios_base::failure&) {
- }
- break;
- }
- case 3: {
- auto_file.fclose();
- break;
- }
- case 4: {
- ReadFromStream(fuzzed_data_provider, auto_file);
- break;
- }
- case 5: {
- WriteToStream(fuzzed_data_provider, auto_file);
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ std::array<uint8_t, 4096> arr{};
+ try {
+ auto_file.read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ } catch (const std::ios_base::failure&) {
+ }
+ },
+ [&] {
+ const std::array<uint8_t, 4096> arr{};
+ try {
+ auto_file.write((const char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ } catch (const std::ios_base::failure&) {
+ }
+ },
+ [&] {
+ try {
+ auto_file.ignore(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ } catch (const std::ios_base::failure&) {
+ }
+ },
+ [&] {
+ auto_file.fclose();
+ },
+ [&] {
+ ReadFromStream(fuzzed_data_provider, auto_file);
+ },
+ [&] {
+ WriteToStream(fuzzed_data_provider, auto_file);
+ });
}
(void)auto_file.Get();
(void)auto_file.GetType();
diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
index cf69fa0722..8bf484722c 100644
--- a/src/test/fuzz/banman.cpp
+++ b/src/test/fuzz/banman.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,6 +8,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
#include <util/system.h>
#include <cstdint>
@@ -26,7 +27,7 @@ int64_t ConsumeBanTimeOffset(FuzzedDataProvider& fuzzed_data_provider) noexcept
void initialize_banman()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(banman, initialize_banman)
@@ -38,51 +39,43 @@ FUZZ_TARGET_INIT(banman, initialize_banman)
{
BanMan ban_man{banlist_file, nullptr, ConsumeBanTimeOffset(fuzzed_data_provider)};
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 11)) {
- case 0: {
- ban_man.Ban(ConsumeNetAddr(fuzzed_data_provider),
- ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
- break;
- }
- case 1: {
- ban_man.Ban(ConsumeSubNet(fuzzed_data_provider),
- ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
- break;
- }
- case 2: {
- ban_man.ClearBanned();
- break;
- }
- case 4: {
- ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider));
- break;
- }
- case 5: {
- ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider));
- break;
- }
- case 6: {
- ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider));
- break;
- }
- case 7: {
- ban_man.Unban(ConsumeSubNet(fuzzed_data_provider));
- break;
- }
- case 8: {
- banmap_t banmap;
- ban_man.GetBanned(banmap);
- break;
- }
- case 9: {
- ban_man.DumpBanlist();
- break;
- }
- case 11: {
- ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider));
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ ban_man.Ban(ConsumeNetAddr(fuzzed_data_provider),
+ ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ ban_man.Ban(ConsumeSubNet(fuzzed_data_provider),
+ ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ ban_man.ClearBanned();
+ },
+ [] {},
+ [&] {
+ ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider));
+ },
+ [&] {
+ ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider));
+ },
+ [&] {
+ ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider));
+ },
+ [&] {
+ ban_man.Unban(ConsumeSubNet(fuzzed_data_provider));
+ },
+ [&] {
+ banmap_t banmap;
+ ban_man.GetBanned(banmap);
+ },
+ [&] {
+ ban_man.DumpBanlist();
+ },
+ [] {},
+ [&] {
+ ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider));
+ });
}
}
fs::remove(banlist_file);
diff --git a/src/test/fuzz/bech32.cpp b/src/test/fuzz/bech32.cpp
index 95cd4b413f..ad3bf73af4 100644
--- a/src/test/fuzz/bech32.cpp
+++ b/src/test/fuzz/bech32.cpp
@@ -16,28 +16,28 @@
FUZZ_TARGET(bech32)
{
const std::string random_string(buffer.begin(), buffer.end());
- const std::pair<std::string, std::vector<uint8_t>> r1 = bech32::Decode(random_string);
- if (r1.first.empty()) {
- assert(r1.second.empty());
+ const auto r1 = bech32::Decode(random_string);
+ if (r1.hrp.empty()) {
+ assert(r1.encoding == bech32::Encoding::INVALID);
+ assert(r1.data.empty());
} else {
- const std::string& hrp = r1.first;
- const std::vector<uint8_t>& data = r1.second;
- const std::string reencoded = bech32::Encode(hrp, data);
+ assert(r1.encoding != bech32::Encoding::INVALID);
+ const std::string reencoded = bech32::Encode(r1.encoding, r1.hrp, r1.data);
assert(CaseInsensitiveEqual(random_string, reencoded));
}
std::vector<unsigned char> input;
ConvertBits<8, 5, true>([&](unsigned char c) { input.push_back(c); }, buffer.begin(), buffer.end());
- const std::string encoded = bech32::Encode("bc", input);
- assert(!encoded.empty());
- const std::pair<std::string, std::vector<uint8_t>> r2 = bech32::Decode(encoded);
- if (r2.first.empty()) {
- assert(r2.second.empty());
- } else {
- const std::string& hrp = r2.first;
- const std::vector<uint8_t>& data = r2.second;
- assert(hrp == "bc");
- assert(data == input);
+ if (input.size() + 3 + 6 <= 90) {
+ // If it's possible to encode input in Bech32(m) without exceeding the 90-character limit:
+ for (auto encoding : {bech32::Encoding::BECH32, bech32::Encoding::BECH32M}) {
+ const std::string encoded = bech32::Encode(encoding, "bc", input);
+ assert(!encoded.empty());
+ const auto r2 = bech32::Decode(encoded);
+ assert(r2.encoding == encoding);
+ assert(r2.hrp == "bc");
+ assert(r2.data == input);
+ }
}
}
diff --git a/src/test/fuzz/bloom_filter.cpp b/src/test/fuzz/bloom_filter.cpp
index c0c66c564b..c5bb8744a4 100644
--- a/src/test/fuzz/bloom_filter.cpp
+++ b/src/test/fuzz/bloom_filter.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -25,47 +25,43 @@ FUZZ_TARGET(bloom_filter)
fuzzed_data_provider.ConsumeIntegral<unsigned int>(),
static_cast<unsigned char>(fuzzed_data_provider.PickValueInArray({BLOOM_UPDATE_NONE, BLOOM_UPDATE_ALL, BLOOM_UPDATE_P2PUBKEY_ONLY, BLOOM_UPDATE_MASK}))};
while (fuzzed_data_provider.remaining_bytes() > 0) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 3)) {
- case 0: {
- const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- (void)bloom_filter.contains(b);
- bloom_filter.insert(b);
- const bool present = bloom_filter.contains(b);
- assert(present);
- break;
- }
- case 1: {
- const std::optional<COutPoint> out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
- if (!out_point) {
- break;
- }
- (void)bloom_filter.contains(*out_point);
- bloom_filter.insert(*out_point);
- const bool present = bloom_filter.contains(*out_point);
- assert(present);
- break;
- }
- case 2: {
- const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
- if (!u256) {
- break;
- }
- (void)bloom_filter.contains(*u256);
- bloom_filter.insert(*u256);
- const bool present = bloom_filter.contains(*u256);
- assert(present);
- break;
- }
- case 3: {
- const std::optional<CMutableTransaction> mut_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
- if (!mut_tx) {
- break;
- }
- const CTransaction tx{*mut_tx};
- (void)bloom_filter.IsRelevantAndUpdate(tx);
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ (void)bloom_filter.contains(b);
+ bloom_filter.insert(b);
+ const bool present = bloom_filter.contains(b);
+ assert(present);
+ },
+ [&] {
+ const std::optional<COutPoint> out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
+ if (!out_point) {
+ return;
+ }
+ (void)bloom_filter.contains(*out_point);
+ bloom_filter.insert(*out_point);
+ const bool present = bloom_filter.contains(*out_point);
+ assert(present);
+ },
+ [&] {
+ const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
+ if (!u256) {
+ return;
+ }
+ (void)bloom_filter.contains(*u256);
+ bloom_filter.insert(*u256);
+ const bool present = bloom_filter.contains(*u256);
+ assert(present);
+ },
+ [&] {
+ const std::optional<CMutableTransaction> mut_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ if (!mut_tx) {
+ return;
+ }
+ const CTransaction tx{*mut_tx};
+ (void)bloom_filter.IsRelevantAndUpdate(tx);
+ });
(void)bloom_filter.IsWithinSizeConstraints();
}
}
diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp
index 23e197456a..ed72260d10 100644
--- a/src/test/fuzz/buffered_file.cpp
+++ b/src/test/fuzz/buffered_file.cpp
@@ -1,8 +1,7 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <optional.h>
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -31,41 +30,36 @@ FUZZ_TARGET(buffered_file)
if (opt_buffered_file && fuzzed_file != nullptr) {
bool setpos_fail = false;
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 4)) {
- case 0: {
- std::array<uint8_t, 4096> arr{};
- try {
- opt_buffered_file->read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- } catch (const std::ios_base::failure&) {
- }
- break;
- }
- case 1: {
- opt_buffered_file->SetLimit(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096));
- break;
- }
- case 2: {
- if (!opt_buffered_file->SetPos(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096))) {
- setpos_fail = true;
- }
- break;
- }
- case 3: {
- if (setpos_fail) {
- // Calling FindByte(...) after a failed SetPos(...) call may result in an infinite loop.
- break;
- }
- try {
- opt_buffered_file->FindByte(fuzzed_data_provider.ConsumeIntegral<char>());
- } catch (const std::ios_base::failure&) {
- }
- break;
- }
- case 4: {
- ReadFromStream(fuzzed_data_provider, *opt_buffered_file);
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ std::array<uint8_t, 4096> arr{};
+ try {
+ opt_buffered_file->read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ } catch (const std::ios_base::failure&) {
+ }
+ },
+ [&] {
+ opt_buffered_file->SetLimit(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096));
+ },
+ [&] {
+ if (!opt_buffered_file->SetPos(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096))) {
+ setpos_fail = true;
+ }
+ },
+ [&] {
+ if (setpos_fail) {
+ // Calling FindByte(...) after a failed SetPos(...) call may result in an infinite loop.
+ return;
+ }
+ try {
+ opt_buffered_file->FindByte(fuzzed_data_provider.ConsumeIntegral<char>());
+ } catch (const std::ios_base::failure&) {
+ }
+ },
+ [&] {
+ ReadFromStream(fuzzed_data_provider, *opt_buffered_file);
+ });
}
opt_buffered_file->GetPos();
opt_buffered_file->GetType();
diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp
index 1ae421493e..b21d2eae79 100644
--- a/src/test/fuzz/coins_view.cpp
+++ b/src/test/fuzz/coins_view.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -16,6 +16,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
#include <validation.h>
#include <cstdint>
@@ -36,9 +37,7 @@ bool operator==(const Coin& a, const Coin& b)
void initialize_coins_view()
{
- static const ECCVerifyHandle ecc_verify_handle;
- ECC_Start();
- SelectParams(CBaseChainParams::REGTEST);
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
}
FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
@@ -50,103 +49,93 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
Coin random_coin;
CMutableTransaction random_mutable_transaction;
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 9)) {
- case 0: {
- if (random_coin.IsSpent()) {
- break;
- }
- Coin coin = random_coin;
- bool expected_code_path = false;
- const bool possible_overwrite = fuzzed_data_provider.ConsumeBool();
- try {
- coins_view_cache.AddCoin(random_out_point, std::move(coin), possible_overwrite);
- expected_code_path = true;
- } catch (const std::logic_error& e) {
- if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) {
- assert(!possible_overwrite);
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ if (random_coin.IsSpent()) {
+ return;
+ }
+ Coin coin = random_coin;
+ bool expected_code_path = false;
+ const bool possible_overwrite = fuzzed_data_provider.ConsumeBool();
+ try {
+ coins_view_cache.AddCoin(random_out_point, std::move(coin), possible_overwrite);
expected_code_path = true;
+ } catch (const std::logic_error& e) {
+ if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) {
+ assert(!possible_overwrite);
+ expected_code_path = true;
+ }
}
- }
- assert(expected_code_path);
- break;
- }
- case 1: {
- (void)coins_view_cache.Flush();
- break;
- }
- case 2: {
- coins_view_cache.SetBestBlock(ConsumeUInt256(fuzzed_data_provider));
- break;
- }
- case 3: {
- Coin move_to;
- (void)coins_view_cache.SpendCoin(random_out_point, fuzzed_data_provider.ConsumeBool() ? &move_to : nullptr);
- break;
- }
- case 4: {
- coins_view_cache.Uncache(random_out_point);
- break;
- }
- case 5: {
- if (fuzzed_data_provider.ConsumeBool()) {
- backend_coins_view = CCoinsView{};
- }
- coins_view_cache.SetBackend(backend_coins_view);
- break;
- }
- case 6: {
- const std::optional<COutPoint> opt_out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
- if (!opt_out_point) {
- break;
- }
- random_out_point = *opt_out_point;
- break;
- }
- case 7: {
- const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider);
- if (!opt_coin) {
- break;
- }
- random_coin = *opt_coin;
- break;
- }
- case 8: {
- const std::optional<CMutableTransaction> opt_mutable_transaction = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
- if (!opt_mutable_transaction) {
- break;
- }
- random_mutable_transaction = *opt_mutable_transaction;
- break;
- }
- case 9: {
- CCoinsMap coins_map;
- while (fuzzed_data_provider.ConsumeBool()) {
- CCoinsCacheEntry coins_cache_entry;
- coins_cache_entry.flags = fuzzed_data_provider.ConsumeIntegral<unsigned char>();
+ assert(expected_code_path);
+ },
+ [&] {
+ (void)coins_view_cache.Flush();
+ },
+ [&] {
+ coins_view_cache.SetBestBlock(ConsumeUInt256(fuzzed_data_provider));
+ },
+ [&] {
+ Coin move_to;
+ (void)coins_view_cache.SpendCoin(random_out_point, fuzzed_data_provider.ConsumeBool() ? &move_to : nullptr);
+ },
+ [&] {
+ coins_view_cache.Uncache(random_out_point);
+ },
+ [&] {
if (fuzzed_data_provider.ConsumeBool()) {
- coins_cache_entry.coin = random_coin;
- } else {
- const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider);
- if (!opt_coin) {
- break;
+ backend_coins_view = CCoinsView{};
+ }
+ coins_view_cache.SetBackend(backend_coins_view);
+ },
+ [&] {
+ const std::optional<COutPoint> opt_out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
+ if (!opt_out_point) {
+ return;
+ }
+ random_out_point = *opt_out_point;
+ },
+ [&] {
+ const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider);
+ if (!opt_coin) {
+ return;
+ }
+ random_coin = *opt_coin;
+ },
+ [&] {
+ const std::optional<CMutableTransaction> opt_mutable_transaction = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ if (!opt_mutable_transaction) {
+ return;
+ }
+ random_mutable_transaction = *opt_mutable_transaction;
+ },
+ [&] {
+ CCoinsMap coins_map;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ CCoinsCacheEntry coins_cache_entry;
+ coins_cache_entry.flags = fuzzed_data_provider.ConsumeIntegral<unsigned char>();
+ if (fuzzed_data_provider.ConsumeBool()) {
+ coins_cache_entry.coin = random_coin;
+ } else {
+ const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider);
+ if (!opt_coin) {
+ return;
+ }
+ coins_cache_entry.coin = *opt_coin;
}
- coins_cache_entry.coin = *opt_coin;
+ coins_map.emplace(random_out_point, std::move(coins_cache_entry));
}
- coins_map.emplace(random_out_point, std::move(coins_cache_entry));
- }
- bool expected_code_path = false;
- try {
- coins_view_cache.BatchWrite(coins_map, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock());
- expected_code_path = true;
- } catch (const std::logic_error& e) {
- if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) {
+ bool expected_code_path = false;
+ try {
+ coins_view_cache.BatchWrite(coins_map, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock());
expected_code_path = true;
+ } catch (const std::logic_error& e) {
+ if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) {
+ expected_code_path = true;
+ }
}
- }
- assert(expected_code_path);
- break;
- }
- }
+ assert(expected_code_path);
+ });
}
{
@@ -199,97 +188,87 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
}
if (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 6)) {
- case 0: {
- const CTransaction transaction{random_mutable_transaction};
- bool is_spent = false;
- for (const CTxOut& tx_out : transaction.vout) {
- if (Coin{tx_out, 0, transaction.IsCoinBase()}.IsSpent()) {
- is_spent = true;
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ const CTransaction transaction{random_mutable_transaction};
+ bool is_spent = false;
+ for (const CTxOut& tx_out : transaction.vout) {
+ if (Coin{tx_out, 0, transaction.IsCoinBase()}.IsSpent()) {
+ is_spent = true;
+ }
+ }
+ if (is_spent) {
+ // Avoid:
+ // coins.cpp:69: void CCoinsViewCache::AddCoin(const COutPoint &, Coin &&, bool): Assertion `!coin.IsSpent()' failed.
+ return;
}
- }
- if (is_spent) {
- // Avoid:
- // coins.cpp:69: void CCoinsViewCache::AddCoin(const COutPoint &, Coin &&, bool): Assertion `!coin.IsSpent()' failed.
- break;
- }
- bool expected_code_path = false;
- const int height = fuzzed_data_provider.ConsumeIntegral<int>();
- const bool possible_overwrite = fuzzed_data_provider.ConsumeBool();
- try {
- AddCoins(coins_view_cache, transaction, height, possible_overwrite);
- expected_code_path = true;
- } catch (const std::logic_error& e) {
- if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) {
- assert(!possible_overwrite);
+ bool expected_code_path = false;
+ const int height = fuzzed_data_provider.ConsumeIntegral<int>();
+ const bool possible_overwrite = fuzzed_data_provider.ConsumeBool();
+ try {
+ AddCoins(coins_view_cache, transaction, height, possible_overwrite);
expected_code_path = true;
+ } catch (const std::logic_error& e) {
+ if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) {
+ assert(!possible_overwrite);
+ expected_code_path = true;
+ }
+ }
+ assert(expected_code_path);
+ },
+ [&] {
+ (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, false);
+ (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, true);
+ },
+ [&] {
+ TxValidationState state;
+ CAmount tx_fee_out;
+ const CTransaction transaction{random_mutable_transaction};
+ if (ContainsSpentInput(transaction, coins_view_cache)) {
+ // Avoid:
+ // consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, TxValidationState &, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed.
+ return;
}
- }
- assert(expected_code_path);
- break;
- }
- case 1: {
- (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, false);
- (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, true);
- break;
- }
- case 2: {
- TxValidationState state;
- CAmount tx_fee_out;
- const CTransaction transaction{random_mutable_transaction};
- if (ContainsSpentInput(transaction, coins_view_cache)) {
- // Avoid:
- // consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, TxValidationState &, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed.
- break;
- }
- try {
(void)Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()), tx_fee_out);
assert(MoneyRange(tx_fee_out));
- } catch (const std::runtime_error&) {
- }
- break;
- }
- case 3: {
- const CTransaction transaction{random_mutable_transaction};
- if (ContainsSpentInput(transaction, coins_view_cache)) {
- // Avoid:
- // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
- break;
- }
- (void)GetP2SHSigOpCount(transaction, coins_view_cache);
- break;
- }
- case 4: {
- const CTransaction transaction{random_mutable_transaction};
- if (ContainsSpentInput(transaction, coins_view_cache)) {
- // Avoid:
- // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
- break;
- }
- const int flags = fuzzed_data_provider.ConsumeIntegral<int>();
- if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
- // Avoid:
- // script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed.
- break;
- }
- (void)GetTransactionSigOpCost(transaction, coins_view_cache, flags);
- break;
- }
- case 5: {
- CCoinsStats stats;
- bool expected_code_path = false;
- try {
- (void)GetUTXOStats(&coins_view_cache, stats, CoinStatsHashType::HASH_SERIALIZED);
- } catch (const std::logic_error&) {
- expected_code_path = true;
- }
- assert(expected_code_path);
- break;
- }
- case 6: {
- (void)IsWitnessStandard(CTransaction{random_mutable_transaction}, coins_view_cache);
- break;
- }
- }
+ },
+ [&] {
+ const CTransaction transaction{random_mutable_transaction};
+ if (ContainsSpentInput(transaction, coins_view_cache)) {
+ // Avoid:
+ // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
+ return;
+ }
+ (void)GetP2SHSigOpCount(transaction, coins_view_cache);
+ },
+ [&] {
+ const CTransaction transaction{random_mutable_transaction};
+ if (ContainsSpentInput(transaction, coins_view_cache)) {
+ // Avoid:
+ // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
+ return;
+ }
+ const int flags = fuzzed_data_provider.ConsumeIntegral<int>();
+ if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
+ // Avoid:
+ // script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed.
+ return;
+ }
+ (void)GetTransactionSigOpCost(transaction, coins_view_cache, flags);
+ },
+ [&] {
+ CCoinsStats stats;
+ bool expected_code_path = false;
+ try {
+ (void)GetUTXOStats(&coins_view_cache, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)), stats, CoinStatsHashType::HASH_SERIALIZED);
+ } catch (const std::logic_error&) {
+ expected_code_path = true;
+ }
+ assert(expected_code_path);
+ },
+ [&] {
+ (void)IsWitnessStandard(CTransaction{random_mutable_transaction}, coins_view_cache);
+ });
}
}
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index 7621751077..e07f25dedf 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,6 +10,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
#include <util/translation.h>
#include <cstdint>
@@ -17,123 +18,100 @@
void initialize_connman()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(connman, initialize_connman)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
SetMockTime(ConsumeTime(fuzzed_data_provider));
- CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeBool()};
- CAddress random_address;
+ CAddrMan addrman;
+ CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman, fuzzed_data_provider.ConsumeBool()};
CNetAddr random_netaddr;
CNode random_node = ConsumeNode(fuzzed_data_provider);
- CService random_service;
CSubNet random_subnet;
std::string random_string;
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 27)) {
- case 0:
- random_address = ConsumeAddress(fuzzed_data_provider);
- break;
- case 1:
- random_netaddr = ConsumeNetAddr(fuzzed_data_provider);
- break;
- case 2:
- random_service = ConsumeService(fuzzed_data_provider);
- break;
- case 3:
- random_subnet = ConsumeSubNet(fuzzed_data_provider);
- break;
- case 4:
- random_string = fuzzed_data_provider.ConsumeRandomLengthString(64);
- break;
- case 5: {
- std::vector<CAddress> addresses;
- while (fuzzed_data_provider.ConsumeBool()) {
- addresses.push_back(ConsumeAddress(fuzzed_data_provider));
- }
- // Limit nTimePenalty to int32_t to avoid signed integer overflow
- (void)connman.AddNewAddresses(addresses, ConsumeAddress(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int32_t>());
- break;
- }
- case 6:
- connman.AddNode(random_string);
- break;
- case 7:
- connman.CheckIncomingNonce(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- break;
- case 8:
- connman.DisconnectNode(fuzzed_data_provider.ConsumeIntegral<NodeId>());
- break;
- case 9:
- connman.DisconnectNode(random_netaddr);
- break;
- case 10:
- connman.DisconnectNode(random_string);
- break;
- case 11:
- connman.DisconnectNode(random_subnet);
- break;
- case 12:
- connman.ForEachNode([](auto) {});
- break;
- case 13:
- connman.ForEachNodeThen([](auto) {}, []() {});
- break;
- case 14:
- (void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral<NodeId>(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); });
- break;
- case 15:
- (void)connman.GetAddresses(fuzzed_data_provider.ConsumeIntegral<size_t>(), fuzzed_data_provider.ConsumeIntegral<size_t>());
- break;
- case 16: {
- (void)connman.GetAddresses(random_node, fuzzed_data_provider.ConsumeIntegral<size_t>(), fuzzed_data_provider.ConsumeIntegral<size_t>());
- break;
- }
- case 17:
- (void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- break;
- case 18:
- (void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({CConnman::CONNECTIONS_NONE, CConnman::CONNECTIONS_IN, CConnman::CONNECTIONS_OUT, CConnman::CONNECTIONS_ALL}));
- break;
- case 19:
- connman.MarkAddressGood(random_address);
- break;
- case 20:
- (void)connman.OutboundTargetReached(fuzzed_data_provider.ConsumeBool());
- break;
- case 21:
- // Limit now to int32_t to avoid signed integer overflow
- (void)connman.PoissonNextSendInbound(fuzzed_data_provider.ConsumeIntegral<int32_t>(), fuzzed_data_provider.ConsumeIntegral<int>());
- break;
- case 22: {
- CSerializedNetMsg serialized_net_msg;
- serialized_net_msg.m_type = fuzzed_data_provider.ConsumeRandomLengthString(CMessageHeader::COMMAND_SIZE);
- serialized_net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- connman.PushMessage(&random_node, std::move(serialized_net_msg));
- break;
- }
- case 23:
- connman.RemoveAddedNode(random_string);
- break;
- case 24: {
- const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
- if (SanityCheckASMap(asmap)) {
- connman.SetAsmap(asmap);
- }
- break;
- }
- case 25:
- connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool());
- break;
- case 26:
- connman.SetServices(random_service, static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>()));
- break;
- case 27:
- connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool());
- break;
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ random_netaddr = ConsumeNetAddr(fuzzed_data_provider);
+ },
+ [&] {
+ random_subnet = ConsumeSubNet(fuzzed_data_provider);
+ },
+ [&] {
+ random_string = fuzzed_data_provider.ConsumeRandomLengthString(64);
+ },
+ [&] {
+ connman.AddNode(random_string);
+ },
+ [&] {
+ connman.CheckIncomingNonce(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ },
+ [&] {
+ connman.DisconnectNode(fuzzed_data_provider.ConsumeIntegral<NodeId>());
+ },
+ [&] {
+ connman.DisconnectNode(random_netaddr);
+ },
+ [&] {
+ connman.DisconnectNode(random_string);
+ },
+ [&] {
+ connman.DisconnectNode(random_subnet);
+ },
+ [&] {
+ connman.ForEachNode([](auto) {});
+ },
+ [&] {
+ connman.ForEachNodeThen([](auto) {}, []() {});
+ },
+ [&] {
+ (void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral<NodeId>(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); });
+ },
+ [&] {
+ (void)connman.GetAddresses(fuzzed_data_provider.ConsumeIntegral<size_t>(), fuzzed_data_provider.ConsumeIntegral<size_t>());
+ },
+ [&] {
+ (void)connman.GetAddresses(random_node, fuzzed_data_provider.ConsumeIntegral<size_t>(), fuzzed_data_provider.ConsumeIntegral<size_t>());
+ },
+ [&] {
+ (void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ },
+ [&] {
+ (void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({ConnectionDirection::None, ConnectionDirection::In, ConnectionDirection::Out, ConnectionDirection::Both}));
+ },
+ [&] {
+ (void)connman.OutboundTargetReached(fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ // Limit now to int32_t to avoid signed integer overflow
+ (void)connman.PoissonNextSendInbound(
+ std::chrono::microseconds{fuzzed_data_provider.ConsumeIntegral<int32_t>()},
+ std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<int>()});
+ },
+ [&] {
+ CSerializedNetMsg serialized_net_msg;
+ serialized_net_msg.m_type = fuzzed_data_provider.ConsumeRandomLengthString(CMessageHeader::COMMAND_SIZE);
+ serialized_net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ connman.PushMessage(&random_node, std::move(serialized_net_msg));
+ },
+ [&] {
+ connman.RemoveAddedNode(random_string);
+ },
+ [&] {
+ const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
+ if (SanityCheckASMap(asmap)) {
+ connman.SetAsmap(asmap);
+ }
+ },
+ [&] {
+ connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool());
+ });
}
(void)connman.GetAddedNodeInfo();
(void)connman.GetExtraFullOutboundCount();
diff --git a/src/test/fuzz/crypto.cpp b/src/test/fuzz/crypto.cpp
index 4783cc1c43..eeeac18968 100644
--- a/src/test/fuzz/crypto.cpp
+++ b/src/test/fuzz/crypto.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -37,97 +37,84 @@ FUZZ_TARGET(crypto)
CSipHasher sip_hasher{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>()};
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 2)) {
- case 0: {
- if (fuzzed_data_provider.ConsumeBool()) {
- data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- if (data.empty()) {
- data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ if (fuzzed_data_provider.ConsumeBool()) {
+ data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ if (data.empty()) {
+ data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ }
}
- }
- (void)hash160.Write(data);
- (void)hash256.Write(data);
- (void)hmac_sha256.Write(data.data(), data.size());
- (void)hmac_sha512.Write(data.data(), data.size());
- (void)ripemd160.Write(data.data(), data.size());
- (void)sha1.Write(data.data(), data.size());
- (void)sha256.Write(data.data(), data.size());
- (void)sha3.Write(data);
- (void)sha512.Write(data.data(), data.size());
- (void)sip_hasher.Write(data.data(), data.size());
+ (void)hash160.Write(data);
+ (void)hash256.Write(data);
+ (void)hmac_sha256.Write(data.data(), data.size());
+ (void)hmac_sha512.Write(data.data(), data.size());
+ (void)ripemd160.Write(data.data(), data.size());
+ (void)sha1.Write(data.data(), data.size());
+ (void)sha256.Write(data.data(), data.size());
+ (void)sha3.Write(data);
+ (void)sha512.Write(data.data(), data.size());
+ (void)sip_hasher.Write(data.data(), data.size());
- (void)Hash(data);
- (void)Hash160(data);
- (void)sha512.Size();
- break;
- }
- case 1: {
- (void)hash160.Reset();
- (void)hash256.Reset();
- (void)ripemd160.Reset();
- (void)sha1.Reset();
- (void)sha256.Reset();
- (void)sha3.Reset();
- (void)sha512.Reset();
- break;
- }
- case 2: {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 9)) {
- case 0: {
- data.resize(CHash160::OUTPUT_SIZE);
- hash160.Finalize(data);
- break;
- }
- case 1: {
- data.resize(CHash256::OUTPUT_SIZE);
- hash256.Finalize(data);
- break;
- }
- case 2: {
- data.resize(CHMAC_SHA256::OUTPUT_SIZE);
- hmac_sha256.Finalize(data.data());
- break;
- }
- case 3: {
- data.resize(CHMAC_SHA512::OUTPUT_SIZE);
- hmac_sha512.Finalize(data.data());
- break;
- }
- case 4: {
- data.resize(CRIPEMD160::OUTPUT_SIZE);
- ripemd160.Finalize(data.data());
- break;
- }
- case 5: {
- data.resize(CSHA1::OUTPUT_SIZE);
- sha1.Finalize(data.data());
- break;
- }
- case 6: {
- data.resize(CSHA256::OUTPUT_SIZE);
- sha256.Finalize(data.data());
- break;
- }
- case 7: {
- data.resize(CSHA512::OUTPUT_SIZE);
- sha512.Finalize(data.data());
- break;
- }
- case 8: {
- data.resize(1);
- data[0] = sip_hasher.Finalize() % 256;
- break;
- }
- case 9: {
- data.resize(SHA3_256::OUTPUT_SIZE);
- sha3.Finalize(data);
- break;
- }
- }
- break;
- }
- }
+ (void)Hash(data);
+ (void)Hash160(data);
+ (void)sha512.Size();
+ },
+ [&] {
+ (void)hash160.Reset();
+ (void)hash256.Reset();
+ (void)ripemd160.Reset();
+ (void)sha1.Reset();
+ (void)sha256.Reset();
+ (void)sha3.Reset();
+ (void)sha512.Reset();
+ },
+ [&] {
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ data.resize(CHash160::OUTPUT_SIZE);
+ hash160.Finalize(data);
+ },
+ [&] {
+ data.resize(CHash256::OUTPUT_SIZE);
+ hash256.Finalize(data);
+ },
+ [&] {
+ data.resize(CHMAC_SHA256::OUTPUT_SIZE);
+ hmac_sha256.Finalize(data.data());
+ },
+ [&] {
+ data.resize(CHMAC_SHA512::OUTPUT_SIZE);
+ hmac_sha512.Finalize(data.data());
+ },
+ [&] {
+ data.resize(CRIPEMD160::OUTPUT_SIZE);
+ ripemd160.Finalize(data.data());
+ },
+ [&] {
+ data.resize(CSHA1::OUTPUT_SIZE);
+ sha1.Finalize(data.data());
+ },
+ [&] {
+ data.resize(CSHA256::OUTPUT_SIZE);
+ sha256.Finalize(data.data());
+ },
+ [&] {
+ data.resize(CSHA512::OUTPUT_SIZE);
+ sha512.Finalize(data.data());
+ },
+ [&] {
+ data.resize(1);
+ data[0] = sip_hasher.Finalize() % 256;
+ },
+ [&] {
+ data.resize(SHA3_256::OUTPUT_SIZE);
+ sha3.Finalize(data);
+ });
+ });
}
if (fuzzed_data_provider.ConsumeBool()) {
uint64_t state[25];
diff --git a/src/test/fuzz/crypto_chacha20.cpp b/src/test/fuzz/crypto_chacha20.cpp
index d751466f11..8adfa92420 100644
--- a/src/test/fuzz/crypto_chacha20.cpp
+++ b/src/test/fuzz/crypto_chacha20.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -20,31 +20,26 @@ FUZZ_TARGET(crypto_chacha20)
chacha20 = ChaCha20{key.data(), key.size()};
}
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 4)) {
- case 0: {
- const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32));
- chacha20.SetKey(key.data(), key.size());
- break;
- }
- case 1: {
- chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- break;
- }
- case 2: {
- chacha20.Seek(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- break;
- }
- case 3: {
- std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- chacha20.Keystream(output.data(), output.size());
- break;
- }
- case 4: {
- std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- const std::vector<uint8_t> input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size());
- chacha20.Crypt(input.data(), output.data(), input.size());
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32));
+ chacha20.SetKey(key.data(), key.size());
+ },
+ [&] {
+ chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ },
+ [&] {
+ chacha20.Seek(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ },
+ [&] {
+ std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ chacha20.Keystream(output.data(), output.size());
+ },
+ [&] {
+ std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ const std::vector<uint8_t> input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size());
+ chacha20.Crypt(input.data(), output.data(), input.size());
+ });
}
}
diff --git a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
index 631af9c70d..bb4ef22158 100644
--- a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
+++ b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -29,44 +29,43 @@ FUZZ_TARGET(crypto_chacha20_poly1305_aead)
std::vector<uint8_t> out(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
bool is_encrypt = fuzzed_data_provider.ConsumeBool();
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 6)) {
- case 0: {
- buffer_size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(64, 4096);
- in = std::vector<uint8_t>(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
- out = std::vector<uint8_t>(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
- break;
- }
- case 1: {
- (void)aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffer_size, is_encrypt);
- break;
- }
- case 2: {
- uint32_t len = 0;
- const bool ok = aead.GetLength(&len, seqnr_aad, aad_pos, in.data());
- assert(ok);
- break;
- }
- case 3: {
- seqnr_payload += 1;
- aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
- if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
- aad_pos = 0;
- seqnr_aad += 1;
- }
- break;
- }
- case 4: {
- seqnr_payload = fuzzed_data_provider.ConsumeIntegral<int>();
- break;
- }
- case 5: {
- seqnr_aad = fuzzed_data_provider.ConsumeIntegral<int>();
- break;
- }
- case 6: {
- is_encrypt = fuzzed_data_provider.ConsumeBool();
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ buffer_size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(64, 4096);
+ in = std::vector<uint8_t>(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
+ out = std::vector<uint8_t>(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
+ },
+ [&] {
+ (void)aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffer_size, is_encrypt);
+ },
+ [&] {
+ uint32_t len = 0;
+ const bool ok = aead.GetLength(&len, seqnr_aad, aad_pos, in.data());
+ assert(ok);
+ },
+ [&] {
+ if (AdditionOverflow(seqnr_payload, static_cast<uint64_t>(1))) {
+ return;
+ }
+ seqnr_payload += 1;
+ aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
+ if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
+ aad_pos = 0;
+ if (AdditionOverflow(seqnr_aad, static_cast<uint64_t>(1))) {
+ return;
+ }
+ seqnr_aad += 1;
+ }
+ },
+ [&] {
+ seqnr_payload = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
+ },
+ [&] {
+ seqnr_aad = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
+ },
+ [&] {
+ is_encrypt = fuzzed_data_provider.ConsumeBool();
+ });
}
}
diff --git a/src/test/fuzz/cuckoocache.cpp b/src/test/fuzz/cuckoocache.cpp
index dc20dc3f62..a522c837ef 100644
--- a/src/test/fuzz/cuckoocache.cpp
+++ b/src/test/fuzz/cuckoocache.cpp
@@ -30,7 +30,7 @@ FUZZ_TARGET(cuckoocache)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
fuzzed_data_provider_ptr = &fuzzed_data_provider;
- CuckooCache::cache<bool, RandomHasher> cuckoo_cache{};
+ CuckooCache::cache<int, RandomHasher> cuckoo_cache{};
if (fuzzed_data_provider.ConsumeBool()) {
const size_t megabytes = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 16);
cuckoo_cache.setup_bytes(megabytes << 20);
diff --git a/src/test/fuzz/data_stream.cpp b/src/test/fuzz/data_stream.cpp
index 28fc528ceb..473caec6ff 100644
--- a/src/test/fuzz/data_stream.cpp
+++ b/src/test/fuzz/data_stream.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,13 +7,14 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
#include <cstdint>
#include <vector>
void initialize_data_stream_addr_man()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(data_stream_addr_man, initialize_data_stream_addr_man)
diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp
index 0d1921f285..ffe4855662 100644
--- a/src/test/fuzz/descriptor_parse.cpp
+++ b/src/test/fuzz/descriptor_parse.cpp
@@ -6,7 +6,6 @@
#include <pubkey.h>
#include <script/descriptor.h>
#include <test/fuzz/fuzz.h>
-#include <util/memory.h>
void initialize_descriptor_parse()
{
diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp
index 74dec6475e..1290c78712 100644
--- a/src/test/fuzz/deserialize.cpp
+++ b/src/test/fuzz/deserialize.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,7 +15,6 @@
#include <net.h>
#include <netbase.h>
#include <node/utxo_snapshot.h>
-#include <optional.h>
#include <primitives/block.h>
#include <protocol.h>
#include <psbt.h>
@@ -26,12 +25,11 @@
#include <version.h>
#include <exception>
+#include <optional>
#include <stdexcept>
#include <stdint.h>
#include <unistd.h>
-#include <vector>
-
#include <test/fuzz/fuzz.h>
void initialize_deserialize()
@@ -71,7 +69,7 @@ T Deserialize(CDataStream ds)
}
template <typename T>
-void DeserializeFromFuzzingInput(const std::vector<uint8_t>& buffer, T& obj, const Optional<int> protocol_version = nullopt)
+void DeserializeFromFuzzingInput(FuzzBufferType buffer, T& obj, const std::optional<int> protocol_version = std::nullopt)
{
CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
if (protocol_version) {
diff --git a/src/test/fuzz/eval_script.cpp b/src/test/fuzz/eval_script.cpp
index 635288fc36..77ed798923 100644
--- a/src/test/fuzz/eval_script.cpp
+++ b/src/test/fuzz/eval_script.cpp
@@ -6,7 +6,6 @@
#include <script/interpreter.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
-#include <util/memory.h>
#include <limits>
diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp
index fd87667755..1fab46ff13 100644
--- a/src/test/fuzz/fuzz.cpp
+++ b/src/test/fuzz/fuzz.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,15 +13,15 @@
const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
-std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize>>& FuzzTargets()
+std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>>& FuzzTargets()
{
- static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize>> g_fuzz_targets;
+ static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>> g_fuzz_targets;
return g_fuzz_targets;
}
-void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init)
+void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init, TypeHidden hidden)
{
- const auto it_ins = FuzzTargets().try_emplace(name, std::move(target), std::move(init));
+ const auto it_ins = FuzzTargets().try_emplace(name, std::move(target), std::move(init), hidden);
Assert(it_ins.second);
}
@@ -31,6 +31,7 @@ void initialize()
{
if (std::getenv("PRINT_ALL_FUZZ_TARGETS_AND_ABORT")) {
for (const auto& t : FuzzTargets()) {
+ if (std::get<2>(t.second)) continue;
std::cout << t.first << std::endl;
}
Assert(false);
@@ -43,7 +44,7 @@ void initialize()
std::get<1>(it->second)();
}
-#if defined(PROVIDE_MAIN_FUNCTION)
+#if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
static bool read_stdin(std::vector<uint8_t>& data)
{
uint8_t buffer[1024];
@@ -59,8 +60,7 @@ static bool read_stdin(std::vector<uint8_t>& data)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
static const auto& test_one_input = *Assert(g_test_one_input);
- const std::vector<uint8_t> input(data, data + size);
- test_one_input(input);
+ test_one_input({data, size});
return 0;
}
@@ -71,8 +71,8 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
return 0;
}
-#if defined(PROVIDE_MAIN_FUNCTION)
-__attribute__((weak)) int main(int argc, char** argv)
+#if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
+int main(int argc, char** argv)
{
initialize();
static const auto& test_one_input = *Assert(g_test_one_input);
diff --git a/src/test/fuzz/fuzz.h b/src/test/fuzz/fuzz.h
index 52841e069a..2bad77bdc1 100644
--- a/src/test/fuzz/fuzz.h
+++ b/src/test/fuzz/fuzz.h
@@ -1,33 +1,40 @@
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_TEST_FUZZ_FUZZ_H
#define BITCOIN_TEST_FUZZ_FUZZ_H
+#include <span.h>
+
#include <cstdint>
#include <functional>
#include <string_view>
-#include <vector>
-using TypeTestOneInput = std::function<void(const std::vector<uint8_t>&)>;
+using FuzzBufferType = Span<const uint8_t>;
+
+using TypeTestOneInput = std::function<void(FuzzBufferType)>;
using TypeInitialize = std::function<void()>;
+using TypeHidden = bool;
-void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init);
+void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init, TypeHidden hidden);
-inline void FuzzFrameworkEmptyFun() {}
+inline void FuzzFrameworkEmptyInitFun() {}
#define FUZZ_TARGET(name) \
- FUZZ_TARGET_INIT(name, FuzzFrameworkEmptyFun)
-
-#define FUZZ_TARGET_INIT(name, init_fun) \
- void name##_fuzz_target(const std::vector<uint8_t>&); \
- struct name##_Before_Main { \
- name##_Before_Main() \
- { \
- FuzzFrameworkRegisterTarget(#name, name##_fuzz_target, init_fun); \
- } \
- } const static g_##name##_before_main; \
- void name##_fuzz_target(const std::vector<uint8_t>& buffer)
+ FUZZ_TARGET_INIT(name, FuzzFrameworkEmptyInitFun)
+
+#define FUZZ_TARGET_INIT(name, init_fun) \
+ FUZZ_TARGET_INIT_HIDDEN(name, init_fun, false)
+
+#define FUZZ_TARGET_INIT_HIDDEN(name, init_fun, hidden) \
+ void name##_fuzz_target(FuzzBufferType); \
+ struct name##_Before_Main { \
+ name##_Before_Main() \
+ { \
+ FuzzFrameworkRegisterTarget(#name, name##_fuzz_target, init_fun, hidden); \
+ } \
+ } const static g_##name##_before_main; \
+ void name##_fuzz_target(FuzzBufferType buffer)
#endif // BITCOIN_TEST_FUZZ_FUZZ_H
diff --git a/src/test/fuzz/i2p.cpp b/src/test/fuzz/i2p.cpp
new file mode 100644
index 0000000000..345d68502a
--- /dev/null
+++ b/src/test/fuzz/i2p.cpp
@@ -0,0 +1,57 @@
+// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <i2p.h>
+#include <netaddress.h>
+#include <netbase.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <threadinterrupt.h>
+#include <util/system.h>
+
+void initialize_i2p()
+{
+ static const auto testing_setup = MakeNoLogFileContext<>();
+}
+
+FUZZ_TARGET_INIT(i2p, initialize_i2p)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+
+ // Mock CreateSock() to create FuzzedSock.
+ auto CreateSockOrig = CreateSock;
+ CreateSock = [&fuzzed_data_provider](const CService&) {
+ return std::make_unique<FuzzedSock>(fuzzed_data_provider);
+ };
+
+ const CService sam_proxy;
+ CThreadInterrupt interrupt;
+
+ i2p::sam::Session sess{GetDataDir() / "fuzzed_i2p_private_key", sam_proxy, &interrupt};
+
+ i2p::Connection conn;
+
+ if (sess.Listen(conn)) {
+ if (sess.Accept(conn)) {
+ try {
+ conn.sock->RecvUntilTerminator('\n', 10ms, interrupt, i2p::sam::MAX_MSG_SIZE);
+ } catch (const std::runtime_error&) {
+ }
+ }
+ }
+
+ const CService to;
+ bool proxy_error;
+
+ if (sess.Connect(to, conn, proxy_error)) {
+ try {
+ conn.sock->SendComplete("verack\n", 10ms, interrupt);
+ } catch (const std::runtime_error&) {
+ }
+ }
+
+ CreateSock = CreateSockOrig;
+}
diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp
index ac83d91ea0..5bc99ddcb9 100644
--- a/src/test/fuzz/integer.cpp
+++ b/src/test/fuzz/integer.cpp
@@ -84,8 +84,7 @@ FUZZ_TARGET_INIT(integer, initialize_integer)
(void)DecompressAmount(u64);
(void)FormatISO8601Date(i64);
(void)FormatISO8601DateTime(i64);
- // FormatMoney(i) not defined when i == std::numeric_limits<int64_t>::min()
- if (i64 != std::numeric_limits<int64_t>::min()) {
+ {
int64_t parsed_money;
if (ParseMoney(FormatMoney(i64), parsed_money)) {
assert(parsed_money == i64);
@@ -132,8 +131,7 @@ FUZZ_TARGET_INIT(integer, initialize_integer)
(void)SipHashUint256Extra(u64, u64, u256, u32);
(void)ToLower(ch);
(void)ToUpper(ch);
- // ValueFromAmount(i) not defined when i == std::numeric_limits<int64_t>::min()
- if (i64 != std::numeric_limits<int64_t>::min()) {
+ {
int64_t parsed_money;
if (ParseMoney(ValueFromAmount(i64).getValStr(), parsed_money)) {
assert(parsed_money == i64);
diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp
index aa8f826e4a..32077b1fe2 100644
--- a/src/test/fuzz/key.cpp
+++ b/src/test/fuzz/key.cpp
@@ -17,7 +17,6 @@
#include <script/standard.h>
#include <streams.h>
#include <test/fuzz/fuzz.h>
-#include <util/memory.h>
#include <util/strencodings.h>
#include <cassert>
diff --git a/src/test/fuzz/kitchen_sink.cpp b/src/test/fuzz/kitchen_sink.cpp
index 4dfb2e3da0..908e9a1c83 100644
--- a/src/test/fuzz/kitchen_sink.cpp
+++ b/src/test/fuzz/kitchen_sink.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -28,12 +28,6 @@ constexpr TransactionError ALL_TRANSACTION_ERROR[] = {
TransactionError::SIGHASH_MISMATCH,
TransactionError::MAX_FEE_EXCEEDED,
};
-
-constexpr FeeEstimateHorizon ALL_FEE_EST_HORIZON[] = {
- FeeEstimateHorizon::SHORT_HALFLIFE,
- FeeEstimateHorizon::MED_HALFLIFE,
- FeeEstimateHorizon::LONG_HALFLIFE,
-};
}; // namespace
// The fuzzing kitchen sink: Fuzzing harness for functions that need to be
@@ -48,7 +42,7 @@ FUZZ_TARGET(kitchen_sink)
(void)RPCErrorFromTransactionError(transaction_error);
(void)TransactionErrorString(transaction_error);
- (void)StringForFeeEstimateHorizon(fuzzed_data_provider.PickValueInArray(ALL_FEE_EST_HORIZON));
+ (void)StringForFeeEstimateHorizon(fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS));
const OutputType output_type = fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES);
const std::string& output_type_string = FormatOutputType(output_type);
diff --git a/src/test/fuzz/load_external_block_file.cpp b/src/test/fuzz/load_external_block_file.cpp
index c428a86631..dbd0c76d42 100644
--- a/src/test/fuzz/load_external_block_file.cpp
+++ b/src/test/fuzz/load_external_block_file.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,7 +15,7 @@
void initialize_load_external_block_file()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
}
FUZZ_TARGET_INIT(load_external_block_file, initialize_load_external_block_file)
@@ -27,5 +27,5 @@ FUZZ_TARGET_INIT(load_external_block_file, initialize_load_external_block_file)
return;
}
FlatFilePos flat_file_pos;
- LoadExternalBlockFile(Params(), fuzzed_block_file, fuzzed_data_provider.ConsumeBool() ? &flat_file_pos : nullptr);
+ ::ChainstateActive().LoadExternalBlockFile(Params(), fuzzed_block_file, fuzzed_data_provider.ConsumeBool() ? &flat_file_pos : nullptr);
}
diff --git a/src/test/fuzz/merkleblock.cpp b/src/test/fuzz/merkleblock.cpp
index 15bcfab3ad..1eefd4c521 100644
--- a/src/test/fuzz/merkleblock.cpp
+++ b/src/test/fuzz/merkleblock.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,33 +17,31 @@ FUZZ_TARGET(merkleblock)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
CPartialMerkleTree partial_merkle_tree;
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 1)) {
- case 0: {
- const std::optional<CPartialMerkleTree> opt_partial_merkle_tree = ConsumeDeserializable<CPartialMerkleTree>(fuzzed_data_provider);
- if (opt_partial_merkle_tree) {
- partial_merkle_tree = *opt_partial_merkle_tree;
- }
- break;
- }
- case 1: {
- CMerkleBlock merkle_block;
- const std::optional<CBlock> opt_block = ConsumeDeserializable<CBlock>(fuzzed_data_provider);
- CBloomFilter bloom_filter;
- std::set<uint256> txids;
- if (opt_block && !opt_block->vtx.empty()) {
- if (fuzzed_data_provider.ConsumeBool()) {
- merkle_block = CMerkleBlock{*opt_block, bloom_filter};
- } else if (fuzzed_data_provider.ConsumeBool()) {
- while (fuzzed_data_provider.ConsumeBool()) {
- txids.insert(ConsumeUInt256(fuzzed_data_provider));
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ const std::optional<CPartialMerkleTree> opt_partial_merkle_tree = ConsumeDeserializable<CPartialMerkleTree>(fuzzed_data_provider);
+ if (opt_partial_merkle_tree) {
+ partial_merkle_tree = *opt_partial_merkle_tree;
+ }
+ },
+ [&] {
+ CMerkleBlock merkle_block;
+ const std::optional<CBlock> opt_block = ConsumeDeserializable<CBlock>(fuzzed_data_provider);
+ CBloomFilter bloom_filter;
+ std::set<uint256> txids;
+ if (opt_block && !opt_block->vtx.empty()) {
+ if (fuzzed_data_provider.ConsumeBool()) {
+ merkle_block = CMerkleBlock{*opt_block, bloom_filter};
+ } else if (fuzzed_data_provider.ConsumeBool()) {
+ while (fuzzed_data_provider.ConsumeBool()) {
+ txids.insert(ConsumeUInt256(fuzzed_data_provider));
+ }
+ merkle_block = CMerkleBlock{*opt_block, txids};
}
- merkle_block = CMerkleBlock{*opt_block, txids};
}
- }
- partial_merkle_tree = merkle_block.txn;
- break;
- }
- }
+ partial_merkle_tree = merkle_block.txn;
+ });
(void)partial_merkle_tree.GetNumTransactions();
std::vector<uint256> matches;
std::vector<unsigned int> indices;
diff --git a/src/test/fuzz/muhash.cpp b/src/test/fuzz/muhash.cpp
new file mode 100644
index 0000000000..4ea9511870
--- /dev/null
+++ b/src/test/fuzz/muhash.cpp
@@ -0,0 +1,63 @@
+// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <crypto/muhash.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <vector>
+
+FUZZ_TARGET(muhash)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ std::vector<uint8_t> data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ std::vector<uint8_t> data2 = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ if (data.empty()) {
+ data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ }
+ if (data2.empty()) {
+ data2.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ }
+
+ data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ data2 = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+
+ MuHash3072 muhash;
+
+ // Test that MuHash result is consistent independent of order of operations
+ muhash.Insert(data);
+ muhash.Insert(data2);
+
+ uint256 out;
+ muhash.Finalize(out);
+
+ muhash = MuHash3072();
+ muhash.Insert(data2);
+ muhash.Insert(data);
+
+ uint256 out2;
+ muhash.Finalize(out2);
+
+ assert(out == out2);
+ MuHash3072 muhash3;
+ muhash3 *= muhash;
+ uint256 out3;
+ muhash3.Finalize(out3);
+ assert(out == out3);
+
+ // Test that removing all added elements brings the object back to it's initial state
+ muhash /= muhash;
+ muhash.Finalize(out);
+
+ MuHash3072 muhash2;
+ muhash2.Finalize(out2);
+
+ assert(out == out2);
+
+ muhash3.Remove(data);
+ muhash3.Remove(data2);
+ muhash3.Finalize(out3);
+ assert(out == out3);
+}
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index ec02cf94e9..272f6415a9 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,21 +7,22 @@
#include <net.h>
#include <net_permissions.h>
#include <netaddress.h>
-#include <optional.h>
#include <protocol.h>
#include <random.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/net.h>
#include <test/util/setup_common.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
void initialize_net()
{
- static const BasicTestingSetup basic_testing_setup;
+ static const auto testing_setup = MakeNoLogFileContext<>(CBaseChainParams::MAIN);
}
FUZZ_TARGET_INIT(net, initialize_net)
@@ -31,85 +32,74 @@ FUZZ_TARGET_INIT(net, initialize_net)
CNode node{ConsumeNode(fuzzed_data_provider)};
node.SetCommonVersion(fuzzed_data_provider.ConsumeIntegral<int>());
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 10)) {
- case 0: {
- node.CloseSocketDisconnect();
- break;
- }
- case 1: {
- node.MaybeSetAddrName(fuzzed_data_provider.ConsumeRandomLengthString(32));
- break;
- }
- case 2: {
- const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
- if (!SanityCheckASMap(asmap)) {
- break;
- }
- CNodeStats stats;
- node.copyStats(stats, asmap);
- break;
- }
- case 3: {
- const CNode* add_ref_node = node.AddRef();
- assert(add_ref_node == &node);
- break;
- }
- case 4: {
- if (node.GetRefCount() > 0) {
- node.Release();
- }
- break;
- }
- case 5: {
- if (node.m_addr_known == nullptr) {
- break;
- }
- const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- if (!addr_opt) {
- break;
- }
- node.AddAddressKnown(*addr_opt);
- break;
- }
- case 6: {
- if (node.m_addr_known == nullptr) {
- break;
- }
- const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- if (!addr_opt) {
- break;
- }
- FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)};
- node.PushAddress(*addr_opt, fast_random_context);
- break;
- }
- case 7: {
- const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider);
- if (!inv_opt) {
- break;
- }
- node.AddKnownTx(inv_opt->hash);
- break;
- }
- case 8: {
- node.PushTxInventory(ConsumeUInt256(fuzzed_data_provider));
- break;
- }
- case 9: {
- const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (!service_opt) {
- break;
- }
- node.SetAddrLocal(*service_opt);
- break;
- }
- case 10: {
- const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- bool complete;
- node.ReceiveMsgBytes(b, complete);
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ node.CloseSocketDisconnect();
+ },
+ [&] {
+ node.MaybeSetAddrName(fuzzed_data_provider.ConsumeRandomLengthString(32));
+ },
+ [&] {
+ const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
+ if (!SanityCheckASMap(asmap)) {
+ return;
+ }
+ CNodeStats stats;
+ node.copyStats(stats, asmap);
+ },
+ [&] {
+ const CNode* add_ref_node = node.AddRef();
+ assert(add_ref_node == &node);
+ },
+ [&] {
+ if (node.GetRefCount() > 0) {
+ node.Release();
+ }
+ },
+ [&] {
+ if (node.m_addr_known == nullptr) {
+ return;
+ }
+ const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
+ if (!addr_opt) {
+ return;
+ }
+ node.AddAddressKnown(*addr_opt);
+ },
+ [&] {
+ if (node.m_addr_known == nullptr) {
+ return;
+ }
+ const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
+ if (!addr_opt) {
+ return;
+ }
+ FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)};
+ node.PushAddress(*addr_opt, fast_random_context);
+ },
+ [&] {
+ const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider);
+ if (!inv_opt) {
+ return;
+ }
+ node.AddKnownTx(inv_opt->hash);
+ },
+ [&] {
+ node.PushTxInventory(ConsumeUInt256(fuzzed_data_provider));
+ },
+ [&] {
+ const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider);
+ if (!service_opt) {
+ return;
+ }
+ node.SetAddrLocal(*service_opt);
+ },
+ [&] {
+ const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ bool complete;
+ node.ReceiveMsgBytes(b, complete);
+ });
}
(void)node.GetAddrLocal();
@@ -122,9 +112,7 @@ FUZZ_TARGET_INIT(net, initialize_net)
(void)node.GetCommonVersion();
(void)node.RelayAddrsWithConn();
- const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ?
- fuzzed_data_provider.PickValueInArray<NetPermissionFlags>({NetPermissionFlags::PF_NONE, NetPermissionFlags::PF_BLOOMFILTER, NetPermissionFlags::PF_RELAY, NetPermissionFlags::PF_FORCERELAY, NetPermissionFlags::PF_NOBAN, NetPermissionFlags::PF_MEMPOOL, NetPermissionFlags::PF_ISIMPLICIT, NetPermissionFlags::PF_ALL}) :
- static_cast<NetPermissionFlags>(fuzzed_data_provider.ConsumeIntegral<uint32_t>());
+ const NetPermissionFlags net_permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
(void)node.HasPermission(net_permission_flags);
(void)node.ConnectedThroughNetwork();
}
diff --git a/src/test/fuzz/net_permissions.cpp b/src/test/fuzz/net_permissions.cpp
index 3620e16d30..544a33047b 100644
--- a/src/test/fuzz/net_permissions.cpp
+++ b/src/test/fuzz/net_permissions.cpp
@@ -17,18 +17,7 @@ FUZZ_TARGET(net_permissions)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(32);
- const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ? fuzzed_data_provider.PickValueInArray<NetPermissionFlags>({
- NetPermissionFlags::PF_NONE,
- NetPermissionFlags::PF_BLOOMFILTER,
- NetPermissionFlags::PF_RELAY,
- NetPermissionFlags::PF_FORCERELAY,
- NetPermissionFlags::PF_NOBAN,
- NetPermissionFlags::PF_MEMPOOL,
- NetPermissionFlags::PF_ADDR,
- NetPermissionFlags::PF_ISIMPLICIT,
- NetPermissionFlags::PF_ALL,
- }) :
- static_cast<NetPermissionFlags>(fuzzed_data_provider.ConsumeIntegral<uint32_t>());
+ const NetPermissionFlags net_permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
NetWhitebindPermissions net_whitebind_permissions;
bilingual_str error_net_whitebind_permissions;
diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp
index 6e9bb47ff6..f9d8129ca9 100644
--- a/src/test/fuzz/netaddress.cpp
+++ b/src/test/fuzz/netaddress.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,7 +9,6 @@
#include <cassert>
#include <cstdint>
-#include <netinet/in.h>
#include <vector>
FUZZ_TARGET(netaddress)
diff --git a/src/test/fuzz/netbase_dns_lookup.cpp b/src/test/fuzz/netbase_dns_lookup.cpp
new file mode 100644
index 0000000000..cf2fa33744
--- /dev/null
+++ b/src/test/fuzz/netbase_dns_lookup.cpp
@@ -0,0 +1,71 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <netaddress.h>
+#include <netbase.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+FUZZ_TARGET(netbase_dns_lookup)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ const std::string name = fuzzed_data_provider.ConsumeRandomLengthString(512);
+ const unsigned int max_results = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
+ const bool allow_lookup = fuzzed_data_provider.ConsumeBool();
+ const uint16_t default_port = fuzzed_data_provider.ConsumeIntegral<uint16_t>();
+
+ auto fuzzed_dns_lookup_function = [&](const std::string&, bool) {
+ std::vector<CNetAddr> resolved_addresses;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ resolved_addresses.push_back(ConsumeNetAddr(fuzzed_data_provider));
+ }
+ return resolved_addresses;
+ };
+
+ {
+ std::vector<CNetAddr> resolved_addresses;
+ if (LookupHost(name, resolved_addresses, max_results, allow_lookup, fuzzed_dns_lookup_function)) {
+ for (const CNetAddr& resolved_address : resolved_addresses) {
+ assert(!resolved_address.IsInternal());
+ }
+ }
+ assert(resolved_addresses.size() <= max_results || max_results == 0);
+ }
+ {
+ CNetAddr resolved_address;
+ if (LookupHost(name, resolved_address, allow_lookup, fuzzed_dns_lookup_function)) {
+ assert(!resolved_address.IsInternal());
+ }
+ }
+ {
+ std::vector<CService> resolved_services;
+ if (Lookup(name, resolved_services, default_port, allow_lookup, max_results, fuzzed_dns_lookup_function)) {
+ for (const CNetAddr& resolved_service : resolved_services) {
+ assert(!resolved_service.IsInternal());
+ }
+ }
+ assert(resolved_services.size() <= max_results || max_results == 0);
+ }
+ {
+ CService resolved_service;
+ if (Lookup(name, resolved_service, default_port, allow_lookup, fuzzed_dns_lookup_function)) {
+ assert(!resolved_service.IsInternal());
+ }
+ }
+ {
+ CService resolved_service = LookupNumeric(name, default_port, fuzzed_dns_lookup_function);
+ assert(!resolved_service.IsInternal());
+ }
+ {
+ CSubNet resolved_subnet;
+ if (LookupSubNet(name, resolved_subnet, fuzzed_dns_lookup_function)) {
+ assert(resolved_subnet.IsValid());
+ }
+ }
+}
diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp
index aaebe83c0a..70ffc6bf37 100644
--- a/src/test/fuzz/node_eviction.cpp
+++ b/src/test/fuzz/node_eviction.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <net.h>
-#include <optional.h>
#include <protocol.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -21,23 +20,24 @@ FUZZ_TARGET(node_eviction)
std::vector<NodeEvictionCandidate> eviction_candidates;
while (fuzzed_data_provider.ConsumeBool()) {
eviction_candidates.push_back({
- fuzzed_data_provider.ConsumeIntegral<NodeId>(),
- fuzzed_data_provider.ConsumeIntegral<int64_t>(),
- fuzzed_data_provider.ConsumeIntegral<int64_t>(),
- fuzzed_data_provider.ConsumeIntegral<int64_t>(),
- fuzzed_data_provider.ConsumeIntegral<int64_t>(),
- fuzzed_data_provider.ConsumeBool(),
- fuzzed_data_provider.ConsumeBool(),
- fuzzed_data_provider.ConsumeBool(),
- fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
- fuzzed_data_provider.ConsumeBool(),
- fuzzed_data_provider.ConsumeBool(),
+ /* id */ fuzzed_data_provider.ConsumeIntegral<NodeId>(),
+ /* nTimeConnected */ fuzzed_data_provider.ConsumeIntegral<int64_t>(),
+ /* m_min_ping_time */ std::chrono::microseconds{fuzzed_data_provider.ConsumeIntegral<int64_t>()},
+ /* nLastBlockTime */ fuzzed_data_provider.ConsumeIntegral<int64_t>(),
+ /* nLastTXTime */ fuzzed_data_provider.ConsumeIntegral<int64_t>(),
+ /* fRelevantServices */ fuzzed_data_provider.ConsumeBool(),
+ /* fRelayTxes */ fuzzed_data_provider.ConsumeBool(),
+ /* fBloomFilter */ fuzzed_data_provider.ConsumeBool(),
+ /* nKeyedNetGroup */ fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
+ /* prefer_evict */ fuzzed_data_provider.ConsumeBool(),
+ /* m_is_local */ fuzzed_data_provider.ConsumeBool(),
+ /* m_is_onion */ fuzzed_data_provider.ConsumeBool(),
});
}
// Make a copy since eviction_candidates may be in some valid but otherwise
// indeterminate state after the SelectNodeToEvict(&&) call.
const std::vector<NodeEvictionCandidate> eviction_candidates_copy = eviction_candidates;
- const Optional<NodeId> node_to_evict = SelectNodeToEvict(std::move(eviction_candidates));
+ const std::optional<NodeId> node_to_evict = SelectNodeToEvict(std::move(eviction_candidates));
if (node_to_evict) {
assert(std::any_of(eviction_candidates_copy.begin(), eviction_candidates_copy.end(), [&node_to_evict](const NodeEvictionCandidate& eviction_candidate) { return *node_to_evict == eviction_candidate.id; }));
}
diff --git a/src/test/fuzz/p2p_transport_deserializer.cpp b/src/test/fuzz/p2p_transport_deserializer.cpp
index 163f1b839e..3a1fdaad8f 100644
--- a/src/test/fuzz/p2p_transport_deserializer.cpp
+++ b/src/test/fuzz/p2p_transport_deserializer.cpp
@@ -10,6 +10,7 @@
#include <cassert>
#include <cstdint>
#include <limits>
+#include <optional>
#include <vector>
void initialize_p2p_transport_deserializer()
@@ -30,7 +31,7 @@ FUZZ_TARGET_INIT(p2p_transport_deserializer, initialize_p2p_transport_deserializ
if (deserializer.Complete()) {
const std::chrono::microseconds m_time{std::numeric_limits<int64_t>::max()};
uint32_t out_err_raw_size{0};
- Optional<CNetMessage> result{deserializer.GetMessage(m_time, out_err_raw_size)};
+ std::optional<CNetMessage> result{deserializer.GetMessage(m_time, out_err_raw_size)};
if (result) {
assert(result->m_command.size() <= CMessageHeader::COMMAND_SIZE);
assert(result->m_raw_message_size <= buffer.size());
diff --git a/src/test/fuzz/parse_numbers.cpp b/src/test/fuzz/parse_numbers.cpp
index ddd2bcfba3..2c546e9b4a 100644
--- a/src/test/fuzz/parse_numbers.cpp
+++ b/src/test/fuzz/parse_numbers.cpp
@@ -18,6 +18,12 @@ FUZZ_TARGET(parse_numbers)
double d;
(void)ParseDouble(random_string, &d);
+ uint8_t u8;
+ (void)ParseUInt8(random_string, &u8);
+
+ uint16_t u16;
+ (void)ParseUInt16(random_string, &u16);
+
int32_t i32;
(void)ParseInt32(random_string, &i32);
(void)atoi(random_string);
diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp
index afe382ba21..3fffaac8d0 100644
--- a/src/test/fuzz/parse_univalue.cpp
+++ b/src/test/fuzz/parse_univalue.cpp
@@ -7,7 +7,6 @@
#include <rpc/client.h>
#include <rpc/util.h>
#include <test/fuzz/fuzz.h>
-#include <util/memory.h>
#include <limits>
#include <string>
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 8a17a4b51b..116b7a71d9 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,6 +7,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
#include <txmempool.h>
#include <cstdint>
@@ -16,7 +17,7 @@
void initialize_policy_estimator()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
@@ -24,52 +25,48 @@ FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
CBlockPolicyEstimator block_policy_estimator;
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 3)) {
- case 0: {
- const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
- if (!mtx) {
- break;
- }
- const CTransaction tx{*mtx};
- block_policy_estimator.processTransaction(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx), fuzzed_data_provider.ConsumeBool());
- if (fuzzed_data_provider.ConsumeBool()) {
- (void)block_policy_estimator.removeTx(tx.GetHash(), /* inBlock */ fuzzed_data_provider.ConsumeBool());
- }
- break;
- }
- case 1: {
- std::vector<CTxMemPoolEntry> mempool_entries;
- while (fuzzed_data_provider.ConsumeBool()) {
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
if (!mtx) {
- break;
+ return;
}
const CTransaction tx{*mtx};
- mempool_entries.push_back(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx));
- }
- std::vector<const CTxMemPoolEntry*> ptrs;
- ptrs.reserve(mempool_entries.size());
- for (const CTxMemPoolEntry& mempool_entry : mempool_entries) {
- ptrs.push_back(&mempool_entry);
- }
- block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral<unsigned int>(), ptrs);
- break;
- }
- case 2: {
- (void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /* inBlock */ fuzzed_data_provider.ConsumeBool());
- break;
- }
- case 3: {
- block_policy_estimator.FlushUnconfirmed();
- break;
- }
- }
+ block_policy_estimator.processTransaction(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx), fuzzed_data_provider.ConsumeBool());
+ if (fuzzed_data_provider.ConsumeBool()) {
+ (void)block_policy_estimator.removeTx(tx.GetHash(), /* inBlock */ fuzzed_data_provider.ConsumeBool());
+ }
+ },
+ [&] {
+ std::vector<CTxMemPoolEntry> mempool_entries;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ if (!mtx) {
+ break;
+ }
+ const CTransaction tx{*mtx};
+ mempool_entries.push_back(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx));
+ }
+ std::vector<const CTxMemPoolEntry*> ptrs;
+ ptrs.reserve(mempool_entries.size());
+ for (const CTxMemPoolEntry& mempool_entry : mempool_entries) {
+ ptrs.push_back(&mempool_entry);
+ }
+ block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral<unsigned int>(), ptrs);
+ },
+ [&] {
+ (void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /* inBlock */ fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ block_policy_estimator.FlushUnconfirmed();
+ });
(void)block_policy_estimator.estimateFee(fuzzed_data_provider.ConsumeIntegral<int>());
EstimationResult result;
- (void)block_policy_estimator.estimateRawFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeFloatingPoint<double>(), fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}), fuzzed_data_provider.ConsumeBool() ? &result : nullptr);
+ (void)block_policy_estimator.estimateRawFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeFloatingPoint<double>(), fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS), fuzzed_data_provider.ConsumeBool() ? &result : nullptr);
FeeCalculation fee_calculation;
(void)block_policy_estimator.estimateSmartFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeBool() ? &fee_calculation : nullptr, fuzzed_data_provider.ConsumeBool());
- (void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}));
+ (void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS));
}
{
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp
index 8fa52143d8..9021d95954 100644
--- a/src/test/fuzz/policy_estimator_io.cpp
+++ b/src/test/fuzz/policy_estimator_io.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,13 +6,14 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
#include <cstdint>
#include <vector>
void initialize_policy_estimator_io()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io)
diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp
index 02beb6eb37..47b4323e81 100644
--- a/src/test/fuzz/pow.cpp
+++ b/src/test/fuzz/pow.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -34,7 +34,7 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
}
CBlockIndex current_block{*block_header};
{
- CBlockIndex* previous_block = !blocks.empty() ? &blocks[fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, blocks.size() - 1)] : nullptr;
+ CBlockIndex* previous_block = blocks.empty() ? nullptr : &PickValue(fuzzed_data_provider, blocks);
const int current_height = (previous_block != nullptr && previous_block->nHeight != std::numeric_limits<int>::max()) ? previous_block->nHeight + 1 : 0;
if (fuzzed_data_provider.ConsumeBool()) {
current_block.pprev = previous_block;
@@ -43,7 +43,10 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
current_block.nHeight = current_height;
}
if (fuzzed_data_provider.ConsumeBool()) {
- current_block.nTime = fixed_time + current_height * consensus_params.nPowTargetSpacing;
+ const uint32_t seconds = current_height * consensus_params.nPowTargetSpacing;
+ if (!AdditionOverflow(fixed_time, seconds)) {
+ current_block.nTime = fixed_time + seconds;
+ }
}
if (fuzzed_data_provider.ConsumeBool()) {
current_block.nBits = fixed_bits;
@@ -63,9 +66,9 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
}
}
{
- const CBlockIndex* to = &blocks[fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, blocks.size() - 1)];
- const CBlockIndex* from = &blocks[fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, blocks.size() - 1)];
- const CBlockIndex* tip = &blocks[fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, blocks.size() - 1)];
+ const CBlockIndex* to = &PickValue(fuzzed_data_provider, blocks);
+ const CBlockIndex* from = &PickValue(fuzzed_data_provider, blocks);
+ const CBlockIndex* tip = &PickValue(fuzzed_data_provider, blocks);
try {
(void)GetBlockProofEquivalentTime(*to, *from, *tip, consensus_params);
} catch (const uint_error&) {
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index 97e2b04a7d..7b99193ad0 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,11 +13,12 @@
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
#include <test/util/mining.h>
#include <test/util/net.h>
#include <test/util/setup_common.h>
#include <test/util/validation.h>
-#include <util/memory.h>
+#include <txorphanage.h>
#include <validationinterface.h>
#include <version.h>
@@ -29,47 +30,66 @@
#include <iostream>
#include <memory>
#include <string>
-#include <vector>
namespace {
const TestingSetup* g_setup;
} // namespace
+size_t& GetNumMsgTypes()
+{
+ static size_t g_num_msg_types{0};
+ return g_num_msg_types;
+}
+#define FUZZ_TARGET_MSG(msg_type) \
+ struct msg_type##_Count_Before_Main { \
+ msg_type##_Count_Before_Main() \
+ { \
+ ++GetNumMsgTypes(); \
+ } \
+ } const static g_##msg_type##_count_before_main; \
+ FUZZ_TARGET_INIT(process_message_##msg_type, initialize_process_message) \
+ { \
+ fuzz_target(buffer, #msg_type); \
+ }
+
void initialize_process_message()
{
- static TestingSetup setup{
- CBaseChainParams::REGTEST,
- {
- "-nodebuglogfile",
- },
- };
- g_setup = &setup;
+ Assert(GetNumMsgTypes() == getAllNetMessageTypes().size()); // If this fails, add or remove the message type below
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+ g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
}
SyncWithValidationInterfaceQueue();
}
-void fuzz_target(const std::vector<uint8_t>& buffer, const std::string& LIMIT_TO_MESSAGE_TYPE)
+void fuzz_target(FuzzBufferType buffer, const std::string& LIMIT_TO_MESSAGE_TYPE)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- ConnmanTestMsg& connman = *(ConnmanTestMsg*)g_setup->m_node.connman.get();
- TestChainState& chainstate = *(TestChainState*)&g_setup->m_node.chainman->ActiveChainstate();
+
+ ConnmanTestMsg& connman = *static_cast<ConnmanTestMsg*>(g_setup->m_node.connman.get());
+ TestChainState& chainstate = *static_cast<TestChainState*>(&g_setup->m_node.chainman->ActiveChainstate());
+ SetMockTime(1610000000); // any time to successfully reset ibd
chainstate.ResetIbd();
+
const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::COMMAND_SIZE).c_str()};
if (!LIMIT_TO_MESSAGE_TYPE.empty() && random_message_type != LIMIT_TO_MESSAGE_TYPE) {
return;
}
- const bool jump_out_of_ibd{fuzzed_data_provider.ConsumeBool()};
- if (jump_out_of_ibd) chainstate.JumpOutOfIbd();
- CDataStream random_bytes_data_stream{fuzzed_data_provider.ConsumeRemainingBytes<unsigned char>(), SER_NETWORK, PROTOCOL_VERSION};
- CNode& p2p_node = *MakeUnique<CNode>(0, ServiceFlags(NODE_NETWORK | NODE_WITNESS | NODE_BLOOM), INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND_FULL_RELAY).release();
- p2p_node.fSuccessfullyConnected = true;
- p2p_node.nVersion = PROTOCOL_VERSION;
- p2p_node.SetCommonVersion(PROTOCOL_VERSION);
+ CNode& p2p_node = *ConsumeNodeAsUniquePtr(fuzzed_data_provider).release();
+
+ const bool successfully_connected{fuzzed_data_provider.ConsumeBool()};
+ p2p_node.fSuccessfullyConnected = successfully_connected;
connman.AddTestNode(p2p_node);
g_setup->m_node.peerman->InitializeNode(&p2p_node);
+ FillNode(fuzzed_data_provider, p2p_node, /* init_version */ successfully_connected);
+
+ const auto mock_time = ConsumeTime(fuzzed_data_provider);
+ SetMockTime(mock_time);
+
+ // fuzzed_data_provider is fully consumed after this call, don't use it
+ CDataStream random_bytes_data_stream{fuzzed_data_provider.ConsumeRemainingBytes<unsigned char>(), SER_NETWORK, PROTOCOL_VERSION};
try {
g_setup->m_node.peerman->ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream,
GetTime<std::chrono::microseconds>(), std::atomic<bool>{false});
@@ -80,32 +100,41 @@ void fuzz_target(const std::vector<uint8_t>& buffer, const std::string& LIMIT_TO
g_setup->m_node.peerman->SendMessages(&p2p_node);
}
SyncWithValidationInterfaceQueue();
- LOCK2(::cs_main, g_cs_orphans); // See init.cpp for rationale for implicit locking order requirement
g_setup->m_node.connman->StopNodes();
}
FUZZ_TARGET_INIT(process_message, initialize_process_message) { fuzz_target(buffer, ""); }
-FUZZ_TARGET_INIT(process_message_addr, initialize_process_message) { fuzz_target(buffer, "addr"); }
-FUZZ_TARGET_INIT(process_message_block, initialize_process_message) { fuzz_target(buffer, "block"); }
-FUZZ_TARGET_INIT(process_message_blocktxn, initialize_process_message) { fuzz_target(buffer, "blocktxn"); }
-FUZZ_TARGET_INIT(process_message_cmpctblock, initialize_process_message) { fuzz_target(buffer, "cmpctblock"); }
-FUZZ_TARGET_INIT(process_message_feefilter, initialize_process_message) { fuzz_target(buffer, "feefilter"); }
-FUZZ_TARGET_INIT(process_message_filteradd, initialize_process_message) { fuzz_target(buffer, "filteradd"); }
-FUZZ_TARGET_INIT(process_message_filterclear, initialize_process_message) { fuzz_target(buffer, "filterclear"); }
-FUZZ_TARGET_INIT(process_message_filterload, initialize_process_message) { fuzz_target(buffer, "filterload"); }
-FUZZ_TARGET_INIT(process_message_getaddr, initialize_process_message) { fuzz_target(buffer, "getaddr"); }
-FUZZ_TARGET_INIT(process_message_getblocks, initialize_process_message) { fuzz_target(buffer, "getblocks"); }
-FUZZ_TARGET_INIT(process_message_getblocktxn, initialize_process_message) { fuzz_target(buffer, "getblocktxn"); }
-FUZZ_TARGET_INIT(process_message_getdata, initialize_process_message) { fuzz_target(buffer, "getdata"); }
-FUZZ_TARGET_INIT(process_message_getheaders, initialize_process_message) { fuzz_target(buffer, "getheaders"); }
-FUZZ_TARGET_INIT(process_message_headers, initialize_process_message) { fuzz_target(buffer, "headers"); }
-FUZZ_TARGET_INIT(process_message_inv, initialize_process_message) { fuzz_target(buffer, "inv"); }
-FUZZ_TARGET_INIT(process_message_mempool, initialize_process_message) { fuzz_target(buffer, "mempool"); }
-FUZZ_TARGET_INIT(process_message_notfound, initialize_process_message) { fuzz_target(buffer, "notfound"); }
-FUZZ_TARGET_INIT(process_message_ping, initialize_process_message) { fuzz_target(buffer, "ping"); }
-FUZZ_TARGET_INIT(process_message_pong, initialize_process_message) { fuzz_target(buffer, "pong"); }
-FUZZ_TARGET_INIT(process_message_sendcmpct, initialize_process_message) { fuzz_target(buffer, "sendcmpct"); }
-FUZZ_TARGET_INIT(process_message_sendheaders, initialize_process_message) { fuzz_target(buffer, "sendheaders"); }
-FUZZ_TARGET_INIT(process_message_tx, initialize_process_message) { fuzz_target(buffer, "tx"); }
-FUZZ_TARGET_INIT(process_message_verack, initialize_process_message) { fuzz_target(buffer, "verack"); }
-FUZZ_TARGET_INIT(process_message_version, initialize_process_message) { fuzz_target(buffer, "version"); }
+FUZZ_TARGET_MSG(addr);
+FUZZ_TARGET_MSG(addrv2);
+FUZZ_TARGET_MSG(block);
+FUZZ_TARGET_MSG(blocktxn);
+FUZZ_TARGET_MSG(cfcheckpt);
+FUZZ_TARGET_MSG(cfheaders);
+FUZZ_TARGET_MSG(cfilter);
+FUZZ_TARGET_MSG(cmpctblock);
+FUZZ_TARGET_MSG(feefilter);
+FUZZ_TARGET_MSG(filteradd);
+FUZZ_TARGET_MSG(filterclear);
+FUZZ_TARGET_MSG(filterload);
+FUZZ_TARGET_MSG(getaddr);
+FUZZ_TARGET_MSG(getblocks);
+FUZZ_TARGET_MSG(getblocktxn);
+FUZZ_TARGET_MSG(getcfcheckpt);
+FUZZ_TARGET_MSG(getcfheaders);
+FUZZ_TARGET_MSG(getcfilters);
+FUZZ_TARGET_MSG(getdata);
+FUZZ_TARGET_MSG(getheaders);
+FUZZ_TARGET_MSG(headers);
+FUZZ_TARGET_MSG(inv);
+FUZZ_TARGET_MSG(mempool);
+FUZZ_TARGET_MSG(merkleblock);
+FUZZ_TARGET_MSG(notfound);
+FUZZ_TARGET_MSG(ping);
+FUZZ_TARGET_MSG(pong);
+FUZZ_TARGET_MSG(sendaddrv2);
+FUZZ_TARGET_MSG(sendcmpct);
+FUZZ_TARGET_MSG(sendheaders);
+FUZZ_TARGET_MSG(tx);
+FUZZ_TARGET_MSG(verack);
+FUZZ_TARGET_MSG(version);
+FUZZ_TARGET_MSG(wtxidrelay);
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index 0ff95ea1ae..11b236c9bd 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,22 +13,18 @@
#include <test/util/net.h>
#include <test/util/setup_common.h>
#include <test/util/validation.h>
-#include <util/memory.h>
+#include <txorphanage.h>
#include <validation.h>
#include <validationinterface.h>
+namespace {
const TestingSetup* g_setup;
+} // namespace
void initialize_process_messages()
{
- static TestingSetup setup{
- CBaseChainParams::REGTEST,
- {
- "-nodebuglogfile",
- },
- };
- g_setup = &setup;
-
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+ g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
}
@@ -39,38 +35,37 @@ FUZZ_TARGET_INIT(process_messages, initialize_process_messages)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- ConnmanTestMsg& connman = *(ConnmanTestMsg*)g_setup->m_node.connman.get();
- TestChainState& chainstate = *(TestChainState*)&g_setup->m_node.chainman->ActiveChainstate();
+ ConnmanTestMsg& connman = *static_cast<ConnmanTestMsg*>(g_setup->m_node.connman.get());
+ TestChainState& chainstate = *static_cast<TestChainState*>(&g_setup->m_node.chainman->ActiveChainstate());
+ SetMockTime(1610000000); // any time to successfully reset ibd
chainstate.ResetIbd();
- std::vector<CNode*> peers;
- bool jump_out_of_ibd{false};
+ std::vector<CNode*> peers;
const auto num_peers_to_add = fuzzed_data_provider.ConsumeIntegralInRange(1, 3);
for (int i = 0; i < num_peers_to_add; ++i) {
- const ServiceFlags service_flags = ServiceFlags(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND_FULL_RELAY, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH});
- peers.push_back(MakeUnique<CNode>(i, service_flags, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, conn_type).release());
+ peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, i).release());
CNode& p2p_node = *peers.back();
- p2p_node.fSuccessfullyConnected = true;
+ const bool successfully_connected{fuzzed_data_provider.ConsumeBool()};
+ p2p_node.fSuccessfullyConnected = successfully_connected;
p2p_node.fPauseSend = false;
- p2p_node.nVersion = PROTOCOL_VERSION;
- p2p_node.SetCommonVersion(PROTOCOL_VERSION);
g_setup->m_node.peerman->InitializeNode(&p2p_node);
+ FillNode(fuzzed_data_provider, p2p_node, /* init_version */ successfully_connected);
connman.AddTestNode(p2p_node);
}
while (fuzzed_data_provider.ConsumeBool()) {
- if (!jump_out_of_ibd) jump_out_of_ibd = fuzzed_data_provider.ConsumeBool();
- if (jump_out_of_ibd && chainstate.IsInitialBlockDownload()) chainstate.JumpOutOfIbd();
const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::COMMAND_SIZE).c_str()};
+ const auto mock_time = ConsumeTime(fuzzed_data_provider);
+ SetMockTime(mock_time);
+
CSerializedNetMsg net_msg;
net_msg.m_type = random_message_type;
net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- CNode& random_node = *peers.at(fuzzed_data_provider.ConsumeIntegralInRange<int>(0, peers.size() - 1));
+ CNode& random_node = *PickValue(fuzzed_data_provider, peers);
(void)connman.ReceiveMsgFrom(random_node, net_msg);
random_node.fPauseSend = false;
@@ -85,6 +80,5 @@ FUZZ_TARGET_INIT(process_messages, initialize_process_messages)
}
}
SyncWithValidationInterfaceQueue();
- LOCK2(::cs_main, g_cs_orphans); // See init.cpp for rationale for implicit locking order requirement
g_setup->m_node.connman->StopNodes();
}
diff --git a/src/test/fuzz/psbt.cpp b/src/test/fuzz/psbt.cpp
index 0b4588c4ce..6c62dd6e48 100644
--- a/src/test/fuzz/psbt.cpp
+++ b/src/test/fuzz/psbt.cpp
@@ -2,18 +2,19 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <node/psbt.h>
-#include <optional.h>
#include <psbt.h>
#include <pubkey.h>
#include <script/script.h>
#include <streams.h>
-#include <util/memory.h>
+#include <util/check.h>
#include <version.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
@@ -24,10 +25,10 @@ void initialize_psbt()
FUZZ_TARGET_INIT(psbt, initialize_psbt)
{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
PartiallySignedTransaction psbt_mut;
- const std::string raw_psbt{buffer.begin(), buffer.end()};
std::string error;
- if (!DecodeRawPSBT(psbt_mut, raw_psbt, error)) {
+ if (!DecodeRawPSBT(psbt_mut, fuzzed_data_provider.ConsumeRandomLengthString(), error)) {
return;
}
const PartiallySignedTransaction psbt = psbt_mut;
@@ -40,7 +41,7 @@ FUZZ_TARGET_INIT(psbt, initialize_psbt)
(void)psbt.IsNull();
- Optional<CMutableTransaction> tx = psbt.tx;
+ std::optional<CMutableTransaction> tx = psbt.tx;
if (tx) {
const CMutableTransaction& mtx = *tx;
const PartiallySignedTransaction psbt_from_tx{mtx};
@@ -50,6 +51,7 @@ FUZZ_TARGET_INIT(psbt, initialize_psbt)
(void)PSBTInputSigned(input);
(void)input.IsNull();
}
+ (void)CountPSBTUnsignedInputs(psbt);
for (const PSBTOutput& output : psbt.outputs) {
(void)output.IsNull();
@@ -72,6 +74,20 @@ FUZZ_TARGET_INIT(psbt, initialize_psbt)
const PartiallySignedTransaction psbt_from_tx{result};
}
+ PartiallySignedTransaction psbt_merge;
+ if (!DecodeRawPSBT(psbt_merge, fuzzed_data_provider.ConsumeRandomLengthString(), error)) {
+ psbt_merge = psbt;
+ }
+ psbt_mut = psbt;
+ (void)psbt_mut.Merge(psbt_merge);
+ psbt_mut = psbt;
+ (void)CombinePSBTs(psbt_mut, {psbt_mut, psbt_merge});
psbt_mut = psbt;
- (void)psbt_mut.Merge(psbt);
+ for (unsigned int i = 0; i < psbt_merge.tx->vin.size(); ++i) {
+ (void)psbt_mut.AddInput(psbt_merge.tx->vin[i], psbt_merge.inputs[i]);
+ }
+ for (unsigned int i = 0; i < psbt_merge.tx->vout.size(); ++i) {
+ Assert(psbt_mut.AddOutput(psbt_merge.tx->vout[i], psbt_merge.outputs[i]));
+ }
+ psbt_mut.unknown.insert(psbt_merge.unknown.begin(), psbt_merge.unknown.end());
}
diff --git a/src/test/fuzz/rolling_bloom_filter.cpp b/src/test/fuzz/rolling_bloom_filter.cpp
index 6087ee964a..07059cce76 100644
--- a/src/test/fuzz/rolling_bloom_filter.cpp
+++ b/src/test/fuzz/rolling_bloom_filter.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -22,29 +22,27 @@ FUZZ_TARGET(rolling_bloom_filter)
fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(1, 1000),
0.999 / fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(1, std::numeric_limits<unsigned int>::max())};
while (fuzzed_data_provider.remaining_bytes() > 0) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 2)) {
- case 0: {
- const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- (void)rolling_bloom_filter.contains(b);
- rolling_bloom_filter.insert(b);
- const bool present = rolling_bloom_filter.contains(b);
- assert(present);
- break;
- }
- case 1: {
- const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
- if (!u256) {
- break;
- }
- (void)rolling_bloom_filter.contains(*u256);
- rolling_bloom_filter.insert(*u256);
- const bool present = rolling_bloom_filter.contains(*u256);
- assert(present);
- break;
- }
- case 2:
- rolling_bloom_filter.reset();
- break;
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ (void)rolling_bloom_filter.contains(b);
+ rolling_bloom_filter.insert(b);
+ const bool present = rolling_bloom_filter.contains(b);
+ assert(present);
+ },
+ [&] {
+ const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
+ if (!u256) {
+ return;
+ }
+ (void)rolling_bloom_filter.contains(*u256);
+ rolling_bloom_filter.insert(*u256);
+ const bool present = rolling_bloom_filter.contains(*u256);
+ assert(present);
+ },
+ [&] {
+ rolling_bloom_filter.reset();
+ });
}
}
diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp
new file mode 100644
index 0000000000..dae6f6b6a7
--- /dev/null
+++ b/src/test/fuzz/rpc.cpp
@@ -0,0 +1,378 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <base58.h>
+#include <chainparamsbase.h>
+#include <core_io.h>
+#include <interfaces/chain.h>
+#include <key.h>
+#include <key_io.h>
+#include <node/context.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <psbt.h>
+#include <rpc/blockchain.h>
+#include <rpc/client.h>
+#include <rpc/request.h>
+#include <rpc/server.h>
+#include <rpc/util.h>
+#include <span.h>
+#include <streams.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <tinyformat.h>
+#include <univalue.h>
+#include <util/strencodings.h>
+#include <util/string.h>
+#include <util/time.h>
+
+#include <cstdint>
+#include <iostream>
+#include <memory>
+#include <optional>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+namespace {
+struct RPCFuzzTestingSetup : public TestingSetup {
+ RPCFuzzTestingSetup(const std::string& chain_name, const std::vector<const char*>& extra_args) : TestingSetup{chain_name, extra_args}
+ {
+ }
+
+ UniValue CallRPC(const std::string& rpc_method, const std::vector<std::string>& arguments)
+ {
+ JSONRPCRequest request;
+ request.context = &m_node;
+ request.strMethod = rpc_method;
+ request.params = RPCConvertValues(rpc_method, arguments);
+ return tableRPC.execute(request);
+ }
+
+ std::vector<std::string> GetRPCCommands() const
+ {
+ return tableRPC.listCommands();
+ }
+};
+
+RPCFuzzTestingSetup* rpc_testing_setup = nullptr;
+std::string g_limit_to_rpc_command;
+
+// RPC commands which are not appropriate for fuzzing: such as RPC commands
+// reading or writing to a filename passed as an RPC parameter, RPC commands
+// resulting in network activity, etc.
+const std::vector<std::string> RPC_COMMANDS_NOT_SAFE_FOR_FUZZING{
+ "addconnection", // avoid DNS lookups
+ "addnode", // avoid DNS lookups
+ "addpeeraddress", // avoid DNS lookups
+ "analyzepsbt", // avoid signed integer overflow in CFeeRate::GetFee(unsigned long) (https://github.com/bitcoin/bitcoin/issues/20607)
+ "dumptxoutset", // avoid writing to disk
+#ifdef ENABLE_WALLET
+ "dumpwallet", // avoid writing to disk
+#endif
+ "echoipc", // avoid assertion failure (Assertion `"EnsureAnyNodeContext(request.context).init" && check' failed.)
+ "generatetoaddress", // avoid timeout
+ "gettxoutproof", // avoid slow execution
+#ifdef ENABLE_WALLET
+ "importwallet", // avoid reading from disk
+ "loadwallet", // avoid reading from disk
+#endif
+ "mockscheduler", // avoid assertion failure (Assertion `delta_seconds.count() > 0 && delta_seconds < std::chrono::hours{1}' failed.)
+ "prioritisetransaction", // avoid signed integer overflow in CTxMemPool::PrioritiseTransaction(uint256 const&, long const&) (https://github.com/bitcoin/bitcoin/issues/20626)
+ "setban", // avoid DNS lookups
+ "stop", // avoid shutdown state
+};
+
+// RPC commands which are safe for fuzzing.
+const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
+ "clearbanned",
+ "combinepsbt",
+ "combinerawtransaction",
+ "converttopsbt",
+ "createmultisig",
+ "createpsbt",
+ "createrawtransaction",
+ "decodepsbt",
+ "decoderawtransaction",
+ "decodescript",
+ "deriveaddresses",
+ "disconnectnode",
+ "echo",
+ "echojson",
+ "estimaterawfee",
+ "estimatesmartfee",
+ "finalizepsbt",
+ "generate",
+ "generateblock",
+ "generatetodescriptor",
+ "getaddednodeinfo",
+ "getbestblockhash",
+ "getblock",
+ "getblockchaininfo",
+ "getblockcount",
+ "getblockfilter",
+ "getblockhash",
+ "getblockheader",
+ "getblockstats",
+ "getblocktemplate",
+ "getchaintips",
+ "getchaintxstats",
+ "getconnectioncount",
+ "getdescriptorinfo",
+ "getdifficulty",
+ "getindexinfo",
+ "getmemoryinfo",
+ "getmempoolancestors",
+ "getmempooldescendants",
+ "getmempoolentry",
+ "getmempoolinfo",
+ "getmininginfo",
+ "getnettotals",
+ "getnetworkhashps",
+ "getnetworkinfo",
+ "getnodeaddresses",
+ "getpeerinfo",
+ "getrawmempool",
+ "getrawtransaction",
+ "getrpcinfo",
+ "gettxout",
+ "gettxoutsetinfo",
+ "help",
+ "invalidateblock",
+ "joinpsbts",
+ "listbanned",
+ "logging",
+ "ping",
+ "preciousblock",
+ "pruneblockchain",
+ "reconsiderblock",
+ "savemempool",
+ "scantxoutset",
+ "sendrawtransaction",
+ "setmocktime",
+ "setnetworkactive",
+ "signmessagewithprivkey",
+ "signrawtransactionwithkey",
+ "submitblock",
+ "submitheader",
+ "syncwithvalidationinterfacequeue",
+ "testmempoolaccept",
+ "uptime",
+ "utxoupdatepsbt",
+ "validateaddress",
+ "verifychain",
+ "verifymessage",
+ "verifytxoutproof",
+ "waitforblock",
+ "waitforblockheight",
+ "waitfornewblock",
+};
+
+std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
+{
+ const size_t max_string_length = 4096;
+ std::string r;
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ // string argument
+ r = fuzzed_data_provider.ConsumeRandomLengthString(max_string_length);
+ },
+ [&] {
+ // base64 argument
+ r = EncodeBase64(fuzzed_data_provider.ConsumeRandomLengthString(max_string_length));
+ },
+ [&] {
+ // hex argument
+ r = HexStr(fuzzed_data_provider.ConsumeRandomLengthString(max_string_length));
+ },
+ [&] {
+ // bool argument
+ r = fuzzed_data_provider.ConsumeBool() ? "true" : "false";
+ },
+ [&] {
+ // range argument
+ r = "[" + ToString(fuzzed_data_provider.ConsumeIntegral<int64_t>()) + "," + ToString(fuzzed_data_provider.ConsumeIntegral<int64_t>()) + "]";
+ },
+ [&] {
+ // integral argument (int64_t)
+ r = ToString(fuzzed_data_provider.ConsumeIntegral<int64_t>());
+ },
+ [&] {
+ // integral argument (uint64_t)
+ r = ToString(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ },
+ [&] {
+ // floating point argument
+ r = strprintf("%f", fuzzed_data_provider.ConsumeFloatingPoint<double>());
+ },
+ [&] {
+ // tx destination argument
+ r = EncodeDestination(ConsumeTxDestination(fuzzed_data_provider));
+ },
+ [&] {
+ // uint160 argument
+ r = ConsumeUInt160(fuzzed_data_provider).ToString();
+ },
+ [&] {
+ // uint256 argument
+ r = ConsumeUInt256(fuzzed_data_provider).ToString();
+ },
+ [&] {
+ // base32 argument
+ r = EncodeBase32(fuzzed_data_provider.ConsumeRandomLengthString(max_string_length));
+ },
+ [&] {
+ // base58 argument
+ r = EncodeBase58(MakeUCharSpan(fuzzed_data_provider.ConsumeRandomLengthString(max_string_length)));
+ },
+ [&] {
+ // base58 argument with checksum
+ r = EncodeBase58Check(MakeUCharSpan(fuzzed_data_provider.ConsumeRandomLengthString(max_string_length)));
+ },
+ [&] {
+ // hex encoded block
+ std::optional<CBlock> opt_block = ConsumeDeserializable<CBlock>(fuzzed_data_provider);
+ if (!opt_block) {
+ return;
+ }
+ CDataStream data_stream{SER_NETWORK, PROTOCOL_VERSION};
+ data_stream << *opt_block;
+ r = HexStr(data_stream);
+ },
+ [&] {
+ // hex encoded block header
+ std::optional<CBlockHeader> opt_block_header = ConsumeDeserializable<CBlockHeader>(fuzzed_data_provider);
+ if (!opt_block_header) {
+ return;
+ }
+ CDataStream data_stream{SER_NETWORK, PROTOCOL_VERSION};
+ data_stream << *opt_block_header;
+ r = HexStr(data_stream);
+ },
+ [&] {
+ // hex encoded tx
+ std::optional<CMutableTransaction> opt_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ if (!opt_tx) {
+ return;
+ }
+ CDataStream data_stream{SER_NETWORK, fuzzed_data_provider.ConsumeBool() ? PROTOCOL_VERSION : (PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)};
+ data_stream << *opt_tx;
+ r = HexStr(data_stream);
+ },
+ [&] {
+ // base64 encoded psbt
+ std::optional<PartiallySignedTransaction> opt_psbt = ConsumeDeserializable<PartiallySignedTransaction>(fuzzed_data_provider);
+ if (!opt_psbt) {
+ return;
+ }
+ CDataStream data_stream{SER_NETWORK, PROTOCOL_VERSION};
+ data_stream << *opt_psbt;
+ r = EncodeBase64({data_stream.begin(), data_stream.end()});
+ },
+ [&] {
+ // base58 encoded key
+ const std::vector<uint8_t> random_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(32);
+ CKey key;
+ key.Set(random_bytes.begin(), random_bytes.end(), fuzzed_data_provider.ConsumeBool());
+ if (!key.IsValid()) {
+ return;
+ }
+ r = EncodeSecret(key);
+ },
+ [&] {
+ // hex encoded pubkey
+ const std::vector<uint8_t> random_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(32);
+ CKey key;
+ key.Set(random_bytes.begin(), random_bytes.end(), fuzzed_data_provider.ConsumeBool());
+ if (!key.IsValid()) {
+ return;
+ }
+ r = HexStr(key.GetPubKey());
+ });
+ return r;
+}
+
+std::string ConsumeArrayRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
+{
+ std::vector<std::string> scalar_arguments;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ scalar_arguments.push_back(ConsumeScalarRPCArgument(fuzzed_data_provider));
+ }
+ return "[\"" + Join(scalar_arguments, "\",\"") + "\"]";
+}
+
+std::string ConsumeRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
+{
+ return fuzzed_data_provider.ConsumeBool() ? ConsumeScalarRPCArgument(fuzzed_data_provider) : ConsumeArrayRPCArgument(fuzzed_data_provider);
+}
+
+RPCFuzzTestingSetup* InitializeRPCFuzzTestingSetup()
+{
+ static const auto setup = MakeNoLogFileContext<RPCFuzzTestingSetup>();
+ SetRPCWarmupFinished();
+ return setup.get();
+}
+}; // namespace
+
+void initialize_rpc()
+{
+ rpc_testing_setup = InitializeRPCFuzzTestingSetup();
+ const std::vector<std::string> supported_rpc_commands = rpc_testing_setup->GetRPCCommands();
+ for (const std::string& rpc_command : supported_rpc_commands) {
+ const bool safe_for_fuzzing = std::find(RPC_COMMANDS_SAFE_FOR_FUZZING.begin(), RPC_COMMANDS_SAFE_FOR_FUZZING.end(), rpc_command) != RPC_COMMANDS_SAFE_FOR_FUZZING.end();
+ const bool not_safe_for_fuzzing = std::find(RPC_COMMANDS_NOT_SAFE_FOR_FUZZING.begin(), RPC_COMMANDS_NOT_SAFE_FOR_FUZZING.end(), rpc_command) != RPC_COMMANDS_NOT_SAFE_FOR_FUZZING.end();
+ if (!(safe_for_fuzzing || not_safe_for_fuzzing)) {
+ std::cerr << "Error: RPC command \"" << rpc_command << "\" not found in RPC_COMMANDS_SAFE_FOR_FUZZING or RPC_COMMANDS_NOT_SAFE_FOR_FUZZING. Please update " << __FILE__ << ".\n";
+ std::terminate();
+ }
+ if (safe_for_fuzzing && not_safe_for_fuzzing) {
+ std::cerr << "Error: RPC command \"" << rpc_command << "\" found in *both* RPC_COMMANDS_SAFE_FOR_FUZZING and RPC_COMMANDS_NOT_SAFE_FOR_FUZZING. Please update " << __FILE__ << ".\n";
+ std::terminate();
+ }
+ }
+ for (const std::string& rpc_command : RPC_COMMANDS_SAFE_FOR_FUZZING) {
+ const bool supported_rpc_command = std::find(supported_rpc_commands.begin(), supported_rpc_commands.end(), rpc_command) != supported_rpc_commands.end();
+ if (!supported_rpc_command) {
+ std::cerr << "Error: Unknown RPC command \"" << rpc_command << "\" found in RPC_COMMANDS_SAFE_FOR_FUZZING. Please update " << __FILE__ << ".\n";
+ std::terminate();
+ }
+ }
+ for (const std::string& rpc_command : RPC_COMMANDS_NOT_SAFE_FOR_FUZZING) {
+ const bool supported_rpc_command = std::find(supported_rpc_commands.begin(), supported_rpc_commands.end(), rpc_command) != supported_rpc_commands.end();
+ if (!supported_rpc_command) {
+ std::cerr << "Error: Unknown RPC command \"" << rpc_command << "\" found in RPC_COMMANDS_NOT_SAFE_FOR_FUZZING. Please update " << __FILE__ << ".\n";
+ std::terminate();
+ }
+ }
+ const char* limit_to_rpc_command_env = std::getenv("LIMIT_TO_RPC_COMMAND");
+ if (limit_to_rpc_command_env != nullptr) {
+ g_limit_to_rpc_command = std::string{limit_to_rpc_command_env};
+ }
+}
+
+FUZZ_TARGET_INIT(rpc, initialize_rpc)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ SetMockTime(ConsumeTime(fuzzed_data_provider));
+ const std::string rpc_command = fuzzed_data_provider.ConsumeRandomLengthString(64);
+ if (!g_limit_to_rpc_command.empty() && rpc_command != g_limit_to_rpc_command) {
+ return;
+ }
+ const bool safe_for_fuzzing = std::find(RPC_COMMANDS_SAFE_FOR_FUZZING.begin(), RPC_COMMANDS_SAFE_FOR_FUZZING.end(), rpc_command) != RPC_COMMANDS_SAFE_FOR_FUZZING.end();
+ if (!safe_for_fuzzing) {
+ return;
+ }
+ std::vector<std::string> arguments;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ arguments.push_back(ConsumeRPCArgument(fuzzed_data_provider));
+ }
+ try {
+ rpc_testing_setup->CallRPC(rpc_command, arguments);
+ } catch (const UniValue&) {
+ } catch (const std::runtime_error&) {
+ }
+}
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index c89ce24171..c8f95c2980 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2020 The Bitcoin Core developers
+// Copyright (c) 2019-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -20,7 +20,6 @@
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <univalue.h>
-#include <util/memory.h>
#include <algorithm>
#include <cassert>
@@ -132,9 +131,11 @@ FUZZ_TARGET_INIT(script, initialize_script)
(void)ScriptToAsmStr(script, true);
UniValue o1(UniValue::VOBJ);
- ScriptPubKeyToUniv(script, o1, true);
+ ScriptPubKeyToUniv(script, o1, true, true);
+ ScriptPubKeyToUniv(script, o1, true, false);
UniValue o2(UniValue::VOBJ);
- ScriptPubKeyToUniv(script, o2, false);
+ ScriptPubKeyToUniv(script, o2, false, true);
+ ScriptPubKeyToUniv(script, o2, false, false);
UniValue o3(UniValue::VOBJ);
ScriptToUniv(script, o3, true);
UniValue o4(UniValue::VOBJ);
@@ -182,13 +183,13 @@ FUZZ_TARGET_INIT(script, initialize_script)
{
WitnessUnknown witness_unknown_1{};
- witness_unknown_1.version = fuzzed_data_provider.ConsumeIntegral<int>();
+ witness_unknown_1.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
witness_unknown_1.length = witness_unknown_program_1.size();
std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown_1.program);
WitnessUnknown witness_unknown_2{};
- witness_unknown_2.version = fuzzed_data_provider.ConsumeIntegral<int>();
+ witness_unknown_2.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
const std::vector<uint8_t> witness_unknown_program_2 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
witness_unknown_2.length = witness_unknown_program_2.size();
std::copy(witness_unknown_program_2.begin(), witness_unknown_program_2.end(), witness_unknown_2.program);
diff --git a/src/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp
index 2091ad5d91..cec5212f42 100644
--- a/src/test/fuzz/script_assets_test_minimizer.cpp
+++ b/src/test/fuzz/script_assets_test_minimizer.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -28,12 +28,12 @@
//
// (normal build)
// $ mkdir dump
-// $ for N in $(seq 1 10); do TEST_DUMP_DIR=dump test/functional/feature_taproot --dumptests; done
+// $ for N in $(seq 1 10); do TEST_DUMP_DIR=dump test/functional/feature_taproot.py --dumptests; done
// $ ...
//
-// (fuzz test build)
+// (libFuzzer build)
// $ mkdir dump-min
-// $ ./src/test/fuzz/script_assets_test_minimizer -merge=1 dump-min/ dump/
+// $ FUZZ=script_assets_test_minimizer ./src/test/fuzz/fuzz -merge=1 -use_value_profile=1 dump-min/ dump/
// $ (echo -en '[\n'; cat dump-min/* | head -c -2; echo -en '\n]') >script_assets_test.json
namespace {
@@ -161,7 +161,7 @@ void Test(const std::string& str)
tx.vin[idx].scriptWitness = ScriptWitnessFromJSON(test["success"]["witness"]);
PrecomputedTransactionData txdata;
txdata.Init(tx, std::vector<CTxOut>(prevouts));
- MutableTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, txdata);
+ MutableTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, txdata, MissingDataBehavior::ASSERT_FAIL);
for (const auto flags : ALL_FLAGS) {
// "final": true tests are valid for all flags. Others are only valid with flags that are
// a subset of test_flags.
@@ -176,7 +176,7 @@ void Test(const std::string& str)
tx.vin[idx].scriptWitness = ScriptWitnessFromJSON(test["failure"]["witness"]);
PrecomputedTransactionData txdata;
txdata.Init(tx, std::vector<CTxOut>(prevouts));
- MutableTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, txdata);
+ MutableTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, txdata, MissingDataBehavior::ASSERT_FAIL);
for (const auto flags : ALL_FLAGS) {
// If a test is supposed to fail with test_flags, it should also fail with any superset thereof.
if ((flags & test_flags) == test_flags) {
@@ -190,7 +190,7 @@ ECCVerifyHandle handle;
} // namespace
-FUZZ_TARGET(script_assets_test_minimizer)
+FUZZ_TARGET_INIT_HIDDEN(script_assets_test_minimizer, FuzzFrameworkEmptyInitFun, /* hidden */ true)
{
if (buffer.size() < 2 || buffer.back() != '\n' || buffer[buffer.size() - 2] != ',') return;
const std::string str((const char*)buffer.data(), buffer.size() - 2);
diff --git a/src/test/fuzz/script_descriptor_cache.cpp b/src/test/fuzz/script_descriptor_cache.cpp
index 1c62c018e7..6ce13d5679 100644
--- a/src/test/fuzz/script_descriptor_cache.cpp
+++ b/src/test/fuzz/script_descriptor_cache.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <optional.h>
#include <pubkey.h>
#include <script/descriptor.h>
#include <test/fuzz/FuzzedDataProvider.h>
@@ -10,6 +9,7 @@
#include <test/fuzz/util.h>
#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp
index ce8915ca2c..1278dc87d4 100644
--- a/src/test/fuzz/script_flags.cpp
+++ b/src/test/fuzz/script_flags.cpp
@@ -5,14 +5,11 @@
#include <pubkey.h>
#include <script/interpreter.h>
#include <streams.h>
-#include <util/memory.h>
+#include <test/util/script.h>
#include <version.h>
#include <test/fuzz/fuzz.h>
-/** Flags that are not forbidden by an assert */
-static bool IsValidFlagCombination(unsigned flags);
-
void initialize_script_flags()
{
static const ECCVerifyHandle verify_handle;
@@ -44,6 +41,10 @@ FUZZ_TARGET_INIT(script_flags, initialize_script_flags)
for (unsigned i = 0; i < tx.vin.size(); ++i) {
CTxOut prevout;
ds >> prevout;
+ if (!MoneyRange(prevout.nValue)) {
+ // prevouts should be consensus-valid
+ prevout.nValue = 1;
+ }
spent_outputs.push_back(prevout);
}
PrecomputedTransactionData txdata;
@@ -51,7 +52,7 @@ FUZZ_TARGET_INIT(script_flags, initialize_script_flags)
for (unsigned i = 0; i < tx.vin.size(); ++i) {
const CTxOut& prevout = txdata.m_spent_outputs.at(i);
- const TransactionSignatureChecker checker{&tx, i, prevout.nValue, txdata};
+ const TransactionSignatureChecker checker{&tx, i, prevout.nValue, txdata, MissingDataBehavior::ASSERT_FAIL};
ScriptError serror;
const bool ret = VerifyScript(tx.vin.at(i).scriptSig, prevout.scriptPubKey, &tx.vin.at(i).scriptWitness, verify_flags, checker, &serror);
@@ -75,10 +76,3 @@ FUZZ_TARGET_INIT(script_flags, initialize_script_flags)
return;
}
}
-
-static bool IsValidFlagCombination(unsigned flags)
-{
- if (flags & SCRIPT_VERIFY_CLEANSTACK && ~flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) return false;
- if (flags & SCRIPT_VERIFY_WITNESS && ~flags & SCRIPT_VERIFY_P2SH) return false;
- return true;
-}
diff --git a/src/test/fuzz/script_ops.cpp b/src/test/fuzz/script_ops.cpp
index d232e984bc..eb1c808a88 100644
--- a/src/test/fuzz/script_ops.cpp
+++ b/src/test/fuzz/script_ops.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -16,56 +16,53 @@ FUZZ_TARGET(script_ops)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
CScript script = ConsumeScript(fuzzed_data_provider);
while (fuzzed_data_provider.remaining_bytes() > 0) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) {
- case 0: {
- CScript s = ConsumeScript(fuzzed_data_provider);
- script = std::move(s);
- break;
- }
- case 1: {
- const CScript& s = ConsumeScript(fuzzed_data_provider);
- script = s;
- break;
- }
- case 2:
- script << fuzzed_data_provider.ConsumeIntegral<int64_t>();
- break;
- case 3:
- script << ConsumeOpcodeType(fuzzed_data_provider);
- break;
- case 4:
- script << ConsumeScriptNum(fuzzed_data_provider);
- break;
- case 5:
- script << ConsumeRandomLengthByteVector(fuzzed_data_provider);
- break;
- case 6:
- script.clear();
- break;
- case 7: {
- (void)script.GetSigOpCount(false);
- (void)script.GetSigOpCount(true);
- (void)script.GetSigOpCount(script);
- (void)script.HasValidOps();
- (void)script.IsPayToScriptHash();
- (void)script.IsPayToWitnessScriptHash();
- (void)script.IsPushOnly();
- (void)script.IsUnspendable();
- {
- CScript::const_iterator pc = script.begin();
- opcodetype opcode;
- (void)script.GetOp(pc, opcode);
- std::vector<uint8_t> data;
- (void)script.GetOp(pc, opcode, data);
- (void)script.IsPushOnly(pc);
- }
- {
- int version;
- std::vector<uint8_t> program;
- (void)script.IsWitnessProgram(version, program);
- }
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ CScript s = ConsumeScript(fuzzed_data_provider);
+ script = std::move(s);
+ },
+ [&] {
+ const CScript& s = ConsumeScript(fuzzed_data_provider);
+ script = s;
+ },
+ [&] {
+ script << fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ },
+ [&] {
+ script << ConsumeOpcodeType(fuzzed_data_provider);
+ },
+ [&] {
+ script << ConsumeScriptNum(fuzzed_data_provider);
+ },
+ [&] {
+ script << ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ },
+ [&] {
+ script.clear();
+ },
+ [&] {
+ (void)script.GetSigOpCount(false);
+ (void)script.GetSigOpCount(true);
+ (void)script.GetSigOpCount(script);
+ (void)script.HasValidOps();
+ (void)script.IsPayToScriptHash();
+ (void)script.IsPayToWitnessScriptHash();
+ (void)script.IsPushOnly();
+ (void)script.IsUnspendable();
+ {
+ CScript::const_iterator pc = script.begin();
+ opcodetype opcode;
+ (void)script.GetOp(pc, opcode);
+ std::vector<uint8_t> data;
+ (void)script.GetOp(pc, opcode, data);
+ (void)script.IsPushOnly(pc);
+ }
+ {
+ int version;
+ std::vector<uint8_t> program;
+ (void)script.IsWitnessProgram(version, program);
+ }
+ });
}
}
diff --git a/src/test/fuzz/scriptnum_ops.cpp b/src/test/fuzz/scriptnum_ops.cpp
index 650318f13c..62ed50d13f 100644
--- a/src/test/fuzz/scriptnum_ops.cpp
+++ b/src/test/fuzz/scriptnum_ops.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -29,105 +29,99 @@ FUZZ_TARGET(scriptnum_ops)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
CScriptNum script_num = ConsumeScriptNum(fuzzed_data_provider);
while (fuzzed_data_provider.remaining_bytes() > 0) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 11)) {
- case 0: {
- const int64_t i = fuzzed_data_provider.ConsumeIntegral<int64_t>();
- assert((script_num == i) != (script_num != i));
- assert((script_num <= i) != (script_num > i));
- assert((script_num >= i) != (script_num < i));
- // Avoid signed integer overflow:
- // script/script.h:264:93: runtime error: signed integer overflow: -2261405121394637306 + -9223372036854775802 cannot be represented in type 'long'
- if (IsValidAddition(script_num, CScriptNum{i})) {
- assert((script_num + i) - i == script_num);
- }
- // Avoid signed integer overflow:
- // script/script.h:265:93: runtime error: signed integer overflow: 9223371895120855039 - -9223372036854710486 cannot be represented in type 'long'
- if (IsValidSubtraction(script_num, CScriptNum{i})) {
- assert((script_num - i) + i == script_num);
- }
- break;
- }
- case 1: {
- const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider);
- assert((script_num == random_script_num) != (script_num != random_script_num));
- assert((script_num <= random_script_num) != (script_num > random_script_num));
- assert((script_num >= random_script_num) != (script_num < random_script_num));
- // Avoid signed integer overflow:
- // script/script.h:264:93: runtime error: signed integer overflow: -9223126527765971126 + -9223372036854756825 cannot be represented in type 'long'
- if (IsValidAddition(script_num, random_script_num)) {
- assert((script_num + random_script_num) - random_script_num == script_num);
- }
- // Avoid signed integer overflow:
- // script/script.h:265:93: runtime error: signed integer overflow: 6052837899185946624 - -9223372036854775808 cannot be represented in type 'long'
- if (IsValidSubtraction(script_num, random_script_num)) {
- assert((script_num - random_script_num) + random_script_num == script_num);
- }
- break;
- }
- case 2: {
- const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider);
- if (!IsValidAddition(script_num, random_script_num)) {
- // Avoid assertion failure:
- // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed.
- break;
- }
- script_num += random_script_num;
- break;
- }
- case 3: {
- const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider);
- if (!IsValidSubtraction(script_num, random_script_num)) {
- // Avoid assertion failure:
- // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed.
- break;
- }
- script_num -= random_script_num;
- break;
- }
- case 4:
- script_num = script_num & fuzzed_data_provider.ConsumeIntegral<int64_t>();
- break;
- case 5:
- script_num = script_num & ConsumeScriptNum(fuzzed_data_provider);
- break;
- case 6:
- script_num &= ConsumeScriptNum(fuzzed_data_provider);
- break;
- case 7:
- if (script_num == CScriptNum{std::numeric_limits<int64_t>::min()}) {
- // Avoid assertion failure:
- // ./script/script.h:279: CScriptNum CScriptNum::operator-() const: Assertion `m_value != std::numeric_limits<int64_t>::min()' failed.
- break;
- }
- script_num = -script_num;
- break;
- case 8:
- script_num = fuzzed_data_provider.ConsumeIntegral<int64_t>();
- break;
- case 9: {
- const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>();
- if (!IsValidAddition(script_num, CScriptNum{random_integer})) {
- // Avoid assertion failure:
- // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed.
- break;
- }
- script_num += random_integer;
- break;
- }
- case 10: {
- const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>();
- if (!IsValidSubtraction(script_num, CScriptNum{random_integer})) {
- // Avoid assertion failure:
- // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed.
- break;
- }
- script_num -= random_integer;
- break;
- }
- case 11:
- script_num &= fuzzed_data_provider.ConsumeIntegral<int64_t>();
- break;
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ const int64_t i = fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ assert((script_num == i) != (script_num != i));
+ assert((script_num <= i) != (script_num > i));
+ assert((script_num >= i) != (script_num < i));
+ // Avoid signed integer overflow:
+ // script/script.h:264:93: runtime error: signed integer overflow: -2261405121394637306 + -9223372036854775802 cannot be represented in type 'long'
+ if (IsValidAddition(script_num, CScriptNum{i})) {
+ assert((script_num + i) - i == script_num);
+ }
+ // Avoid signed integer overflow:
+ // script/script.h:265:93: runtime error: signed integer overflow: 9223371895120855039 - -9223372036854710486 cannot be represented in type 'long'
+ if (IsValidSubtraction(script_num, CScriptNum{i})) {
+ assert((script_num - i) + i == script_num);
+ }
+ },
+ [&] {
+ const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider);
+ assert((script_num == random_script_num) != (script_num != random_script_num));
+ assert((script_num <= random_script_num) != (script_num > random_script_num));
+ assert((script_num >= random_script_num) != (script_num < random_script_num));
+ // Avoid signed integer overflow:
+ // script/script.h:264:93: runtime error: signed integer overflow: -9223126527765971126 + -9223372036854756825 cannot be represented in type 'long'
+ if (IsValidAddition(script_num, random_script_num)) {
+ assert((script_num + random_script_num) - random_script_num == script_num);
+ }
+ // Avoid signed integer overflow:
+ // script/script.h:265:93: runtime error: signed integer overflow: 6052837899185946624 - -9223372036854775808 cannot be represented in type 'long'
+ if (IsValidSubtraction(script_num, random_script_num)) {
+ assert((script_num - random_script_num) + random_script_num == script_num);
+ }
+ },
+ [&] {
+ const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider);
+ if (!IsValidAddition(script_num, random_script_num)) {
+ // Avoid assertion failure:
+ // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed.
+ return;
+ }
+ script_num += random_script_num;
+ },
+ [&] {
+ const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider);
+ if (!IsValidSubtraction(script_num, random_script_num)) {
+ // Avoid assertion failure:
+ // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed.
+ return;
+ }
+ script_num -= random_script_num;
+ },
+ [&] {
+ script_num = script_num & fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ },
+ [&] {
+ script_num = script_num & ConsumeScriptNum(fuzzed_data_provider);
+ },
+ [&] {
+ script_num &= ConsumeScriptNum(fuzzed_data_provider);
+ },
+ [&] {
+ if (script_num == CScriptNum{std::numeric_limits<int64_t>::min()}) {
+ // Avoid assertion failure:
+ // ./script/script.h:279: CScriptNum CScriptNum::operator-() const: Assertion `m_value != std::numeric_limits<int64_t>::min()' failed.
+ return;
+ }
+ script_num = -script_num;
+ },
+ [&] {
+ script_num = fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ },
+ [&] {
+ const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ if (!IsValidAddition(script_num, CScriptNum{random_integer})) {
+ // Avoid assertion failure:
+ // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed.
+ return;
+ }
+ script_num += random_integer;
+ },
+ [&] {
+ const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ if (!IsValidSubtraction(script_num, CScriptNum{random_integer})) {
+ // Avoid assertion failure:
+ // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed.
+ return;
+ }
+ script_num -= random_integer;
+ },
+ [&] {
+ script_num &= fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ });
(void)script_num.getint();
(void)script_num.getvch();
}
diff --git a/src/test/fuzz/signature_checker.cpp b/src/test/fuzz/signature_checker.cpp
index 3e7b72805e..6b86c8889d 100644
--- a/src/test/fuzz/signature_checker.cpp
+++ b/src/test/fuzz/signature_checker.cpp
@@ -6,7 +6,8 @@
#include <script/interpreter.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
-#include <util/memory.h>
+#include <test/fuzz/util.h>
+#include <test/util/script.h>
#include <cstdint>
#include <limits>
@@ -15,7 +16,7 @@
void initialize_signature_checker()
{
- static const auto verify_handle = MakeUnique<ECCVerifyHandle>();
+ static const auto verify_handle = std::make_unique<ECCVerifyHandle>();
}
namespace {
@@ -57,17 +58,12 @@ FUZZ_TARGET_INIT(signature_checker, initialize_signature_checker)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
const SigVersion sig_version = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0});
- const std::string script_string_1 = fuzzed_data_provider.ConsumeRandomLengthString(65536);
- const std::vector<uint8_t> script_bytes_1{script_string_1.begin(), script_string_1.end()};
- const std::string script_string_2 = fuzzed_data_provider.ConsumeRandomLengthString(65536);
- const std::vector<uint8_t> script_bytes_2{script_string_2.begin(), script_string_2.end()};
+ const auto script_1 = ConsumeScript(fuzzed_data_provider, 65536);
+ const auto script_2 = ConsumeScript(fuzzed_data_provider, 65536);
std::vector<std::vector<unsigned char>> stack;
- (void)EvalScript(stack, {script_bytes_1.begin(), script_bytes_1.end()}, flags, FuzzedSignatureChecker(fuzzed_data_provider), sig_version, nullptr);
- if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0 && ((flags & SCRIPT_VERIFY_P2SH) == 0 || (flags & SCRIPT_VERIFY_WITNESS) == 0)) {
+ (void)EvalScript(stack, script_1, flags, FuzzedSignatureChecker(fuzzed_data_provider), sig_version, nullptr);
+ if (!IsValidFlagCombination(flags)) {
return;
}
- if ((flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
- return;
- }
- (void)VerifyScript({script_bytes_1.begin(), script_bytes_1.end()}, {script_bytes_2.begin(), script_bytes_2.end()}, nullptr, flags, FuzzedSignatureChecker(fuzzed_data_provider), nullptr);
+ (void)VerifyScript(script_1, script_2, nullptr, flags, FuzzedSignatureChecker(fuzzed_data_provider), nullptr);
}
diff --git a/src/test/fuzz/signet.cpp b/src/test/fuzz/signet.cpp
index 541322d484..303dcf13e3 100644
--- a/src/test/fuzz/signet.cpp
+++ b/src/test/fuzz/signet.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,6 +10,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
#include <cstdint>
#include <optional>
@@ -17,7 +18,7 @@
void initialize_signet()
{
- InitializeFuzzingContext(CBaseChainParams::SIGNET);
+ static const auto testing_setup = MakeNoLogFileContext<>(CBaseChainParams::SIGNET);
}
FUZZ_TARGET_INIT(signet, initialize_signet)
diff --git a/src/test/fuzz/socks5.cpp b/src/test/fuzz/socks5.cpp
new file mode 100644
index 0000000000..c3a6eed089
--- /dev/null
+++ b/src/test/fuzz/socks5.cpp
@@ -0,0 +1,45 @@
+// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <netaddress.h>
+#include <netbase.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace {
+int default_socks5_recv_timeout;
+};
+
+extern int g_socks5_recv_timeout;
+
+void initialize_socks5()
+{
+ static const auto testing_setup = MakeNoLogFileContext<const BasicTestingSetup>();
+ default_socks5_recv_timeout = g_socks5_recv_timeout;
+}
+
+FUZZ_TARGET_INIT(socks5, initialize_socks5)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ ProxyCredentials proxy_credentials;
+ proxy_credentials.username = fuzzed_data_provider.ConsumeRandomLengthString(512);
+ proxy_credentials.password = fuzzed_data_provider.ConsumeRandomLengthString(512);
+ InterruptSocks5(fuzzed_data_provider.ConsumeBool());
+ // Set FUZZED_SOCKET_FAKE_LATENCY=1 to exercise recv timeout code paths. This
+ // will slow down fuzzing.
+ g_socks5_recv_timeout = (fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) ? 1 : default_socks5_recv_timeout;
+ FuzzedSock fuzzed_sock = ConsumeSock(fuzzed_data_provider);
+ // This Socks5(...) fuzzing harness would have caught CVE-2017-18350 within
+ // a few seconds of fuzzing.
+ (void)Socks5(fuzzed_data_provider.ConsumeRandomLengthString(512),
+ fuzzed_data_provider.ConsumeIntegral<uint16_t>(),
+ fuzzed_data_provider.ConsumeBool() ? &proxy_credentials : nullptr,
+ fuzzed_sock);
+}
diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp
index 282a2cd8ca..286375f7ae 100644
--- a/src/test/fuzz/string.cpp
+++ b/src/test/fuzz/string.cpp
@@ -1,10 +1,11 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <blockfilter.h>
#include <clientversion.h>
#include <logging.h>
+#include <netaddress.h>
#include <netbase.h>
#include <outputtype.h>
#include <rpc/client.h>
@@ -67,6 +68,7 @@ FUZZ_TARGET(string)
}
OutputType output_type;
(void)ParseOutputType(random_string_1, output_type);
+ (void)RemovePrefix(random_string_1, random_string_2);
(void)ResolveErrMsg(random_string_1, random_string_2);
try {
(void)RPCConvertNamedValues(random_string_1, random_string_vector);
@@ -78,8 +80,10 @@ FUZZ_TARGET(string)
}
(void)SanitizeString(random_string_1);
(void)SanitizeString(random_string_1, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 3));
+#ifndef WIN32
(void)ShellEscape(random_string_1);
- int port_out;
+#endif // WIN32
+ uint16_t port_out;
std::string host_out;
SplitHostPort(random_string_1, port_out, host_out);
(void)TimingResistantEqual(random_string_1, random_string_2);
diff --git a/src/test/fuzz/strprintf.cpp b/src/test/fuzz/strprintf.cpp
index 4af0e750ce..2c92b159a5 100644
--- a/src/test/fuzz/strprintf.cpp
+++ b/src/test/fuzz/strprintf.cpp
@@ -1,9 +1,10 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
#include <tinyformat.h>
#include <util/strencodings.h>
#include <util/translation.h>
@@ -109,32 +110,32 @@ FUZZ_TARGET(str_printf)
}
try {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 5)) {
- case 0:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
- break;
- case 1:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
- break;
- case 2:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
- break;
- case 3:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
- break;
- case 4:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<char>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<char>());
- break;
- case 5:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeBool());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeBool());
- break;
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<char>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<char>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeBool());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeBool());
+ });
} catch (const tinyformat::format_error&) {
}
@@ -155,40 +156,40 @@ FUZZ_TARGET(str_printf)
}
try {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) {
- case 0:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
- break;
- case 1:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
- break;
- case 2:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
- break;
- case 3:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
- break;
- case 4:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
- break;
- case 5:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
- break;
- case 6:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
- break;
- case 7:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- break;
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ });
} catch (const tinyformat::format_error&) {
}
}
diff --git a/src/test/fuzz/system.cpp b/src/test/fuzz/system.cpp
index 375a8c1ed0..b25dcfcd3b 100644
--- a/src/test/fuzz/system.cpp
+++ b/src/test/fuzz/system.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Bitcoin Core developers
+// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -32,71 +32,63 @@ FUZZ_TARGET(system)
}
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 7)) {
- case 0: {
- args_manager.SelectConfigNetwork(fuzzed_data_provider.ConsumeRandomLengthString(16));
- break;
- }
- case 1: {
- args_manager.SoftSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16));
- break;
- }
- case 2: {
- args_manager.ForceSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16));
- break;
- }
- case 3: {
- args_manager.SoftSetBoolArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeBool());
- break;
- }
- case 4: {
- const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::HIDDEN});
- // Avoid hitting:
- // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
- const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16));
- if (args_manager.GetArgFlags(argument_name) != nullopt) {
- break;
- }
- args_manager.AddArg(argument_name, fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeIntegral<unsigned int>(), options_category);
- break;
- }
- case 5: {
- // Avoid hitting:
- // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
- const std::vector<std::string> names = ConsumeRandomLengthStringVector(fuzzed_data_provider);
- std::vector<std::string> hidden_arguments;
- for (const std::string& name : names) {
- const std::string hidden_argument = GetArgumentName(name);
- if (args_manager.GetArgFlags(hidden_argument) != nullopt) {
- continue;
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ args_manager.SelectConfigNetwork(fuzzed_data_provider.ConsumeRandomLengthString(16));
+ },
+ [&] {
+ args_manager.SoftSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16));
+ },
+ [&] {
+ args_manager.ForceSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16));
+ },
+ [&] {
+ args_manager.SoftSetBoolArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::HIDDEN});
+ // Avoid hitting:
+ // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
+ const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16));
+ if (args_manager.GetArgFlags(argument_name) != std::nullopt) {
+ return;
}
- if (std::find(hidden_arguments.begin(), hidden_arguments.end(), hidden_argument) != hidden_arguments.end()) {
- continue;
+ args_manager.AddArg(argument_name, fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeIntegral<unsigned int>() & ~ArgsManager::COMMAND, options_category);
+ },
+ [&] {
+ // Avoid hitting:
+ // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
+ const std::vector<std::string> names = ConsumeRandomLengthStringVector(fuzzed_data_provider);
+ std::vector<std::string> hidden_arguments;
+ for (const std::string& name : names) {
+ const std::string hidden_argument = GetArgumentName(name);
+ if (args_manager.GetArgFlags(hidden_argument) != std::nullopt) {
+ continue;
+ }
+ if (std::find(hidden_arguments.begin(), hidden_arguments.end(), hidden_argument) != hidden_arguments.end()) {
+ continue;
+ }
+ hidden_arguments.push_back(hidden_argument);
}
- hidden_arguments.push_back(hidden_argument);
- }
- args_manager.AddHiddenArgs(hidden_arguments);
- break;
- }
- case 6: {
- args_manager.ClearArgs();
- break;
- }
- case 7: {
- const std::vector<std::string> random_arguments = ConsumeRandomLengthStringVector(fuzzed_data_provider);
- std::vector<const char*> argv;
- argv.reserve(random_arguments.size());
- for (const std::string& random_argument : random_arguments) {
- argv.push_back(random_argument.c_str());
- }
- try {
- std::string error;
- (void)args_manager.ParseParameters(argv.size(), argv.data(), error);
- } catch (const std::logic_error&) {
- }
- break;
- }
- }
+ args_manager.AddHiddenArgs(hidden_arguments);
+ },
+ [&] {
+ args_manager.ClearArgs();
+ },
+ [&] {
+ const std::vector<std::string> random_arguments = ConsumeRandomLengthStringVector(fuzzed_data_provider);
+ std::vector<const char*> argv;
+ argv.reserve(random_arguments.size());
+ for (const std::string& random_argument : random_arguments) {
+ argv.push_back(random_argument.c_str());
+ }
+ try {
+ std::string error;
+ (void)args_manager.ParseParameters(argv.size(), argv.data(), error);
+ } catch (const std::logic_error&) {
+ }
+ });
}
const std::string s1 = fuzzed_data_provider.ConsumeRandomLengthString(16);
diff --git a/src/test/fuzz/torcontrol.cpp b/src/test/fuzz/torcontrol.cpp
new file mode 100644
index 0000000000..a97d3962bf
--- /dev/null
+++ b/src/test/fuzz/torcontrol.cpp
@@ -0,0 +1,80 @@
+// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <torcontrol.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+class DummyTorControlConnection : public TorControlConnection
+{
+public:
+ DummyTorControlConnection() : TorControlConnection{nullptr}
+ {
+ }
+
+ bool Connect(const std::string&, const ConnectionCB&, const ConnectionCB&)
+ {
+ return true;
+ }
+
+ void Disconnect()
+ {
+ }
+
+ bool Command(const std::string&, const ReplyHandlerCB&)
+ {
+ return true;
+ }
+};
+
+void initialize_torcontrol()
+{
+ static const auto testing_setup = MakeNoLogFileContext<>();
+}
+
+FUZZ_TARGET_INIT(torcontrol, initialize_torcontrol)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+
+ TorController tor_controller;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ TorControlReply tor_control_reply;
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ tor_control_reply.code = 250;
+ },
+ [&] {
+ tor_control_reply.code = 510;
+ },
+ [&] {
+ tor_control_reply.code = fuzzed_data_provider.ConsumeIntegral<int>();
+ });
+ tor_control_reply.lines = ConsumeRandomLengthStringVector(fuzzed_data_provider);
+ if (tor_control_reply.lines.empty()) {
+ break;
+ }
+ DummyTorControlConnection dummy_tor_control_connection;
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ tor_controller.add_onion_cb(dummy_tor_control_connection, tor_control_reply);
+ },
+ [&] {
+ tor_controller.auth_cb(dummy_tor_control_connection, tor_control_reply);
+ },
+ [&] {
+ tor_controller.authchallenge_cb(dummy_tor_control_connection, tor_control_reply);
+ },
+ [&] {
+ tor_controller.protocolinfo_cb(dummy_tor_control_connection, tor_control_reply);
+ });
+ }
+}
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index 13ae450756..17e4405a13 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -100,16 +100,9 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
(void)IsWitnessStandard(tx, coins_view_cache);
UniValue u(UniValue::VOBJ);
- // ValueFromAmount(i) not defined when i == std::numeric_limits<int64_t>::min()
- bool skip_tx_to_univ = false;
- for (const CTxOut& txout : tx.vout) {
- if (txout.nValue == std::numeric_limits<int64_t>::min()) {
- skip_tx_to_univ = true;
- }
- }
- if (!skip_tx_to_univ) {
- TxToUniv(tx, /* hashBlock */ {}, u);
- static const uint256 u256_max(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
- TxToUniv(tx, u256_max, u);
- }
+ TxToUniv(tx, /* hashBlock */ {}, /* include_addresses */ true, u);
+ TxToUniv(tx, /* hashBlock */ {}, /* include_addresses */ false, u);
+ static const uint256 u256_max(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
+ TxToUniv(tx, u256_max, /* include_addresses */ true, u);
+ TxToUniv(tx, u256_max, /* include_addresses */ false, u);
}
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
new file mode 100644
index 0000000000..fe8d17b24a
--- /dev/null
+++ b/src/test/fuzz/tx_pool.cpp
@@ -0,0 +1,285 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <consensus/validation.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/mining.h>
+#include <test/util/script.h>
+#include <test/util/setup_common.h>
+#include <util/rbf.h>
+#include <validation.h>
+#include <validationinterface.h>
+
+namespace {
+
+const TestingSetup* g_setup;
+std::vector<COutPoint> g_outpoints_coinbase_init_mature;
+std::vector<COutPoint> g_outpoints_coinbase_init_immature;
+
+struct MockedTxPool : public CTxMemPool {
+ void RollingFeeUpdate()
+ {
+ lastRollingFeeUpdate = GetTime();
+ blockSinceLastRollingFeeBump = true;
+ }
+};
+
+void initialize_tx_pool()
+{
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+ g_setup = testing_setup.get();
+
+ for (int i = 0; i < 2 * COINBASE_MATURITY; ++i) {
+ CTxIn in = MineBlock(g_setup->m_node, P2WSH_OP_TRUE);
+ // Remember the txids to avoid expensive disk access later on
+ auto& outpoints = i < COINBASE_MATURITY ?
+ g_outpoints_coinbase_init_mature :
+ g_outpoints_coinbase_init_immature;
+ outpoints.push_back(in.prevout);
+ }
+ SyncWithValidationInterfaceQueue();
+}
+
+struct TransactionsDelta final : public CValidationInterface {
+ std::set<CTransactionRef>& m_removed;
+ std::set<CTransactionRef>& m_added;
+
+ explicit TransactionsDelta(std::set<CTransactionRef>& r, std::set<CTransactionRef>& a)
+ : m_removed{r}, m_added{a} {}
+
+ void TransactionAddedToMempool(const CTransactionRef& tx, uint64_t /* mempool_sequence */) override
+ {
+ Assert(m_added.insert(tx).second);
+ }
+
+ void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t /* mempool_sequence */) override
+ {
+ Assert(m_removed.insert(tx).second);
+ }
+};
+
+void SetMempoolConstraints(ArgsManager& args, FuzzedDataProvider& fuzzed_data_provider)
+{
+ args.ForceSetArg("-limitancestorcount",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 50)));
+ args.ForceSetArg("-limitancestorsize",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 202)));
+ args.ForceSetArg("-limitdescendantcount",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 50)));
+ args.ForceSetArg("-limitdescendantsize",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 202)));
+ args.ForceSetArg("-maxmempool",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 200)));
+ args.ForceSetArg("-mempoolexpiry",
+ ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 999)));
+}
+
+FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const auto& node = g_setup->m_node;
+ auto& chainstate = node.chainman->ActiveChainstate();
+
+ SetMockTime(ConsumeTime(fuzzed_data_provider));
+ SetMempoolConstraints(*node.args, fuzzed_data_provider);
+
+ // All RBF-spendable outpoints
+ std::set<COutPoint> outpoints_rbf;
+ // All outpoints counting toward the total supply (subset of outpoints_rbf)
+ std::set<COutPoint> outpoints_supply;
+ for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
+ Assert(outpoints_supply.insert(outpoint).second);
+ }
+ outpoints_rbf = outpoints_supply;
+
+ // The sum of the values of all spendable outpoints
+ constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};
+
+ CTxMemPool tx_pool_{/* estimator */ nullptr, /* check_ratio */ 1};
+ MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
+
+ // Helper to query an amount
+ const CCoinsViewMemPool amount_view{WITH_LOCK(::cs_main, return &chainstate.CoinsTip()), tx_pool};
+ const auto GetAmount = [&](const COutPoint& outpoint) {
+ Coin c;
+ Assert(amount_view.GetCoin(outpoint, c));
+ return c.out.nValue;
+ };
+
+ while (fuzzed_data_provider.ConsumeBool()) {
+ {
+ // Total supply is the mempool fee + all outpoints
+ CAmount supply_now{WITH_LOCK(tx_pool.cs, return tx_pool.GetTotalFee())};
+ for (const auto& op : outpoints_supply) {
+ supply_now += GetAmount(op);
+ }
+ Assert(supply_now == SUPPLY_TOTAL);
+ }
+ Assert(!outpoints_supply.empty());
+
+ // Create transaction to add to the mempool
+ const CTransactionRef tx = [&] {
+ CMutableTransaction tx_mut;
+ tx_mut.nVersion = CTransaction::CURRENT_VERSION;
+ tx_mut.nLockTime = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+ const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, outpoints_rbf.size());
+ const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, outpoints_rbf.size() * 2);
+
+ CAmount amount_in{0};
+ for (int i = 0; i < num_in; ++i) {
+ // Pop random outpoint
+ auto pop = outpoints_rbf.begin();
+ std::advance(pop, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, outpoints_rbf.size() - 1));
+ const auto outpoint = *pop;
+ outpoints_rbf.erase(pop);
+ amount_in += GetAmount(outpoint);
+
+ // Create input
+ const auto sequence = ConsumeSequence(fuzzed_data_provider);
+ const auto script_sig = CScript{};
+ const auto script_wit_stack = std::vector<std::vector<uint8_t>>{WITNESS_STACK_ELEM_OP_TRUE};
+ CTxIn in;
+ in.prevout = outpoint;
+ in.nSequence = sequence;
+ in.scriptSig = script_sig;
+ in.scriptWitness.stack = script_wit_stack;
+
+ tx_mut.vin.push_back(in);
+ }
+ const auto amount_fee = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-1000, amount_in);
+ const auto amount_out = (amount_in - amount_fee) / num_out;
+ for (int i = 0; i < num_out; ++i) {
+ tx_mut.vout.emplace_back(amount_out, P2WSH_OP_TRUE);
+ }
+ const auto tx = MakeTransactionRef(tx_mut);
+ // Restore previously removed outpoints
+ for (const auto& in : tx->vin) {
+ Assert(outpoints_rbf.insert(in.prevout).second);
+ }
+ return tx;
+ }();
+
+ if (fuzzed_data_provider.ConsumeBool()) {
+ SetMockTime(ConsumeTime(fuzzed_data_provider));
+ }
+ if (fuzzed_data_provider.ConsumeBool()) {
+ SetMempoolConstraints(*node.args, fuzzed_data_provider);
+ }
+ if (fuzzed_data_provider.ConsumeBool()) {
+ tx_pool.RollingFeeUpdate();
+ }
+ if (fuzzed_data_provider.ConsumeBool()) {
+ const auto& txid = fuzzed_data_provider.ConsumeBool() ?
+ tx->GetHash() :
+ PickValue(fuzzed_data_provider, outpoints_rbf).hash;
+ const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
+ tx_pool.PrioritiseTransaction(txid, delta);
+ }
+
+ // Remember all removed and added transactions
+ std::set<CTransactionRef> removed;
+ std::set<CTransactionRef> added;
+ auto txr = std::make_shared<TransactionsDelta>(removed, added);
+ RegisterSharedValidationInterface(txr);
+ const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
+ ::fRequireStandard = fuzzed_data_provider.ConsumeBool();
+ const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx_pool, tx, bypass_limits));
+ const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
+ SyncWithValidationInterfaceQueue();
+ UnregisterSharedValidationInterface(txr);
+
+ Assert(accepted != added.empty());
+ Assert(accepted == res.m_state.IsValid());
+ Assert(accepted != res.m_state.IsInvalid());
+ if (accepted) {
+ Assert(added.size() == 1); // For now, no package acceptance
+ Assert(tx == *added.begin());
+ } else {
+ // Do not consider rejected transaction removed
+ removed.erase(tx);
+ }
+
+ // Helper to insert spent and created outpoints of a tx into collections
+ using Sets = std::vector<std::reference_wrapper<std::set<COutPoint>>>;
+ const auto insert_tx = [](Sets created_by_tx, Sets consumed_by_tx, const auto& tx) {
+ for (size_t i{0}; i < tx.vout.size(); ++i) {
+ for (auto& set : created_by_tx) {
+ Assert(set.get().emplace(tx.GetHash(), i).second);
+ }
+ }
+ for (const auto& in : tx.vin) {
+ for (auto& set : consumed_by_tx) {
+ Assert(set.get().insert(in.prevout).second);
+ }
+ }
+ };
+ // Add created outpoints, remove spent outpoints
+ {
+ // Outpoints that no longer exist at all
+ std::set<COutPoint> consumed_erased;
+ // Outpoints that no longer count toward the total supply
+ std::set<COutPoint> consumed_supply;
+ for (const auto& removed_tx : removed) {
+ insert_tx(/* created_by_tx */ {consumed_erased}, /* consumed_by_tx */ {outpoints_supply}, /* tx */ *removed_tx);
+ }
+ for (const auto& added_tx : added) {
+ insert_tx(/* created_by_tx */ {outpoints_supply, outpoints_rbf}, /* consumed_by_tx */ {consumed_supply}, /* tx */ *added_tx);
+ }
+ for (const auto& p : consumed_erased) {
+ Assert(outpoints_supply.erase(p) == 1);
+ Assert(outpoints_rbf.erase(p) == 1);
+ }
+ for (const auto& p : consumed_supply) {
+ Assert(outpoints_supply.erase(p) == 1);
+ }
+ }
+ }
+ WITH_LOCK(::cs_main, tx_pool.check(chainstate));
+ const auto info_all = tx_pool.infoAll();
+ if (!info_all.empty()) {
+ const auto& tx_to_remove = *PickValue(fuzzed_data_provider, info_all).tx;
+ WITH_LOCK(tx_pool.cs, tx_pool.removeRecursive(tx_to_remove, /* dummy */ MemPoolRemovalReason::BLOCK));
+ std::vector<uint256> all_txids;
+ tx_pool.queryHashes(all_txids);
+ assert(all_txids.size() < info_all.size());
+ WITH_LOCK(::cs_main, tx_pool.check(chainstate));
+ }
+ SyncWithValidationInterfaceQueue();
+}
+
+FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const auto& node = g_setup->m_node;
+
+ std::vector<uint256> txids;
+ for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
+ txids.push_back(outpoint.hash);
+ }
+ for (int i{0}; i <= 3; ++i) {
+ // Add some immature and non-existent outpoints
+ txids.push_back(g_outpoints_coinbase_init_immature.at(i).hash);
+ txids.push_back(ConsumeUInt256(fuzzed_data_provider));
+ }
+
+ CTxMemPool tx_pool{/* estimator */ nullptr, /* check_ratio */ 1};
+
+ while (fuzzed_data_provider.ConsumeBool()) {
+ const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids);
+
+ const auto tx = MakeTransactionRef(mut_tx);
+ const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
+ ::fRequireStandard = fuzzed_data_provider.ConsumeBool();
+ const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(node.chainman->ActiveChainstate(), tx_pool, tx, bypass_limits));
+ const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
+ if (accepted) {
+ txids.push_back(tx->GetHash());
+ }
+
+ SyncWithValidationInterfaceQueue();
+ }
+}
+} // namespace
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
new file mode 100644
index 0000000000..b8d846a995
--- /dev/null
+++ b/src/test/fuzz/util.cpp
@@ -0,0 +1,292 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <test/fuzz/util.h>
+#include <test/util/script.h>
+#include <util/rbf.h>
+#include <version.h>
+
+FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider)
+ : m_fuzzed_data_provider{fuzzed_data_provider}
+{
+ m_socket = fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET);
+}
+
+FuzzedSock::~FuzzedSock()
+{
+ // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call
+ // Sock::Reset() (not FuzzedSock::Reset()!) which will call CloseSocket(m_socket).
+ // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which
+ // theoretically may concide with a real opened file descriptor).
+ Reset();
+}
+
+FuzzedSock& FuzzedSock::operator=(Sock&& other)
+{
+ assert(false && "Move of Sock into FuzzedSock not allowed.");
+ return *this;
+}
+
+void FuzzedSock::Reset()
+{
+ m_socket = INVALID_SOCKET;
+}
+
+ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const
+{
+ constexpr std::array send_errnos{
+ EACCES,
+ EAGAIN,
+ EALREADY,
+ EBADF,
+ ECONNRESET,
+ EDESTADDRREQ,
+ EFAULT,
+ EINTR,
+ EINVAL,
+ EISCONN,
+ EMSGSIZE,
+ ENOBUFS,
+ ENOMEM,
+ ENOTCONN,
+ ENOTSOCK,
+ EOPNOTSUPP,
+ EPIPE,
+ EWOULDBLOCK,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ return len;
+ }
+ const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
+ if (r == -1) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos);
+ }
+ return r;
+}
+
+ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
+{
+ // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted
+ // SetFuzzedErrNo() will always return the first element and we want to avoid Recv()
+ // returning -1 and setting errno to EAGAIN repeatedly.
+ constexpr std::array recv_errnos{
+ ECONNREFUSED,
+ EAGAIN,
+ EBADF,
+ EFAULT,
+ EINTR,
+ EINVAL,
+ ENOMEM,
+ ENOTCONN,
+ ENOTSOCK,
+ EWOULDBLOCK,
+ };
+ assert(buf != nullptr || len == 0);
+ if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
+ const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
+ if (r == -1) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos);
+ }
+ return r;
+ }
+ std::vector<uint8_t> random_bytes;
+ bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()};
+ if (m_peek_data.has_value()) {
+ // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`.
+ random_bytes.assign({m_peek_data.value()});
+ if ((flags & MSG_PEEK) == 0) {
+ m_peek_data.reset();
+ }
+ pad_to_len_bytes = false;
+ } else if ((flags & MSG_PEEK) != 0) {
+ // New call with `MSG_PEEK`.
+ random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1);
+ if (!random_bytes.empty()) {
+ m_peek_data = random_bytes[0];
+ pad_to_len_bytes = false;
+ }
+ } else {
+ random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(
+ m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len));
+ }
+ if (random_bytes.empty()) {
+ const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
+ if (r == -1) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos);
+ }
+ return r;
+ }
+ std::memcpy(buf, random_bytes.data(), random_bytes.size());
+ if (pad_to_len_bytes) {
+ if (len > random_bytes.size()) {
+ std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size());
+ }
+ return len;
+ }
+ if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
+ std::this_thread::sleep_for(std::chrono::milliseconds{2});
+ }
+ return random_bytes.size();
+}
+
+int FuzzedSock::Connect(const sockaddr*, socklen_t) const
+{
+ // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
+ // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
+ // returning -1 and setting errno to EAGAIN repeatedly.
+ constexpr std::array connect_errnos{
+ ECONNREFUSED,
+ EAGAIN,
+ ECONNRESET,
+ EHOSTUNREACH,
+ EINPROGRESS,
+ EINTR,
+ ENETUNREACH,
+ ETIMEDOUT,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
+ return -1;
+ }
+ return 0;
+}
+
+int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
+{
+ constexpr std::array getsockopt_errnos{
+ ENOMEM,
+ ENOBUFS,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
+ return -1;
+ }
+ if (opt_val == nullptr) {
+ return 0;
+ }
+ std::memcpy(opt_val,
+ ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(),
+ *opt_len);
+ return 0;
+}
+
+bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
+{
+ constexpr std::array wait_errnos{
+ EBADF,
+ EINTR,
+ EINVAL,
+ };
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ SetFuzzedErrNo(m_fuzzed_data_provider, wait_errnos);
+ return false;
+ }
+ if (occurred != nullptr) {
+ *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0;
+ }
+ return true;
+}
+
+bool FuzzedSock::IsConnected(std::string& errmsg) const
+{
+ if (m_fuzzed_data_provider.ConsumeBool()) {
+ return true;
+ }
+ errmsg = "disconnected at random by the fuzzer";
+ return false;
+}
+
+void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_version) noexcept
+{
+ const ServiceFlags remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
+ const NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
+ const int32_t version = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max());
+ const bool filter_txs = fuzzed_data_provider.ConsumeBool();
+
+ node.nServices = remote_services;
+ node.m_permissionFlags = permission_flags;
+ if (init_version) {
+ node.nVersion = version;
+ node.SetCommonVersion(std::min(version, PROTOCOL_VERSION));
+ }
+ if (node.m_tx_relay != nullptr) {
+ LOCK(node.m_tx_relay->cs_filter);
+ node.m_tx_relay->fRelayTxes = filter_txs;
+ }
+}
+
+CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in, const int max_num_out) noexcept
+{
+ CMutableTransaction tx_mut;
+ const auto p2wsh_op_true = fuzzed_data_provider.ConsumeBool();
+ tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ?
+ CTransaction::CURRENT_VERSION :
+ fuzzed_data_provider.ConsumeIntegral<int32_t>();
+ tx_mut.nLockTime = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+ const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_in);
+ const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_out);
+ for (int i = 0; i < num_in; ++i) {
+ const auto& txid_prev = prevout_txids ?
+ PickValue(fuzzed_data_provider, *prevout_txids) :
+ ConsumeUInt256(fuzzed_data_provider);
+ const auto index_out = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, max_num_out);
+ const auto sequence = ConsumeSequence(fuzzed_data_provider);
+ const auto script_sig = p2wsh_op_true ? CScript{} : ConsumeScript(fuzzed_data_provider);
+ CScriptWitness script_wit;
+ if (p2wsh_op_true) {
+ script_wit.stack = std::vector<std::vector<uint8_t>>{WITNESS_STACK_ELEM_OP_TRUE};
+ } else {
+ script_wit = ConsumeScriptWitness(fuzzed_data_provider);
+ }
+ CTxIn in;
+ in.prevout = COutPoint{txid_prev, index_out};
+ in.nSequence = sequence;
+ in.scriptSig = script_sig;
+ in.scriptWitness = script_wit;
+
+ tx_mut.vin.push_back(in);
+ }
+ for (int i = 0; i < num_out; ++i) {
+ const auto amount = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-10, 50 * COIN + 10);
+ const auto script_pk = p2wsh_op_true ?
+ P2WSH_OP_TRUE :
+ ConsumeScript(fuzzed_data_provider, /* max_length */ 128, /* maybe_p2wsh */ true);
+ tx_mut.vout.emplace_back(amount, script_pk);
+ }
+ return tx_mut;
+}
+
+CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size) noexcept
+{
+ CScriptWitness ret;
+ const auto n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_stack_elem_size);
+ for (size_t i = 0; i < n_elements; ++i) {
+ ret.stack.push_back(ConsumeRandomLengthByteVector(fuzzed_data_provider));
+ }
+ return ret;
+}
+
+CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length, const bool maybe_p2wsh) noexcept
+{
+ const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
+ CScript r_script{b.begin(), b.end()};
+ if (maybe_p2wsh && fuzzed_data_provider.ConsumeBool()) {
+ uint256 script_hash;
+ CSHA256().Write(&r_script[0], r_script.size()).Finalize(script_hash.begin());
+ r_script.clear();
+ r_script << OP_0 << ToByteVector(script_hash);
+ }
+ return r_script;
+}
+
+uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return fuzzed_data_provider.ConsumeBool() ?
+ fuzzed_data_provider.PickValueInArray({
+ CTxIn::SEQUENCE_FINAL,
+ CTxIn::SEQUENCE_FINAL - 1,
+ MAX_BIP125_RBF_SEQUENCE,
+ }) :
+ fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+}
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index ff79dfe5f3..8f4f87fbdc 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,6 +10,7 @@
#include <attributes.h>
#include <chainparamsbase.h>
#include <coins.h>
+#include <compat.h>
#include <consensus/consensus.h>
#include <merkleblock.h>
#include <net.h>
@@ -22,19 +23,41 @@
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
-#include <test/util/setup_common.h>
+#include <test/util/net.h>
#include <txmempool.h>
#include <uint256.h>
#include <util/time.h>
#include <version.h>
#include <algorithm>
+#include <array>
#include <cstdint>
#include <cstdio>
#include <optional>
#include <string>
#include <vector>
+template <typename... Callables>
+void CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables)
+{
+ constexpr size_t call_size{sizeof...(callables)};
+ static_assert(call_size >= 1);
+ const size_t call_index{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, call_size - 1)};
+
+ size_t i{0};
+ return ((i++ == call_index ? callables() : void()), ...);
+}
+
+template <typename Collection>
+auto& PickValue(FuzzedDataProvider& fuzzed_data_provider, Collection& col)
+{
+ const auto sz = col.size();
+ assert(sz >= 1);
+ auto it = col.begin();
+ std::advance(it, fuzzed_data_provider.ConsumeIntegralInRange<decltype(sz)>(0, sz - 1));
+ return *it;
+}
+
[[nodiscard]] inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
{
const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(max_length);
@@ -48,7 +71,7 @@
[[nodiscard]] inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
{
- return {ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length), SER_NETWORK, INIT_PROTO_VERSION};
+ return CDataStream{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length), SER_NETWORK, INIT_PROTO_VERSION};
}
[[nodiscard]] inline std::vector<std::string> ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16, const size_t max_string_length = 16) noexcept
@@ -86,6 +109,14 @@ template <typename T>
return obj;
}
+template <typename WeakEnumType, size_t size>
+[[nodiscard]] WeakEnumType ConsumeWeakEnum(FuzzedDataProvider& fuzzed_data_provider, const WeakEnumType (&all_types)[size]) noexcept
+{
+ return fuzzed_data_provider.ConsumeBool() ?
+ fuzzed_data_provider.PickValueInArray<WeakEnumType>(all_types) :
+ WeakEnumType(fuzzed_data_provider.ConsumeIntegral<typename std::underlying_type<WeakEnumType>::type>());
+}
+
[[nodiscard]] inline opcodetype ConsumeOpcodeType(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return static_cast<opcodetype>(fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, MAX_OPCODE));
@@ -104,11 +135,13 @@ template <typename T>
return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(time_min, time_max);
}
-[[nodiscard]] inline CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider) noexcept
-{
- const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- return {b.begin(), b.end()};
-}
+[[nodiscard]] CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in = 10, const int max_num_out = 10) noexcept;
+
+[[nodiscard]] CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size = 32) noexcept;
+
+[[nodiscard]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096, const bool maybe_p2wsh = false) noexcept;
+
+[[nodiscard]] uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept;
[[nodiscard]] inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
@@ -156,37 +189,31 @@ template <typename T>
[[nodiscard]] inline CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
CTxDestination tx_destination;
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
- case 0: {
- tx_destination = CNoDestination{};
- break;
- }
- case 1: {
- tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)};
- break;
- }
- case 2: {
- tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)};
- break;
- }
- case 3: {
- tx_destination = WitnessV0ScriptHash{ConsumeUInt256(fuzzed_data_provider)};
- break;
- }
- case 4: {
- tx_destination = WitnessV0KeyHash{ConsumeUInt160(fuzzed_data_provider)};
- break;
- }
- case 5: {
- WitnessUnknown witness_unknown{};
- witness_unknown.version = fuzzed_data_provider.ConsumeIntegral<int>();
- const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
- witness_unknown.length = witness_unknown_program_1.size();
- std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown.program);
- tx_destination = witness_unknown;
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ tx_destination = CNoDestination{};
+ },
+ [&] {
+ tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)};
+ },
+ [&] {
+ tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)};
+ },
+ [&] {
+ tx_destination = WitnessV0ScriptHash{ConsumeUInt256(fuzzed_data_provider)};
+ },
+ [&] {
+ tx_destination = WitnessV0KeyHash{ConsumeUInt160(fuzzed_data_provider)};
+ },
+ [&] {
+ WitnessUnknown witness_unknown{};
+ witness_unknown.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+ const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
+ witness_unknown.length = witness_unknown_program_1.size();
+ std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown.program);
+ tx_destination = witness_unknown;
+ });
return tx_destination;
}
@@ -236,6 +263,25 @@ template <class T>
}
/**
+ * Sets errno to a value selected from the given std::array `errnos`.
+ */
+template <typename T, size_t size>
+void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider, const std::array<T, size>& errnos)
+{
+ errno = fuzzed_data_provider.PickValueInArray(errnos);
+}
+
+/*
+ * Sets a fuzzed errno in the range [0, 133 (EHWPOISON)]. Can be used from functions emulating
+ * standard library functions that set errno, or in other contexts where the value of errno
+ * might be relevant for the execution path that will be taken.
+ */
+inline void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ errno = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 133);
+}
+
+/**
* Returns a byte vector of specified size regardless of the number of remaining bytes available
* from the fuzzer. Pads with zero value bytes if needed to achieve the specified size.
*/
@@ -254,8 +300,8 @@ inline CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcep
const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
CNetAddr net_addr;
if (network == Network::NET_IPV4) {
- const in_addr v4_addr = {
- .s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
+ in_addr v4_addr = {};
+ v4_addr.s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
net_addr = CNetAddr{v4_addr};
} else if (network == Network::NET_IPV6) {
if (fuzzed_data_provider.remaining_bytes() >= 16) {
@@ -283,28 +329,31 @@ inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcep
inline CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
- return {ConsumeService(fuzzed_data_provider), static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>()), fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
+ return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
}
-inline CNode ConsumeNode(FuzzedDataProvider& fuzzed_data_provider) noexcept
+template <bool ReturnUniquePtr = false>
+auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
{
- const NodeId node_id = fuzzed_data_provider.ConsumeIntegral<NodeId>();
- const ServiceFlags local_services = static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegral<NodeId>());
+ const ServiceFlags local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
const SOCKET socket = INVALID_SOCKET;
const CAddress address = ConsumeAddress(fuzzed_data_provider);
const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider);
const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
- const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND_FULL_RELAY, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH});
+ const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
- return {node_id, local_services, socket, address, keyed_net_group, local_host_nonce, addr_bind, addr_name, conn_type, inbound_onion};
+ if constexpr (ReturnUniquePtr) {
+ return std::make_unique<CNode>(node_id, local_services, socket, address, keyed_net_group, local_host_nonce, addr_bind, addr_name, conn_type, inbound_onion);
+ } else {
+ return CNode{node_id, local_services, socket, address, keyed_net_group, local_host_nonce, addr_bind, addr_name, conn_type, inbound_onion};
+ }
}
+inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); }
-inline void InitializeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST)
-{
- static const BasicTestingSetup basic_testing_setup{chain_name, {"-nodebuglogfile"}};
-}
+void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_version) noexcept;
class FuzzedFileProvider
{
@@ -318,36 +367,31 @@ public:
FILE* open()
{
+ SetFuzzedErrNo(m_fuzzed_data_provider);
if (m_fuzzed_data_provider.ConsumeBool()) {
return nullptr;
}
std::string mode;
- switch (m_fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
- case 0: {
- mode = "r";
- break;
- }
- case 1: {
- mode = "r+";
- break;
- }
- case 2: {
- mode = "w";
- break;
- }
- case 3: {
- mode = "w+";
- break;
- }
- case 4: {
- mode = "a";
- break;
- }
- case 5: {
- mode = "a+";
- break;
- }
- }
+ CallOneOf(
+ m_fuzzed_data_provider,
+ [&] {
+ mode = "r";
+ },
+ [&] {
+ mode = "r+";
+ },
+ [&] {
+ mode = "w";
+ },
+ [&] {
+ mode = "w+";
+ },
+ [&] {
+ mode = "a";
+ },
+ [&] {
+ mode = "a+";
+ });
#ifdef _GNU_SOURCE
const cookie_io_functions_t io_hooks = {
FuzzedFileProvider::read,
@@ -365,6 +409,7 @@ public:
static ssize_t read(void* cookie, char* buf, size_t size)
{
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
if (buf == nullptr || size == 0 || fuzzed_file->m_fuzzed_data_provider.ConsumeBool()) {
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
}
@@ -383,6 +428,7 @@ public:
static ssize_t write(void* cookie, const char* buf, size_t size)
{
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size);
if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)n)) {
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
@@ -393,8 +439,9 @@ public:
static int seek(void* cookie, int64_t* offset, int whence)
{
- assert(whence == SEEK_SET || whence == SEEK_CUR); // SEEK_END not implemented yet.
+ assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END);
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
int64_t new_offset = 0;
if (whence == SEEK_SET) {
new_offset = *offset;
@@ -403,6 +450,12 @@ public:
return -1;
}
new_offset = fuzzed_file->m_offset + *offset;
+ } else if (whence == SEEK_END) {
+ const int64_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 4096);
+ if (AdditionOverflow(n, *offset)) {
+ return -1;
+ }
+ new_offset = n + *offset;
}
if (new_offset < 0) {
return -1;
@@ -415,6 +468,7 @@ public:
static int close(void* cookie)
{
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
}
};
@@ -445,70 +499,106 @@ public:
return {fuzzed_data_provider};
}
-#define WRITE_TO_STREAM_CASE(id, type, consume) \
- case id: { \
- type o = consume; \
- stream << o; \
- break; \
+#define WRITE_TO_STREAM_CASE(type, consume) \
+ [&] { \
+ type o = consume; \
+ stream << o; \
}
template <typename Stream>
void WriteToStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept
{
while (fuzzed_data_provider.ConsumeBool()) {
try {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 13)) {
- WRITE_TO_STREAM_CASE(0, bool, fuzzed_data_provider.ConsumeBool())
- WRITE_TO_STREAM_CASE(1, char, fuzzed_data_provider.ConsumeIntegral<char>())
- WRITE_TO_STREAM_CASE(2, int8_t, fuzzed_data_provider.ConsumeIntegral<int8_t>())
- WRITE_TO_STREAM_CASE(3, uint8_t, fuzzed_data_provider.ConsumeIntegral<uint8_t>())
- WRITE_TO_STREAM_CASE(4, int16_t, fuzzed_data_provider.ConsumeIntegral<int16_t>())
- WRITE_TO_STREAM_CASE(5, uint16_t, fuzzed_data_provider.ConsumeIntegral<uint16_t>())
- WRITE_TO_STREAM_CASE(6, int32_t, fuzzed_data_provider.ConsumeIntegral<int32_t>())
- WRITE_TO_STREAM_CASE(7, uint32_t, fuzzed_data_provider.ConsumeIntegral<uint32_t>())
- WRITE_TO_STREAM_CASE(8, int64_t, fuzzed_data_provider.ConsumeIntegral<int64_t>())
- WRITE_TO_STREAM_CASE(9, uint64_t, fuzzed_data_provider.ConsumeIntegral<uint64_t>())
- WRITE_TO_STREAM_CASE(10, float, fuzzed_data_provider.ConsumeFloatingPoint<float>())
- WRITE_TO_STREAM_CASE(11, double, fuzzed_data_provider.ConsumeFloatingPoint<double>())
- WRITE_TO_STREAM_CASE(12, std::string, fuzzed_data_provider.ConsumeRandomLengthString(32))
- WRITE_TO_STREAM_CASE(13, std::vector<char>, ConsumeRandomLengthIntegralVector<char>(fuzzed_data_provider))
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ WRITE_TO_STREAM_CASE(bool, fuzzed_data_provider.ConsumeBool()),
+ WRITE_TO_STREAM_CASE(char, fuzzed_data_provider.ConsumeIntegral<char>()),
+ WRITE_TO_STREAM_CASE(int8_t, fuzzed_data_provider.ConsumeIntegral<int8_t>()),
+ WRITE_TO_STREAM_CASE(uint8_t, fuzzed_data_provider.ConsumeIntegral<uint8_t>()),
+ WRITE_TO_STREAM_CASE(int16_t, fuzzed_data_provider.ConsumeIntegral<int16_t>()),
+ WRITE_TO_STREAM_CASE(uint16_t, fuzzed_data_provider.ConsumeIntegral<uint16_t>()),
+ WRITE_TO_STREAM_CASE(int32_t, fuzzed_data_provider.ConsumeIntegral<int32_t>()),
+ WRITE_TO_STREAM_CASE(uint32_t, fuzzed_data_provider.ConsumeIntegral<uint32_t>()),
+ WRITE_TO_STREAM_CASE(int64_t, fuzzed_data_provider.ConsumeIntegral<int64_t>()),
+ WRITE_TO_STREAM_CASE(uint64_t, fuzzed_data_provider.ConsumeIntegral<uint64_t>()),
+ WRITE_TO_STREAM_CASE(float, fuzzed_data_provider.ConsumeFloatingPoint<float>()),
+ WRITE_TO_STREAM_CASE(double, fuzzed_data_provider.ConsumeFloatingPoint<double>()),
+ WRITE_TO_STREAM_CASE(std::string, fuzzed_data_provider.ConsumeRandomLengthString(32)),
+ WRITE_TO_STREAM_CASE(std::vector<char>, ConsumeRandomLengthIntegralVector<char>(fuzzed_data_provider)));
} catch (const std::ios_base::failure&) {
break;
}
}
}
-#define READ_FROM_STREAM_CASE(id, type) \
- case id: { \
- type o; \
- stream >> o; \
- break; \
+#define READ_FROM_STREAM_CASE(type) \
+ [&] { \
+ type o; \
+ stream >> o; \
}
template <typename Stream>
void ReadFromStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept
{
while (fuzzed_data_provider.ConsumeBool()) {
try {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 13)) {
- READ_FROM_STREAM_CASE(0, bool)
- READ_FROM_STREAM_CASE(1, char)
- READ_FROM_STREAM_CASE(2, int8_t)
- READ_FROM_STREAM_CASE(3, uint8_t)
- READ_FROM_STREAM_CASE(4, int16_t)
- READ_FROM_STREAM_CASE(5, uint16_t)
- READ_FROM_STREAM_CASE(6, int32_t)
- READ_FROM_STREAM_CASE(7, uint32_t)
- READ_FROM_STREAM_CASE(8, int64_t)
- READ_FROM_STREAM_CASE(9, uint64_t)
- READ_FROM_STREAM_CASE(10, float)
- READ_FROM_STREAM_CASE(11, double)
- READ_FROM_STREAM_CASE(12, std::string)
- READ_FROM_STREAM_CASE(13, std::vector<char>)
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ READ_FROM_STREAM_CASE(bool),
+ READ_FROM_STREAM_CASE(char),
+ READ_FROM_STREAM_CASE(int8_t),
+ READ_FROM_STREAM_CASE(uint8_t),
+ READ_FROM_STREAM_CASE(int16_t),
+ READ_FROM_STREAM_CASE(uint16_t),
+ READ_FROM_STREAM_CASE(int32_t),
+ READ_FROM_STREAM_CASE(uint32_t),
+ READ_FROM_STREAM_CASE(int64_t),
+ READ_FROM_STREAM_CASE(uint64_t),
+ READ_FROM_STREAM_CASE(float),
+ READ_FROM_STREAM_CASE(double),
+ READ_FROM_STREAM_CASE(std::string),
+ READ_FROM_STREAM_CASE(std::vector<char>));
} catch (const std::ios_base::failure&) {
break;
}
}
}
+class FuzzedSock : public Sock
+{
+ FuzzedDataProvider& m_fuzzed_data_provider;
+
+ /**
+ * Data to return when `MSG_PEEK` is used as a `Recv()` flag.
+ * If `MSG_PEEK` is used, then our `Recv()` returns some random data as usual, but on the next
+ * `Recv()` call we must return the same data, thus we remember it here.
+ */
+ mutable std::optional<uint8_t> m_peek_data;
+
+public:
+ explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider);
+
+ ~FuzzedSock() override;
+
+ FuzzedSock& operator=(Sock&& other) override;
+
+ void Reset() override;
+
+ ssize_t Send(const void* data, size_t len, int flags) const override;
+
+ ssize_t Recv(void* buf, size_t len, int flags) const override;
+
+ int Connect(const sockaddr*, socklen_t) const override;
+
+ int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override;
+
+ bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override;
+
+ bool IsConnected(std::string& errmsg) const override;
+};
+
+[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider)
+{
+ return FuzzedSock{fuzzed_data_provider};
+}
+
#endif // BITCOIN_TEST_FUZZ_UTIL_H
diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp
new file mode 100644
index 0000000000..e1a21b6c53
--- /dev/null
+++ b/src/test/fuzz/validation_load_mempool.cpp
@@ -0,0 +1,34 @@
+// Copyright (c) 2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <chainparamsbase.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <txmempool.h>
+#include <util/time.h>
+#include <validation.h>
+
+#include <cstdint>
+#include <vector>
+
+void initialize_validation_load_mempool()
+{
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+}
+
+FUZZ_TARGET_INIT(validation_load_mempool, initialize_validation_load_mempool)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ SetMockTime(ConsumeTime(fuzzed_data_provider));
+ FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider);
+
+ CTxMemPool pool{};
+ auto fuzzed_fopen = [&](const fs::path&, const char*) {
+ return fuzzed_file_provider.open();
+ };
+ (void)LoadMempool(pool, ::ChainstateActive(), fuzzed_fopen);
+ (void)DumpMempool(pool, fuzzed_fopen, true);
+}
diff --git a/src/test/fuzz/versionbits.cpp b/src/test/fuzz/versionbits.cpp
new file mode 100644
index 0000000000..9186821836
--- /dev/null
+++ b/src/test/fuzz/versionbits.cpp
@@ -0,0 +1,350 @@
+// Copyright (c) 2020-2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <chain.h>
+#include <chainparams.h>
+#include <consensus/params.h>
+#include <primitives/block.h>
+#include <versionbits.h>
+
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <limits>
+#include <memory>
+#include <vector>
+
+namespace {
+class TestConditionChecker : public AbstractThresholdConditionChecker
+{
+private:
+ mutable ThresholdConditionCache m_cache;
+ const Consensus::Params dummy_params{};
+
+public:
+ const int64_t m_begin;
+ const int64_t m_end;
+ const int m_period;
+ const int m_threshold;
+ const int m_min_activation_height;
+ const int m_bit;
+
+ TestConditionChecker(int64_t begin, int64_t end, int period, int threshold, int min_activation_height, int bit)
+ : m_begin{begin}, m_end{end}, m_period{period}, m_threshold{threshold}, m_min_activation_height{min_activation_height}, m_bit{bit}
+ {
+ assert(m_period > 0);
+ assert(0 <= m_threshold && m_threshold <= m_period);
+ assert(0 <= m_bit && m_bit < 32 && m_bit < VERSIONBITS_NUM_BITS);
+ assert(0 <= m_min_activation_height);
+ }
+
+ bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override { return Condition(pindex->nVersion); }
+ int64_t BeginTime(const Consensus::Params& params) const override { return m_begin; }
+ int64_t EndTime(const Consensus::Params& params) const override { return m_end; }
+ int Period(const Consensus::Params& params) const override { return m_period; }
+ int Threshold(const Consensus::Params& params) const override { return m_threshold; }
+ int MinActivationHeight(const Consensus::Params& params) const override { return m_min_activation_height; }
+
+ ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, dummy_params, m_cache); }
+ int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, dummy_params, m_cache); }
+ BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateStatisticsFor(pindexPrev, dummy_params); }
+
+ bool Condition(int32_t version) const
+ {
+ uint32_t mask = ((uint32_t)1) << m_bit;
+ return (((version & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (version & mask) != 0);
+ }
+
+ bool Condition(const CBlockIndex* pindex) const { return Condition(pindex->nVersion); }
+};
+
+/** Track blocks mined for test */
+class Blocks
+{
+private:
+ std::vector<std::unique_ptr<CBlockIndex>> m_blocks;
+ const uint32_t m_start_time;
+ const uint32_t m_interval;
+ const int32_t m_signal;
+ const int32_t m_no_signal;
+
+public:
+ Blocks(uint32_t start_time, uint32_t interval, int32_t signal, int32_t no_signal)
+ : m_start_time{start_time}, m_interval{interval}, m_signal{signal}, m_no_signal{no_signal} {}
+
+ size_t size() const { return m_blocks.size(); }
+
+ CBlockIndex* tip() const
+ {
+ return m_blocks.empty() ? nullptr : m_blocks.back().get();
+ }
+
+ CBlockIndex* mine_block(bool signal)
+ {
+ CBlockHeader header;
+ header.nVersion = signal ? m_signal : m_no_signal;
+ header.nTime = m_start_time + m_blocks.size() * m_interval;
+ header.nBits = 0x1d00ffff;
+
+ auto current_block = std::make_unique<CBlockIndex>(header);
+ current_block->pprev = tip();
+ current_block->nHeight = m_blocks.size();
+ current_block->BuildSkip();
+
+ return m_blocks.emplace_back(std::move(current_block)).get();
+ }
+};
+
+std::unique_ptr<const CChainParams> g_params;
+
+void initialize()
+{
+ // this is actually comparatively slow, so only do it once
+ g_params = CreateChainParams(ArgsManager{}, CBaseChainParams::MAIN);
+ assert(g_params != nullptr);
+}
+
+constexpr uint32_t MAX_START_TIME = 4102444800; // 2100-01-01
+
+FUZZ_TARGET_INIT(versionbits, initialize)
+{
+ const CChainParams& params = *g_params;
+ const int64_t interval = params.GetConsensus().nPowTargetSpacing;
+ assert(interval > 1); // need to be able to halve it
+ assert(interval < std::numeric_limits<int32_t>::max());
+
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+
+ // making period/max_periods larger slows these tests down significantly
+ const int period = 32;
+ const size_t max_periods = 16;
+ const size_t max_blocks = 2 * period * max_periods;
+
+ const int threshold = fuzzed_data_provider.ConsumeIntegralInRange(1, period);
+ assert(0 < threshold && threshold <= period); // must be able to both pass and fail threshold!
+
+ // too many blocks at 10min each might cause uint32_t time to overflow if
+ // block_start_time is at the end of the range above
+ assert(std::numeric_limits<uint32_t>::max() - MAX_START_TIME > interval * max_blocks);
+
+ const int64_t block_start_time = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(params.GenesisBlock().nTime, MAX_START_TIME);
+
+ // what values for version will we use to signal / not signal?
+ const int32_t ver_signal = fuzzed_data_provider.ConsumeIntegral<int32_t>();
+ const int32_t ver_nosignal = fuzzed_data_provider.ConsumeIntegral<int32_t>();
+
+ // select deployment parameters: bit, start time, timeout
+ const int bit = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, VERSIONBITS_NUM_BITS - 1);
+
+ bool always_active_test = false;
+ bool never_active_test = false;
+ int64_t start_time;
+ int64_t timeout;
+ if (fuzzed_data_provider.ConsumeBool()) {
+ // pick the timestamp to switch based on a block
+ // note states will change *after* these blocks because mediantime lags
+ int start_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * (max_periods - 3));
+ int end_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * (max_periods - 3));
+
+ start_time = block_start_time + start_block * interval;
+ timeout = block_start_time + end_block * interval;
+
+ // allow for times to not exactly match a block
+ if (fuzzed_data_provider.ConsumeBool()) start_time += interval / 2;
+ if (fuzzed_data_provider.ConsumeBool()) timeout += interval / 2;
+ } else {
+ if (fuzzed_data_provider.ConsumeBool()) {
+ start_time = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
+ always_active_test = true;
+ } else {
+ start_time = Consensus::BIP9Deployment::NEVER_ACTIVE;
+ never_active_test = true;
+ }
+ timeout = fuzzed_data_provider.ConsumeBool() ? Consensus::BIP9Deployment::NO_TIMEOUT : fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ }
+ int min_activation = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * max_periods);
+
+ TestConditionChecker checker(start_time, timeout, period, threshold, min_activation, bit);
+
+ // Early exit if the versions don't signal sensibly for the deployment
+ if (!checker.Condition(ver_signal)) return;
+ if (checker.Condition(ver_nosignal)) return;
+ if (ver_nosignal < 0) return;
+
+ // TOP_BITS should ensure version will be positive and meet min
+ // version requirement
+ assert(ver_signal > 0);
+ assert(ver_signal >= VERSIONBITS_LAST_OLD_BLOCK_VERSION);
+
+ // Now that we have chosen time and versions, setup to mine blocks
+ Blocks blocks(block_start_time, interval, ver_signal, ver_nosignal);
+
+ /* Strategy:
+ * * we will mine a final period worth of blocks, with
+ * randomised signalling according to a mask
+ * * but before we mine those blocks, we will mine some
+ * randomised number of prior periods; with either all
+ * or no blocks in the period signalling
+ *
+ * We establish the mask first, then consume "bools" until
+ * we run out of fuzz data to work out how many prior periods
+ * there are and which ones will signal.
+ */
+
+ // establish the mask
+ const uint32_t signalling_mask = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+
+ // mine prior periods
+ while (fuzzed_data_provider.remaining_bytes() > 0) {
+ // all blocks in these periods either do or don't signal
+ bool signal = fuzzed_data_provider.ConsumeBool();
+ for (int b = 0; b < period; ++b) {
+ blocks.mine_block(signal);
+ }
+
+ // don't risk exceeding max_blocks or times may wrap around
+ if (blocks.size() + 2 * period > max_blocks) break;
+ }
+ // NOTE: fuzzed_data_provider may be fully consumed at this point and should not be used further
+
+ // now we mine the final period and check that everything looks sane
+
+ // count the number of signalling blocks
+ int blocks_sig = 0;
+
+ // get the info for the first block of the period
+ CBlockIndex* prev = blocks.tip();
+ const int exp_since = checker.GetStateSinceHeightFor(prev);
+ const ThresholdState exp_state = checker.GetStateFor(prev);
+ BIP9Stats last_stats = checker.GetStateStatisticsFor(prev);
+
+ int prev_next_height = (prev == nullptr ? 0 : prev->nHeight + 1);
+ assert(exp_since <= prev_next_height);
+
+ // mine (period-1) blocks and check state
+ for (int b = 1; b < period; ++b) {
+ const bool signal = (signalling_mask >> (b % 32)) & 1;
+ if (signal) ++blocks_sig;
+
+ CBlockIndex* current_block = blocks.mine_block(signal);
+
+ // verify that signalling attempt was interpreted correctly
+ assert(checker.Condition(current_block) == signal);
+
+ // state and since don't change within the period
+ const ThresholdState state = checker.GetStateFor(current_block);
+ const int since = checker.GetStateSinceHeightFor(current_block);
+ assert(state == exp_state);
+ assert(since == exp_since);
+
+ // GetStateStatistics may crash when state is not STARTED
+ if (state != ThresholdState::STARTED) continue;
+
+ // check that after mining this block stats change as expected
+ const BIP9Stats stats = checker.GetStateStatisticsFor(current_block);
+ assert(stats.period == period);
+ assert(stats.threshold == threshold);
+ assert(stats.elapsed == b);
+ assert(stats.count == last_stats.count + (signal ? 1 : 0));
+ assert(stats.possible == (stats.count + period >= stats.elapsed + threshold));
+ last_stats = stats;
+ }
+
+ if (exp_state == ThresholdState::STARTED) {
+ // double check that stats.possible is sane
+ if (blocks_sig >= threshold - 1) assert(last_stats.possible);
+ }
+
+ // mine the final block
+ bool signal = (signalling_mask >> (period % 32)) & 1;
+ if (signal) ++blocks_sig;
+ CBlockIndex* current_block = blocks.mine_block(signal);
+ assert(checker.Condition(current_block) == signal);
+
+ // GetStateStatistics is safe on a period boundary
+ // and has progressed to a new period
+ const BIP9Stats stats = checker.GetStateStatisticsFor(current_block);
+ assert(stats.period == period);
+ assert(stats.threshold == threshold);
+ assert(stats.elapsed == 0);
+ assert(stats.count == 0);
+ assert(stats.possible == true);
+
+ // More interesting is whether the state changed.
+ const ThresholdState state = checker.GetStateFor(current_block);
+ const int since = checker.GetStateSinceHeightFor(current_block);
+
+ // since is straightforward:
+ assert(since % period == 0);
+ assert(0 <= since && since <= current_block->nHeight + 1);
+ if (state == exp_state) {
+ assert(since == exp_since);
+ } else {
+ assert(since == current_block->nHeight + 1);
+ }
+
+ // state is where everything interesting is
+ switch (state) {
+ case ThresholdState::DEFINED:
+ assert(since == 0);
+ assert(exp_state == ThresholdState::DEFINED);
+ assert(current_block->GetMedianTimePast() < checker.m_begin);
+ break;
+ case ThresholdState::STARTED:
+ assert(current_block->GetMedianTimePast() >= checker.m_begin);
+ if (exp_state == ThresholdState::STARTED) {
+ assert(blocks_sig < threshold);
+ assert(current_block->GetMedianTimePast() < checker.m_end);
+ } else {
+ assert(exp_state == ThresholdState::DEFINED);
+ }
+ break;
+ case ThresholdState::LOCKED_IN:
+ if (exp_state == ThresholdState::LOCKED_IN) {
+ assert(current_block->nHeight + 1 < min_activation);
+ } else {
+ assert(exp_state == ThresholdState::STARTED);
+ assert(blocks_sig >= threshold);
+ }
+ break;
+ case ThresholdState::ACTIVE:
+ assert(always_active_test || min_activation <= current_block->nHeight + 1);
+ assert(exp_state == ThresholdState::ACTIVE || exp_state == ThresholdState::LOCKED_IN);
+ break;
+ case ThresholdState::FAILED:
+ assert(never_active_test || current_block->GetMedianTimePast() >= checker.m_end);
+ if (exp_state == ThresholdState::STARTED) {
+ assert(blocks_sig < threshold);
+ } else {
+ assert(exp_state == ThresholdState::FAILED);
+ }
+ break;
+ default:
+ assert(false);
+ }
+
+ if (blocks.size() >= period * max_periods) {
+ // we chose the timeout (and block times) so that by the time we have this many blocks it's all over
+ assert(state == ThresholdState::ACTIVE || state == ThresholdState::FAILED);
+ }
+
+ if (always_active_test) {
+ // "always active" has additional restrictions
+ assert(state == ThresholdState::ACTIVE);
+ assert(exp_state == ThresholdState::ACTIVE);
+ assert(since == 0);
+ } else if (never_active_test) {
+ // "never active" does too
+ assert(state == ThresholdState::FAILED);
+ assert(exp_state == ThresholdState::FAILED);
+ assert(since == 0);
+ } else {
+ // for signalled deployments, the initial state is always DEFINED
+ assert(since > 0 || state == ThresholdState::DEFINED);
+ assert(exp_since > 0 || exp_state == ThresholdState::DEFINED);
+ }
+}
+} // namespace