aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/data/script_tests.json2
-rw-r--r--src/test/denialofservice_tests.cpp102
-rw-r--r--src/test/descriptor_tests.cpp2
-rw-r--r--src/test/fuzz/addrdb.cpp2
-rw-r--r--src/test/fuzz/autofile.cpp72
-rw-r--r--src/test/fuzz/banman.cpp88
-rw-r--r--src/test/fuzz/buffered_file.cpp78
-rw-r--r--src/test/fuzz/crypto_aes256.cpp30
-rw-r--r--src/test/fuzz/crypto_aes256cbc.cpp34
-rw-r--r--src/test/fuzz/crypto_chacha20.cpp50
-rw-r--r--src/test/fuzz/crypto_chacha20_poly1305_aead.cpp72
-rw-r--r--src/test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp25
-rw-r--r--src/test/fuzz/crypto_poly1305.cpp22
-rw-r--r--src/test/fuzz/http_request.cpp10
-rw-r--r--src/test/fuzz/load_external_block_file.cpp31
-rw-r--r--src/test/fuzz/netaddress.cpp30
-rw-r--r--src/test/fuzz/policy_estimator.cpp11
-rw-r--r--src/test/fuzz/policy_estimator_io.cpp28
-rw-r--r--src/test/fuzz/process_message.cpp4
-rw-r--r--src/test/fuzz/script.cpp2
-rw-r--r--src/test/fuzz/scriptnum_ops.cpp2
-rw-r--r--src/test/fuzz/signature_checker.cpp6
-rw-r--r--src/test/fuzz/util.h242
-rw-r--r--src/test/netbase_tests.cpp2
-rw-r--r--src/test/settings_tests.cpp80
-rw-r--r--src/test/sync_tests.cpp2
-rw-r--r--src/test/util_tests.cpp33
27 files changed, 956 insertions, 106 deletions
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
index c01ef307b7..724789bbf9 100644
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -678,7 +678,7 @@
["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "", "OK"],
["While not really correctly DER encoded, the empty signature is allowed by"],
-["STRICTENC to provide a compact way to provide a delibrately invalid signature."],
+["STRICTENC to provide a compact way to provide a deliberately invalid signature."],
["0", "0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT", "STRICTENC", "OK"],
["0 0", "1 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 1 CHECKMULTISIG NOT", "STRICTENC", "OK"],
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 1fe01fae04..b1a635d9da 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -4,10 +4,12 @@
// Unit tests for denial-of-service detection/prevention code
+#include <arith_uint256.h>
#include <banman.h>
#include <chainparams.h>
#include <net.h>
#include <net_processing.h>
+#include <pubkey.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <script/standard.h>
@@ -98,11 +100,11 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
// Test starts here
{
- LOCK2(cs_main, dummyNode1.cs_sendProcessing);
+ LOCK(dummyNode1.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in getheaders
}
{
- LOCK2(cs_main, dummyNode1.cs_vSend);
+ LOCK(dummyNode1.cs_vSend);
BOOST_CHECK(dummyNode1.vSendMsg.size() > 0);
dummyNode1.vSendMsg.clear();
}
@@ -111,17 +113,17 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
// Wait 21 minutes
SetMockTime(nStartTime+21*60);
{
- LOCK2(cs_main, dummyNode1.cs_sendProcessing);
+ LOCK(dummyNode1.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in getheaders
}
{
- LOCK2(cs_main, dummyNode1.cs_vSend);
+ LOCK(dummyNode1.cs_vSend);
BOOST_CHECK(dummyNode1.vSendMsg.size() > 0);
}
// Wait 3 more minutes
SetMockTime(nStartTime+24*60);
{
- LOCK2(cs_main, dummyNode1.cs_sendProcessing);
+ LOCK(dummyNode1.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in disconnect
}
BOOST_CHECK(dummyNode1.fDisconnect == true);
@@ -217,7 +219,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
connman->ClearNodes();
}
-BOOST_AUTO_TEST_CASE(DoS_banning)
+BOOST_AUTO_TEST_CASE(peer_discouragement)
{
auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
@@ -232,14 +234,14 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
dummyNode1.fSuccessfullyConnected = true;
{
LOCK(cs_main);
- Misbehaving(dummyNode1.GetId(), 100); // Should get banned
+ Misbehaving(dummyNode1.GetId(), DISCOURAGEMENT_THRESHOLD); // Should be discouraged
}
{
- LOCK2(cs_main, dummyNode1.cs_sendProcessing);
+ LOCK(dummyNode1.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
}
BOOST_CHECK(banman->IsDiscouraged(addr1));
- BOOST_CHECK(!banman->IsDiscouraged(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
+ BOOST_CHECK(!banman->IsDiscouraged(ip(0xa0b0c001|0x0000ff00))); // Different IP, not discouraged
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", true);
@@ -249,76 +251,30 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
dummyNode2.fSuccessfullyConnected = true;
{
LOCK(cs_main);
- Misbehaving(dummyNode2.GetId(), 50);
+ Misbehaving(dummyNode2.GetId(), DISCOURAGEMENT_THRESHOLD - 1);
}
{
- LOCK2(cs_main, dummyNode2.cs_sendProcessing);
+ LOCK(dummyNode2.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode2));
}
- BOOST_CHECK(!banman->IsDiscouraged(addr2)); // 2 not banned yet...
+ BOOST_CHECK(!banman->IsDiscouraged(addr2)); // 2 not discouraged yet...
BOOST_CHECK(banman->IsDiscouraged(addr1)); // ... but 1 still should be
{
LOCK(cs_main);
- Misbehaving(dummyNode2.GetId(), 50);
+ Misbehaving(dummyNode2.GetId(), 1); // 2 reaches discouragement threshold
}
{
- LOCK2(cs_main, dummyNode2.cs_sendProcessing);
+ LOCK(dummyNode2.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode2));
}
- BOOST_CHECK(banman->IsDiscouraged(addr2));
+ BOOST_CHECK(banman->IsDiscouraged(addr1)); // Expect both 1 and 2
+ BOOST_CHECK(banman->IsDiscouraged(addr2)); // to be discouraged now
bool dummy;
peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
peerLogic->FinalizeNode(dummyNode2.GetId(), dummy);
}
-BOOST_AUTO_TEST_CASE(DoS_banscore)
-{
- auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
- auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
-
- banman->ClearBanned();
- gArgs.ForceSetArg("-banscore", "111"); // because 11 is my favorite number
- CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, CAddress(), "", true);
- dummyNode1.SetSendVersion(PROTOCOL_VERSION);
- peerLogic->InitializeNode(&dummyNode1);
- dummyNode1.nVersion = 1;
- dummyNode1.fSuccessfullyConnected = true;
- {
- LOCK(cs_main);
- Misbehaving(dummyNode1.GetId(), 100);
- }
- {
- LOCK2(cs_main, dummyNode1.cs_sendProcessing);
- BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
- }
- BOOST_CHECK(!banman->IsDiscouraged(addr1));
- {
- LOCK(cs_main);
- Misbehaving(dummyNode1.GetId(), 10);
- }
- {
- LOCK2(cs_main, dummyNode1.cs_sendProcessing);
- BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
- }
- BOOST_CHECK(!banman->IsDiscouraged(addr1));
- {
- LOCK(cs_main);
- Misbehaving(dummyNode1.GetId(), 1);
- }
- {
- LOCK2(cs_main, dummyNode1.cs_sendProcessing);
- BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
- }
- BOOST_CHECK(banman->IsDiscouraged(addr1));
- gArgs.ForceSetArg("-banscore", ToString(DEFAULT_BANSCORE_THRESHOLD));
-
- bool dummy;
- peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
-}
-
BOOST_AUTO_TEST_CASE(DoS_bantime)
{
auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
@@ -338,10 +294,10 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
{
LOCK(cs_main);
- Misbehaving(dummyNode.GetId(), 100);
+ Misbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD);
}
{
- LOCK2(cs_main, dummyNode.cs_sendProcessing);
+ LOCK(dummyNode.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode));
}
BOOST_CHECK(banman->IsDiscouraged(addr));
@@ -360,10 +316,26 @@ static CTransactionRef RandomOrphan()
return it->second.tx;
}
+static void MakeNewKeyWithFastRandomContext(CKey& key)
+{
+ std::vector<unsigned char> keydata;
+ keydata = g_insecure_rand_ctx.randbytes(32);
+ key.Set(keydata.data(), keydata.data() + keydata.size(), /*fCompressedIn*/ true);
+ assert(key.IsValid());
+}
+
BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{
+ // This test had non-deterministic coverage due to
+ // randomly selected seeds.
+ // This seed is chosen so that all branches of the function
+ // ecdsa_signature_parse_der_lax are executed during this test.
+ // Specifically branches that run only when an ECDSA
+ // signature's R and S values have leading zeros.
+ g_insecure_rand_ctx = FastRandomContext(ArithToUint256(arith_uint256(33)));
+
CKey key;
- key.MakeNewKey(true);
+ MakeNewKeyWithFastRandomContext(key);
FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKey(key));
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index 5d7065dafb..20132d5782 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -135,7 +135,7 @@ void DoCheck(const std::string& prv, const std::string& pub, int flags, const st
// When the descriptor is hardened, evaluate with access to the private keys inside.
const FlatSigningProvider& key_provider = (flags & HARDENED) ? keys_priv : keys_pub;
- // Evaluate the descriptor selected by `t` in poisition `i`.
+ // Evaluate the descriptor selected by `t` in position `i`.
FlatSigningProvider script_provider, script_provider_cached;
std::vector<CScript> spks, spks_cached;
DescriptorCache desc_cache;
diff --git a/src/test/fuzz/addrdb.cpp b/src/test/fuzz/addrdb.cpp
index ad6461650f..16b1cb755a 100644
--- a/src/test/fuzz/addrdb.cpp
+++ b/src/test/fuzz/addrdb.cpp
@@ -17,6 +17,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ // The point of this code is to exercise all CBanEntry constructors.
const CBanEntry ban_entry = [&] {
switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 2)) {
case 0:
@@ -32,4 +33,5 @@ void test_one_input(const std::vector<uint8_t>& buffer)
}
return CBanEntry{};
}();
+ (void)ban_entry; // currently unused
}
diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp
new file mode 100644
index 0000000000..7ea0bdd2a7
--- /dev/null
+++ b/src/test/fuzz/autofile.cpp
@@ -0,0 +1,72 @@
+// 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 <optional.h>
+#include <streams.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <array>
+#include <cstdint>
+#include <iostream>
+#include <optional>
+#include <string>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ 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;
+ }
+ }
+ }
+ (void)auto_file.Get();
+ (void)auto_file.GetType();
+ (void)auto_file.GetVersion();
+ (void)auto_file.IsNull();
+ if (fuzzed_data_provider.ConsumeBool()) {
+ FILE* f = auto_file.release();
+ if (f != nullptr) {
+ fclose(f);
+ }
+ }
+}
diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
new file mode 100644
index 0000000000..fc4a1d9261
--- /dev/null
+++ b/src/test/fuzz/banman.cpp
@@ -0,0 +1,88 @@
+// 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 <banman.h>
+#include <fs.h>
+#include <netaddress.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <util/system.h>
+
+#include <cstdint>
+#include <limits>
+#include <string>
+#include <vector>
+
+namespace {
+int64_t ConsumeBanTimeOffset(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ // Avoid signed integer overflow by capping to int32_t max:
+ // banman.cpp:137:73: runtime error: signed integer overflow: 1591700817 + 9223372036854775807 cannot be represented in type 'long'
+ return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(std::numeric_limits<int64_t>::min(), std::numeric_limits<int32_t>::max());
+}
+} // namespace
+
+void initialize()
+{
+ InitializeFuzzingContext();
+}
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ const fs::path banlist_file = GetDataDir() / "fuzzed_banlist.dat";
+ fs::remove(banlist_file);
+ {
+ 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;
+ }
+ }
+ }
+ }
+ fs::remove(banlist_file);
+}
diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp
new file mode 100644
index 0000000000..6bbd13eb5c
--- /dev/null
+++ b/src/test/fuzz/buffered_file.cpp
@@ -0,0 +1,78 @@
+// 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 <optional.h>
+#include <streams.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <array>
+#include <cstdint>
+#include <iostream>
+#include <optional>
+#include <string>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider);
+ std::optional<CBufferedFile> opt_buffered_file;
+ FILE* fuzzed_file = fuzzed_file_provider.open();
+ try {
+ opt_buffered_file.emplace(fuzzed_file, fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096), fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeIntegral<int>());
+ } catch (const std::ios_base::failure&) {
+ if (fuzzed_file != nullptr) {
+ fclose(fuzzed_file);
+ }
+ }
+ if (opt_buffered_file && fuzzed_file != nullptr) {
+ bool setpos_fail = false;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
+ 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->Seek(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096));
+ break;
+ }
+ case 2: {
+ opt_buffered_file->SetLimit(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096));
+ break;
+ }
+ case 3: {
+ if (!opt_buffered_file->SetPos(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096))) {
+ setpos_fail = true;
+ }
+ break;
+ }
+ case 4: {
+ 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 5: {
+ ReadFromStream(fuzzed_data_provider, *opt_buffered_file);
+ break;
+ }
+ }
+ }
+ opt_buffered_file->GetPos();
+ opt_buffered_file->GetType();
+ opt_buffered_file->GetVersion();
+ }
+}
diff --git a/src/test/fuzz/crypto_aes256.cpp b/src/test/fuzz/crypto_aes256.cpp
new file mode 100644
index 0000000000..ae14073c96
--- /dev/null
+++ b/src/test/fuzz/crypto_aes256.cpp
@@ -0,0 +1,30 @@
+// 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 <crypto/aes.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cassert>
+#include <cstdint>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ const std::vector<uint8_t> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, AES256_KEYSIZE);
+
+ AES256Encrypt encrypt{key.data()};
+ AES256Decrypt decrypt{key.data()};
+
+ while (fuzzed_data_provider.ConsumeBool()) {
+ const std::vector<uint8_t> plaintext = ConsumeFixedLengthByteVector(fuzzed_data_provider, AES_BLOCKSIZE);
+ std::vector<uint8_t> ciphertext(AES_BLOCKSIZE);
+ encrypt.Encrypt(ciphertext.data(), plaintext.data());
+ std::vector<uint8_t> decrypted_plaintext(AES_BLOCKSIZE);
+ decrypt.Decrypt(decrypted_plaintext.data(), ciphertext.data());
+ assert(decrypted_plaintext == plaintext);
+ }
+}
diff --git a/src/test/fuzz/crypto_aes256cbc.cpp b/src/test/fuzz/crypto_aes256cbc.cpp
new file mode 100644
index 0000000000..52983c7e79
--- /dev/null
+++ b/src/test/fuzz/crypto_aes256cbc.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 <crypto/aes.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cassert>
+#include <cstdint>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ const std::vector<uint8_t> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, AES256_KEYSIZE);
+ const std::vector<uint8_t> iv = ConsumeFixedLengthByteVector(fuzzed_data_provider, AES_BLOCKSIZE);
+ const bool pad = fuzzed_data_provider.ConsumeBool();
+
+ AES256CBCEncrypt encrypt{key.data(), iv.data(), pad};
+ AES256CBCDecrypt decrypt{key.data(), iv.data(), pad};
+
+ while (fuzzed_data_provider.ConsumeBool()) {
+ const std::vector<uint8_t> plaintext = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ std::vector<uint8_t> ciphertext(plaintext.size() + AES_BLOCKSIZE);
+ const int encrypt_ret = encrypt.Encrypt(plaintext.data(), plaintext.size(), ciphertext.data());
+ ciphertext.resize(encrypt_ret);
+ std::vector<uint8_t> decrypted_plaintext(ciphertext.size());
+ const int decrypt_ret = decrypt.Decrypt(ciphertext.data(), ciphertext.size(), decrypted_plaintext.data());
+ decrypted_plaintext.resize(decrypt_ret);
+ assert(decrypted_plaintext == plaintext || (!pad && plaintext.size() % AES_BLOCKSIZE != 0 && encrypt_ret == 0 && decrypt_ret == 0));
+ }
+}
diff --git a/src/test/fuzz/crypto_chacha20.cpp b/src/test/fuzz/crypto_chacha20.cpp
new file mode 100644
index 0000000000..b7438d312d
--- /dev/null
+++ b/src/test/fuzz/crypto_chacha20.cpp
@@ -0,0 +1,50 @@
+// 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 <crypto/chacha20.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+
+ ChaCha20 chacha20;
+ if (fuzzed_data_provider.ConsumeBool()) {
+ const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32));
+ 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;
+ }
+ }
+ }
+}
diff --git a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
new file mode 100644
index 0000000000..48e4263f27
--- /dev/null
+++ b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
@@ -0,0 +1,72 @@
+// 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 <crypto/chacha_poly_aead.h>
+#include <crypto/poly1305.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cassert>
+#include <cstdint>
+#include <limits>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+
+ const std::vector<uint8_t> k1 = ConsumeFixedLengthByteVector(fuzzed_data_provider, CHACHA20_POLY1305_AEAD_KEY_LEN);
+ const std::vector<uint8_t> k2 = ConsumeFixedLengthByteVector(fuzzed_data_provider, CHACHA20_POLY1305_AEAD_KEY_LEN);
+
+ ChaCha20Poly1305AEAD aead(k1.data(), k1.size(), k2.data(), k2.size());
+ uint64_t seqnr_payload = 0;
+ 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);
+ 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;
+ }
+ }
+ }
+}
diff --git a/src/test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp b/src/test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp
new file mode 100644
index 0000000000..e0a4e90c10
--- /dev/null
+++ b/src/test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp
@@ -0,0 +1,25 @@
+// 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 <crypto/hkdf_sha256_32.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+
+ const std::vector<uint8_t> initial_key_material = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+
+ CHKDF_HMAC_SHA256_L32 hkdf_hmac_sha256_l32(initial_key_material.data(), initial_key_material.size(), fuzzed_data_provider.ConsumeRandomLengthString(1024));
+ while (fuzzed_data_provider.ConsumeBool()) {
+ std::vector<uint8_t> out(32);
+ hkdf_hmac_sha256_l32.Expand32(fuzzed_data_provider.ConsumeRandomLengthString(128), out.data());
+ }
+}
diff --git a/src/test/fuzz/crypto_poly1305.cpp b/src/test/fuzz/crypto_poly1305.cpp
new file mode 100644
index 0000000000..5681e6a693
--- /dev/null
+++ b/src/test/fuzz/crypto_poly1305.cpp
@@ -0,0 +1,22 @@
+// 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 <crypto/poly1305.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ 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> in = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+
+ std::vector<uint8_t> tag_out(POLY1305_TAGLEN);
+ poly1305_auth(tag_out.data(), in.data(), in.size(), key.data());
+}
diff --git a/src/test/fuzz/http_request.cpp b/src/test/fuzz/http_request.cpp
index ebf89749e9..36d44e361f 100644
--- a/src/test/fuzz/http_request.cpp
+++ b/src/test/fuzz/http_request.cpp
@@ -7,6 +7,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <util/strencodings.h>
#include <event2/buffer.h>
#include <event2/event.h>
@@ -48,7 +49,14 @@ void test_one_input(const std::vector<uint8_t>& buffer)
assert(evbuf != nullptr);
const std::vector<uint8_t> http_buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, 4096);
evbuffer_add(evbuf, http_buffer.data(), http_buffer.size());
- if (evhttp_parse_firstline_(evreq, evbuf) != 1 || evhttp_parse_headers_(evreq, evbuf) != 1) {
+ // Avoid constructing requests that will be interpreted by libevent as PROXY requests to avoid triggering
+ // a nullptr dereference. The dereference (req->evcon->http_server) takes place in evhttp_parse_request_line
+ // and is a consequence of our hacky but necessary use of the internal function evhttp_parse_firstline_ in
+ // this fuzzing harness. The workaround is not aesthetically pleasing, but it successfully avoids the troublesome
+ // code path. " http:// HTTP/1.1\n" was a crashing input prior to this workaround.
+ const std::string http_buffer_str = ToLower({http_buffer.begin(), http_buffer.end()});
+ if (http_buffer_str.find(" http://") != std::string::npos || http_buffer_str.find(" https://") != std::string::npos ||
+ evhttp_parse_firstline_(evreq, evbuf) != 1 || evhttp_parse_headers_(evreq, evbuf) != 1) {
evbuffer_free(evbuf);
evhttp_request_free(evreq);
return;
diff --git a/src/test/fuzz/load_external_block_file.cpp b/src/test/fuzz/load_external_block_file.cpp
new file mode 100644
index 0000000000..d9de9d9866
--- /dev/null
+++ b/src/test/fuzz/load_external_block_file.cpp
@@ -0,0 +1,31 @@
+// 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 <chainparams.h>
+#include <flatfile.h>
+#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>
+#include <vector>
+
+void initialize()
+{
+ InitializeFuzzingContext();
+}
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider);
+ FILE* fuzzed_block_file = fuzzed_file_provider.open();
+ if (fuzzed_block_file == nullptr) {
+ return;
+ }
+ FlatFilePos flat_file_pos;
+ LoadExternalBlockFile(Params(), fuzzed_block_file, fuzzed_data_provider.ConsumeBool() ? &flat_file_pos : nullptr);
+}
diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp
index d8d53566c7..2901c704f6 100644
--- a/src/test/fuzz/netaddress.cpp
+++ b/src/test/fuzz/netaddress.cpp
@@ -5,41 +5,13 @@
#include <netaddress.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
#include <cassert>
#include <cstdint>
#include <netinet/in.h>
#include <vector>
-namespace {
-CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
-{
- const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
- if (network == Network::NET_IPV4) {
- const in_addr v4_addr = {
- .s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
- return CNetAddr{v4_addr};
- } else if (network == Network::NET_IPV6) {
- if (fuzzed_data_provider.remaining_bytes() < 16) {
- return CNetAddr{};
- }
- in6_addr v6_addr = {};
- memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
- return CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
- } else if (network == Network::NET_INTERNAL) {
- CNetAddr net_addr;
- net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
- return net_addr;
- } else if (network == Network::NET_ONION) {
- CNetAddr net_addr;
- net_addr.SetSpecial(fuzzed_data_provider.ConsumeBytesAsString(32));
- return net_addr;
- } else {
- assert(false);
- }
-}
-}; // namespace
-
void test_one_input(const std::vector<uint8_t>& buffer)
{
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 1cbf9b347f..6c94a47f3c 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -14,6 +14,11 @@
#include <string>
#include <vector>
+void initialize()
+{
+ InitializeFuzzingContext();
+}
+
void test_one_input(const std::vector<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
@@ -66,4 +71,10 @@ void test_one_input(const std::vector<uint8_t>& buffer)
(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}));
}
+ {
+ FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
+ CAutoFile fuzzed_auto_file = fuzzed_auto_file_provider.open();
+ block_policy_estimator.Write(fuzzed_auto_file);
+ block_policy_estimator.Read(fuzzed_auto_file);
+ }
}
diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp
new file mode 100644
index 0000000000..0edcf201c7
--- /dev/null
+++ b/src/test/fuzz/policy_estimator_io.cpp
@@ -0,0 +1,28 @@
+// 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 <policy/fees.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <vector>
+
+void initialize()
+{
+ InitializeFuzzingContext();
+}
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
+ CAutoFile 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;
+ if (block_policy_estimator.Read(fuzzed_auto_file)) {
+ block_policy_estimator.Write(fuzzed_auto_file);
+ }
+}
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index fa8d67059c..9e40d5cd55 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -38,7 +38,7 @@ void ProcessMessage(
const CChainParams& chainparams,
ChainstateManager& chainman,
CTxMemPool& mempool,
- CConnman* connman,
+ CConnman& connman,
BanMan* banman,
const std::atomic<bool>& interruptMsgProc);
@@ -89,7 +89,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
try {
ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream, GetTime<std::chrono::microseconds>(),
Params(), *g_setup->m_node.chainman, *g_setup->m_node.mempool,
- g_setup->m_node.connman.get(), g_setup->m_node.banman.get(),
+ *g_setup->m_node.connman, g_setup->m_node.banman.get(),
std::atomic<bool>{false});
} catch (const std::ios_base::failure&) {
}
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index cad548178d..85aac6ac7a 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -48,7 +48,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
if (CompressScript(script, compressed)) {
const unsigned int size = compressed[0];
compressed.erase(compressed.begin());
- assert(size >= 0 && size <= 5);
+ assert(size <= 5);
CScript decompressed_script;
const bool ok = DecompressScript(decompressed_script, size, compressed);
assert(ok);
diff --git a/src/test/fuzz/scriptnum_ops.cpp b/src/test/fuzz/scriptnum_ops.cpp
index f4e079fb89..68c1ae58ca 100644
--- a/src/test/fuzz/scriptnum_ops.cpp
+++ b/src/test/fuzz/scriptnum_ops.cpp
@@ -33,7 +33,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
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));
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'
diff --git a/src/test/fuzz/signature_checker.cpp b/src/test/fuzz/signature_checker.cpp
index 4a8c7a63af..3aaeb66649 100644
--- a/src/test/fuzz/signature_checker.cpp
+++ b/src/test/fuzz/signature_checker.cpp
@@ -28,17 +28,17 @@ public:
{
}
- virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
+ bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
{
return m_fuzzed_data_provider.ConsumeBool();
}
- virtual bool CheckLockTime(const CScriptNum& nLockTime) const
+ bool CheckLockTime(const CScriptNum& nLockTime) const override
{
return m_fuzzed_data_provider.ConsumeBool();
}
- virtual bool CheckSequence(const CScriptNum& nSequence) const
+ bool CheckSequence(const CScriptNum& nSequence) const override
{
return m_fuzzed_data_provider.ConsumeBool();
}
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index 1c1b2cd254..9f9552edb9 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -8,8 +8,11 @@
#include <amount.h>
#include <arith_uint256.h>
#include <attributes.h>
+#include <chainparamsbase.h>
#include <coins.h>
#include <consensus/consensus.h>
+#include <netaddress.h>
+#include <netbase.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <script/standard.h>
@@ -17,12 +20,14 @@
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <test/util/setup_common.h>
#include <txmempool.h>
#include <uint256.h>
#include <version.h>
#include <algorithm>
#include <cstdint>
+#include <cstdio>
#include <optional>
#include <string>
#include <vector>
@@ -228,4 +233,241 @@ NODISCARD inline std::vector<uint8_t> ConsumeFixedLengthByteVector(FuzzedDataPro
return result;
}
+CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ 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>()};
+ net_addr = CNetAddr{v4_addr};
+ } else if (network == Network::NET_IPV6) {
+ if (fuzzed_data_provider.remaining_bytes() >= 16) {
+ in6_addr v6_addr = {};
+ memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
+ net_addr = CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
+ }
+ } else if (network == Network::NET_INTERNAL) {
+ net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
+ } else if (network == Network::NET_ONION) {
+ net_addr.SetSpecial(fuzzed_data_provider.ConsumeBytesAsString(32));
+ }
+ return net_addr;
+}
+
+CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int32_t>()};
+}
+
+void InitializeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST)
+{
+ static const BasicTestingSetup basic_testing_setup{chain_name, {"-nodebuglogfile"}};
+}
+
+class FuzzedFileProvider
+{
+ FuzzedDataProvider& m_fuzzed_data_provider;
+ int64_t m_offset = 0;
+
+public:
+ FuzzedFileProvider(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider{fuzzed_data_provider}
+ {
+ }
+
+ FILE* open()
+ {
+ 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;
+ }
+ }
+#ifdef _GNU_SOURCE
+ const cookie_io_functions_t io_hooks = {
+ FuzzedFileProvider::read,
+ FuzzedFileProvider::write,
+ FuzzedFileProvider::seek,
+ FuzzedFileProvider::close,
+ };
+ return fopencookie(this, mode.c_str(), io_hooks);
+#else
+ (void)mode;
+ return nullptr;
+#endif
+ }
+
+ static ssize_t read(void* cookie, char* buf, size_t size)
+ {
+ FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ if (buf == nullptr || size == 0 || fuzzed_file->m_fuzzed_data_provider.ConsumeBool()) {
+ return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
+ }
+ const std::vector<uint8_t> random_bytes = fuzzed_file->m_fuzzed_data_provider.ConsumeBytes<uint8_t>(size);
+ if (random_bytes.empty()) {
+ return 0;
+ }
+ std::memcpy(buf, random_bytes.data(), random_bytes.size());
+ if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)random_bytes.size())) {
+ return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
+ }
+ fuzzed_file->m_offset += random_bytes.size();
+ return random_bytes.size();
+ }
+
+ static ssize_t write(void* cookie, const char* buf, size_t size)
+ {
+ FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ 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;
+ }
+ fuzzed_file->m_offset += n;
+ return n;
+ }
+
+ static int seek(void* cookie, int64_t* offset, int whence)
+ {
+ assert(whence == SEEK_SET || whence == SEEK_CUR); // SEEK_END not implemented yet.
+ FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ int64_t new_offset = 0;
+ if (whence == SEEK_SET) {
+ new_offset = *offset;
+ } else if (whence == SEEK_CUR) {
+ if (AdditionOverflow(fuzzed_file->m_offset, *offset)) {
+ return -1;
+ }
+ new_offset = fuzzed_file->m_offset + *offset;
+ }
+ if (new_offset < 0) {
+ return -1;
+ }
+ fuzzed_file->m_offset = new_offset;
+ *offset = new_offset;
+ return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
+ }
+
+ static int close(void* cookie)
+ {
+ FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
+ return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
+ }
+};
+
+NODISCARD inline FuzzedFileProvider ConsumeFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return {fuzzed_data_provider};
+}
+
+class FuzzedAutoFileProvider
+{
+ FuzzedDataProvider& m_fuzzed_data_provider;
+ FuzzedFileProvider m_fuzzed_file_provider;
+
+public:
+ FuzzedAutoFileProvider(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider{fuzzed_data_provider}, m_fuzzed_file_provider{fuzzed_data_provider}
+ {
+ }
+
+ CAutoFile open()
+ {
+ return {m_fuzzed_file_provider.open(), m_fuzzed_data_provider.ConsumeIntegral<int>(), m_fuzzed_data_provider.ConsumeIntegral<int>()};
+ }
+};
+
+NODISCARD inline FuzzedAutoFileProvider ConsumeAutoFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return {fuzzed_data_provider};
+}
+
+#define WRITE_TO_STREAM_CASE(id, type, consume) \
+ case id: { \
+ type o = consume; \
+ stream << o; \
+ break; \
+ }
+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))
+ }
+ } catch (const std::ios_base::failure&) {
+ break;
+ }
+ }
+}
+
+#define READ_FROM_STREAM_CASE(id, type) \
+ case id: { \
+ type o; \
+ stream >> o; \
+ break; \
+ }
+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>)
+ }
+ } catch (const std::ios_base::failure&) {
+ break;
+ }
+ }
+}
+
#endif // BITCOIN_TEST_FUZZ_UTIL_H
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index c4d5d0b6d0..ea3e633cc2 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -383,7 +383,7 @@ BOOST_AUTO_TEST_CASE(netpermissions_test)
BOOST_CHECK(!NetWhitebindPermissions::TryParse("bloom,forcerelay,oopsie@1.2.3.4:32", whitebindPermissions, error));
BOOST_CHECK(error.original.find("Invalid P2P permission") != std::string::npos);
- // Check whitelist error
+ // Check netmask error
BOOST_CHECK(!NetWhitelistPermissions::TryParse("bloom,forcerelay,noban@1.2.3.4:32", whitelistPermissions, error));
BOOST_CHECK(error.original.find("Invalid netmask specified in -whitelist") != std::string::npos);
diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp
index fcd831ccda..1a2d775f49 100644
--- a/src/test/settings_tests.cpp
+++ b/src/test/settings_tests.cpp
@@ -12,10 +12,90 @@
#include <univalue.h>
#include <util/strencodings.h>
#include <util/string.h>
+#include <util/system.h>
#include <vector>
+inline bool operator==(const util::SettingsValue& a, const util::SettingsValue& b)
+{
+ return a.write() == b.write();
+}
+
+inline std::ostream& operator<<(std::ostream& os, const util::SettingsValue& value)
+{
+ os << value.write();
+ return os;
+}
+
+inline std::ostream& operator<<(std::ostream& os, const std::pair<std::string, util::SettingsValue>& kv)
+{
+ util::SettingsValue out(util::SettingsValue::VOBJ);
+ out.__pushKV(kv.first, kv.second);
+ os << out.write();
+ return os;
+}
+
+inline void WriteText(const fs::path& path, const std::string& text)
+{
+ fsbridge::ofstream file;
+ file.open(path);
+ file << text;
+}
+
BOOST_FIXTURE_TEST_SUITE(settings_tests, BasicTestingSetup)
+BOOST_AUTO_TEST_CASE(ReadWrite)
+{
+ fs::path path = GetDataDir() / "settings.json";
+
+ WriteText(path, R"({
+ "string": "string",
+ "num": 5,
+ "bool": true,
+ "null": null
+ })");
+
+ std::map<std::string, util::SettingsValue> expected{
+ {"string", "string"},
+ {"num", 5},
+ {"bool", true},
+ {"null", {}},
+ };
+
+ // Check file read.
+ std::map<std::string, util::SettingsValue> values;
+ std::vector<std::string> errors;
+ BOOST_CHECK(util::ReadSettings(path, values, errors));
+ BOOST_CHECK_EQUAL_COLLECTIONS(values.begin(), values.end(), expected.begin(), expected.end());
+ BOOST_CHECK(errors.empty());
+
+ // Check no errors if file doesn't exist.
+ fs::remove(path);
+ BOOST_CHECK(util::ReadSettings(path, values, errors));
+ BOOST_CHECK(values.empty());
+ BOOST_CHECK(errors.empty());
+
+ // Check duplicate keys not allowed
+ WriteText(path, R"({
+ "dupe": "string",
+ "dupe": "dupe"
+ })");
+ BOOST_CHECK(!util::ReadSettings(path, values, errors));
+ std::vector<std::string> dup_keys = {strprintf("Found duplicate key dupe in settings file %s", path.string())};
+ BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), dup_keys.begin(), dup_keys.end());
+
+ // Check non-kv json files not allowed
+ WriteText(path, R"("non-kv")");
+ BOOST_CHECK(!util::ReadSettings(path, values, errors));
+ std::vector<std::string> non_kv = {strprintf("Found non-object value \"non-kv\" in settings file %s", path.string())};
+ BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), non_kv.begin(), non_kv.end());
+
+ // Check invalid json not allowed
+ WriteText(path, R"(invalid json)");
+ BOOST_CHECK(!util::ReadSettings(path, values, errors));
+ std::vector<std::string> fail_parse = {strprintf("Unable to parse settings file %s", path.string())};
+ BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), fail_parse.begin(), fail_parse.end());
+}
+
//! Check settings struct contents against expected json strings.
static void CheckValues(const util::Settings& settings, const std::string& single_val, const std::string& list_val)
{
diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp
index 5c6c2ee38e..3ea8714f3a 100644
--- a/src/test/sync_tests.cpp
+++ b/src/test/sync_tests.cpp
@@ -18,7 +18,7 @@ void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2)
try {
LOCK2(mutex2, mutex1);
} catch (const std::logic_error& e) {
- BOOST_CHECK_EQUAL(e.what(), "potential deadlock detected");
+ BOOST_CHECK_EQUAL(e.what(), "potential deadlock detected: mutex1 -> mutex2 -> mutex1");
error_thrown = true;
}
#ifdef DEBUG_LOCKORDER
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 257328974b..a30e366028 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -9,6 +9,7 @@
#include <key.h> // For CKey
#include <optional.h>
#include <sync.h>
+#include <test/util/logging.h>
#include <test/util/setup_common.h>
#include <test/util/str.h>
#include <uint256.h>
@@ -41,6 +42,16 @@ namespace BCLog {
BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup)
+BOOST_AUTO_TEST_CASE(util_check)
+{
+ // Check that Assert can forward
+ const std::unique_ptr<int> p_two = Assert(MakeUnique<int>(2));
+ // Check that Assert works on lvalues and rvalues
+ const int two = *Assert(p_two);
+ Assert(two == 2);
+ Assert(true);
+}
+
BOOST_AUTO_TEST_CASE(util_criticalsection)
{
RecursiveMutex cs;
@@ -1128,6 +1139,28 @@ BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup)
BOOST_CHECK_EQUAL(out_sha_hex, "f0b3a3c29869edc765d579c928f7f1690a71fbb673b49ccf39cbc4de18156a0d");
}
+BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
+{
+ // Test writing setting.
+ TestArgsManager args1;
+ args1.LockSettings([&](util::Settings& settings) { settings.rw_settings["name"] = "value"; });
+ args1.WriteSettingsFile();
+
+ // Test reading setting.
+ TestArgsManager args2;
+ args2.ReadSettingsFile();
+ args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); });
+
+ // Test error logging, and remove previously written setting.
+ {
+ ASSERT_DEBUG_LOG("Failed renaming settings file");
+ fs::remove(GetDataDir() / "settings.json");
+ fs::create_directory(GetDataDir() / "settings.json");
+ args2.WriteSettingsFile();
+ fs::remove(GetDataDir() / "settings.json");
+ }
+}
+
BOOST_AUTO_TEST_CASE(util_FormatMoney)
{
BOOST_CHECK_EQUAL(FormatMoney(0), "0.00");