1
- // Copyright (c) 2020-2022 The Bitcoin Core developers
1
+ // Copyright (c) 2020-present The Bitcoin Core developers
2
2
// Distributed under the MIT software license, see the accompanying
3
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
4
14
14
#include < test/fuzz/fuzz.h>
15
15
#include < test/fuzz/util.h>
16
16
#include < test/util/setup_common.h>
17
+ #include < txdb.h>
17
18
#include < util/hasher.h>
18
19
19
20
#include < cassert>
@@ -41,13 +42,12 @@ void initialize_coins_view()
41
42
static const auto testing_setup = MakeNoLogFileContext<>();
42
43
}
43
44
44
- FUZZ_TARGET (coins_view, .init = initialize_coins_view )
45
+ void TestCoinsView (FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend_coins_view, bool is_db )
45
46
{
46
- FuzzedDataProvider fuzzed_data_provider{buffer.data (), buffer.size ()};
47
47
bool good_data{true };
48
48
49
- CCoinsView backend_coins_view;
50
49
CCoinsViewCache coins_view_cache{&backend_coins_view, /* deterministic=*/ true };
50
+ if (is_db) coins_view_cache.SetBestBlock (uint256::ONE);
51
51
COutPoint random_out_point;
52
52
Coin random_coin;
53
53
CMutableTransaction random_mutable_transaction;
@@ -69,6 +69,12 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
69
69
if (e.what () == std::string{" Attempted to overwrite an unspent coin (when possible_overwrite is false)" }) {
70
70
assert (!possible_overwrite);
71
71
expected_code_path = true ;
72
+ // AddCoin() decreases cachedCoinsUsage by the memory usage of the old coin at the beginning and
73
+ // increases it by the value of the new coin at the end. If it throws in the process, the value
74
+ // of cachedCoinsUsage would have been incorrectly decreased, leading to an underflow later on.
75
+ // To avoid this, use Flush() to reset the value of cachedCoinsUsage in sync with the cacheCoins
76
+ // mapping.
77
+ (void )coins_view_cache.Flush ();
72
78
}
73
79
}
74
80
assert (expected_code_path);
@@ -80,7 +86,10 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
80
86
(void )coins_view_cache.Sync ();
81
87
},
82
88
[&] {
83
- coins_view_cache.SetBestBlock (ConsumeUInt256 (fuzzed_data_provider));
89
+ uint256 best_block{ConsumeUInt256 (fuzzed_data_provider)};
90
+ // Set best block hash to non-null to satisfy the assertion in CCoinsViewDB::BatchWrite().
91
+ if (is_db && best_block.IsNull ()) best_block = uint256::ONE;
92
+ coins_view_cache.SetBestBlock (best_block);
84
93
},
85
94
[&] {
86
95
Coin move_to;
@@ -148,7 +157,11 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
148
157
bool expected_code_path = false ;
149
158
try {
150
159
auto cursor{CoinsViewCacheCursor (usage, sentinel, coins_map, /* will_erase=*/ true )};
151
- coins_view_cache.BatchWrite (cursor, fuzzed_data_provider.ConsumeBool () ? ConsumeUInt256 (fuzzed_data_provider) : coins_view_cache.GetBestBlock ());
160
+ uint256 best_block{coins_view_cache.GetBestBlock ()};
161
+ if (fuzzed_data_provider.ConsumeBool ()) best_block = ConsumeUInt256 (fuzzed_data_provider);
162
+ // Set best block hash to non-null to satisfy the assertion in CCoinsViewDB::BatchWrite().
163
+ if (is_db && best_block.IsNull ()) best_block = uint256::ONE;
164
+ coins_view_cache.BatchWrite (cursor, best_block);
152
165
expected_code_path = true ;
153
166
} catch (const std::logic_error& e) {
154
167
if (e.what () == std::string{" FRESH flag misapplied to coin that exists in parent cache" }) {
@@ -202,7 +215,7 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
202
215
203
216
{
204
217
std::unique_ptr<CCoinsViewCursor> coins_view_cursor = backend_coins_view.Cursor ();
205
- assert (!coins_view_cursor);
218
+ assert (is_db == ! !coins_view_cursor);
206
219
(void )backend_coins_view.EstimateSize ();
207
220
(void )backend_coins_view.GetBestBlock ();
208
221
(void )backend_coins_view.GetHeadBlocks ();
@@ -288,3 +301,22 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
288
301
});
289
302
}
290
303
}
304
+
305
+ FUZZ_TARGET (coins_view, .init = initialize_coins_view)
306
+ {
307
+ FuzzedDataProvider fuzzed_data_provider{buffer.data (), buffer.size ()};
308
+ CCoinsView backend_coins_view;
309
+ TestCoinsView (fuzzed_data_provider, backend_coins_view, /* is_db=*/ false );
310
+ }
311
+
312
+ FUZZ_TARGET (coins_view_db, .init = initialize_coins_view)
313
+ {
314
+ FuzzedDataProvider fuzzed_data_provider{buffer.data (), buffer.size ()};
315
+ auto db_params = DBParams{
316
+ .path = " " ,
317
+ .cache_bytes = 1_MiB,
318
+ .memory_only = true ,
319
+ };
320
+ CCoinsViewDB coins_db{std::move (db_params), CoinsViewOptions{}};
321
+ TestCoinsView (fuzzed_data_provider, coins_db, /* is_db=*/ true );
322
+ }
0 commit comments