/root/bitcoin/src/test/fuzz/mini_miner.cpp
Line | Count | Source |
1 | | // Copyright (c) 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 <node/mini_miner.h> |
6 | | |
7 | | #include <consensus/amount.h> |
8 | | #include <kernel/cs_main.h> |
9 | | #include <policy/feerate.h> |
10 | | #include <primitives/transaction.h> |
11 | | #include <script/script.h> |
12 | | #include <sync.h> |
13 | | #include <test/fuzz/FuzzedDataProvider.h> |
14 | | #include <test/fuzz/fuzz.h> |
15 | | #include <test/fuzz/util.h> |
16 | | #include <test/util/script.h> |
17 | | #include <test/util/random.h> |
18 | | #include <test/util/setup_common.h> |
19 | | #include <test/util/time.h> |
20 | | #include <test/util/txmempool.h> |
21 | | #include <txmempool.h> |
22 | | #include <uint256.h> |
23 | | #include <util/check.h> |
24 | | #include <util/translation.h> |
25 | | |
26 | | #include <algorithm> |
27 | | #include <cstddef> |
28 | | #include <cstdint> |
29 | | #include <deque> |
30 | | #include <functional> |
31 | | #include <map> |
32 | | #include <optional> |
33 | | #include <utility> |
34 | | #include <vector> |
35 | | |
36 | | namespace { |
37 | | |
38 | | std::deque<COutPoint> g_available_coins; |
39 | | void initialize_miner() |
40 | 0 | { |
41 | 0 | static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(); |
42 | 0 | for (uint32_t i = 0; i < uint32_t{100}; ++i) { Branch (42:26): [True: 0, False: 0]
|
43 | 0 | g_available_coins.emplace_back(Txid::FromUint256(uint256::ZERO), i); |
44 | 0 | } |
45 | 0 | } |
46 | | |
47 | | // Test that the MiniMiner can run with various outpoints and feerates. |
48 | | FUZZ_TARGET(mini_miner, .init = initialize_miner) |
49 | 3.23k | { |
50 | 3.23k | SeedRandomStateForTest(SeedRand::ZEROS); |
51 | 3.23k | FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; |
52 | 3.23k | FakeNodeClock clock{ConsumeTime(fuzzed_data_provider)}; |
53 | 3.23k | bilingual_str error; |
54 | 3.23k | CTxMemPool pool{CTxMemPool::Options{}, error}; |
55 | 3.23k | Assert(error.empty()); |
56 | 3.23k | std::vector<COutPoint> outpoints; |
57 | 3.23k | std::deque<COutPoint> available_coins = g_available_coins; |
58 | 3.23k | LOCK2(::cs_main, pool.cs); |
59 | | // Cluster size cannot exceed 500 |
60 | 110k | LIMITED_WHILE (!available_coins.empty(), 100) { |
61 | 110k | CMutableTransaction mtx = CMutableTransaction(); |
62 | 110k | const size_t num_inputs = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, available_coins.size()); |
63 | 110k | const size_t num_outputs = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50); |
64 | 840k | for (size_t n{0}; n < num_inputs; ++n) { Branch (64:27): [True: 730k, False: 110k]
|
65 | 730k | auto prevout = available_coins.front(); |
66 | 730k | mtx.vin.emplace_back(prevout, CScript()); |
67 | 730k | available_coins.pop_front(); |
68 | 730k | } |
69 | 1.01M | for (uint32_t n{0}; n < num_outputs; ++n) { Branch (69:29): [True: 900k, False: 110k]
|
70 | 900k | mtx.vout.emplace_back(100, P2WSH_OP_TRUE); |
71 | 900k | } |
72 | 110k | CTransactionRef tx = MakeTransactionRef(mtx); |
73 | 110k | TestMemPoolEntryHelper entry; |
74 | 110k | const CAmount fee{ConsumeMoney(fuzzed_data_provider, /*max=*/MAX_MONEY/100000)}; |
75 | 110k | assert(MoneyRange(fee)); Branch (75:9): [True: 110k, False: 0]
|
76 | 110k | TryAddToMempool(pool, entry.Fee(fee).FromTx(tx)); |
77 | | |
78 | | // All outputs are available to spend |
79 | 1.01M | for (uint32_t n{0}; n < num_outputs; ++n) { Branch (79:29): [True: 900k, False: 110k]
|
80 | 900k | if (fuzzed_data_provider.ConsumeBool()) { Branch (80:17): [True: 602k, False: 298k]
|
81 | 602k | available_coins.emplace_back(tx->GetHash(), n); |
82 | 602k | } |
83 | 900k | } |
84 | | |
85 | 110k | if (fuzzed_data_provider.ConsumeBool() && !tx->vout.empty()) { Branch (85:13): [True: 59.0k, False: 51.1k]
Branch (85:51): [True: 59.0k, False: 0]
|
86 | | // Add outpoint from this tx (may or not be spent by a later tx) |
87 | 59.0k | outpoints.emplace_back(tx->GetHash(), |
88 | 59.0k | (uint32_t)fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, tx->vout.size())); |
89 | 59.0k | } else { |
90 | | // Add some random outpoint (will be interpreted as confirmed or not yet submitted |
91 | | // to mempool). |
92 | 51.1k | auto outpoint = ConsumeDeserializable<COutPoint>(fuzzed_data_provider); |
93 | 51.1k | if (outpoint.has_value() && std::find(outpoints.begin(), outpoints.end(), *outpoint) == outpoints.end()) { Branch (93:17): [True: 8.19k, False: 42.9k]
Branch (93:17): [True: 5.27k, False: 45.8k]
Branch (93:41): [True: 5.27k, False: 2.91k]
|
94 | 5.27k | outpoints.push_back(*outpoint); |
95 | 5.27k | } |
96 | 51.1k | } |
97 | 110k | } |
98 | | |
99 | 3.23k | const CFeeRate target_feerate{CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/MAX_MONEY/1000)}}; |
100 | 3.23k | std::optional<CAmount> total_bumpfee; |
101 | 3.23k | CAmount sum_fees = 0; |
102 | 3.23k | { |
103 | 3.23k | node::MiniMiner mini_miner{pool, outpoints}; |
104 | 3.23k | assert(mini_miner.IsReadyToCalculate()); Branch (104:9): [True: 1.61k, False: 1.61k]
|
105 | 1.61k | const auto bump_fees = mini_miner.CalculateBumpFees(target_feerate); |
106 | 64.3k | for (const auto& outpoint : outpoints) { Branch (106:35): [True: 64.3k, False: 1.61k]
|
107 | 64.3k | auto it = bump_fees.find(outpoint); |
108 | 64.3k | assert(it != bump_fees.end()); Branch (108:13): [True: 64.3k, False: 0]
|
109 | 64.3k | assert(it->second >= 0); Branch (109:13): [True: 64.3k, False: 0]
|
110 | 64.3k | sum_fees += it->second; |
111 | 64.3k | } |
112 | 1.61k | assert(!mini_miner.IsReadyToCalculate()); Branch (112:9): [True: 1.61k, False: 0]
|
113 | 1.61k | } |
114 | 1.61k | { |
115 | 1.61k | node::MiniMiner mini_miner{pool, outpoints}; |
116 | 1.61k | assert(mini_miner.IsReadyToCalculate()); Branch (116:9): [True: 1.61k, False: 0]
|
117 | 1.61k | total_bumpfee = mini_miner.CalculateTotalBumpFees(target_feerate); |
118 | 1.61k | assert(total_bumpfee.has_value()); Branch (118:9): [True: 1.61k, False: 0]
|
119 | 1.61k | assert(!mini_miner.IsReadyToCalculate()); Branch (119:9): [True: 1.61k, False: 0]
|
120 | 1.61k | } |
121 | | // Overlapping ancestry across multiple outpoints can only reduce the total bump fee. |
122 | 1.61k | assert (sum_fees >= *total_bumpfee); Branch (122:5): [True: 1.61k, False: 0]
|
123 | 1.61k | } |
124 | | } // namespace |