diff options
Diffstat (limited to 'src/test/fuzz')
53 files changed, 430 insertions, 144 deletions
diff --git a/src/test/fuzz/FuzzedDataProvider.h b/src/test/fuzz/FuzzedDataProvider.h index 6cbfc39bc2..8a8214bd99 100644 --- a/src/test/fuzz/FuzzedDataProvider.h +++ b/src/test/fuzz/FuzzedDataProvider.h @@ -209,7 +209,7 @@ T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) { abort(); // Use the biggest type possible to hold the range and the result. - uint64_t range = static_cast<uint64_t>(max) - min; + uint64_t range = static_cast<uint64_t>(max) - static_cast<uint64_t>(min); uint64_t result = 0; size_t offset = 0; @@ -230,7 +230,7 @@ T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) { if (range != std::numeric_limits<decltype(range)>::max()) result = result % (range + 1); - return static_cast<T>(min + result); + return static_cast<T>(static_cast<uint64_t>(min) + result); } // Returns a floating point value in the range [Type's lowest, Type's max] by @@ -390,7 +390,7 @@ TS FuzzedDataProvider::ConvertUnsignedToSigned(TU value) { return static_cast<TS>(value); } else { constexpr auto TS_min = std::numeric_limits<TS>::min(); - return TS_min + static_cast<char>(value - TS_min); + return TS_min + static_cast<TS>(value - TS_min); } } diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index 92ce4945f9..02df4590de 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -46,7 +46,7 @@ void initialize_addrman() return NetGroupManager(asmap); } -FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman) +FUZZ_TARGET(data_stream_addr_man, .init = initialize_addrman) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider); @@ -171,8 +171,8 @@ public: hasher.Write(a.source.GetNetwork()); hasher.Write(addr_key.size()); hasher.Write(source_key.size()); - hasher.Write(addr_key.data(), addr_key.size()); - hasher.Write(source_key.data(), source_key.size()); + hasher.Write(addr_key); + hasher.Write(source_key); return (size_t)hasher.Finalize(); }; @@ -233,7 +233,7 @@ public: } }; -FUZZ_TARGET_INIT(addrman, initialize_addrman) +FUZZ_TARGET(addrman, .init = initialize_addrman) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); SetMockTime(ConsumeTime(fuzzed_data_provider)); @@ -281,18 +281,26 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman) }); } const AddrMan& const_addr_man{addr_man}; + std::optional<Network> network; + if (fuzzed_data_provider.ConsumeBool()) { + network = fuzzed_data_provider.PickValueInArray(ALL_NETWORKS); + } (void)const_addr_man.GetAddr( /*max_addresses=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), /*max_pct=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), - /*network=*/std::nullopt); - (void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool()); - (void)const_addr_man.Size(); + network); + (void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool(), network); + std::optional<bool> in_new; + if (fuzzed_data_provider.ConsumeBool()) { + in_new = fuzzed_data_provider.ConsumeBool(); + } + (void)const_addr_man.Size(network, in_new); CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION); data_stream << const_addr_man; } // Check that serialize followed by unserialize produces the same addrman. -FUZZ_TARGET_INIT(addrman_serdeser, initialize_addrman) +FUZZ_TARGET(addrman_serdeser, .init = initialize_addrman) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); SetMockTime(ConsumeTime(fuzzed_data_provider)); diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp index cb5d29d9b8..3882e0e547 100644 --- a/src/test/fuzz/banman.cpp +++ b/src/test/fuzz/banman.cpp @@ -40,7 +40,7 @@ static bool operator==(const CBanEntry& lhs, const CBanEntry& rhs) lhs.nBanUntil == rhs.nBanUntil; } -FUZZ_TARGET_INIT(banman, initialize_banman) +FUZZ_TARGET(banman, .init = initialize_banman) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; SetMockTime(ConsumeTime(fuzzed_data_provider)); diff --git a/src/test/fuzz/bitdeque.cpp b/src/test/fuzz/bitdeque.cpp index 634a3de346..65f5cb3fd0 100644 --- a/src/test/fuzz/bitdeque.cpp +++ b/src/test/fuzz/bitdeque.cpp @@ -31,7 +31,7 @@ void InitRandData() } // namespace -FUZZ_TARGET_INIT(bitdeque, InitRandData) +FUZZ_TARGET(bitdeque, .init = InitRandData) { FuzzedDataProvider provider(buffer.data(), buffer.size()); FastRandomContext ctx(true); diff --git a/src/test/fuzz/block.cpp b/src/test/fuzz/block.cpp index e90dcc189a..8c97fba323 100644 --- a/src/test/fuzz/block.cpp +++ b/src/test/fuzz/block.cpp @@ -23,7 +23,7 @@ void initialize_block() SelectParams(ChainType::REGTEST); } -FUZZ_TARGET_INIT(block, initialize_block) +FUZZ_TARGET(block, .init = initialize_block) { CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); CBlock block; diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index fc7e000dc7..723dc6420f 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -41,7 +41,7 @@ void initialize_coins_view() g_setup = testing_setup.get(); } -FUZZ_TARGET_INIT(coins_view, initialize_coins_view) +FUZZ_TARGET(coins_view, .init = initialize_coins_view) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; CCoinsView backend_coins_view; diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp index f81658b832..cdf240dc59 100644 --- a/src/test/fuzz/connman.cpp +++ b/src/test/fuzz/connman.cpp @@ -28,11 +28,11 @@ void initialize_connman() g_setup = testing_setup.get(); } -FUZZ_TARGET_INIT(connman, initialize_connman) +FUZZ_TARGET(connman, .init = initialize_connman) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; SetMockTime(ConsumeTime(fuzzed_data_provider)); - CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), + ConnmanTestMsg connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), *g_setup->m_node.addrman, *g_setup->m_node.netgroupman, @@ -41,6 +41,12 @@ FUZZ_TARGET_INIT(connman, initialize_connman) CNode random_node = ConsumeNode(fuzzed_data_provider); CSubNet random_subnet; std::string random_string; + + LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100) { + CNode& p2p_node{*ConsumeNodeAsUniquePtr(fuzzed_data_provider).release()}; + connman.AddTestNode(p2p_node); + } + LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) { CallOneOf( fuzzed_data_provider, @@ -128,4 +134,6 @@ FUZZ_TARGET_INIT(connman, initialize_connman) (void)connman.GetTotalBytesSent(); (void)connman.GetTryNewOutboundPeer(); (void)connman.GetUseAddrmanOutgoing(); + + connman.ClearTestNodes(); } diff --git a/src/test/fuzz/crypto.cpp b/src/test/fuzz/crypto.cpp index 84b95117e2..ca8c1cd033 100644 --- a/src/test/fuzz/crypto.cpp +++ b/src/test/fuzz/crypto.cpp @@ -57,7 +57,7 @@ FUZZ_TARGET(crypto) (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)sip_hasher.Write(data); (void)Hash(data); (void)Hash160(data); diff --git a/src/test/fuzz/crypto_chacha20.cpp b/src/test/fuzz/crypto_chacha20.cpp index 3fa445096a..63c7bf3b45 100644 --- a/src/test/fuzz/crypto_chacha20.cpp +++ b/src/test/fuzz/crypto_chacha20.cpp @@ -28,10 +28,11 @@ FUZZ_TARGET(crypto_chacha20) chacha20.SetKey32(key.data()); }, [&] { - chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); - }, - [&] { - chacha20.Seek64(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); + chacha20.Seek64( + { + fuzzed_data_provider.ConsumeIntegral<uint32_t>(), + fuzzed_data_provider.ConsumeIntegral<uint64_t>() + }, fuzzed_data_provider.ConsumeIntegral<uint32_t>()); }, [&] { std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); @@ -63,17 +64,16 @@ void ChaCha20SplitFuzz(FuzzedDataProvider& provider) auto key_bytes = provider.ConsumeBytes<unsigned char>(32); std::copy(key_bytes.begin(), key_bytes.end(), key); uint64_t iv = provider.ConsumeIntegral<uint64_t>(); + uint32_t iv_prefix = provider.ConsumeIntegral<uint32_t>(); uint64_t total_bytes = provider.ConsumeIntegralInRange<uint64_t>(0, 1000000); - /* ~x = 2^64 - 1 - x, so ~(total_bytes >> 6) is the maximal seek position. */ - uint64_t seek = provider.ConsumeIntegralInRange<uint64_t>(0, ~(total_bytes >> 6)); + /* ~x = 2^BITS - 1 - x, so ~(total_bytes >> 6) is the maximal seek position. */ + uint32_t seek = provider.ConsumeIntegralInRange<uint32_t>(0, ~(uint32_t)(total_bytes >> 6)); // Initialize two ChaCha20 ciphers, with the same key/iv/position. ChaCha20 crypt1(key); ChaCha20 crypt2(key); - crypt1.SetIV(iv); - crypt1.Seek64(seek); - crypt2.SetIV(iv); - crypt2.Seek64(seek); + crypt1.Seek64({iv_prefix, iv}, seek); + crypt2.Seek64({iv_prefix, iv}, seek); // Construct vectors with data. std::vector<unsigned char> data1, data2; diff --git a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp index 596614a71b..84ac65dd88 100644 --- a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp +++ b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp @@ -26,16 +26,16 @@ FUZZ_TARGET(crypto_chacha20_poly1305_aead) uint64_t seqnr_aad = 0; int aad_pos = 0; size_t buffer_size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096); - std::vector<uint8_t> in(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0); - std::vector<uint8_t> out(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0); + std::vector<uint8_t> in(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + Poly1305::TAGLEN, 0); + std::vector<uint8_t> out(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + Poly1305::TAGLEN, 0); bool is_encrypt = fuzzed_data_provider.ConsumeBool(); LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) { 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); + 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); diff --git a/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp b/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp index 78fee48de6..285ea2dfe0 100644 --- a/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp +++ b/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp @@ -284,6 +284,8 @@ FUZZ_TARGET(crypto_diff_fuzz_chacha20) // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey32() does static const uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + ChaCha20::Nonce96 nonce{0, 0}; + uint32_t counter{0}; ECRYPT_ivsetup(&ctx, iv); LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 3000) { @@ -292,45 +294,56 @@ FUZZ_TARGET(crypto_diff_fuzz_chacha20) [&] { const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32); chacha20.SetKey32(key.data()); + nonce = {0, 0}; + counter = 0; ECRYPT_keysetup(&ctx, key.data(), key.size() * 8, 0); // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey32() does uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0}; ECRYPT_ivsetup(&ctx, iv); }, [&] { + uint32_t iv_prefix = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); uint64_t iv = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); - chacha20.SetIV(iv); + nonce = {iv_prefix, iv}; + counter = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); + chacha20.Seek64(nonce, counter); + ctx.input[12] = counter; + ctx.input[13] = iv_prefix; ctx.input[14] = iv; ctx.input[15] = iv >> 32; }, [&] { - uint64_t counter = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); - chacha20.Seek64(counter); - ctx.input[12] = counter; - ctx.input[13] = counter >> 32; - }, - [&] { uint32_t integralInRange = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096); - // DJB's version seeks forward to a multiple of 64 bytes after every operation. Correct for that. - uint64_t pos = ctx.input[12] + (((uint64_t)ctx.input[13]) << 32) + ((integralInRange + 63) >> 6); std::vector<uint8_t> output(integralInRange); chacha20.Keystream(output.data(), output.size()); std::vector<uint8_t> djb_output(integralInRange); ECRYPT_keystream_bytes(&ctx, djb_output.data(), djb_output.size()); assert(output == djb_output); - chacha20.Seek64(pos); + // DJB's version seeks forward to a multiple of 64 bytes after every operation. Correct for that. + uint32_t old_counter = counter; + counter += (integralInRange + 63) >> 6; + if (counter < old_counter) ++nonce.first; + if (integralInRange & 63) { + chacha20.Seek64(nonce, counter); + } + assert(counter == ctx.input[12]); }, [&] { uint32_t integralInRange = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096); - // DJB's version seeks forward to a multiple of 64 bytes after every operation. Correct for that. - uint64_t pos = ctx.input[12] + (((uint64_t)ctx.input[13]) << 32) + ((integralInRange + 63) >> 6); std::vector<uint8_t> output(integralInRange); const std::vector<uint8_t> input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size()); chacha20.Crypt(input.data(), output.data(), input.size()); std::vector<uint8_t> djb_output(integralInRange); ECRYPT_encrypt_bytes(&ctx, input.data(), djb_output.data(), input.size()); assert(output == djb_output); - chacha20.Seek64(pos); + // DJB's version seeks forward to a multiple of 64 bytes after every operation. Correct for that. + uint32_t old_counter = counter; + counter += (integralInRange + 63) >> 6; + if (counter < old_counter) ++nonce.first; + if (integralInRange & 63) { + chacha20.Seek64(nonce, counter); + } + assert(counter == ctx.input[12]); }); } } diff --git a/src/test/fuzz/crypto_poly1305.cpp b/src/test/fuzz/crypto_poly1305.cpp index ac555ed68c..f49729a34b 100644 --- a/src/test/fuzz/crypto_poly1305.cpp +++ b/src/test/fuzz/crypto_poly1305.cpp @@ -14,9 +14,40 @@ FUZZ_TARGET(crypto_poly1305) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; - const std::vector<uint8_t> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, POLY1305_KEYLEN); + const std::vector<uint8_t> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, Poly1305::KEYLEN); const std::vector<uint8_t> in = ConsumeRandomLengthByteVector(fuzzed_data_provider); - std::vector<uint8_t> tag_out(POLY1305_TAGLEN); - poly1305_auth(tag_out.data(), in.data(), in.size(), key.data()); + std::vector<std::byte> tag_out(Poly1305::TAGLEN); + Poly1305{MakeByteSpan(key)}.Update(MakeByteSpan(in)).Finalize(tag_out); +} + + +FUZZ_TARGET(crypto_poly1305_split) +{ + FuzzedDataProvider provider{buffer.data(), buffer.size()}; + + // Read key and instantiate two Poly1305 objects with it. + auto key = provider.ConsumeBytes<std::byte>(Poly1305::KEYLEN); + key.resize(Poly1305::KEYLEN); + Poly1305 poly_full{key}, poly_split{key}; + + // Vector that holds all bytes processed so far. + std::vector<std::byte> total_input; + + // Process input in pieces. + LIMITED_WHILE(provider.remaining_bytes(), 100) { + auto in = provider.ConsumeRandomLengthString(); + poly_split.Update(MakeByteSpan(in)); + // Update total_input to match what was processed. + total_input.insert(total_input.end(), MakeByteSpan(in).begin(), MakeByteSpan(in).end()); + } + + // Process entire input at once. + poly_full.Update(total_input); + + // Verify both agree. + std::array<std::byte, Poly1305::TAGLEN> tag_split, tag_full; + poly_split.Finalize(tag_split); + poly_full.Finalize(tag_full); + assert(tag_full == tag_split); } diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp index 12c22ef2ed..8ed659323c 100644 --- a/src/test/fuzz/descriptor_parse.cpp +++ b/src/test/fuzz/descriptor_parse.cpp @@ -3,28 +3,167 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <chainparams.h> +#include <key_io.h> #include <pubkey.h> #include <script/descriptor.h> #include <test/fuzz/fuzz.h> #include <util/chaintype.h> +//! Types are raw (un)compressed pubkeys, raw xonly pubkeys, raw privkeys (WIF), xpubs, xprvs. +static constexpr uint8_t KEY_TYPES_COUNT{6}; +//! How many keys we'll generate in total. +static constexpr size_t TOTAL_KEYS_GENERATED{std::numeric_limits<uint8_t>::max() + 1}; + +/** + * Converts a mocked descriptor string to a valid one. Every key in a mocked descriptor key is + * represented by 2 hex characters preceded by the '%' character. We parse the two hex characters + * as an index in a list of pre-generated keys. This list contains keys of the various types + * accepted in descriptor keys expressions. + */ +class MockedDescriptorConverter { + //! 256 keys of various types. + std::array<std::string, TOTAL_KEYS_GENERATED> keys_str; + +public: + // We derive the type of key to generate from the 1-byte id parsed from hex. + bool IdIsCompPubKey(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 0; } + bool IdIsUnCompPubKey(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 1; } + bool IdIsXOnlyPubKey(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 2; } + bool IdIsConstPrivKey(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 3; } + bool IdIsXpub(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 4; } + bool IdIsXprv(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 5; } + + //! When initializing the target, populate the list of keys. + void Init() { + // The data to use as a private key or a seed for an xprv. + std::array<std::byte, 32> key_data{std::byte{1}}; + // Generate keys of all kinds and store them in the keys array. + for (size_t i{0}; i < TOTAL_KEYS_GENERATED; i++) { + key_data[31] = std::byte(i); + + // If this is a "raw" key, generate a normal privkey. Otherwise generate + // an extended one. + if (IdIsCompPubKey(i) || IdIsUnCompPubKey(i) || IdIsXOnlyPubKey(i) || IdIsConstPrivKey(i)) { + CKey privkey; + privkey.Set(UCharCast(key_data.begin()), UCharCast(key_data.end()), !IdIsUnCompPubKey(i)); + if (IdIsCompPubKey(i) || IdIsUnCompPubKey(i)) { + CPubKey pubkey{privkey.GetPubKey()}; + keys_str[i] = HexStr(pubkey); + } else if (IdIsXOnlyPubKey(i)) { + const XOnlyPubKey pubkey{privkey.GetPubKey()}; + keys_str[i] = HexStr(pubkey); + } else { + keys_str[i] = EncodeSecret(privkey); + } + } else { + CExtKey ext_privkey; + ext_privkey.SetSeed(key_data); + if (IdIsXprv(i)) { + keys_str[i] = EncodeExtKey(ext_privkey); + } else { + const CExtPubKey ext_pubkey{ext_privkey.Neuter()}; + keys_str[i] = EncodeExtPubKey(ext_pubkey); + } + } + } + } + + //! Parse an id in the keys vectors from a 2-characters hex string. + std::optional<uint8_t> IdxFromHex(std::string_view hex_characters) const { + if (hex_characters.size() != 2) return {}; + auto idx = ParseHex(hex_characters); + if (idx.size() != 1) return {}; + return idx[0]; + } + + //! Get an actual descriptor string from a descriptor string whose keys were mocked. + std::optional<std::string> GetDescriptor(std::string_view mocked_desc) const { + // The smallest fragment would be "pk(%00)" + if (mocked_desc.size() < 7) return {}; + + // The actual descriptor string to be returned. + std::string desc; + desc.reserve(mocked_desc.size()); + + // Replace all occurrences of '%' followed by two hex characters with the corresponding key. + for (size_t i = 0; i < mocked_desc.size();) { + if (mocked_desc[i] == '%') { + if (i + 3 >= mocked_desc.size()) return {}; + if (const auto idx = IdxFromHex(mocked_desc.substr(i + 1, 2))) { + desc += keys_str[*idx]; + i += 3; + } else { + return {}; + } + } else { + desc += mocked_desc[i++]; + } + } + + return desc; + } +}; + +//! The converter of mocked descriptors, needs to be initialized when the target is. +MockedDescriptorConverter MOCKED_DESC_CONVERTER; + +/** Test a successfully parsed descriptor. */ +static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_provider, std::string& dummy) +{ + // Trivial helpers. + (void)desc.IsRange(); + (void)desc.IsSolvable(); + (void)desc.IsSingleType(); + (void)desc.GetOutputType(); + + // Serialization to string representation. + (void)desc.ToString(); + (void)desc.ToPrivateString(sig_provider, dummy); + (void)desc.ToNormalizedString(sig_provider, dummy); + + // Serialization to Script. + DescriptorCache cache; + std::vector<CScript> out_scripts; + (void)desc.Expand(0, sig_provider, out_scripts, sig_provider, &cache); + (void)desc.ExpandPrivate(0, sig_provider, sig_provider); + (void)desc.ExpandFromCache(0, cache, out_scripts, sig_provider); + + // If we could serialize to script we must be able to infer using the same provider. + if (!out_scripts.empty()) { + assert(InferDescriptor(out_scripts.back(), sig_provider)); + } +} + void initialize_descriptor_parse() { ECC_Start(); SelectParams(ChainType::MAIN); } -FUZZ_TARGET_INIT(descriptor_parse, initialize_descriptor_parse) +void initialize_mocked_descriptor_parse() +{ + initialize_descriptor_parse(); + MOCKED_DESC_CONVERTER.Init(); +} + +FUZZ_TARGET(mocked_descriptor_parse, .init = initialize_mocked_descriptor_parse) +{ + const std::string mocked_descriptor{buffer.begin(), buffer.end()}; + if (const auto descriptor = MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)) { + FlatSigningProvider signing_provider; + std::string error; + const auto desc = Parse(*descriptor, signing_provider, error); + if (desc) TestDescriptor(*desc, signing_provider, error); + } +} + +FUZZ_TARGET(descriptor_parse, .init = initialize_descriptor_parse) { const std::string descriptor(buffer.begin(), buffer.end()); FlatSigningProvider signing_provider; std::string error; for (const bool require_checksum : {true, false}) { const auto desc = Parse(descriptor, signing_provider, error, require_checksum); - if (desc) { - (void)desc->ToString(); - (void)desc->IsRange(); - (void)desc->IsSolvable(); - } + if (desc) TestDescriptor(*desc, signing_provider, error); } } diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp index 177711c6e4..09402233bd 100644 --- a/src/test/fuzz/deserialize.cpp +++ b/src/test/fuzz/deserialize.cpp @@ -49,7 +49,7 @@ void initialize_deserialize() } #define FUZZ_TARGET_DESERIALIZE(name, code) \ - FUZZ_TARGET_INIT(name, initialize_deserialize) \ + FUZZ_TARGET(name, .init = initialize_deserialize) \ { \ try { \ code \ diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp index 44ba8bc254..c20cbde05f 100644 --- a/src/test/fuzz/fuzz.cpp +++ b/src/test/fuzz/fuzz.cpp @@ -54,20 +54,25 @@ const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS = return g_args; }; -std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>>& FuzzTargets() +struct FuzzTarget { + const TypeTestOneInput test_one_input; + const FuzzTargetOptions opts; +}; + +auto& FuzzTargets() { - static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>> g_fuzz_targets; + static std::map<std::string_view, FuzzTarget> g_fuzz_targets; return g_fuzz_targets; } -void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init, TypeHidden hidden) +void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, FuzzTargetOptions opts) { - const auto it_ins = FuzzTargets().try_emplace(name, std::move(target), std::move(init), hidden); + const auto it_ins{FuzzTargets().try_emplace(name, FuzzTarget /* temporary can be dropped in C++20 */ {std::move(target), std::move(opts)})}; Assert(it_ins.second); } static std::string_view g_fuzz_target; -static TypeTestOneInput* g_test_one_input{nullptr}; +static const TypeTestOneInput* g_test_one_input{nullptr}; void initialize() { @@ -84,22 +89,22 @@ void initialize() bool should_exit{false}; 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; + for (const auto& [name, t] : FuzzTargets()) { + if (t.opts.hidden) continue; + std::cout << name << std::endl; } should_exit = true; } if (const char* out_path = std::getenv("WRITE_ALL_FUZZ_TARGETS_AND_ABORT")) { std::cout << "Writing all fuzz target names to '" << out_path << "'." << std::endl; std::ofstream out_stream{out_path, std::ios::binary}; - for (const auto& t : FuzzTargets()) { - if (std::get<2>(t.second)) continue; - out_stream << t.first << std::endl; + for (const auto& [name, t] : FuzzTargets()) { + if (t.opts.hidden) continue; + out_stream << name << std::endl; } - should_exit= true; + should_exit = true; } - if (should_exit){ + if (should_exit) { std::exit(EXIT_SUCCESS); } if (const auto* env_fuzz{std::getenv("FUZZ")}) { @@ -117,8 +122,8 @@ void initialize() std::exit(EXIT_FAILURE); } Assert(!g_test_one_input); - g_test_one_input = &std::get<0>(it->second); - std::get<1>(it->second)(); + g_test_one_input = &it->second.test_one_input; + it->second.opts.init(); } #if defined(PROVIDE_FUZZ_MAIN_FUNCTION) diff --git a/src/test/fuzz/fuzz.h b/src/test/fuzz/fuzz.h index c91c33da67..0534f9bcf1 100644 --- a/src/test/fuzz/fuzz.h +++ b/src/test/fuzz/fuzz.h @@ -21,25 +21,25 @@ using FuzzBufferType = Span<const uint8_t>; using TypeTestOneInput = std::function<void(FuzzBufferType)>; -using TypeInitialize = std::function<void()>; -using TypeHidden = bool; +struct FuzzTargetOptions { + std::function<void()> init{[] {}}; + bool hidden{false}; +}; -void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init, TypeHidden hidden); +void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, FuzzTargetOptions opts); -inline void FuzzFrameworkEmptyInitFun() {} +#if defined(__clang__) +#define FUZZ_TARGET(...) _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"") DETAIL_FUZZ(__VA_ARGS__) _Pragma("clang diagnostic pop") +#else +#define FUZZ_TARGET(...) DETAIL_FUZZ(__VA_ARGS__) +#endif -#define FUZZ_TARGET(name) \ - 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) \ +#define DETAIL_FUZZ(name, ...) \ void name##_fuzz_target(FuzzBufferType); \ struct name##_Before_Main { \ name##_Before_Main() \ { \ - FuzzFrameworkRegisterTarget(#name, name##_fuzz_target, init_fun, hidden); \ + FuzzFrameworkRegisterTarget(#name, name##_fuzz_target, {__VA_ARGS__}); \ } \ } const static g_##name##_before_main; \ void name##_fuzz_target(FuzzBufferType buffer) diff --git a/src/test/fuzz/golomb_rice.cpp b/src/test/fuzz/golomb_rice.cpp index 1a1225b635..e006653ca9 100644 --- a/src/test/fuzz/golomb_rice.cpp +++ b/src/test/fuzz/golomb_rice.cpp @@ -23,7 +23,7 @@ namespace { uint64_t HashToRange(const std::vector<uint8_t>& element, const uint64_t f) { const uint64_t hash = CSipHasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL) - .Write(element.data(), element.size()) + .Write(element) .Finalize(); return FastRange64(hash, f); } diff --git a/src/test/fuzz/headerssync.cpp b/src/test/fuzz/headerssync.cpp index c1a187038b..62f6bbaffe 100644 --- a/src/test/fuzz/headerssync.cpp +++ b/src/test/fuzz/headerssync.cpp @@ -46,7 +46,7 @@ public: } }; -FUZZ_TARGET_INIT(headers_sync_state, initialize_headers_sync_state_fuzz) +FUZZ_TARGET(headers_sync_state, .init = initialize_headers_sync_state_fuzz) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); auto mock_time{ConsumeTime(fuzzed_data_provider)}; diff --git a/src/test/fuzz/i2p.cpp b/src/test/fuzz/i2p.cpp index 3c6db96446..943595f8a4 100644 --- a/src/test/fuzz/i2p.cpp +++ b/src/test/fuzz/i2p.cpp @@ -18,7 +18,7 @@ void initialize_i2p() static const auto testing_setup = MakeNoLogFileContext<>(); } -FUZZ_TARGET_INIT(i2p, initialize_i2p) +FUZZ_TARGET(i2p, .init = initialize_i2p) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp index edb1dca457..91521bc7f4 100644 --- a/src/test/fuzz/integer.cpp +++ b/src/test/fuzz/integer.cpp @@ -46,7 +46,7 @@ void initialize_integer() SelectParams(ChainType::REGTEST); } -FUZZ_TARGET_INIT(integer, initialize_integer) +FUZZ_TARGET(integer, .init = initialize_integer) { if (buffer.size() < sizeof(uint256) + sizeof(uint160)) { return; diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp index 3eab2e20c0..8faeb9e04f 100644 --- a/src/test/fuzz/key.cpp +++ b/src/test/fuzz/key.cpp @@ -15,13 +15,17 @@ #include <script/signingprovider.h> #include <script/standard.h> #include <streams.h> +#include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <util/chaintype.h> #include <util/strencodings.h> +#include <array> #include <cassert> +#include <cstddef> #include <cstdint> #include <numeric> +#include <optional> #include <string> #include <vector> @@ -31,7 +35,7 @@ void initialize_key() SelectParams(ChainType::REGTEST); } -FUZZ_TARGET_INIT(key, initialize_key) +FUZZ_TARGET(key, .init = initialize_key) { const CKey key = [&] { CKey k; @@ -303,3 +307,79 @@ FUZZ_TARGET_INIT(key, initialize_key) } } } + +FUZZ_TARGET(ellswift_roundtrip, .init = initialize_key) +{ + FuzzedDataProvider fdp{buffer.data(), buffer.size()}; + + auto key_bytes = fdp.ConsumeBytes<uint8_t>(32); + key_bytes.resize(32); + CKey key; + key.Set(key_bytes.begin(), key_bytes.end(), true); + if (!key.IsValid()) return; + + auto ent32 = fdp.ConsumeBytes<std::byte>(32); + ent32.resize(32); + + auto encoded_ellswift = key.EllSwiftCreate(ent32); + auto decoded_pubkey = encoded_ellswift.Decode(); + + assert(key.VerifyPubKey(decoded_pubkey)); +} + +FUZZ_TARGET(bip324_ecdh, .init = initialize_key) +{ + FuzzedDataProvider fdp{buffer.data(), buffer.size()}; + + // We generate private key, k1. + auto rnd32 = fdp.ConsumeBytes<uint8_t>(32); + rnd32.resize(32); + CKey k1; + k1.Set(rnd32.begin(), rnd32.end(), true); + if (!k1.IsValid()) return; + + // They generate private key, k2. + rnd32 = fdp.ConsumeBytes<uint8_t>(32); + rnd32.resize(32); + CKey k2; + k2.Set(rnd32.begin(), rnd32.end(), true); + if (!k2.IsValid()) return; + + // We construct an ellswift encoding for our key, k1_ellswift. + auto ent32_1 = fdp.ConsumeBytes<std::byte>(32); + ent32_1.resize(32); + auto k1_ellswift = k1.EllSwiftCreate(ent32_1); + + // They construct an ellswift encoding for their key, k2_ellswift. + auto ent32_2 = fdp.ConsumeBytes<std::byte>(32); + ent32_2.resize(32); + auto k2_ellswift = k2.EllSwiftCreate(ent32_2); + + // They construct another (possibly distinct) ellswift encoding for their key, k2_ellswift_bad. + auto ent32_2_bad = fdp.ConsumeBytes<std::byte>(32); + ent32_2_bad.resize(32); + auto k2_ellswift_bad = k2.EllSwiftCreate(ent32_2_bad); + assert((ent32_2_bad == ent32_2) == (k2_ellswift_bad == k2_ellswift)); + + // Determine who is who. + bool initiating = fdp.ConsumeBool(); + + // We compute our shared secret using our key and their public key. + auto ecdh_secret_1 = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, initiating); + // They compute their shared secret using their key and our public key. + auto ecdh_secret_2 = k2.ComputeBIP324ECDHSecret(k1_ellswift, k2_ellswift, !initiating); + // Those must match, as everyone is behaving correctly. + assert(ecdh_secret_1 == ecdh_secret_2); + + if (k1_ellswift != k2_ellswift) { + // Unless the two keys are exactly identical, acting as the wrong party breaks things. + auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, !initiating); + assert(ecdh_secret_bad != ecdh_secret_1); + } + + if (k2_ellswift_bad != k2_ellswift) { + // Unless both encodings created by them are identical, using the second one breaks things. + auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift_bad, k1_ellswift, initiating); + assert(ecdh_secret_bad != ecdh_secret_1); + } +} diff --git a/src/test/fuzz/key_io.cpp b/src/test/fuzz/key_io.cpp index a1c587a75b..5f98f2b7f1 100644 --- a/src/test/fuzz/key_io.cpp +++ b/src/test/fuzz/key_io.cpp @@ -18,7 +18,7 @@ void initialize_key_io() SelectParams(ChainType::MAIN); } -FUZZ_TARGET_INIT(key_io, initialize_key_io) +FUZZ_TARGET(key_io, .init = initialize_key_io) { const std::string random_string(buffer.begin(), buffer.end()); diff --git a/src/test/fuzz/load_external_block_file.cpp b/src/test/fuzz/load_external_block_file.cpp index f4b7dc08fd..bdaa4ad1b8 100644 --- a/src/test/fuzz/load_external_block_file.cpp +++ b/src/test/fuzz/load_external_block_file.cpp @@ -23,7 +23,7 @@ void initialize_load_external_block_file() g_setup = testing_setup.get(); } -FUZZ_TARGET_INIT(load_external_block_file, initialize_load_external_block_file) +FUZZ_TARGET(load_external_block_file, .init = initialize_load_external_block_file) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider); @@ -35,9 +35,9 @@ FUZZ_TARGET_INIT(load_external_block_file, initialize_load_external_block_file) // Corresponds to the -reindex case (track orphan blocks across files). FlatFilePos flat_file_pos; std::multimap<uint256, FlatFilePos> blocks_with_unknown_parent; - g_setup->m_node.chainman->ActiveChainstate().LoadExternalBlockFile(fuzzed_block_file, &flat_file_pos, &blocks_with_unknown_parent); + g_setup->m_node.chainman->LoadExternalBlockFile(fuzzed_block_file, &flat_file_pos, &blocks_with_unknown_parent); } else { // Corresponds to the -loadblock= case (orphan blocks aren't tracked across files). - g_setup->m_node.chainman->ActiveChainstate().LoadExternalBlockFile(fuzzed_block_file); + g_setup->m_node.chainman->LoadExternalBlockFile(fuzzed_block_file); } } diff --git a/src/test/fuzz/message.cpp b/src/test/fuzz/message.cpp index 8b7e3f11cc..f839f9e326 100644 --- a/src/test/fuzz/message.cpp +++ b/src/test/fuzz/message.cpp @@ -23,7 +23,7 @@ void initialize_message() SelectParams(ChainType::REGTEST); } -FUZZ_TARGET_INIT(message, initialize_message) +FUZZ_TARGET(message, .init = initialize_message) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::string random_message = fuzzed_data_provider.ConsumeRandomLengthString(1024); diff --git a/src/test/fuzz/mini_miner.cpp b/src/test/fuzz/mini_miner.cpp index 2b371f6d5f..e17e2bad60 100644 --- a/src/test/fuzz/mini_miner.cpp +++ b/src/test/fuzz/mini_miner.cpp @@ -30,7 +30,7 @@ void initialize_miner() } // Test that the MiniMiner can run with various outpoints and feerates. -FUZZ_TARGET_INIT(mini_miner, initialize_miner) +FUZZ_TARGET(mini_miner, .init = initialize_miner) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; CTxMemPool pool{CTxMemPool::Options{}}; @@ -106,7 +106,7 @@ FUZZ_TARGET_INIT(mini_miner, initialize_miner) } // Test that MiniMiner and BlockAssembler build the same block given the same transactions and constraints. -FUZZ_TARGET_INIT(mini_miner_selection, initialize_miner) +FUZZ_TARGET(mini_miner_selection, .init = initialize_miner) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; CTxMemPool pool{CTxMemPool::Options{}}; diff --git a/src/test/fuzz/miniscript.cpp b/src/test/fuzz/miniscript.cpp index 81c6f076b2..56327b9665 100644 --- a/src/test/fuzz/miniscript.cpp +++ b/src/test/fuzz/miniscript.cpp @@ -943,7 +943,8 @@ void TestNode(const NodeRef& node, FuzzedDataProvider& provider) assert(decoded->ToScript(PARSER_CTX) == script); assert(decoded->GetType() == node->GetType()); - if (provider.ConsumeBool() && node->GetOps() < MAX_OPS_PER_SCRIPT && node->ScriptSize() < MAX_STANDARD_P2WSH_SCRIPT_SIZE) { + const auto node_ops{node->GetOps()}; + if (provider.ConsumeBool() && node_ops && *node_ops < MAX_OPS_PER_SCRIPT && node->ScriptSize() < MAX_STANDARD_P2WSH_SCRIPT_SIZE) { // Optionally pad the script with OP_NOPs to max op the ops limit of the constructed script. // This makes the script obviously not actually miniscript-compatible anymore, but the // signatures constructed in this test don't commit to the script anyway, so the same @@ -954,7 +955,7 @@ void TestNode(const NodeRef& node, FuzzedDataProvider& provider) // Do not pad more than what would cause MAX_STANDARD_P2WSH_SCRIPT_SIZE to be reached, however, // as that also invalidates scripts. int add = std::min<int>( - MAX_OPS_PER_SCRIPT - node->GetOps(), + MAX_OPS_PER_SCRIPT - *node_ops, MAX_STANDARD_P2WSH_SCRIPT_SIZE - node->ScriptSize()); for (int i = 0; i < add; ++i) script.push_back(OP_NOP); } @@ -972,7 +973,7 @@ void TestNode(const NodeRef& node, FuzzedDataProvider& provider) if (nonmal_success) { // Non-malleable satisfactions are bounded by GetStackSize(). - assert(witness_nonmal.stack.size() <= node->GetStackSize()); + assert(witness_nonmal.stack.size() <= *node->GetStackSize()); // If a non-malleable satisfaction exists, the malleable one must also exist, and be identical to it. assert(mal_success); assert(witness_nonmal.stack == witness_mal.stack); @@ -1058,7 +1059,7 @@ void FuzzInitSmart() } /** Fuzz target that runs TestNode on nodes generated using ConsumeNodeStable. */ -FUZZ_TARGET_INIT(miniscript_stable, FuzzInit) +FUZZ_TARGET(miniscript_stable, .init = FuzzInit) { FuzzedDataProvider provider(buffer.data(), buffer.size()); TestNode(GenNode([&](Type needed_type) { @@ -1067,7 +1068,7 @@ FUZZ_TARGET_INIT(miniscript_stable, FuzzInit) } /** Fuzz target that runs TestNode on nodes generated using ConsumeNodeSmart. */ -FUZZ_TARGET_INIT(miniscript_smart, FuzzInitSmart) +FUZZ_TARGET(miniscript_smart, .init = FuzzInitSmart) { /** The set of types we aim to construct nodes for. Together they cover all. */ static constexpr std::array<Type, 4> BASE_TYPES{"B"_mst, "V"_mst, "K"_mst, "W"_mst}; @@ -1079,7 +1080,7 @@ FUZZ_TARGET_INIT(miniscript_smart, FuzzInitSmart) } /* Fuzz tests that test parsing from a string, and roundtripping via string. */ -FUZZ_TARGET_INIT(miniscript_string, FuzzInit) +FUZZ_TARGET(miniscript_string, .init = FuzzInit) { FuzzedDataProvider provider(buffer.data(), buffer.size()); auto str = provider.ConsumeRemainingBytesAsString(); diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp index e090f13061..ddf919f2e6 100644 --- a/src/test/fuzz/net.cpp +++ b/src/test/fuzz/net.cpp @@ -27,7 +27,7 @@ void initialize_net() static const auto testing_setup = MakeNoLogFileContext<>(ChainType::MAIN); } -FUZZ_TARGET_INIT(net, initialize_net) +FUZZ_TARGET(net, .init = initialize_net) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); SetMockTime(ConsumeTime(fuzzed_data_provider)); diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp index 049ae02f4d..5141d3362d 100644 --- a/src/test/fuzz/netaddress.cpp +++ b/src/test/fuzz/netaddress.cpp @@ -84,7 +84,7 @@ FUZZ_TARGET(netaddress) (void)CServiceHash(0, 0)(service); const CNetAddr other_net_addr = ConsumeNetAddr(fuzzed_data_provider); - (void)net_addr.GetReachabilityFrom(&other_net_addr); + (void)net_addr.GetReachabilityFrom(other_net_addr); (void)sub_net.Match(other_net_addr); const CService other_service{net_addr, fuzzed_data_provider.ConsumeIntegral<uint16_t>()}; diff --git a/src/test/fuzz/p2p_transport_serialization.cpp b/src/test/fuzz/p2p_transport_serialization.cpp index ec3cdbff5a..78350a600e 100644 --- a/src/test/fuzz/p2p_transport_serialization.cpp +++ b/src/test/fuzz/p2p_transport_serialization.cpp @@ -22,7 +22,7 @@ void initialize_p2p_transport_serialization() SelectParams(ChainType::REGTEST); } -FUZZ_TARGET_INIT(p2p_transport_serialization, initialize_p2p_transport_serialization) +FUZZ_TARGET(p2p_transport_serialization, .init = initialize_p2p_transport_serialization) { // Construct deserializer, with a dummy NodeId V1TransportDeserializer deserializer{Params(), NodeId{0}, SER_NETWORK, INIT_PROTO_VERSION}; @@ -77,7 +77,7 @@ FUZZ_TARGET_INIT(p2p_transport_serialization, initialize_p2p_transport_serializa assert(msg.m_time == m_time); std::vector<unsigned char> header; - auto msg2 = CNetMsgMaker{msg.m_recv.GetVersion()}.Make(msg.m_type, MakeUCharSpan(msg.m_recv)); + auto msg2 = CNetMsgMaker{msg.m_recv.GetVersion()}.Make(msg.m_type, Span{msg.m_recv}); serializer.prepareForTransport(msg2, header); } } diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp index 6d33c1a8cc..a3d6ab6375 100644 --- a/src/test/fuzz/parse_univalue.cpp +++ b/src/test/fuzz/parse_univalue.cpp @@ -3,7 +3,6 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <chainparams.h> -#include <core_io.h> #include <rpc/client.h> #include <rpc/util.h> #include <test/fuzz/fuzz.h> @@ -17,7 +16,7 @@ void initialize_parse_univalue() SelectParams(ChainType::REGTEST); } -FUZZ_TARGET_INIT(parse_univalue, initialize_parse_univalue) +FUZZ_TARGET(parse_univalue, .init = initialize_parse_univalue) { const std::string random_string(buffer.begin(), buffer.end()); bool valid = true; @@ -58,12 +57,6 @@ FUZZ_TARGET_INIT(parse_univalue, initialize_parse_univalue) } catch (const UniValue&) { } try { - (void)ParseHexUV(univalue, "A"); - (void)ParseHexUV(univalue, random_string); - } catch (const UniValue&) { - } catch (const std::runtime_error&) { - } - try { (void)ParseHexV(univalue, "A"); } catch (const UniValue&) { } catch (const std::runtime_error&) { @@ -74,8 +67,8 @@ FUZZ_TARGET_INIT(parse_univalue, initialize_parse_univalue) } catch (const std::runtime_error&) { } try { - (void)ParseSighashString(univalue); - } catch (const std::runtime_error&) { + if (univalue.isNull() || univalue.isStr()) (void)ParseSighashString(univalue); + } catch (const UniValue&) { } try { (void)AmountFromValue(univalue); diff --git a/src/test/fuzz/partially_downloaded_block.cpp b/src/test/fuzz/partially_downloaded_block.cpp index f8ba4f08d9..ae7a68762e 100644 --- a/src/test/fuzz/partially_downloaded_block.cpp +++ b/src/test/fuzz/partially_downloaded_block.cpp @@ -40,7 +40,7 @@ PartiallyDownloadedBlock::CheckBlockFn FuzzedCheckBlock(std::optional<BlockValid }; } -FUZZ_TARGET_INIT(partially_downloaded_block, initialize_pdb) +FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp index 116fbd9015..227ee9d2c4 100644 --- a/src/test/fuzz/policy_estimator.cpp +++ b/src/test/fuzz/policy_estimator.cpp @@ -28,10 +28,10 @@ void initialize_policy_estimator() g_setup = testing_setup.get(); } -FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator) +FUZZ_TARGET(policy_estimator, .init = initialize_policy_estimator) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args)}; + CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES}; LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) { CallOneOf( fuzzed_data_provider, diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp index 7c3289cd26..c04ef8f5b0 100644 --- a/src/test/fuzz/policy_estimator_io.cpp +++ b/src/test/fuzz/policy_estimator_io.cpp @@ -22,13 +22,13 @@ void initialize_policy_estimator_io() g_setup = testing_setup.get(); } -FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io) +FUZZ_TARGET(policy_estimator_io, .init = initialize_policy_estimator_io) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider); AutoFile fuzzed_auto_file{fuzzed_auto_file_provider.open()}; // Re-using block_policy_estimator across runs to avoid costly creation of CBlockPolicyEstimator object. - static CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args)}; + static CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES}; if (block_policy_estimator.Read(fuzzed_auto_file)) { block_policy_estimator.Write(fuzzed_auto_file); } diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp index 6d584c9f10..05cdb740e4 100644 --- a/src/test/fuzz/pow.cpp +++ b/src/test/fuzz/pow.cpp @@ -23,7 +23,7 @@ void initialize_pow() SelectParams(ChainType::MAIN); } -FUZZ_TARGET_INIT(pow, initialize_pow) +FUZZ_TARGET(pow, .init = initialize_pow) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const Consensus::Params& consensus_params = Params().GetConsensus(); @@ -87,7 +87,7 @@ FUZZ_TARGET_INIT(pow, initialize_pow) } -FUZZ_TARGET_INIT(pow_transition, initialize_pow) +FUZZ_TARGET(pow_transition, .init = initialize_pow) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const Consensus::Params& consensus_params{Params().GetConsensus()}; diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index 744ff4701d..6ed83feddf 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -58,7 +58,7 @@ void initialize_process_message() SyncWithValidationInterfaceQueue(); } -FUZZ_TARGET_INIT(process_message, initialize_process_message) +FUZZ_TARGET(process_message, .init = initialize_process_message) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index 68d4e02a26..58e023956c 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -33,7 +33,7 @@ void initialize_process_messages() SyncWithValidationInterfaceQueue(); } -FUZZ_TARGET_INIT(process_messages, initialize_process_messages) +FUZZ_TARGET(process_messages, .init = initialize_process_messages) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp index 57a9a15a85..dbe99029c3 100644 --- a/src/test/fuzz/rbf.cpp +++ b/src/test/fuzz/rbf.cpp @@ -29,7 +29,7 @@ void initialize_rbf() g_setup = testing_setup.get(); } -FUZZ_TARGET_INIT(rbf, initialize_rbf) +FUZZ_TARGET(rbf, .init = initialize_rbf) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); SetMockTime(ConsumeTime(fuzzed_data_provider)); diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp index b1858a1800..2782888dc3 100644 --- a/src/test/fuzz/rpc.cpp +++ b/src/test/fuzz/rpc.cpp @@ -73,6 +73,7 @@ const std::vector<std::string> RPC_COMMANDS_NOT_SAFE_FOR_FUZZING{ "addpeeraddress", // avoid DNS lookups "dumptxoutset", // avoid writing to disk "dumpwallet", // avoid writing to disk + "enumeratesigners", "echoipc", // avoid assertion failure (Assertion `"EnsureAnyNodeContext(request.context).init" && check' failed.) "generatetoaddress", // avoid prohibitively slow execution (when `num_blocks` is large) "generatetodescriptor", // avoid prohibitively slow execution (when `nblocks` is large) @@ -347,7 +348,7 @@ void initialize_rpc() } } -FUZZ_TARGET_INIT(rpc, initialize_rpc) +FUZZ_TARGET(rpc, .init = initialize_rpc) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; SetMockTime(ConsumeTime(fuzzed_data_provider)); diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index 8a88c1107a..1cb7d01906 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -36,7 +36,7 @@ void initialize_script() SelectParams(ChainType::REGTEST); } -FUZZ_TARGET_INIT(script, initialize_script) +FUZZ_TARGET(script, .init = initialize_script) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const CScript script{ConsumeScript(fuzzed_data_provider)}; diff --git a/src/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp index 206d219afe..7862be2f21 100644 --- a/src/test/fuzz/script_assets_test_minimizer.cpp +++ b/src/test/fuzz/script_assets_test_minimizer.cpp @@ -186,7 +186,7 @@ void Test(const std::string& str) void test_init() {} -FUZZ_TARGET_INIT_HIDDEN(script_assets_test_minimizer, test_init, /*hidden=*/true) +FUZZ_TARGET(script_assets_test_minimizer, .init = test_init, .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_format.cpp b/src/test/fuzz/script_format.cpp index 5aa0ea58ff..10150dcd7f 100644 --- a/src/test/fuzz/script_format.cpp +++ b/src/test/fuzz/script_format.cpp @@ -18,7 +18,7 @@ void initialize_script_format() SelectParams(ChainType::REGTEST); } -FUZZ_TARGET_INIT(script_format, initialize_script_format) +FUZZ_TARGET(script_format, .init = initialize_script_format) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const CScript script{ConsumeScript(fuzzed_data_provider)}; diff --git a/src/test/fuzz/script_sigcache.cpp b/src/test/fuzz/script_sigcache.cpp index f332987987..486b1e5197 100644 --- a/src/test/fuzz/script_sigcache.cpp +++ b/src/test/fuzz/script_sigcache.cpp @@ -26,7 +26,7 @@ void initialize_script_sigcache() g_setup = testing_setup.get(); } -FUZZ_TARGET_INIT(script_sigcache, initialize_script_sigcache) +FUZZ_TARGET(script_sigcache, .init = initialize_script_sigcache) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); diff --git a/src/test/fuzz/script_sign.cpp b/src/test/fuzz/script_sign.cpp index 8b62daf162..cec98432e1 100644 --- a/src/test/fuzz/script_sign.cpp +++ b/src/test/fuzz/script_sign.cpp @@ -30,7 +30,7 @@ void initialize_script_sign() SelectParams(ChainType::REGTEST); } -FUZZ_TARGET_INIT(script_sign, initialize_script_sign) +FUZZ_TARGET(script_sign, .init = initialize_script_sign) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::vector<uint8_t> key = ConsumeRandomLengthByteVector(fuzzed_data_provider, 128); diff --git a/src/test/fuzz/signet.cpp b/src/test/fuzz/signet.cpp index e9af93c639..3ccf5eb6f0 100644 --- a/src/test/fuzz/signet.cpp +++ b/src/test/fuzz/signet.cpp @@ -22,7 +22,7 @@ void initialize_signet() static const auto testing_setup = MakeNoLogFileContext<>(ChainType::SIGNET); } -FUZZ_TARGET_INIT(signet, initialize_signet) +FUZZ_TARGET(signet, .init = initialize_signet) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; const std::optional<CBlock> block = ConsumeDeserializable<CBlock>(fuzzed_data_provider); diff --git a/src/test/fuzz/socks5.cpp b/src/test/fuzz/socks5.cpp index 73235b7ced..05b8312ab2 100644 --- a/src/test/fuzz/socks5.cpp +++ b/src/test/fuzz/socks5.cpp @@ -26,7 +26,7 @@ void initialize_socks5() default_socks5_recv_timeout = g_socks5_recv_timeout; } -FUZZ_TARGET_INIT(socks5, initialize_socks5) +FUZZ_TARGET(socks5, .init = initialize_socks5) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; ProxyCredentials proxy_credentials; diff --git a/src/test/fuzz/system.cpp b/src/test/fuzz/system.cpp index 73c01d9297..73ae89b52a 100644 --- a/src/test/fuzz/system.cpp +++ b/src/test/fuzz/system.cpp @@ -27,7 +27,7 @@ std::string GetArgumentName(const std::string& name) return name.substr(0, idx); } -FUZZ_TARGET_INIT(system, initialize_system) +FUZZ_TARGET(system, .init = initialize_system) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); ArgsManager args_manager{}; diff --git a/src/test/fuzz/torcontrol.cpp b/src/test/fuzz/torcontrol.cpp index a78715f769..6189b3c08d 100644 --- a/src/test/fuzz/torcontrol.cpp +++ b/src/test/fuzz/torcontrol.cpp @@ -39,7 +39,7 @@ void initialize_torcontrol() static const auto testing_setup = MakeNoLogFileContext<>(); } -FUZZ_TARGET_INIT(torcontrol, initialize_torcontrol) +FUZZ_TARGET(torcontrol, .init = initialize_torcontrol) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp index 7035c53d13..88c2a334c7 100644 --- a/src/test/fuzz/transaction.cpp +++ b/src/test/fuzz/transaction.cpp @@ -27,7 +27,7 @@ void initialize_transaction() SelectParams(ChainType::REGTEST); } -FUZZ_TARGET_INIT(transaction, initialize_transaction) +FUZZ_TARGET(transaction, .init = initialize_transaction) { CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); try { @@ -101,7 +101,14 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction) (void)AreInputsStandard(tx, coins_view_cache); (void)IsWitnessStandard(tx, coins_view_cache); - UniValue u(UniValue::VOBJ); - TxToUniv(tx, /*block_hash=*/uint256::ZERO, /*entry=*/u); - TxToUniv(tx, /*block_hash=*/uint256::ONE, /*entry=*/u); + if (tx.GetTotalSize() < 250'000) { // Avoid high memory usage (with msan) due to json encoding + { + UniValue u{UniValue::VOBJ}; + TxToUniv(tx, /*block_hash=*/uint256::ZERO, /*entry=*/u); + } + { + UniValue u{UniValue::VOBJ}; + TxToUniv(tx, /*block_hash=*/uint256::ONE, /*entry=*/u); + } + } } diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index b758c715ef..ee73f67f66 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -131,7 +131,7 @@ CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeConte return CTxMemPool{mempool_opts}; } -FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool) +FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const auto& node = g_setup->m_node; @@ -307,7 +307,7 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool) Finish(fuzzed_data_provider, tx_pool, chainstate); } -FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool) +FUZZ_TARGET(tx_pool, .init = initialize_tx_pool) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const auto& node = g_setup->m_node; diff --git a/src/test/fuzz/txorphan.cpp b/src/test/fuzz/txorphan.cpp index ed55e3fad5..a84dc951fc 100644 --- a/src/test/fuzz/txorphan.cpp +++ b/src/test/fuzz/txorphan.cpp @@ -30,7 +30,7 @@ void initialize_orphanage() static const auto testing_setup = MakeNoLogFileContext(); } -FUZZ_TARGET_INIT(txorphan, initialize_orphanage) +FUZZ_TARGET(txorphan, .init = initialize_orphanage) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); SetMockTime(ConsumeTime(fuzzed_data_provider)); diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp index b4ef0c7a3e..dce728d96b 100644 --- a/src/test/fuzz/utxo_snapshot.cpp +++ b/src/test/fuzz/utxo_snapshot.cpp @@ -28,7 +28,7 @@ void initialize_chain() g_chain = &chain; } -FUZZ_TARGET_INIT(utxo_snapshot, initialize_chain) +FUZZ_TARGET(utxo_snapshot, .init = initialize_chain) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); std::unique_ptr<const TestingSetup> setup{MakeNoLogFileContext<const TestingSetup>()}; diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp index 4e2ca6d903..c203dd4e39 100644 --- a/src/test/fuzz/validation_load_mempool.cpp +++ b/src/test/fuzz/validation_load_mempool.cpp @@ -33,7 +33,7 @@ void initialize_validation_load_mempool() g_setup = testing_setup.get(); } -FUZZ_TARGET_INIT(validation_load_mempool, initialize_validation_load_mempool) +FUZZ_TARGET(validation_load_mempool, .init = initialize_validation_load_mempool) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; SetMockTime(ConsumeTime(fuzzed_data_provider)); diff --git a/src/test/fuzz/versionbits.cpp b/src/test/fuzz/versionbits.cpp index b3df4dadd2..c1b0f552ea 100644 --- a/src/test/fuzz/versionbits.cpp +++ b/src/test/fuzz/versionbits.cpp @@ -111,7 +111,7 @@ void initialize() constexpr uint32_t MAX_START_TIME = 4102444800; // 2100-01-01 -FUZZ_TARGET_INIT(versionbits, initialize) +FUZZ_TARGET(versionbits, .init = initialize) { const CChainParams& params = *g_params; const int64_t interval = params.GetConsensus().nPowTargetSpacing; |