Branch data Line data Source code
1 : : // Copyright (c) 2022-present 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 <test/fuzz/FuzzedDataProvider.h>
6 : : #include <test/fuzz/fuzz.h>
7 : : #include <test/fuzz/util.h>
8 : : #include <test/util/setup_common.h>
9 : : #include <test/util/txmempool.h>
10 : : #include <validation.h>
11 : : #include <wallet/coincontrol.h>
12 : : #include <wallet/fees.h>
13 : : #include <wallet/test/util.h>
14 : : #include <wallet/wallet.h>
15 : :
16 : : namespace wallet {
17 : : namespace {
18 : :
19 : : struct FeeEstimatorTestingSetup : public TestingSetup {
20 [ + - ]: 1 : FeeEstimatorTestingSetup(const ChainType chain_type, TestOpts opts) : TestingSetup{chain_type, opts}
21 : : {
22 : 1 : }
23 : :
24 : 1 : ~FeeEstimatorTestingSetup() {
25 [ + - ]: 1 : m_node.fee_estimator.reset();
26 : 1 : }
27 : :
28 : 91 : void SetFeeEstimator(std::unique_ptr<CBlockPolicyEstimator> fee_estimator)
29 : : {
30 : 91 : m_node.fee_estimator = std::move(fee_estimator);
31 : : }
32 : : };
33 : :
34 : : FeeEstimatorTestingSetup* g_setup;
35 : :
36 : : class FuzzedBlockPolicyEstimator : public CBlockPolicyEstimator
37 : : {
38 : : FuzzedDataProvider& fuzzed_data_provider;
39 : :
40 : : public:
41 : 91 : FuzzedBlockPolicyEstimator(FuzzedDataProvider& provider)
42 [ + - ]: 182 : : CBlockPolicyEstimator(fs::path{}, false), fuzzed_data_provider(provider) {}
43 : :
44 : 271 : CFeeRate estimateSmartFee(int confTarget, FeeCalculation* feeCalc, bool conservative) const override
45 : : {
46 : 271 : return CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/1'000'000)};
47 : : }
48 : :
49 : 91 : unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const override
50 : : {
51 : 91 : return fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(1, 1000);
52 : : }
53 : : };
54 : :
55 : 1 : void initialize_setup()
56 : : {
57 [ + - + - : 1 : static const auto testing_setup = MakeNoLogFileContext<FeeEstimatorTestingSetup>();
+ - ]
58 : 1 : g_setup = testing_setup.get();
59 : 1 : }
60 : :
61 [ + - ]: 549 : FUZZ_TARGET(wallet_fees, .init = initialize_setup)
62 : : {
63 : 91 : SeedRandomStateForTest(SeedRand::ZEROS);
64 : 91 : FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
65 : 91 : SetMockTime(ConsumeTime(fuzzed_data_provider));
66 : 91 : auto& node{g_setup->m_node};
67 : 91 : Chainstate* chainstate = &node.chainman->ActiveChainstate();
68 : :
69 : 91 : bilingual_str error;
70 : 91 : CTxMemPool::Options mempool_opts{
71 : 91 : .incremental_relay_feerate = CFeeRate{ConsumeMoney(fuzzed_data_provider, 1'000'000)},
72 : 91 : .min_relay_feerate = CFeeRate{ConsumeMoney(fuzzed_data_provider, 1'000'000)},
73 : 91 : .dust_relay_feerate = CFeeRate{ConsumeMoney(fuzzed_data_provider, 1'000'000)}
74 [ + - ]: 91 : };
75 [ + - ]: 91 : node.mempool = std::make_unique<CTxMemPool>(mempool_opts, error);
76 [ + - ]: 91 : std::unique_ptr<CBlockPolicyEstimator> fee_estimator = std::make_unique<FuzzedBlockPolicyEstimator>(fuzzed_data_provider);
77 : 91 : g_setup->SetFeeEstimator(std::move(fee_estimator));
78 [ + + ]: 91 : auto target_feerate{CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/1'000'000)}};
79 [ + + + + ]: 91 : if (target_feerate > node.mempool->m_opts.incremental_relay_feerate &&
80 [ + + ]: 18 : target_feerate > node.mempool->m_opts.min_relay_feerate) {
81 [ + - ]: 12 : MockMempoolMinFee(target_feerate, *node.mempool);
82 : : }
83 [ + - + - ]: 91 : std::unique_ptr<CWallet> wallet_ptr{std::make_unique<CWallet>(node.chain.get(), "", CreateMockableWalletDatabase())};
84 [ + - ]: 91 : CWallet& wallet{*wallet_ptr};
85 : 91 : {
86 [ + - ]: 91 : LOCK(wallet.cs_wallet);
87 [ - + + - ]: 182 : wallet.SetLastBlockProcessed(chainstate->m_chain.Height(), chainstate->m_chain.Tip()->GetBlockHash());
88 : 0 : }
89 : :
90 [ + + ]: 91 : if (fuzzed_data_provider.ConsumeBool()) {
91 : 10 : wallet.m_fallback_fee = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
92 : : }
93 : :
94 [ + + ]: 91 : if (fuzzed_data_provider.ConsumeBool()) {
95 : 8 : wallet.m_discard_rate = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
96 : : }
97 [ + - ]: 91 : (void)GetDiscardRate(wallet);
98 : :
99 : 91 : const auto tx_bytes{fuzzed_data_provider.ConsumeIntegralInRange(0, std::numeric_limits<int32_t>::max())};
100 [ + + ]: 91 : if (fuzzed_data_provider.ConsumeBool()) {
101 : 1 : wallet.m_pay_tx_fee = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
102 : 1 : wallet.m_min_fee = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
103 : : }
104 : :
105 [ + - ]: 91 : (void)GetRequiredFee(wallet, tx_bytes);
106 [ + - ]: 91 : (void)GetRequiredFeeRate(wallet);
107 : :
108 [ + - ]: 91 : CCoinControl coin_control;
109 [ - + ]: 91 : if (fuzzed_data_provider.ConsumeBool()) {
110 [ # # ]: 0 : coin_control.m_feerate = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
111 : : }
112 [ + + ]: 91 : if (fuzzed_data_provider.ConsumeBool()) {
113 : 2 : coin_control.m_confirm_target = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, 999'000);
114 : : }
115 [ - + ]: 91 : if (fuzzed_data_provider.ConsumeBool()) {
116 [ # # ]: 0 : coin_control.m_fee_mode = fuzzed_data_provider.ConsumeBool() ? FeeEstimateMode::CONSERVATIVE : FeeEstimateMode::ECONOMICAL;
117 : : }
118 : :
119 : 91 : FeeCalculation fee_calculation;
120 [ + - ]: 91 : FeeCalculation* maybe_fee_calculation{fuzzed_data_provider.ConsumeBool() ? nullptr : &fee_calculation};
121 [ + - ]: 91 : (void)GetMinimumFeeRate(wallet, coin_control, maybe_fee_calculation);
122 [ + - ]: 91 : (void)GetMinimumFee(wallet, tx_bytes, coin_control, maybe_fee_calculation);
123 [ + - ]: 273 : }
124 : : } // namespace
125 : : } // namespace wallet
|