LCOV - code coverage report
Current view: top level - src/test/fuzz/util - wallet.h (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 98.8 % 81 80
Test Date: 2024-12-04 04:00:22 Functions: 100.0 % 7 7
Branches: 51.9 % 162 84

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2024-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                 :             : #ifndef BITCOIN_TEST_FUZZ_UTIL_WALLET_H
       6                 :             : #define BITCOIN_TEST_FUZZ_UTIL_WALLET_H
       7                 :             : 
       8                 :             : #include <test/fuzz/FuzzedDataProvider.h>
       9                 :             : #include <test/fuzz/fuzz.h>
      10                 :             : #include <test/fuzz/util.h>
      11                 :             : #include <policy/policy.h>
      12                 :             : #include <wallet/coincontrol.h>
      13                 :             : #include <wallet/fees.h>
      14                 :             : #include <wallet/spend.h>
      15                 :             : #include <wallet/test/util.h>
      16                 :             : #include <wallet/wallet.h>
      17                 :             : 
      18                 :             : namespace wallet {
      19                 :             : 
      20                 :             : /**
      21                 :             :  * Wraps a descriptor wallet for fuzzing.
      22                 :             :  */
      23   [ +  -  +  -  :        7470 : struct FuzzedWallet {
             -  -  #  # ]
           [ +  -  +  -  
             -  -  -  - ]
      24                 :             :     std::shared_ptr<CWallet> wallet;
      25                 :        4440 :     FuzzedWallet(interfaces::Chain& chain, const std::string& name, const std::string& seed_insecure)
      26         [ +  - ]:        4440 :     {
      27   [ +  -  +  -  :        4440 :         wallet = std::make_shared<CWallet>(&chain, name, CreateMockableWalletDatabase());
                   -  + ]
      28                 :        4440 :         {
      29         [ +  - ]:        4440 :             LOCK(wallet->cs_wallet);
      30         [ +  - ]:        4440 :             wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
      31   [ +  -  +  -  :        4440 :             auto height{*Assert(chain.getHeight())};
                   +  - ]
      32   [ +  -  +  - ]:        4440 :             wallet->SetLastBlockProcessed(height, chain.getBlockHash(height));
      33                 :           0 :         }
      34         [ +  - ]:        4440 :         wallet->m_keypool_size = 1; // Avoid timeout in TopUp()
      35   [ +  -  -  + ]:        4440 :         assert(wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
      36         [ +  - ]:        4440 :         ImportDescriptors(seed_insecure);
      37         [ -  - ]:        4440 :     }
      38                 :        4440 :     void ImportDescriptors(const std::string& seed_insecure)
      39                 :             :     {
      40                 :        4440 :         const std::vector<std::string> DESCS{
      41                 :             :             "pkh(%s/%s/*)",
      42                 :             :             "sh(wpkh(%s/%s/*))",
      43                 :             :             "tr(%s/%s/*)",
      44                 :             :             "wpkh(%s/%s/*)",
      45   [ +  -  +  +  :       44400 :         };
          +  -  +  +  -  
                -  -  - ]
      46                 :             : 
      47         [ +  + ]:       22200 :         for (const std::string& desc_fmt : DESCS) {
      48         [ +  + ]:       53280 :             for (bool internal : {true, false}) {
      49   [ +  -  +  - ]:       35520 :                 const auto descriptor{(strprintf)(desc_fmt, "[5aa9973a/66h/4h/2h]" + seed_insecure, int{internal})};
      50                 :             : 
      51                 :       35520 :                 FlatSigningProvider keys;
      52         [ +  - ]:       35520 :                 std::string error;
      53         [ +  - ]:       71040 :                 auto parsed_desc = std::move(Parse(descriptor, keys, error, /*require_checksum=*/false).at(0));
      54         [ -  + ]:       35520 :                 assert(parsed_desc);
      55         [ -  + ]:       35520 :                 assert(error.empty());
      56   [ +  -  -  + ]:       35520 :                 assert(parsed_desc->IsRange());
      57   [ +  -  -  + ]:       35520 :                 assert(parsed_desc->IsSingleType());
      58         [ -  + ]:       35520 :                 assert(!keys.keys.empty());
      59   [ +  -  +  - ]:       35520 :                 WalletDescriptor w_desc{std::move(parsed_desc), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/1, /*next_index=*/0};
      60   [ +  -  -  + ]:       35520 :                 assert(!wallet->GetDescriptorScriptPubKeyMan(w_desc));
      61         [ +  - ]:       35520 :                 LOCK(wallet->cs_wallet);
      62   [ +  -  +  - ]:       35520 :                 auto spk_manager{wallet->AddWalletDescriptor(w_desc, keys, /*label=*/"", internal)};
      63         [ -  + ]:       35520 :                 assert(spk_manager);
      64   [ +  -  +  -  :       35520 :                 wallet->AddActiveScriptPubKeyMan(spk_manager->GetID(), *Assert(w_desc.descriptor->GetOutputType()), internal);
             +  -  +  - ]
      65                 :       35520 :             }
      66                 :             :         }
      67                 :        4440 :     }
      68                 :      259494 :     CTxDestination GetDestination(FuzzedDataProvider& fuzzed_data_provider)
      69                 :             :     {
      70                 :      259494 :         auto type{fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)};
      71         [ +  + ]:      259494 :         if (fuzzed_data_provider.ConsumeBool()) {
      72   [ +  -  +  -  :      342672 :             return *Assert(wallet->GetNewDestination(type, ""));
                   +  - ]
      73                 :             :         } else {
      74   [ +  -  +  - ]:      176316 :             return *Assert(wallet->GetNewChangeDestination(type));
      75                 :             :         }
      76                 :             :     }
      77         [ +  - ]:      340012 :     CScript GetScriptPubKey(FuzzedDataProvider& fuzzed_data_provider) { return GetScriptForDestination(GetDestination(fuzzed_data_provider)); }
      78                 :       84640 :     void FundTx(FuzzedDataProvider& fuzzed_data_provider, CMutableTransaction tx)
      79                 :             :     {
      80                 :             :         // The fee of "tx" is 0, so this is the total input and output amount
      81                 :       84640 :         const CAmount total_amt{
      82                 :      424652 :             std::accumulate(tx.vout.begin(), tx.vout.end(), CAmount{}, [](CAmount t, const CTxOut& out) { return t + out.nValue; })};
      83         [ +  - ]:       84640 :         const uint32_t tx_size(GetVirtualTransactionSize(CTransaction{tx}));
      84                 :       84640 :         std::set<int> subtract_fee_from_outputs;
      85         [ +  + ]:       84640 :         if (fuzzed_data_provider.ConsumeBool()) {
      86         [ +  + ]:      272776 :             for (size_t i{}; i < tx.vout.size(); ++i) {
      87         [ +  + ]:      236710 :                 if (fuzzed_data_provider.ConsumeBool()) {
      88         [ +  - ]:      197651 :                     subtract_fee_from_outputs.insert(i);
      89                 :             :                 }
      90                 :             :             }
      91                 :             :         }
      92                 :       84640 :         std::vector<CRecipient> recipients;
      93         [ +  + ]:      424652 :         for (size_t idx = 0; idx < tx.vout.size(); idx++) {
      94         [ +  - ]:      340012 :             const CTxOut& tx_out = tx.vout[idx];
      95                 :      340012 :             CTxDestination dest;
      96         [ +  - ]:      340012 :             ExtractDestination(tx_out.scriptPubKey, dest);
      97         [ +  - ]:      680024 :             CRecipient recipient = {dest, tx_out.nValue, subtract_fee_from_outputs.count(idx) == 1};
      98         [ +  - ]:      340012 :             recipients.push_back(recipient);
      99                 :      340012 :         }
     100         [ +  - ]:       84640 :         CCoinControl coin_control;
     101                 :       84640 :         coin_control.m_allow_other_inputs = fuzzed_data_provider.ConsumeBool();
     102         [ +  - ]:       84640 :         CallOneOf(
     103                 :       57265 :             fuzzed_data_provider, [&] { coin_control.destChange = GetDestination(fuzzed_data_provider); },
     104         [ -  + ]:       23112 :             [&] { coin_control.m_change_type.emplace(fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)); },
     105                 :             :             [&] { /* no op (leave uninitialized) */ });
     106                 :       84640 :         coin_control.fAllowWatchOnly = fuzzed_data_provider.ConsumeBool();
     107                 :       84640 :         coin_control.m_include_unsafe_inputs = fuzzed_data_provider.ConsumeBool();
     108                 :       84640 :         {
     109                 :       84640 :             auto& r{coin_control.m_signal_bip125_rbf};
     110                 :       84640 :             CallOneOf(
     111         [ -  + ]:       84640 :                 fuzzed_data_provider, [&] { r = true; }, [&] { r = false; }, [&] { r = std::nullopt; });
     112                 :             :         }
     113                 :       84640 :         coin_control.m_feerate = CFeeRate{
     114                 :             :             // A fee of this range should cover all cases
     115                 :       84640 :             fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, 2 * total_amt),
     116                 :             :             tx_size,
     117         [ +  - ]:       84640 :         };
     118         [ +  + ]:       84640 :         if (fuzzed_data_provider.ConsumeBool()) {
     119         [ +  - ]:       55458 :             *coin_control.m_feerate += GetMinimumFeeRate(*wallet, coin_control, nullptr);
     120                 :             :         }
     121                 :       84640 :         coin_control.fOverrideFeeRate = fuzzed_data_provider.ConsumeBool();
     122                 :             :         // Add solving data (m_external_provider and SelectExternal)?
     123                 :             : 
     124                 :       84640 :         int change_position{fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, tx.vout.size() - 1)};
     125                 :       84640 :         bilingual_str error;
     126                 :             :         // Clear tx.vout since it is not meant to be used now that we are passing outputs directly.
     127                 :             :         // This sets us up for a future PR to completely remove tx from the function signature in favor of passing inputs directly
     128                 :       84640 :         tx.vout.clear();
     129   [ +  -  +  - ]:      169280 :         (void)FundTransaction(*wallet, tx, recipients, change_position, /*lockUnspents=*/false, coin_control);
     130                 :       84640 :     }
     131                 :             : };
     132                 :             : }
     133                 :             : 
     134                 :             : #endif // BITCOIN_TEST_FUZZ_UTIL_WALLET_H
        

Generated by: LCOV version 2.0-1