From fa91994b1b9b6da3bb2a2f722d9251d7d0f2167e Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sat, 3 Apr 2021 13:39:42 +0200 Subject: fuzz: Add utxo_snapshot target --- src/Makefile.test.include | 1 + src/chainparams.cpp | 4 +- src/test/fuzz/utxo_snapshot.cpp | 87 +++++++++++++++++++++++++++++++++++++++++ src/test/util/mining.cpp | 33 ++++++++++++++++ src/test/util/mining.h | 5 +++ src/test/validation_tests.cpp | 8 ++-- 6 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 src/test/fuzz/utxo_snapshot.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index d55f5e1850..dc79ea3125 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -303,6 +303,7 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/tx_out.cpp \ test/fuzz/tx_pool.cpp \ test/fuzz/txrequest.cpp \ + test/fuzz/utxo_snapshot.cpp \ test/fuzz/validation_load_mempool.cpp \ test/fuzz/versionbits.cpp endif # ENABLE_FUZZ_BINARY diff --git a/src/chainparams.cpp b/src/chainparams.cpp index fc5a9d84cc..1b71c4db43 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -454,8 +454,8 @@ public: {AssumeutxoHash{uint256S("0x1ebbf5850204c0bdb15bf030f47c7fe91d45c44c712697e4509ba67adb01c618")}, 110}, }, { - 210, - {AssumeutxoHash{uint256S("0x9c5ed99ef98544b34f8920b6d1802f72ac28ae6e2bd2bd4c316ff10c230df3f2")}, 210}, + 200, + {AssumeutxoHash{uint256S("0x51c8d11d8b5c1de51543c579736e786aa2736206d1e11e627568029ce092cf62")}, 200}, }, }; diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp new file mode 100644 index 0000000000..0b42282b34 --- /dev/null +++ b/src/test/fuzz/utxo_snapshot.cpp @@ -0,0 +1,87 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +const std::vector>* g_chain; + +void initialize_chain() +{ + const auto params{CreateChainParams(ArgsManager{}, CBaseChainParams::REGTEST)}; + static const auto chain{CreateBlockChain(2 * COINBASE_MATURITY, *params)}; + g_chain = &chain; +} + +FUZZ_TARGET_INIT(utxo_snapshot, initialize_chain) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + std::unique_ptr setup{MakeNoLogFileContext()}; + const auto& node = setup->m_node; + auto& chainman{*node.chainman}; + + const auto snapshot_path = GetDataDir() / "fuzzed_snapshot.dat"; + + Assert(!chainman.SnapshotBlockhash()); + + { + CAutoFile outfile{fsbridge::fopen(snapshot_path, "wb"), SER_DISK, CLIENT_VERSION}; + const auto file_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; + outfile << Span{file_data}; + } + + const auto ActivateFuzzedSnapshot{[&] { + CAutoFile infile{fsbridge::fopen(snapshot_path, "rb"), SER_DISK, CLIENT_VERSION}; + SnapshotMetadata metadata; + try { + infile >> metadata; + } catch (const std::ios_base::failure&) { + return false; + } + return chainman.ActivateSnapshot(infile, metadata, /* in_memory */ true); + }}; + + if (fuzzed_data_provider.ConsumeBool()) { + for (const auto& block : *g_chain) { + BlockValidationState dummy; + bool processed{chainman.ProcessNewBlockHeaders({*block}, dummy, ::Params())}; + Assert(processed); + const auto* index{WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block->GetHash()))}; + Assert(index); + } + } + + if (ActivateFuzzedSnapshot()) { + LOCK(::cs_main); + Assert(!chainman.ActiveChainstate().m_from_snapshot_blockhash->IsNull()); + Assert(*chainman.ActiveChainstate().m_from_snapshot_blockhash == + *chainman.SnapshotBlockhash()); + const auto& coinscache{chainman.ActiveChainstate().CoinsTip()}; + int64_t chain_tx{}; + for (const auto& block : *g_chain) { + Assert(coinscache.HaveCoin(COutPoint{block->vtx.at(0)->GetHash(), 0})); + const auto* index{chainman.m_blockman.LookupBlockIndex(block->GetHash())}; + const auto num_tx{Assert(index)->nTx}; + Assert(num_tx == 1); + chain_tx += num_tx; + } + Assert(g_chain->size() == coinscache.GetCacheSize()); + Assert(chain_tx == chainman.ActiveTip()->nChainTx); + } else { + Assert(!chainman.SnapshotBlockhash()); + Assert(!chainman.ActiveChainstate().m_from_snapshot_blockhash); + } + // Snapshot should refuse to load a second time regardless of validity + Assert(!ActivateFuzzedSnapshot()); +} +} // namespace diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp index 3fc3329da2..1204873828 100644 --- a/src/test/util/mining.cpp +++ b/src/test/util/mining.cpp @@ -11,8 +11,10 @@ #include #include #include