fees.cpp raw

   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/time.h>
  10  #include <test/util/txmempool.h>
  11  #include <validation.h>
  12  #include <wallet/coincontrol.h>
  13  #include <wallet/fees.h>
  14  #include <wallet/test/util.h>
  15  #include <wallet/wallet.h>
  16  
  17  namespace wallet {
  18  namespace {
  19  
  20  struct FeeEstimatorTestingSetup : public TestingSetup {
  21      FeeEstimatorTestingSetup(const ChainType chain_type, TestOpts opts) : TestingSetup{chain_type, opts}
  22      {
  23      }
  24  
  25      ~FeeEstimatorTestingSetup() {
  26          m_node.fee_estimator.reset();
  27      }
  28  
  29      void SetFeeEstimator(std::unique_ptr<CBlockPolicyEstimator> fee_estimator)
  30      {
  31          m_node.fee_estimator = std::move(fee_estimator);
  32      }
  33  };
  34  
  35  FeeEstimatorTestingSetup* g_setup;
  36  
  37  class FuzzedBlockPolicyEstimator : public CBlockPolicyEstimator
  38  {
  39      FuzzedDataProvider& fuzzed_data_provider;
  40  
  41  public:
  42      FuzzedBlockPolicyEstimator(FuzzedDataProvider& provider)
  43          : CBlockPolicyEstimator(fs::path{}, false), fuzzed_data_provider(provider) {}
  44  
  45      CFeeRate estimateSmartFee(int confTarget, FeeCalculation* feeCalc, bool conservative) const override
  46      {
  47          return CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/1'000'000)};
  48      }
  49  
  50      unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const override
  51      {
  52          return fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(1, 1000);
  53      }
  54  };
  55  
  56  void initialize_setup()
  57  {
  58      static const auto testing_setup = MakeNoLogFileContext<FeeEstimatorTestingSetup>();
  59      g_setup = testing_setup.get();
  60  }
  61  
  62  FUZZ_TARGET(wallet_fees, .init = initialize_setup)
  63  {
  64      SeedRandomStateForTest(SeedRand::ZEROS);
  65      FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
  66      FakeNodeClock clock{ConsumeTime(fuzzed_data_provider)};
  67      auto& node{g_setup->m_node};
  68      Chainstate* chainstate = &node.chainman->ActiveChainstate();
  69  
  70      bilingual_str error;
  71      CTxMemPool::Options mempool_opts{
  72          .incremental_relay_feerate = CFeeRate{ConsumeMoney(fuzzed_data_provider, 1'000'000)},
  73          .min_relay_feerate = CFeeRate{ConsumeMoney(fuzzed_data_provider, 1'000'000)},
  74          .dust_relay_feerate = CFeeRate{ConsumeMoney(fuzzed_data_provider, 1'000'000)}
  75      };
  76      node.mempool = std::make_unique<CTxMemPool>(mempool_opts, error);
  77      std::unique_ptr<CBlockPolicyEstimator> fee_estimator = std::make_unique<FuzzedBlockPolicyEstimator>(fuzzed_data_provider);
  78      g_setup->SetFeeEstimator(std::move(fee_estimator));
  79      auto target_feerate{CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/1'000'000)}};
  80      if (target_feerate > node.mempool->m_opts.incremental_relay_feerate &&
  81          target_feerate > node.mempool->m_opts.min_relay_feerate) {
  82          MockMempoolMinFee(target_feerate, *node.mempool);
  83      }
  84      std::unique_ptr<CWallet> wallet_ptr{std::make_unique<CWallet>(node.chain.get(), "", CreateMockableWalletDatabase())};
  85      CWallet& wallet{*wallet_ptr};
  86      {
  87          LOCK(wallet.cs_wallet);
  88          wallet.SetLastBlockProcessed(chainstate->m_chain.Height(), chainstate->m_chain.Tip()->GetBlockHash());
  89      }
  90  
  91      if (fuzzed_data_provider.ConsumeBool()) {
  92          wallet.m_fallback_fee = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
  93      }
  94  
  95      if (fuzzed_data_provider.ConsumeBool()) {
  96          wallet.m_discard_rate = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
  97      }
  98      (void)GetDiscardRate(wallet);
  99  
 100      const auto tx_bytes{fuzzed_data_provider.ConsumeIntegralInRange(0, std::numeric_limits<int32_t>::max())};
 101      if (fuzzed_data_provider.ConsumeBool()) {
 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
 126