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