Skip to content

Commit fa91994

Browse files
author
MarcoFalke
committed
fuzz: Add utxo_snapshot target
1 parent c857148 commit fa91994

File tree

6 files changed

+132
-6
lines changed

6 files changed

+132
-6
lines changed

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ test_fuzz_fuzz_SOURCES = \
303303
test/fuzz/tx_out.cpp \
304304
test/fuzz/tx_pool.cpp \
305305
test/fuzz/txrequest.cpp \
306+
test/fuzz/utxo_snapshot.cpp \
306307
test/fuzz/validation_load_mempool.cpp \
307308
test/fuzz/versionbits.cpp
308309
endif # ENABLE_FUZZ_BINARY

src/chainparams.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,8 @@ class CRegTestParams : public CChainParams {
454454
{AssumeutxoHash{uint256S("0x1ebbf5850204c0bdb15bf030f47c7fe91d45c44c712697e4509ba67adb01c618")}, 110},
455455
},
456456
{
457-
210,
458-
{AssumeutxoHash{uint256S("0x9c5ed99ef98544b34f8920b6d1802f72ac28ae6e2bd2bd4c316ff10c230df3f2")}, 210},
457+
200,
458+
{AssumeutxoHash{uint256S("0x51c8d11d8b5c1de51543c579736e786aa2736206d1e11e627568029ce092cf62")}, 200},
459459
},
460460
};
461461

src/test/fuzz/utxo_snapshot.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) 2021 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <chainparams.h>
6+
#include <consensus/validation.h>
7+
#include <test/fuzz/FuzzedDataProvider.h>
8+
#include <test/fuzz/fuzz.h>
9+
#include <test/fuzz/util.h>
10+
#include <test/util/mining.h>
11+
#include <test/util/setup_common.h>
12+
#include <validation.h>
13+
#include <validationinterface.h>
14+
15+
namespace {
16+
17+
const std::vector<std::shared_ptr<CBlock>>* g_chain;
18+
19+
void initialize_chain()
20+
{
21+
const auto params{CreateChainParams(ArgsManager{}, CBaseChainParams::REGTEST)};
22+
static const auto chain{CreateBlockChain(2 * COINBASE_MATURITY, *params)};
23+
g_chain = &chain;
24+
}
25+
26+
FUZZ_TARGET_INIT(utxo_snapshot, initialize_chain)
27+
{
28+
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
29+
std::unique_ptr<const TestingSetup> setup{MakeNoLogFileContext<const TestingSetup>()};
30+
const auto& node = setup->m_node;
31+
auto& chainman{*node.chainman};
32+
33+
const auto snapshot_path = GetDataDir() / "fuzzed_snapshot.dat";
34+
35+
Assert(!chainman.SnapshotBlockhash());
36+
37+
{
38+
CAutoFile outfile{fsbridge::fopen(snapshot_path, "wb"), SER_DISK, CLIENT_VERSION};
39+
const auto file_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
40+
outfile << Span<const uint8_t>{file_data};
41+
}
42+
43+
const auto ActivateFuzzedSnapshot{[&] {
44+
CAutoFile infile{fsbridge::fopen(snapshot_path, "rb"), SER_DISK, CLIENT_VERSION};
45+
SnapshotMetadata metadata;
46+
try {
47+
infile >> metadata;
48+
} catch (const std::ios_base::failure&) {
49+
return false;
50+
}
51+
return chainman.ActivateSnapshot(infile, metadata, /* in_memory */ true);
52+
}};
53+
54+
if (fuzzed_data_provider.ConsumeBool()) {
55+
for (const auto& block : *g_chain) {
56+
BlockValidationState dummy;
57+
bool processed{chainman.ProcessNewBlockHeaders({*block}, dummy, ::Params())};
58+
Assert(processed);
59+
const auto* index{WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block->GetHash()))};
60+
Assert(index);
61+
}
62+
}
63+
64+
if (ActivateFuzzedSnapshot()) {
65+
LOCK(::cs_main);
66+
Assert(!chainman.ActiveChainstate().m_from_snapshot_blockhash->IsNull());
67+
Assert(*chainman.ActiveChainstate().m_from_snapshot_blockhash ==
68+
*chainman.SnapshotBlockhash());
69+
const auto& coinscache{chainman.ActiveChainstate().CoinsTip()};
70+
int64_t chain_tx{};
71+
for (const auto& block : *g_chain) {
72+
Assert(coinscache.HaveCoin(COutPoint{block->vtx.at(0)->GetHash(), 0}));
73+
const auto* index{chainman.m_blockman.LookupBlockIndex(block->GetHash())};
74+
const auto num_tx{Assert(index)->nTx};
75+
Assert(num_tx == 1);
76+
chain_tx += num_tx;
77+
}
78+
Assert(g_chain->size() == coinscache.GetCacheSize());
79+
Assert(chain_tx == chainman.ActiveTip()->nChainTx);
80+
} else {
81+
Assert(!chainman.SnapshotBlockhash());
82+
Assert(!chainman.ActiveChainstate().m_from_snapshot_blockhash);
83+
}
84+
// Snapshot should refuse to load a second time regardless of validity
85+
Assert(!ActivateFuzzedSnapshot());
86+
}
87+
} // namespace

src/test/util/mining.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
#include <node/context.h>
1212
#include <pow.h>
1313
#include <script/standard.h>
14+
#include <test/util/script.h>
1415
#include <util/check.h>
1516
#include <validation.h>
17+
#include <versionbits.h>
1618

1719
CTxIn generatetoaddress(const NodeContext& node, const std::string& address)
1820
{
@@ -23,6 +25,37 @@ CTxIn generatetoaddress(const NodeContext& node, const std::string& address)
2325
return MineBlock(node, coinbase_script);
2426
}
2527

28+
std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const CChainParams& params)
29+
{
30+
std::vector<std::shared_ptr<CBlock>> ret{total_height};
31+
auto time{params.GenesisBlock().nTime};
32+
for (size_t height{0}; height < total_height; ++height) {
33+
CBlock& block{*(ret.at(height) = std::make_shared<CBlock>())};
34+
35+
CMutableTransaction coinbase_tx;
36+
coinbase_tx.vin.resize(1);
37+
coinbase_tx.vin[0].prevout.SetNull();
38+
coinbase_tx.vout.resize(1);
39+
coinbase_tx.vout[0].scriptPubKey = P2WSH_OP_TRUE;
40+
coinbase_tx.vout[0].nValue = GetBlockSubsidy(height + 1, params.GetConsensus());
41+
coinbase_tx.vin[0].scriptSig = CScript() << (height + 1) << OP_0;
42+
block.vtx = {MakeTransactionRef(std::move(coinbase_tx))};
43+
44+
block.nVersion = VERSIONBITS_LAST_OLD_BLOCK_VERSION;
45+
block.hashPrevBlock = (height >= 1 ? *ret.at(height - 1) : params.GenesisBlock()).GetHash();
46+
block.hashMerkleRoot = BlockMerkleRoot(block);
47+
block.nTime = ++time;
48+
block.nBits = params.GenesisBlock().nBits;
49+
block.nNonce = 0;
50+
51+
while (!CheckProofOfWork(block.GetHash(), block.nBits, params.GetConsensus())) {
52+
++block.nNonce;
53+
assert(block.nNonce);
54+
}
55+
}
56+
return ret;
57+
}
58+
2659
CTxIn MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey)
2760
{
2861
auto block = PrepareBlock(node, coinbase_scriptPubKey);

src/test/util/mining.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@
77

88
#include <memory>
99
#include <string>
10+
#include <vector>
1011

1112
class CBlock;
13+
class CChainParams;
1214
class CScript;
1315
class CTxIn;
1416
struct NodeContext;
1517

18+
/** Create a blockchain, starting from genesis */
19+
std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const CChainParams& params);
20+
1621
/** Returns the generated coin */
1722
CTxIn MineBlock(const NodeContext&, const CScript& coinbase_scriptPubKey);
1823

src/test/validation_tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,11 @@ BOOST_AUTO_TEST_CASE(test_assumeutxo)
136136

137137
const auto out110 = *ExpectedAssumeutxo(110, *params);
138138
BOOST_CHECK_EQUAL(out110.hash_serialized.ToString(), "1ebbf5850204c0bdb15bf030f47c7fe91d45c44c712697e4509ba67adb01c618");
139-
BOOST_CHECK_EQUAL(out110.nChainTx, (unsigned int)110);
139+
BOOST_CHECK_EQUAL(out110.nChainTx, 110U);
140140

141-
const auto out210 = *ExpectedAssumeutxo(210, *params);
142-
BOOST_CHECK_EQUAL(out210.hash_serialized.ToString(), "9c5ed99ef98544b34f8920b6d1802f72ac28ae6e2bd2bd4c316ff10c230df3f2");
143-
BOOST_CHECK_EQUAL(out210.nChainTx, (unsigned int)210);
141+
const auto out210 = *ExpectedAssumeutxo(200, *params);
142+
BOOST_CHECK_EQUAL(out210.hash_serialized.ToString(), "51c8d11d8b5c1de51543c579736e786aa2736206d1e11e627568029ce092cf62");
143+
BOOST_CHECK_EQUAL(out210.nChainTx, 200U);
144144
}
145145

146146
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)