LCOV - code coverage report
Current view: top level - src/wallet - wallet.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 18 2611 0.7 %
Date: 2023-09-26 12:08:55 Functions: 11 208 5.3 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2022 The Bitcoin Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include <wallet/wallet.h>
       7             : 
       8             : #if defined(HAVE_CONFIG_H)
       9             : #include <config/bitcoin-config.h>
      10             : #endif
      11             : #include <addresstype.h>
      12             : #include <blockfilter.h>
      13             : #include <chain.h>
      14             : #include <coins.h>
      15             : #include <common/args.h>
      16             : #include <common/settings.h>
      17           2 : #include <common/system.h>
      18           2 : #include <consensus/amount.h>
      19             : #include <consensus/consensus.h>
      20             : #include <consensus/validation.h>
      21             : #include <external_signer.h>
      22             : #include <interfaces/chain.h>
      23             : #include <interfaces/handler.h>
      24             : #include <interfaces/wallet.h>
      25             : #include <kernel/mempool_removal_reason.h>
      26             : #include <key.h>
      27           2 : #include <key_io.h>
      28             : #include <logging.h>
      29             : #include <outputtype.h>
      30             : #include <policy/feerate.h>
      31             : #include <primitives/block.h>
      32             : #include <primitives/transaction.h>
      33             : #include <psbt.h>
      34             : #include <pubkey.h>
      35             : #include <random.h>
      36             : #include <script/descriptor.h>
      37             : #include <script/interpreter.h>
      38             : #include <script/script.h>
      39             : #include <script/sign.h>
      40             : #include <script/signingprovider.h>
      41             : #include <script/solver.h>
      42             : #include <serialize.h>
      43             : #include <span.h>
      44             : #include <streams.h>
      45             : #include <support/allocators/secure.h>
      46             : #include <support/allocators/zeroafterfree.h>
      47             : #include <support/cleanse.h>
      48             : #include <sync.h>
      49             : #include <tinyformat.h>
      50             : #include <uint256.h>
      51             : #include <univalue.h>
      52             : #include <util/check.h>
      53           0 : #include <util/error.h>
      54             : #include <util/fs.h>
      55             : #include <util/fs_helpers.h>
      56             : #include <util/message.h>
      57             : #include <util/moneystr.h>
      58             : #include <util/result.h>
      59             : #include <util/string.h>
      60             : #include <util/time.h>
      61             : #include <util/translation.h>
      62             : #include <wallet/coincontrol.h>
      63             : #include <wallet/context.h>
      64             : #include <wallet/crypter.h>
      65             : #include <wallet/db.h>
      66             : #include <wallet/external_signer_scriptpubkeyman.h>
      67             : #include <wallet/scriptpubkeyman.h>
      68             : #include <wallet/transaction.h>
      69             : #include <wallet/types.h>
      70             : #include <wallet/walletdb.h>
      71             : #include <wallet/walletutil.h>
      72             : 
      73             : #include <algorithm>
      74           2 : #include <cassert>
      75             : #include <condition_variable>
      76             : #include <exception>
      77             : #include <optional>
      78             : #include <stdexcept>
      79             : #include <thread>
      80             : #include <tuple>
      81             : #include <variant>
      82             : 
      83             : struct KeyOriginInfo;
      84             : 
      85             : using interfaces::FoundBlock;
      86             : 
      87             : namespace wallet {
      88             : 
      89           0 : bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
      90             : {
      91           2 :     common::SettingsValue setting_value = chain.getRwSetting("wallet");
      92           0 :     if (!setting_value.isArray()) setting_value.setArray();
      93           0 :     for (const common::SettingsValue& value : setting_value.getValues()) {
      94           0 :         if (value.isStr() && value.get_str() == wallet_name) return true;
      95             :     }
      96           0 :     setting_value.push_back(wallet_name);
      97           0 :     return chain.updateRwSetting("wallet", setting_value);
      98           0 : }
      99           2 : 
     100           0 : bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
     101             : {
     102           0 :     common::SettingsValue setting_value = chain.getRwSetting("wallet");
     103           0 :     if (!setting_value.isArray()) return true;
     104           0 :     common::SettingsValue new_value(common::SettingsValue::VARR);
     105           0 :     for (const common::SettingsValue& value : setting_value.getValues()) {
     106           0 :         if (!value.isStr() || value.get_str() != wallet_name) new_value.push_back(value);
     107             :     }
     108           0 :     if (new_value.size() == setting_value.size()) return true;
     109           0 :     return chain.updateRwSetting("wallet", new_value);
     110           0 : }
     111             : 
     112           0 : static void UpdateWalletSetting(interfaces::Chain& chain,
     113             :                                 const std::string& wallet_name,
     114             :                                 std::optional<bool> load_on_startup,
     115             :                                 std::vector<bilingual_str>& warnings)
     116             : {
     117           0 :     if (!load_on_startup) return;
     118           0 :     if (load_on_startup.value() && !AddWalletSetting(chain, wallet_name)) {
     119           0 :         warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
     120           0 :     } else if (!load_on_startup.value() && !RemoveWalletSetting(chain, wallet_name)) {
     121           0 :         warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));
     122           0 :     }
     123           0 : }
     124             : 
     125             : /**
     126             :  * Refresh mempool status so the wallet is in an internally consistent state and
     127             :  * immediately knows the transaction's status: Whether it can be considered
     128             :  * trusted and is eligible to be abandoned ...
     129             :  */
     130           0 : static void RefreshMempoolStatus(CWalletTx& tx, interfaces::Chain& chain)
     131             : {
     132           0 :     if (chain.isInMempool(tx.GetHash())) {
     133           0 :         tx.m_state = TxStateInMempool();
     134           0 :     } else if (tx.state<TxStateInMempool>()) {
     135           0 :         tx.m_state = TxStateInactive();
     136           0 :     }
     137           0 : }
     138             : 
     139           0 : bool AddWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet)
     140             : {
     141           0 :     LOCK(context.wallets_mutex);
     142           0 :     assert(wallet);
     143           0 :     std::vector<std::shared_ptr<CWallet>>::const_iterator i = std::find(context.wallets.begin(), context.wallets.end(), wallet);
     144           0 :     if (i != context.wallets.end()) return false;
     145           0 :     context.wallets.push_back(wallet);
     146           0 :     wallet->ConnectScriptPubKeyManNotifiers();
     147           0 :     wallet->NotifyCanGetAddressesChanged();
     148           0 :     return true;
     149           0 : }
     150             : 
     151           0 : bool RemoveWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet, std::optional<bool> load_on_start, std::vector<bilingual_str>& warnings)
     152             : {
     153           0 :     assert(wallet);
     154             : 
     155           0 :     interfaces::Chain& chain = wallet->chain();
     156           0 :     std::string name = wallet->GetName();
     157             : 
     158             :     // Unregister with the validation interface which also drops shared pointers.
     159           0 :     wallet->m_chain_notifications_handler.reset();
     160           0 :     LOCK(context.wallets_mutex);
     161           0 :     std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(context.wallets.begin(), context.wallets.end(), wallet);
     162           0 :     if (i == context.wallets.end()) return false;
     163           2 :     context.wallets.erase(i);
     164           2 : 
     165           2 :     // Write the wallet setting
     166           2 :     UpdateWalletSetting(chain, name, load_on_start, warnings);
     167           2 : 
     168           2 :     return true;
     169           2 : }
     170           2 : 
     171           0 : bool RemoveWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet, std::optional<bool> load_on_start)
     172             : {
     173           0 :     std::vector<bilingual_str> warnings;
     174           0 :     return RemoveWallet(context, wallet, load_on_start, warnings);
     175           0 : }
     176             : 
     177           0 : std::vector<std::shared_ptr<CWallet>> GetWallets(WalletContext& context)
     178             : {
     179           0 :     LOCK(context.wallets_mutex);
     180           0 :     return context.wallets;
     181           0 : }
     182             : 
     183           0 : std::shared_ptr<CWallet> GetDefaultWallet(WalletContext& context, size_t& count)
     184             : {
     185           0 :     LOCK(context.wallets_mutex);
     186           0 :     count = context.wallets.size();
     187           0 :     return count == 1 ? context.wallets[0] : nullptr;
     188           0 : }
     189             : 
     190           0 : std::shared_ptr<CWallet> GetWallet(WalletContext& context, const std::string& name)
     191             : {
     192           0 :     LOCK(context.wallets_mutex);
     193           0 :     for (const std::shared_ptr<CWallet>& wallet : context.wallets) {
     194           0 :         if (wallet->GetName() == name) return wallet;
     195             :     }
     196           0 :     return nullptr;
     197           0 : }
     198             : 
     199           0 : std::unique_ptr<interfaces::Handler> HandleLoadWallet(WalletContext& context, LoadWalletFn load_wallet)
     200             : {
     201           0 :     LOCK(context.wallets_mutex);
     202           0 :     auto it = context.wallet_load_fns.emplace(context.wallet_load_fns.end(), std::move(load_wallet));
     203           0 :     return interfaces::MakeCleanupHandler([&context, it] { LOCK(context.wallets_mutex); context.wallet_load_fns.erase(it); });
     204           0 : }
     205             : 
     206           0 : void NotifyWalletLoaded(WalletContext& context, const std::shared_ptr<CWallet>& wallet)
     207             : {
     208           0 :     LOCK(context.wallets_mutex);
     209           0 :     for (auto& load_wallet : context.wallet_load_fns) {
     210           0 :         load_wallet(interfaces::MakeWallet(context, wallet));
     211             :     }
     212           0 : }
     213             : 
     214             : static GlobalMutex g_loading_wallet_mutex;
     215             : static GlobalMutex g_wallet_release_mutex;
     216           2 : static std::condition_variable g_wallet_release_cv;
     217           2 : static std::set<std::string> g_loading_wallet_set GUARDED_BY(g_loading_wallet_mutex);
     218           2 : static std::set<std::string> g_unloading_wallet_set GUARDED_BY(g_wallet_release_mutex);
     219             : 
     220             : // Custom deleter for shared_ptr<CWallet>.
     221           0 : static void ReleaseWallet(CWallet* wallet)
     222             : {
     223           0 :     const std::string name = wallet->GetName();
     224           0 :     wallet->WalletLogPrintf("Releasing wallet\n");
     225           0 :     wallet->Flush();
     226           0 :     delete wallet;
     227             :     // Wallet is now released, notify UnloadWallet, if any.
     228             :     {
     229           0 :         LOCK(g_wallet_release_mutex);
     230           0 :         if (g_unloading_wallet_set.erase(name) == 0) {
     231             :             // UnloadWallet was not called for this wallet, all done.
     232           0 :             return;
     233             :         }
     234           0 :     }
     235           0 :     g_wallet_release_cv.notify_all();
     236           0 : }
     237             : 
     238           0 : void UnloadWallet(std::shared_ptr<CWallet>&& wallet)
     239             : {
     240             :     // Mark wallet for unloading.
     241           0 :     const std::string name = wallet->GetName();
     242             :     {
     243           0 :         LOCK(g_wallet_release_mutex);
     244           0 :         auto it = g_unloading_wallet_set.insert(name);
     245           0 :         assert(it.second);
     246           0 :     }
     247             :     // The wallet can be in use so it's not possible to explicitly unload here.
     248             :     // Notify the unload intent so that all remaining shared pointers are
     249             :     // released.
     250           0 :     wallet->NotifyUnload();
     251             : 
     252             :     // Time to ditch our shared_ptr and wait for ReleaseWallet call.
     253           0 :     wallet.reset();
     254             :     {
     255           0 :         WAIT_LOCK(g_wallet_release_mutex, lock);
     256           0 :         while (g_unloading_wallet_set.count(name) == 1) {
     257           0 :             g_wallet_release_cv.wait(lock);
     258             :         }
     259           0 :     }
     260           0 : }
     261             : 
     262             : namespace {
     263           0 : std::shared_ptr<CWallet> LoadWalletInternal(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
     264             : {
     265             :     try {
     266           0 :         std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
     267           0 :         if (!database) {
     268           0 :             error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
     269           0 :             return nullptr;
     270           2 :         }
     271             : 
     272           0 :         context.chain->initMessage(_("Loading wallet…").translated);
     273           0 :         std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), options.create_flags, error, warnings);
     274           0 :         if (!wallet) {
     275           0 :             error = Untranslated("Wallet loading failed.") + Untranslated(" ") + error;
     276           0 :             status = DatabaseStatus::FAILED_LOAD;
     277           0 :             return nullptr;
     278             :         }
     279             : 
     280             :         // Legacy wallets are being deprecated, warn if the loaded wallet is legacy
     281           0 :         if (!wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
     282           0 :             warnings.push_back(_("Wallet loaded successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future. Legacy wallets can be migrated to a descriptor wallet with migratewallet."));
     283           0 :         }
     284             : 
     285           0 :         NotifyWalletLoaded(context, wallet);
     286           0 :         AddWallet(context, wallet);
     287           0 :         wallet->postInitProcess();
     288             : 
     289             :         // Write the wallet setting
     290           0 :         UpdateWalletSetting(*context.chain, name, load_on_start, warnings);
     291             : 
     292           0 :         return wallet;
     293           0 :     } catch (const std::runtime_error& e) {
     294           0 :         error = Untranslated(e.what());
     295           0 :         status = DatabaseStatus::FAILED_LOAD;
     296           0 :         return nullptr;
     297           0 :     }
     298           0 : }
     299             : 
     300             : class FastWalletRescanFilter
     301             : {
     302             : public:
     303           0 :     FastWalletRescanFilter(const CWallet& wallet) : m_wallet(wallet)
     304             :     {
     305             :         // fast rescanning via block filters is only supported by descriptor wallets right now
     306           0 :         assert(!m_wallet.IsLegacy());
     307             : 
     308             :         // create initial filter with scripts from all ScriptPubKeyMans
     309           0 :         for (auto spkm : m_wallet.GetAllScriptPubKeyMans()) {
     310           0 :             auto desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(spkm)};
     311           0 :             assert(desc_spkm != nullptr);
     312           0 :             AddScriptPubKeys(desc_spkm);
     313             :             // save each range descriptor's end for possible future filter updates
     314           0 :             if (desc_spkm->IsHDEnabled()) {
     315           0 :                 m_last_range_ends.emplace(desc_spkm->GetID(), desc_spkm->GetEndRange());
     316           0 :             }
     317             :         }
     318           0 :     }
     319             : 
     320           0 :     void UpdateIfNeeded()
     321             :     {
     322             :         // repopulate filter with new scripts if top-up has happened since last iteration
     323           0 :         for (const auto& [desc_spkm_id, last_range_end] : m_last_range_ends) {
     324           0 :             auto desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(m_wallet.GetScriptPubKeyMan(desc_spkm_id))};
     325           0 :             assert(desc_spkm != nullptr);
     326           0 :             int32_t current_range_end{desc_spkm->GetEndRange()};
     327           0 :             if (current_range_end > last_range_end) {
     328           0 :                 AddScriptPubKeys(desc_spkm, last_range_end);
     329           0 :                 m_last_range_ends.at(desc_spkm->GetID()) = current_range_end;
     330           0 :             }
     331             :         }
     332           0 :     }
     333             : 
     334           0 :     std::optional<bool> MatchesBlock(const uint256& block_hash) const
     335             :     {
     336           0 :         return m_wallet.chain().blockFilterMatchesAny(BlockFilterType::BASIC, block_hash, m_filter_set);
     337             :     }
     338             : 
     339             : private:
     340             :     const CWallet& m_wallet;
     341             :     /** Map for keeping track of each range descriptor's last seen end range.
     342             :       * This information is used to detect whether new addresses were derived
     343             :       * (that is, if the current end range is larger than the saved end range)
     344             :       * after processing a block and hence a filter set update is needed to
     345             :       * take possible keypool top-ups into account.
     346             :       */
     347             :     std::map<uint256, int32_t> m_last_range_ends;
     348             :     GCSFilter::ElementSet m_filter_set;
     349             : 
     350           0 :     void AddScriptPubKeys(const DescriptorScriptPubKeyMan* desc_spkm, int32_t last_range_end = 0)
     351             :     {
     352           0 :         for (const auto& script_pub_key : desc_spkm->GetScriptPubKeys(last_range_end)) {
     353           0 :             m_filter_set.emplace(script_pub_key.begin(), script_pub_key.end());
     354             :         }
     355           0 :     }
     356             : };
     357             : } // namespace
     358             : 
     359           0 : std::shared_ptr<CWallet> LoadWallet(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
     360             : {
     361           0 :     auto result = WITH_LOCK(g_loading_wallet_mutex, return g_loading_wallet_set.insert(name));
     362           0 :     if (!result.second) {
     363           0 :         error = Untranslated("Wallet already loading.");
     364           0 :         status = DatabaseStatus::FAILED_LOAD;
     365           0 :         return nullptr;
     366             :     }
     367           0 :     auto wallet = LoadWalletInternal(context, name, load_on_start, options, status, error, warnings);
     368           0 :     WITH_LOCK(g_loading_wallet_mutex, g_loading_wallet_set.erase(result.first));
     369           0 :     return wallet;
     370           0 : }
     371             : 
     372           0 : std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
     373             : {
     374           0 :     uint64_t wallet_creation_flags = options.create_flags;
     375           0 :     const SecureString& passphrase = options.create_passphrase;
     376             : 
     377           0 :     if (wallet_creation_flags & WALLET_FLAG_DESCRIPTORS) options.require_format = DatabaseFormat::SQLITE;
     378             : 
     379             :     // Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted
     380           0 :     bool create_blank = (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET);
     381             : 
     382             :     // Born encrypted wallets need to be created blank first.
     383           0 :     if (!passphrase.empty()) {
     384           0 :         wallet_creation_flags |= WALLET_FLAG_BLANK_WALLET;
     385           0 :     }
     386             : 
     387             :     // Private keys must be disabled for an external signer wallet
     388           0 :     if ((wallet_creation_flags & WALLET_FLAG_EXTERNAL_SIGNER) && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
     389           0 :         error = Untranslated("Private keys must be disabled when using an external signer");
     390           0 :         status = DatabaseStatus::FAILED_CREATE;
     391           0 :         return nullptr;
     392             :     }
     393             : 
     394             :     // Descriptor support must be enabled for an external signer wallet
     395           0 :     if ((wallet_creation_flags & WALLET_FLAG_EXTERNAL_SIGNER) && !(wallet_creation_flags & WALLET_FLAG_DESCRIPTORS)) {
     396           0 :         error = Untranslated("Descriptor support must be enabled when using an external signer");
     397           0 :         status = DatabaseStatus::FAILED_CREATE;
     398           0 :         return nullptr;
     399             :     }
     400             : 
     401             :     // Do not allow a passphrase when private keys are disabled
     402           0 :     if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
     403           0 :         error = Untranslated("Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.");
     404           0 :         status = DatabaseStatus::FAILED_CREATE;
     405           0 :         return nullptr;
     406             :     }
     407             : 
     408             :     // Wallet::Verify will check if we're trying to create a wallet with a duplicate name.
     409           0 :     std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
     410           0 :     if (!database) {
     411           0 :         error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
     412           0 :         status = DatabaseStatus::FAILED_VERIFY;
     413           0 :         return nullptr;
     414             :     }
     415             : 
     416             :     // Make the wallet
     417           0 :     context.chain->initMessage(_("Loading wallet…").translated);
     418           0 :     std::shared_ptr<CWallet> wallet = CWallet::Create(context, name, std::move(database), wallet_creation_flags, error, warnings);
     419           0 :     if (!wallet) {
     420           0 :         error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error;
     421           0 :         status = DatabaseStatus::FAILED_CREATE;
     422           0 :         return nullptr;
     423             :     }
     424             : 
     425             :     // Encrypt the wallet
     426           0 :     if (!passphrase.empty() && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
     427           0 :         if (!wallet->EncryptWallet(passphrase)) {
     428           0 :             error = Untranslated("Error: Wallet created but failed to encrypt.");
     429           0 :             status = DatabaseStatus::FAILED_ENCRYPT;
     430           0 :             return nullptr;
     431             :         }
     432           0 :         if (!create_blank) {
     433             :             // Unlock the wallet
     434           0 :             if (!wallet->Unlock(passphrase)) {
     435           0 :                 error = Untranslated("Error: Wallet was encrypted but could not be unlocked");
     436           0 :                 status = DatabaseStatus::FAILED_ENCRYPT;
     437           0 :                 return nullptr;
     438             :             }
     439             : 
     440             :             // Set a seed for the wallet
     441             :             {
     442           0 :                 LOCK(wallet->cs_wallet);
     443           0 :                 if (wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
     444           0 :                     wallet->SetupDescriptorScriptPubKeyMans();
     445           0 :                 } else {
     446           0 :                     for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
     447           0 :                         if (!spk_man->SetupGeneration()) {
     448           0 :                             error = Untranslated("Unable to generate initial keys");
     449           0 :                             status = DatabaseStatus::FAILED_CREATE;
     450           0 :                             return nullptr;
     451             :                         }
     452             :                     }
     453             :                 }
     454           0 :             }
     455             : 
     456             :             // Relock the wallet
     457           0 :             wallet->Lock();
     458           0 :         }
     459           0 :     }
     460             : 
     461           0 :     NotifyWalletLoaded(context, wallet);
     462           0 :     AddWallet(context, wallet);
     463           0 :     wallet->postInitProcess();
     464             : 
     465             :     // Write the wallet settings
     466           0 :     UpdateWalletSetting(*context.chain, name, load_on_start, warnings);
     467             : 
     468             :     // Legacy wallets are being deprecated, warn if a newly created wallet is legacy
     469           0 :     if (!(wallet_creation_flags & WALLET_FLAG_DESCRIPTORS)) {
     470           0 :         warnings.push_back(_("Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future."));
     471           0 :     }
     472             : 
     473           0 :     status = DatabaseStatus::SUCCESS;
     474           0 :     return wallet;
     475           0 : }
     476             : 
     477           0 : std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& backup_file, const std::string& wallet_name, std::optional<bool> load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
     478             : {
     479           0 :     DatabaseOptions options;
     480           0 :     ReadDatabaseArgs(*context.args, options);
     481           0 :     options.require_existing = true;
     482             : 
     483           0 :     const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::u8path(wallet_name));
     484           0 :     auto wallet_file = wallet_path / "wallet.dat";
     485           0 :     std::shared_ptr<CWallet> wallet;
     486             : 
     487             :     try {
     488           0 :         if (!fs::exists(backup_file)) {
     489           0 :             error = Untranslated("Backup file does not exist");
     490           0 :             status = DatabaseStatus::FAILED_INVALID_BACKUP_FILE;
     491           0 :             return nullptr;
     492             :         }
     493             : 
     494           0 :         if (fs::exists(wallet_path) || !TryCreateDirectories(wallet_path)) {
     495           0 :             error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(wallet_path)));
     496           0 :             status = DatabaseStatus::FAILED_ALREADY_EXISTS;
     497           0 :             return nullptr;
     498             :         }
     499             : 
     500           0 :         fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
     501             : 
     502           0 :         wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
     503           0 :     } catch (const std::exception& e) {
     504           0 :         assert(!wallet);
     505           0 :         if (!error.empty()) error += Untranslated("\n");
     506           0 :         error += strprintf(Untranslated("Unexpected exception: %s"), e.what());
     507           0 :     }
     508           0 :     if (!wallet) {
     509           0 :         fs::remove_all(wallet_path);
     510           0 :     }
     511             : 
     512           0 :     return wallet;
     513           0 : }
     514             : 
     515             : /** @defgroup mapWallet
     516             :  *
     517             :  * @{
     518             :  */
     519             : 
     520           0 : const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
     521             : {
     522           0 :     AssertLockHeld(cs_wallet);
     523           0 :     const auto it = mapWallet.find(hash);
     524           0 :     if (it == mapWallet.end())
     525           0 :         return nullptr;
     526           0 :     return &(it->second);
     527           0 : }
     528             : 
     529           0 : void CWallet::UpgradeKeyMetadata()
     530             : {
     531           0 :     if (IsLocked() || IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) {
     532           0 :         return;
     533             :     }
     534             : 
     535           0 :     auto spk_man = GetLegacyScriptPubKeyMan();
     536           0 :     if (!spk_man) {
     537           0 :         return;
     538             :     }
     539             : 
     540           0 :     spk_man->UpgradeKeyMetadata();
     541           0 :     SetWalletFlag(WALLET_FLAG_KEY_ORIGIN_METADATA);
     542           0 : }
     543             : 
     544           0 : void CWallet::UpgradeDescriptorCache()
     545             : {
     546           0 :     if (!IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) || IsLocked() || IsWalletFlagSet(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED)) {
     547           0 :         return;
     548             :     }
     549             : 
     550           0 :     for (ScriptPubKeyMan* spkm : GetAllScriptPubKeyMans()) {
     551           0 :         DescriptorScriptPubKeyMan* desc_spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(spkm);
     552           0 :         desc_spkm->UpgradeDescriptorCache();
     553             :     }
     554           0 :     SetWalletFlag(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED);
     555           0 : }
     556             : 
     557           0 : bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys)
     558             : {
     559           0 :     CCrypter crypter;
     560           0 :     CKeyingMaterial _vMasterKey;
     561             : 
     562             :     {
     563           0 :         LOCK(cs_wallet);
     564           0 :         for (const MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
     565             :         {
     566           0 :             if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
     567           0 :                 return false;
     568           0 :             if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
     569           0 :                 continue; // try another master key
     570           0 :             if (Unlock(_vMasterKey, accept_no_keys)) {
     571             :                 // Now that we've unlocked, upgrade the key metadata
     572           0 :                 UpgradeKeyMetadata();
     573             :                 // Now that we've unlocked, upgrade the descriptor cache
     574           0 :                 UpgradeDescriptorCache();
     575           0 :                 return true;
     576             :             }
     577             :         }
     578           0 :     }
     579           0 :     return false;
     580           0 : }
     581             : 
     582           0 : bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
     583             : {
     584           0 :     bool fWasLocked = IsLocked();
     585             : 
     586             :     {
     587           0 :         LOCK2(m_relock_mutex, cs_wallet);
     588           0 :         Lock();
     589             : 
     590           0 :         CCrypter crypter;
     591           0 :         CKeyingMaterial _vMasterKey;
     592           0 :         for (MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
     593             :         {
     594           0 :             if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
     595           0 :                 return false;
     596           0 :             if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
     597           0 :                 return false;
     598           0 :             if (Unlock(_vMasterKey))
     599             :             {
     600           0 :                 constexpr MillisecondsDouble target{100};
     601           0 :                 auto start{SteadyClock::now()};
     602           0 :                 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
     603           0 :                 pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start));
     604             : 
     605           0 :                 start = SteadyClock::now();
     606           0 :                 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
     607           0 :                 pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
     608             : 
     609           0 :                 if (pMasterKey.second.nDeriveIterations < 25000)
     610           0 :                     pMasterKey.second.nDeriveIterations = 25000;
     611             : 
     612           0 :                 WalletLogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
     613             : 
     614           0 :                 if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
     615           0 :                     return false;
     616           0 :                 if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey))
     617           0 :                     return false;
     618           0 :                 WalletBatch(GetDatabase()).WriteMasterKey(pMasterKey.first, pMasterKey.second);
     619           0 :                 if (fWasLocked)
     620           0 :                     Lock();
     621           0 :                 return true;
     622             :             }
     623             :         }
     624           0 :     }
     625             : 
     626           0 :     return false;
     627           0 : }
     628             : 
     629           0 : void CWallet::chainStateFlushed(const CBlockLocator& loc)
     630             : {
     631             :     // Don't update the best block until the chain is attached so that in case of a shutdown,
     632             :     // the rescan will be restarted at next startup.
     633           0 :     if (m_attaching_chain) {
     634           0 :         return;
     635             :     }
     636           0 :     WalletBatch batch(GetDatabase());
     637           0 :     batch.WriteBestBlock(loc);
     638           0 : }
     639             : 
     640           0 : void CWallet::SetMinVersion(enum WalletFeature nVersion, WalletBatch* batch_in)
     641             : {
     642           0 :     LOCK(cs_wallet);
     643           0 :     if (nWalletVersion >= nVersion)
     644           0 :         return;
     645           0 :     WalletLogPrintf("Setting minversion to %d\n", nVersion);
     646           0 :     nWalletVersion = nVersion;
     647             : 
     648             :     {
     649           0 :         WalletBatch* batch = batch_in ? batch_in : new WalletBatch(GetDatabase());
     650           0 :         if (nWalletVersion > 40000)
     651           0 :             batch->WriteMinVersion(nWalletVersion);
     652           0 :         if (!batch_in)
     653           0 :             delete batch;
     654             :     }
     655           0 : }
     656             : 
     657           0 : std::set<uint256> CWallet::GetConflicts(const uint256& txid) const
     658             : {
     659           0 :     std::set<uint256> result;
     660           0 :     AssertLockHeld(cs_wallet);
     661             : 
     662           0 :     const auto it = mapWallet.find(txid);
     663           0 :     if (it == mapWallet.end())
     664           0 :         return result;
     665           0 :     const CWalletTx& wtx = it->second;
     666             : 
     667           0 :     std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
     668             : 
     669           0 :     for (const CTxIn& txin : wtx.tx->vin)
     670             :     {
     671           0 :         if (mapTxSpends.count(txin.prevout) <= 1)
     672           0 :             continue;  // No conflict if zero or one spends
     673           0 :         range = mapTxSpends.equal_range(txin.prevout);
     674           0 :         for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
     675           0 :             result.insert(_it->second);
     676             :     }
     677           0 :     return result;
     678           0 : }
     679             : 
     680           0 : bool CWallet::HasWalletSpend(const CTransactionRef& tx) const
     681             : {
     682           0 :     AssertLockHeld(cs_wallet);
     683           0 :     const uint256& txid = tx->GetHash();
     684           0 :     for (unsigned int i = 0; i < tx->vout.size(); ++i) {
     685           0 :         if (IsSpent(COutPoint(txid, i))) {
     686           0 :             return true;
     687             :         }
     688           0 :     }
     689           0 :     return false;
     690           0 : }
     691             : 
     692           0 : void CWallet::Flush()
     693             : {
     694           0 :     GetDatabase().Flush();
     695           0 : }
     696             : 
     697           0 : void CWallet::Close()
     698             : {
     699           0 :     GetDatabase().Close();
     700           0 : }
     701             : 
     702           0 : void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> range)
     703             : {
     704             :     // We want all the wallet transactions in range to have the same metadata as
     705             :     // the oldest (smallest nOrderPos).
     706             :     // So: find smallest nOrderPos:
     707             : 
     708           0 :     int nMinOrderPos = std::numeric_limits<int>::max();
     709           0 :     const CWalletTx* copyFrom = nullptr;
     710           0 :     for (TxSpends::iterator it = range.first; it != range.second; ++it) {
     711           0 :         const CWalletTx* wtx = &mapWallet.at(it->second);
     712           0 :         if (wtx->nOrderPos < nMinOrderPos) {
     713           0 :             nMinOrderPos = wtx->nOrderPos;
     714           0 :             copyFrom = wtx;
     715           0 :         }
     716           0 :     }
     717             : 
     718           0 :     if (!copyFrom) {
     719           0 :         return;
     720             :     }
     721             : 
     722             :     // Now copy data from copyFrom to rest:
     723           0 :     for (TxSpends::iterator it = range.first; it != range.second; ++it)
     724             :     {
     725           0 :         const uint256& hash = it->second;
     726           0 :         CWalletTx* copyTo = &mapWallet.at(hash);
     727           0 :         if (copyFrom == copyTo) continue;
     728           0 :         assert(copyFrom && "Oldest wallet transaction in range assumed to have been found.");
     729           0 :         if (!copyFrom->IsEquivalentTo(*copyTo)) continue;
     730           0 :         copyTo->mapValue = copyFrom->mapValue;
     731           0 :         copyTo->vOrderForm = copyFrom->vOrderForm;
     732             :         // fTimeReceivedIsTxTime not copied on purpose
     733             :         // nTimeReceived not copied on purpose
     734           0 :         copyTo->nTimeSmart = copyFrom->nTimeSmart;
     735           0 :         copyTo->fFromMe = copyFrom->fFromMe;
     736             :         // nOrderPos not copied on purpose
     737             :         // cached members not copied on purpose
     738           0 :     }
     739           0 : }
     740             : 
     741             : /**
     742             :  * Outpoint is spent if any non-conflicted transaction
     743             :  * spends it:
     744             :  */
     745           0 : bool CWallet::IsSpent(const COutPoint& outpoint) const
     746             : {
     747           0 :     std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
     748           0 :     range = mapTxSpends.equal_range(outpoint);
     749             : 
     750           0 :     for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
     751           0 :         const uint256& wtxid = it->second;
     752           0 :         const auto mit = mapWallet.find(wtxid);
     753           0 :         if (mit != mapWallet.end()) {
     754           0 :             int depth = GetTxDepthInMainChain(mit->second);
     755           0 :             if (depth > 0  || (depth == 0 && !mit->second.isAbandoned()))
     756           0 :                 return true; // Spent
     757           0 :         }
     758           0 :     }
     759           0 :     return false;
     760           0 : }
     761             : 
     762           0 : void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid, WalletBatch* batch)
     763             : {
     764           0 :     mapTxSpends.insert(std::make_pair(outpoint, wtxid));
     765             : 
     766           0 :     if (batch) {
     767           0 :         UnlockCoin(outpoint, batch);
     768           0 :     } else {
     769           0 :         WalletBatch temp_batch(GetDatabase());
     770           0 :         UnlockCoin(outpoint, &temp_batch);
     771           0 :     }
     772             : 
     773           0 :     std::pair<TxSpends::iterator, TxSpends::iterator> range;
     774           0 :     range = mapTxSpends.equal_range(outpoint);
     775           0 :     SyncMetaData(range);
     776           0 : }
     777             : 
     778             : 
     779           0 : void CWallet::AddToSpends(const CWalletTx& wtx, WalletBatch* batch)
     780             : {
     781           0 :     if (wtx.IsCoinBase()) // Coinbases don't spend anything!
     782           0 :         return;
     783             : 
     784           0 :     for (const CTxIn& txin : wtx.tx->vin)
     785           0 :         AddToSpends(txin.prevout, wtx.GetHash(), batch);
     786           0 : }
     787             : 
     788           0 : bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
     789             : {
     790           0 :     if (IsCrypted())
     791           0 :         return false;
     792             : 
     793           0 :     CKeyingMaterial _vMasterKey;
     794             : 
     795           0 :     _vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
     796           0 :     GetStrongRandBytes(_vMasterKey);
     797             : 
     798           0 :     CMasterKey kMasterKey;
     799             : 
     800           0 :     kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
     801           0 :     GetStrongRandBytes(kMasterKey.vchSalt);
     802             : 
     803           0 :     CCrypter crypter;
     804           0 :     constexpr MillisecondsDouble target{100};
     805           0 :     auto start{SteadyClock::now()};
     806           0 :     crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
     807           0 :     kMasterKey.nDeriveIterations = static_cast<unsigned int>(25000 * target / (SteadyClock::now() - start));
     808             : 
     809           0 :     start = SteadyClock::now();
     810           0 :     crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
     811           0 :     kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
     812             : 
     813           0 :     if (kMasterKey.nDeriveIterations < 25000)
     814           0 :         kMasterKey.nDeriveIterations = 25000;
     815             : 
     816           0 :     WalletLogPrintf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
     817             : 
     818           0 :     if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
     819           0 :         return false;
     820           0 :     if (!crypter.Encrypt(_vMasterKey, kMasterKey.vchCryptedKey))
     821           0 :         return false;
     822             : 
     823             :     {
     824           0 :         LOCK2(m_relock_mutex, cs_wallet);
     825           0 :         mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
     826           0 :         WalletBatch* encrypted_batch = new WalletBatch(GetDatabase());
     827           0 :         if (!encrypted_batch->TxnBegin()) {
     828           0 :             delete encrypted_batch;
     829           0 :             encrypted_batch = nullptr;
     830           0 :             return false;
     831             :         }
     832           0 :         encrypted_batch->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
     833             : 
     834           0 :         for (const auto& spk_man_pair : m_spk_managers) {
     835           0 :             auto spk_man = spk_man_pair.second.get();
     836           0 :             if (!spk_man->Encrypt(_vMasterKey, encrypted_batch)) {
     837           0 :                 encrypted_batch->TxnAbort();
     838           0 :                 delete encrypted_batch;
     839           0 :                 encrypted_batch = nullptr;
     840             :                 // We now probably have half of our keys encrypted in memory, and half not...
     841             :                 // die and let the user reload the unencrypted wallet.
     842           0 :                 assert(false);
     843             :             }
     844             :         }
     845             : 
     846             :         // Encryption was introduced in version 0.4.0
     847           0 :         SetMinVersion(FEATURE_WALLETCRYPT, encrypted_batch);
     848             : 
     849           0 :         if (!encrypted_batch->TxnCommit()) {
     850           0 :             delete encrypted_batch;
     851           0 :             encrypted_batch = nullptr;
     852             :             // We now have keys encrypted in memory, but not on disk...
     853             :             // die to avoid confusion and let the user reload the unencrypted wallet.
     854           0 :             assert(false);
     855             :         }
     856             : 
     857           0 :         delete encrypted_batch;
     858           0 :         encrypted_batch = nullptr;
     859             : 
     860           0 :         Lock();
     861           0 :         Unlock(strWalletPassphrase);
     862             : 
     863             :         // If we are using descriptors, make new descriptors with a new seed
     864           0 :         if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) && !IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET)) {
     865           0 :             SetupDescriptorScriptPubKeyMans();
     866           0 :         } else if (auto spk_man = GetLegacyScriptPubKeyMan()) {
     867             :             // if we are using HD, replace the HD seed with a new one
     868           0 :             if (spk_man->IsHDEnabled()) {
     869           0 :                 if (!spk_man->SetupGeneration(true)) {
     870           0 :                     return false;
     871             :                 }
     872           0 :             }
     873           0 :         }
     874           0 :         Lock();
     875             : 
     876             :         // Need to completely rewrite the wallet file; if we don't, bdb might keep
     877             :         // bits of the unencrypted private key in slack space in the database file.
     878           0 :         GetDatabase().Rewrite();
     879             : 
     880             :         // BDB seems to have a bad habit of writing old data into
     881             :         // slack space in .dat files; that is bad if the old data is
     882             :         // unencrypted private keys. So:
     883           0 :         GetDatabase().ReloadDbEnv();
     884             : 
     885           0 :     }
     886           0 :     NotifyStatusChanged(this);
     887             : 
     888           0 :     return true;
     889           0 : }
     890             : 
     891           0 : DBErrors CWallet::ReorderTransactions()
     892             : {
     893           0 :     LOCK(cs_wallet);
     894           0 :     WalletBatch batch(GetDatabase());
     895             : 
     896             :     // Old wallets didn't have any defined order for transactions
     897             :     // Probably a bad idea to change the output of this
     898             : 
     899             :     // First: get all CWalletTx into a sorted-by-time multimap.
     900             :     typedef std::multimap<int64_t, CWalletTx*> TxItems;
     901           0 :     TxItems txByTime;
     902             : 
     903           0 :     for (auto& entry : mapWallet)
     904             :     {
     905           0 :         CWalletTx* wtx = &entry.second;
     906           0 :         txByTime.insert(std::make_pair(wtx->nTimeReceived, wtx));
     907             :     }
     908             : 
     909           0 :     nOrderPosNext = 0;
     910           0 :     std::vector<int64_t> nOrderPosOffsets;
     911           0 :     for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
     912             :     {
     913           0 :         CWalletTx *const pwtx = (*it).second;
     914           0 :         int64_t& nOrderPos = pwtx->nOrderPos;
     915             : 
     916           0 :         if (nOrderPos == -1)
     917             :         {
     918           0 :             nOrderPos = nOrderPosNext++;
     919           0 :             nOrderPosOffsets.push_back(nOrderPos);
     920             : 
     921           0 :             if (!batch.WriteTx(*pwtx))
     922           0 :                 return DBErrors::LOAD_FAIL;
     923           0 :         }
     924             :         else
     925             :         {
     926           0 :             int64_t nOrderPosOff = 0;
     927           0 :             for (const int64_t& nOffsetStart : nOrderPosOffsets)
     928             :             {
     929           0 :                 if (nOrderPos >= nOffsetStart)
     930           0 :                     ++nOrderPosOff;
     931             :             }
     932           0 :             nOrderPos += nOrderPosOff;
     933           0 :             nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
     934             : 
     935           0 :             if (!nOrderPosOff)
     936           0 :                 continue;
     937             : 
     938             :             // Since we're changing the order, write it back
     939           0 :             if (!batch.WriteTx(*pwtx))
     940           0 :                 return DBErrors::LOAD_FAIL;
     941             :         }
     942           0 :     }
     943           0 :     batch.WriteOrderPosNext(nOrderPosNext);
     944             : 
     945           0 :     return DBErrors::LOAD_OK;
     946           0 : }
     947             : 
     948           0 : int64_t CWallet::IncOrderPosNext(WalletBatch* batch)
     949             : {
     950           0 :     AssertLockHeld(cs_wallet);
     951           0 :     int64_t nRet = nOrderPosNext++;
     952           0 :     if (batch) {
     953           0 :         batch->WriteOrderPosNext(nOrderPosNext);
     954           0 :     } else {
     955           0 :         WalletBatch(GetDatabase()).WriteOrderPosNext(nOrderPosNext);
     956             :     }
     957           0 :     return nRet;
     958           0 : }
     959             : 
     960           0 : void CWallet::MarkDirty()
     961             : {
     962             :     {
     963           0 :         LOCK(cs_wallet);
     964           0 :         for (std::pair<const uint256, CWalletTx>& item : mapWallet)
     965           0 :             item.second.MarkDirty();
     966           0 :     }
     967           0 : }
     968             : 
     969           0 : bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
     970             : {
     971           0 :     LOCK(cs_wallet);
     972             : 
     973           0 :     auto mi = mapWallet.find(originalHash);
     974             : 
     975             :     // There is a bug if MarkReplaced is not called on an existing wallet transaction.
     976           0 :     assert(mi != mapWallet.end());
     977             : 
     978           0 :     CWalletTx& wtx = (*mi).second;
     979             : 
     980             :     // Ensure for now that we're not overwriting data
     981           0 :     assert(wtx.mapValue.count("replaced_by_txid") == 0);
     982             : 
     983           0 :     wtx.mapValue["replaced_by_txid"] = newHash.ToString();
     984             : 
     985             :     // Refresh mempool status without waiting for transactionRemovedFromMempool or transactionAddedToMempool
     986           0 :     RefreshMempoolStatus(wtx, chain());
     987             : 
     988           0 :     WalletBatch batch(GetDatabase());
     989             : 
     990           0 :     bool success = true;
     991           0 :     if (!batch.WriteTx(wtx)) {
     992           0 :         WalletLogPrintf("%s: Updating batch tx %s failed\n", __func__, wtx.GetHash().ToString());
     993           0 :         success = false;
     994           0 :     }
     995             : 
     996           0 :     NotifyTransactionChanged(originalHash, CT_UPDATED);
     997             : 
     998           0 :     return success;
     999           0 : }
    1000             : 
    1001           0 : void CWallet::SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations)
    1002             : {
    1003           0 :     AssertLockHeld(cs_wallet);
    1004           0 :     const CWalletTx* srctx = GetWalletTx(hash);
    1005           0 :     if (!srctx) return;
    1006             : 
    1007           0 :     CTxDestination dst;
    1008           0 :     if (ExtractDestination(srctx->tx->vout[n].scriptPubKey, dst)) {
    1009           0 :         if (IsMine(dst)) {
    1010           0 :             if (used != IsAddressPreviouslySpent(dst)) {
    1011           0 :                 if (used) {
    1012           0 :                     tx_destinations.insert(dst);
    1013           0 :                 }
    1014           0 :                 SetAddressPreviouslySpent(batch, dst, used);
    1015           0 :             }
    1016           0 :         }
    1017           0 :     }
    1018           0 : }
    1019             : 
    1020           0 : bool CWallet::IsSpentKey(const CScript& scriptPubKey) const
    1021             : {
    1022           0 :     AssertLockHeld(cs_wallet);
    1023           0 :     CTxDestination dest;
    1024           0 :     if (!ExtractDestination(scriptPubKey, dest)) {
    1025           0 :         return false;
    1026             :     }
    1027           0 :     if (IsAddressPreviouslySpent(dest)) {
    1028           0 :         return true;
    1029             :     }
    1030           0 :     if (IsLegacy()) {
    1031           0 :         LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan();
    1032           0 :         assert(spk_man != nullptr);
    1033           0 :         for (const auto& keyid : GetAffectedKeys(scriptPubKey, *spk_man)) {
    1034           0 :             WitnessV0KeyHash wpkh_dest(keyid);
    1035           0 :             if (IsAddressPreviouslySpent(wpkh_dest)) {
    1036           0 :                 return true;
    1037             :             }
    1038           0 :             ScriptHash sh_wpkh_dest(GetScriptForDestination(wpkh_dest));
    1039           0 :             if (IsAddressPreviouslySpent(sh_wpkh_dest)) {
    1040           0 :                 return true;
    1041             :             }
    1042           0 :             PKHash pkh_dest(keyid);
    1043           0 :             if (IsAddressPreviouslySpent(pkh_dest)) {
    1044           0 :                 return true;
    1045             :             }
    1046             :         }
    1047           0 :     }
    1048           0 :     return false;
    1049           0 : }
    1050             : 
    1051           0 : CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const UpdateWalletTxFn& update_wtx, bool fFlushOnClose, bool rescanning_old_block)
    1052             : {
    1053           0 :     LOCK(cs_wallet);
    1054             : 
    1055           0 :     WalletBatch batch(GetDatabase(), fFlushOnClose);
    1056             : 
    1057           0 :     uint256 hash = tx->GetHash();
    1058             : 
    1059           0 :     if (IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
    1060             :         // Mark used destinations
    1061           0 :         std::set<CTxDestination> tx_destinations;
    1062             : 
    1063           0 :         for (const CTxIn& txin : tx->vin) {
    1064           0 :             const COutPoint& op = txin.prevout;
    1065           0 :             SetSpentKeyState(batch, op.hash, op.n, true, tx_destinations);
    1066             :         }
    1067             : 
    1068           0 :         MarkDestinationsDirty(tx_destinations);
    1069           0 :     }
    1070             : 
    1071             :     // Inserts only if not already there, returns tx inserted or tx found
    1072           0 :     auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(tx, state));
    1073           0 :     CWalletTx& wtx = (*ret.first).second;
    1074           0 :     bool fInsertedNew = ret.second;
    1075           0 :     bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
    1076           0 :     if (fInsertedNew) {
    1077           0 :         wtx.nTimeReceived = GetTime();
    1078           0 :         wtx.nOrderPos = IncOrderPosNext(&batch);
    1079           0 :         wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
    1080           0 :         wtx.nTimeSmart = ComputeTimeSmart(wtx, rescanning_old_block);
    1081           0 :         AddToSpends(wtx, &batch);
    1082           0 :     }
    1083             : 
    1084           0 :     if (!fInsertedNew)
    1085             :     {
    1086           0 :         if (state.index() != wtx.m_state.index()) {
    1087           0 :             wtx.m_state = state;
    1088           0 :             fUpdated = true;
    1089           0 :         } else {
    1090           0 :             assert(TxStateSerializedIndex(wtx.m_state) == TxStateSerializedIndex(state));
    1091           0 :             assert(TxStateSerializedBlockHash(wtx.m_state) == TxStateSerializedBlockHash(state));
    1092             :         }
    1093             :         // If we have a witness-stripped version of this transaction, and we
    1094             :         // see a new version with a witness, then we must be upgrading a pre-segwit
    1095             :         // wallet.  Store the new version of the transaction with the witness,
    1096             :         // as the stripped-version must be invalid.
    1097             :         // TODO: Store all versions of the transaction, instead of just one.
    1098           0 :         if (tx->HasWitness() && !wtx.tx->HasWitness()) {
    1099           0 :             wtx.SetTx(tx);
    1100           0 :             fUpdated = true;
    1101           0 :         }
    1102           0 :     }
    1103             : 
    1104             :     // Mark inactive coinbase transactions and their descendants as abandoned
    1105           0 :     if (wtx.IsCoinBase() && wtx.isInactive()) {
    1106           0 :         std::vector<CWalletTx*> txs{&wtx};
    1107             : 
    1108           0 :         TxStateInactive inactive_state = TxStateInactive{/*abandoned=*/true};
    1109             : 
    1110           0 :         while (!txs.empty()) {
    1111           0 :             CWalletTx* desc_tx = txs.back();
    1112           0 :             txs.pop_back();
    1113           0 :             desc_tx->m_state = inactive_state;
    1114             :             // Break caches since we have changed the state
    1115           0 :             desc_tx->MarkDirty();
    1116           0 :             batch.WriteTx(*desc_tx);
    1117           0 :             MarkInputsDirty(desc_tx->tx);
    1118           0 :             for (unsigned int i = 0; i < desc_tx->tx->vout.size(); ++i) {
    1119           0 :                 COutPoint outpoint(desc_tx->GetHash(), i);
    1120           0 :                 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(outpoint);
    1121           0 :                 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
    1122           0 :                     const auto wit = mapWallet.find(it->second);
    1123           0 :                     if (wit != mapWallet.end()) {
    1124           0 :                         txs.push_back(&wit->second);
    1125           0 :                     }
    1126           0 :                 }
    1127           0 :             }
    1128             :         }
    1129           0 :     }
    1130             : 
    1131             :     //// debug print
    1132           0 :     WalletLogPrintf("AddToWallet %s  %s%s\n", hash.ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
    1133             : 
    1134             :     // Write to disk
    1135           0 :     if (fInsertedNew || fUpdated)
    1136           0 :         if (!batch.WriteTx(wtx))
    1137           0 :             return nullptr;
    1138             : 
    1139             :     // Break debit/credit balance caches:
    1140           0 :     wtx.MarkDirty();
    1141             : 
    1142             :     // Notify UI of new or updated transaction
    1143           0 :     NotifyTransactionChanged(hash, fInsertedNew ? CT_NEW : CT_UPDATED);
    1144             : 
    1145             : #if HAVE_SYSTEM
    1146             :     // notify an external script when a wallet transaction comes in or is updated
    1147           0 :     std::string strCmd = m_notify_tx_changed_script;
    1148             : 
    1149           0 :     if (!strCmd.empty())
    1150             :     {
    1151           0 :         ReplaceAll(strCmd, "%s", hash.GetHex());
    1152           0 :         if (auto* conf = wtx.state<TxStateConfirmed>())
    1153             :         {
    1154           0 :             ReplaceAll(strCmd, "%b", conf->confirmed_block_hash.GetHex());
    1155           0 :             ReplaceAll(strCmd, "%h", ToString(conf->confirmed_block_height));
    1156           0 :         } else {
    1157           0 :             ReplaceAll(strCmd, "%b", "unconfirmed");
    1158           0 :             ReplaceAll(strCmd, "%h", "-1");
    1159             :         }
    1160             : #ifndef WIN32
    1161             :         // Substituting the wallet name isn't currently supported on windows
    1162             :         // because windows shell escaping has not been implemented yet:
    1163             :         // https://github.com/bitcoin/bitcoin/pull/13339#issuecomment-537384875
    1164             :         // A few ways it could be implemented in the future are described in:
    1165             :         // https://github.com/bitcoin/bitcoin/pull/13339#issuecomment-461288094
    1166           0 :         ReplaceAll(strCmd, "%w", ShellEscape(GetName()));
    1167             : #endif
    1168           0 :         std::thread t(runCommand, strCmd);
    1169           0 :         t.detach(); // thread runs free
    1170           0 :     }
    1171             : #endif
    1172             : 
    1173           0 :     return &wtx;
    1174           0 : }
    1175             : 
    1176           0 : bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx)
    1177             : {
    1178           0 :     const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(nullptr, TxStateInactive{}));
    1179           0 :     CWalletTx& wtx = ins.first->second;
    1180           0 :     if (!fill_wtx(wtx, ins.second)) {
    1181           0 :         return false;
    1182             :     }
    1183             :     // If wallet doesn't have a chain (e.g when using bitcoin-wallet tool),
    1184             :     // don't bother to update txn.
    1185           0 :     if (HaveChain()) {
    1186             :         bool active;
    1187           0 :         auto lookup_block = [&](const uint256& hash, int& height, TxState& state) {
    1188             :             // If tx block (or conflicting block) was reorged out of chain
    1189             :             // while the wallet was shutdown, change tx status to UNCONFIRMED
    1190             :             // and reset block height, hash, and index. ABANDONED tx don't have
    1191             :             // associated blocks and don't need to be updated. The case where a
    1192             :             // transaction was reorged out while online and then reconfirmed
    1193             :             // while offline is covered by the rescan logic.
    1194           0 :             if (!chain().findBlock(hash, FoundBlock().inActiveChain(active).height(height)) || !active) {
    1195           0 :                 state = TxStateInactive{};
    1196           0 :             }
    1197           0 :         };
    1198           0 :         if (auto* conf = wtx.state<TxStateConfirmed>()) {
    1199           0 :             lookup_block(conf->confirmed_block_hash, conf->confirmed_block_height, wtx.m_state);
    1200           0 :         } else if (auto* conf = wtx.state<TxStateConflicted>()) {
    1201           0 :             lookup_block(conf->conflicting_block_hash, conf->conflicting_block_height, wtx.m_state);
    1202           0 :         }
    1203           0 :     }
    1204           0 :     if (/* insertion took place */ ins.second) {
    1205           0 :         wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
    1206           0 :     }
    1207           0 :     AddToSpends(wtx);
    1208           0 :     for (const CTxIn& txin : wtx.tx->vin) {
    1209           0 :         auto it = mapWallet.find(txin.prevout.hash);
    1210           0 :         if (it != mapWallet.end()) {
    1211           0 :             CWalletTx& prevtx = it->second;
    1212           0 :             if (auto* prev = prevtx.state<TxStateConflicted>()) {
    1213           0 :                 MarkConflicted(prev->conflicting_block_hash, prev->conflicting_block_height, wtx.GetHash());
    1214           0 :             }
    1215           0 :         }
    1216             :     }
    1217           0 :     return true;
    1218           0 : }
    1219             : 
    1220           0 : bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxState& state, bool fUpdate, bool rescanning_old_block)
    1221             : {
    1222           0 :     const CTransaction& tx = *ptx;
    1223             :     {
    1224           0 :         AssertLockHeld(cs_wallet);
    1225             : 
    1226           0 :         if (auto* conf = std::get_if<TxStateConfirmed>(&state)) {
    1227           0 :             for (const CTxIn& txin : tx.vin) {
    1228           0 :                 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
    1229           0 :                 while (range.first != range.second) {
    1230           0 :                     if (range.first->second != tx.GetHash()) {
    1231           0 :                         WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), conf->confirmed_block_hash.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
    1232           0 :                         MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
    1233           0 :                     }
    1234           0 :                     range.first++;
    1235             :                 }
    1236             :             }
    1237           0 :         }
    1238             : 
    1239           0 :         bool fExisted = mapWallet.count(tx.GetHash()) != 0;
    1240           0 :         if (fExisted && !fUpdate) return false;
    1241           0 :         if (fExisted || IsMine(tx) || IsFromMe(tx))
    1242             :         {
    1243             :             /* Check if any keys in the wallet keypool that were supposed to be unused
    1244             :              * have appeared in a new transaction. If so, remove those keys from the keypool.
    1245             :              * This can happen when restoring an old wallet backup that does not contain
    1246             :              * the mostly recently created transactions from newer versions of the wallet.
    1247             :              */
    1248             : 
    1249             :             // loop though all outputs
    1250           0 :             for (const CTxOut& txout: tx.vout) {
    1251           0 :                 for (const auto& spk_man : GetScriptPubKeyMans(txout.scriptPubKey)) {
    1252           0 :                     for (auto &dest : spk_man->MarkUnusedAddresses(txout.scriptPubKey)) {
    1253             :                         // If internal flag is not defined try to infer it from the ScriptPubKeyMan
    1254           0 :                         if (!dest.internal.has_value()) {
    1255           0 :                             dest.internal = IsInternalScriptPubKeyMan(spk_man);
    1256           0 :                         }
    1257             : 
    1258             :                         // skip if can't determine whether it's a receiving address or not
    1259           0 :                         if (!dest.internal.has_value()) continue;
    1260             : 
    1261             :                         // If this is a receiving address and it's not in the address book yet
    1262             :                         // (e.g. it wasn't generated on this node or we're restoring from backup)
    1263             :                         // add it to the address book for proper transaction accounting
    1264           0 :                         if (!*dest.internal && !FindAddressBookEntry(dest.dest, /* allow_change= */ false)) {
    1265           0 :                             SetAddressBook(dest.dest, "", AddressPurpose::RECEIVE);
    1266           0 :                         }
    1267             :                     }
    1268             :                 }
    1269             :             }
    1270             : 
    1271             :             // Block disconnection override an abandoned tx as unconfirmed
    1272             :             // which means user may have to call abandontransaction again
    1273           0 :             TxState tx_state = std::visit([](auto&& s) -> TxState { return s; }, state);
    1274           0 :             CWalletTx* wtx = AddToWallet(MakeTransactionRef(tx), tx_state, /*update_wtx=*/nullptr, /*fFlushOnClose=*/false, rescanning_old_block);
    1275           0 :             if (!wtx) {
    1276             :                 // Can only be nullptr if there was a db write error (missing db, read-only db or a db engine internal writing error).
    1277             :                 // As we only store arriving transaction in this process, and we don't want an inconsistent state, let's throw an error.
    1278           0 :                 throw std::runtime_error("DB error adding transaction to wallet, write failed");
    1279             :             }
    1280           0 :             return true;
    1281             :         }
    1282             :     }
    1283           0 :     return false;
    1284           0 : }
    1285             : 
    1286           0 : bool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const
    1287             : {
    1288           0 :     LOCK(cs_wallet);
    1289           0 :     const CWalletTx* wtx = GetWalletTx(hashTx);
    1290           0 :     return wtx && !wtx->isAbandoned() && GetTxDepthInMainChain(*wtx) == 0 && !wtx->InMempool();
    1291           0 : }
    1292             : 
    1293           0 : void CWallet::MarkInputsDirty(const CTransactionRef& tx)
    1294             : {
    1295           0 :     for (const CTxIn& txin : tx->vin) {
    1296           0 :         auto it = mapWallet.find(txin.prevout.hash);
    1297           0 :         if (it != mapWallet.end()) {
    1298           0 :             it->second.MarkDirty();
    1299           0 :         }
    1300             :     }
    1301           0 : }
    1302             : 
    1303           0 : bool CWallet::AbandonTransaction(const uint256& hashTx)
    1304             : {
    1305           0 :     LOCK(cs_wallet);
    1306             : 
    1307             :     // Can't mark abandoned if confirmed or in mempool
    1308           0 :     auto it = mapWallet.find(hashTx);
    1309           0 :     assert(it != mapWallet.end());
    1310           0 :     const CWalletTx& origtx = it->second;
    1311           0 :     if (GetTxDepthInMainChain(origtx) != 0 || origtx.InMempool()) {
    1312           0 :         return false;
    1313             :     }
    1314             : 
    1315           0 :     auto try_updating_state = [](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
    1316             :         // If the orig tx was not in block/mempool, none of its spends can be.
    1317           0 :         assert(!wtx.isConfirmed());
    1318           0 :         assert(!wtx.InMempool());
    1319             :         // If already conflicted or abandoned, no need to set abandoned
    1320           0 :         if (!wtx.isConflicted() && !wtx.isAbandoned()) {
    1321           0 :             wtx.m_state = TxStateInactive{/*abandoned=*/true};
    1322           0 :             return TxUpdate::NOTIFY_CHANGED;
    1323             :         }
    1324           0 :         return TxUpdate::UNCHANGED;
    1325           0 :     };
    1326             : 
    1327             :     // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too.
    1328             :     // States are not permanent, so these transactions can become unabandoned if they are re-added to the
    1329             :     // mempool, or confirmed in a block, or conflicted.
    1330             :     // Note: If the reorged coinbase is re-added to the main chain, the descendants that have not had their
    1331             :     // states change will remain abandoned and will require manual broadcast if the user wants them.
    1332             : 
    1333           0 :     RecursiveUpdateTxState(hashTx, try_updating_state);
    1334             : 
    1335           0 :     return true;
    1336           0 : }
    1337             : 
    1338           0 : void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, const uint256& hashTx)
    1339             : {
    1340           0 :     LOCK(cs_wallet);
    1341             : 
    1342           0 :     int conflictconfirms = (m_last_block_processed_height - conflicting_height + 1) * -1;
    1343             :     // If number of conflict confirms cannot be determined, this means
    1344             :     // that the block is still unknown or not yet part of the main chain,
    1345             :     // for example when loading the wallet during a reindex. Do nothing in that
    1346             :     // case.
    1347           0 :     if (conflictconfirms >= 0)
    1348           0 :         return;
    1349             : 
    1350           0 :     auto try_updating_state = [&](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
    1351           0 :         if (conflictconfirms < GetTxDepthInMainChain(wtx)) {
    1352             :             // Block is 'more conflicted' than current confirm; update.
    1353             :             // Mark transaction as conflicted with this block.
    1354           0 :             wtx.m_state = TxStateConflicted{hashBlock, conflicting_height};
    1355           0 :             return TxUpdate::CHANGED;
    1356             :         }
    1357           0 :         return TxUpdate::UNCHANGED;
    1358           0 :     };
    1359             : 
    1360             :     // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too.
    1361           0 :     RecursiveUpdateTxState(hashTx, try_updating_state);
    1362             : 
    1363           0 : }
    1364             : 
    1365           0 : void CWallet::RecursiveUpdateTxState(const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
    1366             :     // Do not flush the wallet here for performance reasons
    1367           0 :     WalletBatch batch(GetDatabase(), false);
    1368             : 
    1369           0 :     std::set<uint256> todo;
    1370           0 :     std::set<uint256> done;
    1371             : 
    1372           0 :     todo.insert(tx_hash);
    1373             : 
    1374           0 :     while (!todo.empty()) {
    1375           0 :         uint256 now = *todo.begin();
    1376           0 :         todo.erase(now);
    1377           0 :         done.insert(now);
    1378           0 :         auto it = mapWallet.find(now);
    1379           0 :         assert(it != mapWallet.end());
    1380           0 :         CWalletTx& wtx = it->second;
    1381             : 
    1382           0 :         TxUpdate update_state = try_updating_state(wtx);
    1383           0 :         if (update_state != TxUpdate::UNCHANGED) {
    1384           0 :             wtx.MarkDirty();
    1385           0 :             batch.WriteTx(wtx);
    1386             :             // Iterate over all its outputs, and update those tx states as well (if applicable)
    1387           0 :             for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
    1388           0 :                 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(COutPoint(now, i));
    1389           0 :                 for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
    1390           0 :                     if (!done.count(iter->second)) {
    1391           0 :                         todo.insert(iter->second);
    1392           0 :                     }
    1393           0 :                 }
    1394           0 :             }
    1395             : 
    1396           0 :             if (update_state == TxUpdate::NOTIFY_CHANGED) {
    1397           0 :                 NotifyTransactionChanged(wtx.GetHash(), CT_UPDATED);
    1398           0 :             }
    1399             : 
    1400             :             // If a transaction changes its tx state, that usually changes the balance
    1401             :             // available of the outputs it spends. So force those to be recomputed
    1402           0 :             MarkInputsDirty(wtx.tx);
    1403           0 :         }
    1404             :     }
    1405           0 : }
    1406             : 
    1407           0 : void CWallet::SyncTransaction(const CTransactionRef& ptx, const SyncTxState& state, bool update_tx, bool rescanning_old_block)
    1408             : {
    1409           0 :     if (!AddToWalletIfInvolvingMe(ptx, state, update_tx, rescanning_old_block))
    1410           0 :         return; // Not one of ours
    1411             : 
    1412             :     // If a transaction changes 'conflicted' state, that changes the balance
    1413             :     // available of the outputs it spends. So force those to be
    1414             :     // recomputed, also:
    1415           0 :     MarkInputsDirty(ptx);
    1416           0 : }
    1417             : 
    1418           0 : void CWallet::transactionAddedToMempool(const CTransactionRef& tx) {
    1419           0 :     LOCK(cs_wallet);
    1420           0 :     SyncTransaction(tx, TxStateInMempool{});
    1421             : 
    1422           0 :     auto it = mapWallet.find(tx->GetHash());
    1423           0 :     if (it != mapWallet.end()) {
    1424           0 :         RefreshMempoolStatus(it->second, chain());
    1425           0 :     }
    1426           0 : }
    1427             : 
    1428           0 : void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {
    1429           0 :     LOCK(cs_wallet);
    1430           0 :     auto it = mapWallet.find(tx->GetHash());
    1431           0 :     if (it != mapWallet.end()) {
    1432           0 :         RefreshMempoolStatus(it->second, chain());
    1433           0 :     }
    1434             :     // Handle transactions that were removed from the mempool because they
    1435             :     // conflict with transactions in a newly connected block.
    1436           0 :     if (reason == MemPoolRemovalReason::CONFLICT) {
    1437             :         // Trigger external -walletnotify notifications for these transactions.
    1438             :         // Set Status::UNCONFIRMED instead of Status::CONFLICTED for a few reasons:
    1439             :         //
    1440             :         // 1. The transactionRemovedFromMempool callback does not currently
    1441             :         //    provide the conflicting block's hash and height, and for backwards
    1442             :         //    compatibility reasons it may not be not safe to store conflicted
    1443             :         //    wallet transactions with a null block hash. See
    1444             :         //    https://github.com/bitcoin/bitcoin/pull/18600#discussion_r420195993.
    1445             :         // 2. For most of these transactions, the wallet's internal conflict
    1446             :         //    detection in the blockConnected handler will subsequently call
    1447             :         //    MarkConflicted and update them with CONFLICTED status anyway. This
    1448             :         //    applies to any wallet transaction that has inputs spent in the
    1449             :         //    block, or that has ancestors in the wallet with inputs spent by
    1450             :         //    the block.
    1451             :         // 3. Longstanding behavior since the sync implementation in
    1452             :         //    https://github.com/bitcoin/bitcoin/pull/9371 and the prior sync
    1453             :         //    implementation before that was to mark these transactions
    1454             :         //    unconfirmed rather than conflicted.
    1455             :         //
    1456             :         // Nothing described above should be seen as an unchangeable requirement
    1457             :         // when improving this code in the future. The wallet's heuristics for
    1458             :         // distinguishing between conflicted and unconfirmed transactions are
    1459             :         // imperfect, and could be improved in general, see
    1460             :         // https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Wallet-Transaction-Conflict-Tracking
    1461           0 :         SyncTransaction(tx, TxStateInactive{});
    1462           0 :     }
    1463           0 : }
    1464             : 
    1465           0 : void CWallet::blockConnected(const interfaces::BlockInfo& block)
    1466             : {
    1467           0 :     assert(block.data);
    1468           0 :     LOCK(cs_wallet);
    1469             : 
    1470           0 :     m_last_block_processed_height = block.height;
    1471           0 :     m_last_block_processed = block.hash;
    1472             : 
    1473             :     // No need to scan block if it was created before the wallet birthday.
    1474             :     // Uses chain max time and twice the grace period to adjust time for block time variability.
    1475           0 :     if (block.chain_time_max < m_birth_time.load() - (TIMESTAMP_WINDOW * 2)) return;
    1476             : 
    1477             :     // Scan block
    1478           0 :     for (size_t index = 0; index < block.data->vtx.size(); index++) {
    1479           0 :         SyncTransaction(block.data->vtx[index], TxStateConfirmed{block.hash, block.height, static_cast<int>(index)});
    1480           0 :         transactionRemovedFromMempool(block.data->vtx[index], MemPoolRemovalReason::BLOCK);
    1481           0 :     }
    1482           0 : }
    1483             : 
    1484           0 : void CWallet::blockDisconnected(const interfaces::BlockInfo& block)
    1485             : {
    1486           0 :     assert(block.data);
    1487           0 :     LOCK(cs_wallet);
    1488             : 
    1489             :     // At block disconnection, this will change an abandoned transaction to
    1490             :     // be unconfirmed, whether or not the transaction is added back to the mempool.
    1491             :     // User may have to call abandontransaction again. It may be addressed in the
    1492             :     // future with a stickier abandoned state or even removing abandontransaction call.
    1493           0 :     m_last_block_processed_height = block.height - 1;
    1494           0 :     m_last_block_processed = *Assert(block.prev_hash);
    1495             : 
    1496           0 :     int disconnect_height = block.height;
    1497             : 
    1498           0 :     for (const CTransactionRef& ptx : Assert(block.data)->vtx) {
    1499           0 :         SyncTransaction(ptx, TxStateInactive{});
    1500             : 
    1501           0 :         for (const CTxIn& tx_in : ptx->vin) {
    1502             :             // No other wallet transactions conflicted with this transaction
    1503           0 :             if (mapTxSpends.count(tx_in.prevout) < 1) continue;
    1504             : 
    1505           0 :             std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(tx_in.prevout);
    1506             : 
    1507             :             // For all of the spends that conflict with this transaction
    1508           0 :             for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) {
    1509           0 :                 CWalletTx& wtx = mapWallet.find(_it->second)->second;
    1510             : 
    1511           0 :                 if (!wtx.isConflicted()) continue;
    1512             : 
    1513           0 :                 auto try_updating_state = [&](CWalletTx& tx) {
    1514           0 :                     if (!tx.isConflicted()) return TxUpdate::UNCHANGED;
    1515           0 :                     if (tx.state<TxStateConflicted>()->conflicting_block_height >= disconnect_height) {
    1516           0 :                         tx.m_state = TxStateInactive{};
    1517           0 :                         return TxUpdate::CHANGED;
    1518             :                     }
    1519           0 :                     return TxUpdate::UNCHANGED;
    1520           0 :                 };
    1521             : 
    1522           0 :                 RecursiveUpdateTxState(wtx.tx->GetHash(), try_updating_state);
    1523           0 :             }
    1524             :         }
    1525             :     }
    1526           0 : }
    1527             : 
    1528           0 : void CWallet::updatedBlockTip()
    1529             : {
    1530           0 :     m_best_block_time = GetTime();
    1531           0 : }
    1532             : 
    1533           0 : void CWallet::BlockUntilSyncedToCurrentChain() const {
    1534           0 :     AssertLockNotHeld(cs_wallet);
    1535             :     // Skip the queue-draining stuff if we know we're caught up with
    1536             :     // chain().Tip(), otherwise put a callback in the validation interface queue and wait
    1537             :     // for the queue to drain enough to execute it (indicating we are caught up
    1538             :     // at least with the time we entered this function).
    1539           0 :     uint256 last_block_hash = WITH_LOCK(cs_wallet, return m_last_block_processed);
    1540           0 :     chain().waitForNotificationsIfTipChanged(last_block_hash);
    1541           0 : }
    1542             : 
    1543             : // Note that this function doesn't distinguish between a 0-valued input,
    1544             : // and a not-"is mine" (according to the filter) input.
    1545           0 : CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
    1546             : {
    1547             :     {
    1548           0 :         LOCK(cs_wallet);
    1549           0 :         const auto mi = mapWallet.find(txin.prevout.hash);
    1550           0 :         if (mi != mapWallet.end())
    1551             :         {
    1552           0 :             const CWalletTx& prev = (*mi).second;
    1553           0 :             if (txin.prevout.n < prev.tx->vout.size())
    1554           0 :                 if (IsMine(prev.tx->vout[txin.prevout.n]) & filter)
    1555           0 :                     return prev.tx->vout[txin.prevout.n].nValue;
    1556           0 :         }
    1557           0 :     }
    1558           0 :     return 0;
    1559           0 : }
    1560             : 
    1561           0 : isminetype CWallet::IsMine(const CTxOut& txout) const
    1562             : {
    1563           0 :     AssertLockHeld(cs_wallet);
    1564           0 :     return IsMine(txout.scriptPubKey);
    1565             : }
    1566             : 
    1567           0 : isminetype CWallet::IsMine(const CTxDestination& dest) const
    1568             : {
    1569           0 :     AssertLockHeld(cs_wallet);
    1570           0 :     return IsMine(GetScriptForDestination(dest));
    1571           0 : }
    1572             : 
    1573           0 : isminetype CWallet::IsMine(const CScript& script) const
    1574             : {
    1575           0 :     AssertLockHeld(cs_wallet);
    1576           0 :     isminetype result = ISMINE_NO;
    1577           0 :     for (const auto& spk_man_pair : m_spk_managers) {
    1578           0 :         result = std::max(result, spk_man_pair.second->IsMine(script));
    1579             :     }
    1580           0 :     return result;
    1581             : }
    1582             : 
    1583           0 : bool CWallet::IsMine(const CTransaction& tx) const
    1584             : {
    1585           0 :     AssertLockHeld(cs_wallet);
    1586           0 :     for (const CTxOut& txout : tx.vout)
    1587           0 :         if (IsMine(txout))
    1588           0 :             return true;
    1589           0 :     return false;
    1590           0 : }
    1591             : 
    1592           0 : isminetype CWallet::IsMine(const COutPoint& outpoint) const
    1593             : {
    1594           0 :     AssertLockHeld(cs_wallet);
    1595           0 :     auto wtx = GetWalletTx(outpoint.hash);
    1596           0 :     if (!wtx) {
    1597           0 :         return ISMINE_NO;
    1598             :     }
    1599           0 :     if (outpoint.n >= wtx->tx->vout.size()) {
    1600           0 :         return ISMINE_NO;
    1601             :     }
    1602           0 :     return IsMine(wtx->tx->vout[outpoint.n]);
    1603           0 : }
    1604             : 
    1605           0 : bool CWallet::IsFromMe(const CTransaction& tx) const
    1606             : {
    1607           0 :     return (GetDebit(tx, ISMINE_ALL) > 0);
    1608             : }
    1609             : 
    1610           0 : CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const
    1611             : {
    1612           0 :     CAmount nDebit = 0;
    1613           0 :     for (const CTxIn& txin : tx.vin)
    1614             :     {
    1615           0 :         nDebit += GetDebit(txin, filter);
    1616           0 :         if (!MoneyRange(nDebit))
    1617           0 :             throw std::runtime_error(std::string(__func__) + ": value out of range");
    1618             :     }
    1619           0 :     return nDebit;
    1620           0 : }
    1621             : 
    1622           0 : bool CWallet::IsHDEnabled() const
    1623             : {
    1624             :     // All Active ScriptPubKeyMans must be HD for this to be true
    1625           0 :     bool result = false;
    1626           0 :     for (const auto& spk_man : GetActiveScriptPubKeyMans()) {
    1627           0 :         if (!spk_man->IsHDEnabled()) return false;
    1628           0 :         result = true;
    1629             :     }
    1630           0 :     return result;
    1631           0 : }
    1632             : 
    1633           0 : bool CWallet::CanGetAddresses(bool internal) const
    1634             : {
    1635           0 :     LOCK(cs_wallet);
    1636           0 :     if (m_spk_managers.empty()) return false;
    1637           0 :     for (OutputType t : OUTPUT_TYPES) {
    1638           0 :         auto spk_man = GetScriptPubKeyMan(t, internal);
    1639           0 :         if (spk_man && spk_man->CanGetAddresses(internal)) {
    1640           0 :             return true;
    1641             :         }
    1642             :     }
    1643           0 :     return false;
    1644           0 : }
    1645             : 
    1646           0 : void CWallet::SetWalletFlag(uint64_t flags)
    1647             : {
    1648           0 :     LOCK(cs_wallet);
    1649           0 :     m_wallet_flags |= flags;
    1650           0 :     if (!WalletBatch(GetDatabase()).WriteWalletFlags(m_wallet_flags))
    1651           0 :         throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
    1652           0 : }
    1653             : 
    1654           0 : void CWallet::UnsetWalletFlag(uint64_t flag)
    1655             : {
    1656           0 :     WalletBatch batch(GetDatabase());
    1657           0 :     UnsetWalletFlagWithDB(batch, flag);
    1658           0 : }
    1659             : 
    1660           0 : void CWallet::UnsetWalletFlagWithDB(WalletBatch& batch, uint64_t flag)
    1661             : {
    1662           0 :     LOCK(cs_wallet);
    1663           0 :     m_wallet_flags &= ~flag;
    1664           0 :     if (!batch.WriteWalletFlags(m_wallet_flags))
    1665           0 :         throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
    1666           0 : }
    1667             : 
    1668           0 : void CWallet::UnsetBlankWalletFlag(WalletBatch& batch)
    1669             : {
    1670           0 :     UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET);
    1671           0 : }
    1672             : 
    1673           0 : bool CWallet::IsWalletFlagSet(uint64_t flag) const
    1674             : {
    1675           0 :     return (m_wallet_flags & flag);
    1676             : }
    1677             : 
    1678           0 : bool CWallet::LoadWalletFlags(uint64_t flags)
    1679             : {
    1680           0 :     LOCK(cs_wallet);
    1681           0 :     if (((flags & KNOWN_WALLET_FLAGS) >> 32) ^ (flags >> 32)) {
    1682             :         // contains unknown non-tolerable wallet flags
    1683           0 :         return false;
    1684             :     }
    1685           0 :     m_wallet_flags = flags;
    1686             : 
    1687           0 :     return true;
    1688           0 : }
    1689             : 
    1690           0 : void CWallet::InitWalletFlags(uint64_t flags)
    1691             : {
    1692           0 :     LOCK(cs_wallet);
    1693             : 
    1694             :     // We should never be writing unknown non-tolerable wallet flags
    1695           0 :     assert(((flags & KNOWN_WALLET_FLAGS) >> 32) == (flags >> 32));
    1696             :     // This should only be used once, when creating a new wallet - so current flags are expected to be blank
    1697           0 :     assert(m_wallet_flags == 0);
    1698             : 
    1699           0 :     if (!WalletBatch(GetDatabase()).WriteWalletFlags(flags)) {
    1700           0 :         throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
    1701             :     }
    1702             : 
    1703           0 :     if (!LoadWalletFlags(flags)) assert(false);
    1704           0 : }
    1705             : 
    1706           0 : bool CWallet::ImportScripts(const std::set<CScript> scripts, int64_t timestamp)
    1707             : {
    1708           0 :     auto spk_man = GetLegacyScriptPubKeyMan();
    1709           0 :     if (!spk_man) {
    1710           0 :         return false;
    1711             :     }
    1712           0 :     LOCK(spk_man->cs_KeyStore);
    1713           0 :     return spk_man->ImportScripts(scripts, timestamp);
    1714           0 : }
    1715             : 
    1716           0 : bool CWallet::ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp)
    1717             : {
    1718           0 :     auto spk_man = GetLegacyScriptPubKeyMan();
    1719           0 :     if (!spk_man) {
    1720           0 :         return false;
    1721             :     }
    1722           0 :     LOCK(spk_man->cs_KeyStore);
    1723           0 :     return spk_man->ImportPrivKeys(privkey_map, timestamp);
    1724           0 : }
    1725             : 
    1726           0 : bool CWallet::ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp)
    1727             : {
    1728           0 :     auto spk_man = GetLegacyScriptPubKeyMan();
    1729           0 :     if (!spk_man) {
    1730           0 :         return false;
    1731             :     }
    1732           0 :     LOCK(spk_man->cs_KeyStore);
    1733           0 :     return spk_man->ImportPubKeys(ordered_pubkeys, pubkey_map, key_origins, add_keypool, internal, timestamp);
    1734           0 : }
    1735             : 
    1736           0 : bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp)
    1737             : {
    1738           0 :     auto spk_man = GetLegacyScriptPubKeyMan();
    1739           0 :     if (!spk_man) {
    1740           0 :         return false;
    1741             :     }
    1742           0 :     LOCK(spk_man->cs_KeyStore);
    1743           0 :     if (!spk_man->ImportScriptPubKeys(script_pub_keys, have_solving_data, timestamp)) {
    1744           0 :         return false;
    1745             :     }
    1746           0 :     if (apply_label) {
    1747           0 :         WalletBatch batch(GetDatabase());
    1748           0 :         for (const CScript& script : script_pub_keys) {
    1749           0 :             CTxDestination dest;
    1750           0 :             ExtractDestination(script, dest);
    1751           0 :             if (IsValidDestination(dest)) {
    1752           0 :                 SetAddressBookWithDB(batch, dest, label, AddressPurpose::RECEIVE);
    1753           0 :             }
    1754           0 :         }
    1755           0 :     }
    1756           0 :     return true;
    1757           0 : }
    1758             : 
    1759           0 : void CWallet::FirstKeyTimeChanged(const ScriptPubKeyMan* spkm, int64_t new_birth_time)
    1760             : {
    1761           0 :     int64_t birthtime = m_birth_time.load();
    1762           0 :     if (new_birth_time < birthtime) {
    1763           0 :         m_birth_time = new_birth_time;
    1764           0 :     }
    1765           0 : }
    1766             : 
    1767             : /**
    1768             :  * Scan active chain for relevant transactions after importing keys. This should
    1769             :  * be called whenever new keys are added to the wallet, with the oldest key
    1770             :  * creation time.
    1771             :  *
    1772             :  * @return Earliest timestamp that could be successfully scanned from. Timestamp
    1773             :  * returned will be higher than startTime if relevant blocks could not be read.
    1774             :  */
    1775           0 : int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update)
    1776             : {
    1777             :     // Find starting block. May be null if nCreateTime is greater than the
    1778             :     // highest blockchain timestamp, in which case there is nothing that needs
    1779             :     // to be scanned.
    1780           0 :     int start_height = 0;
    1781           0 :     uint256 start_block;
    1782           0 :     bool start = chain().findFirstBlockWithTimeAndHeight(startTime - TIMESTAMP_WINDOW, 0, FoundBlock().hash(start_block).height(start_height));
    1783           0 :     WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, start ? WITH_LOCK(cs_wallet, return GetLastBlockHeight()) - start_height + 1 : 0);
    1784             : 
    1785           0 :     if (start) {
    1786             :         // TODO: this should take into account failure by ScanResult::USER_ABORT
    1787           0 :         ScanResult result = ScanForWalletTransactions(start_block, start_height, /*max_height=*/{}, reserver, /*fUpdate=*/update, /*save_progress=*/false);
    1788           0 :         if (result.status == ScanResult::FAILURE) {
    1789             :             int64_t time_max;
    1790           0 :             CHECK_NONFATAL(chain().findBlock(result.last_failed_block, FoundBlock().maxTime(time_max)));
    1791           0 :             return time_max + TIMESTAMP_WINDOW + 1;
    1792             :         }
    1793           0 :     }
    1794           0 :     return startTime;
    1795           0 : }
    1796             : 
    1797             : /**
    1798             :  * Scan the block chain (starting in start_block) for transactions
    1799             :  * from or to us. If fUpdate is true, found transactions that already
    1800             :  * exist in the wallet will be updated. If max_height is not set, the
    1801             :  * mempool will be scanned as well.
    1802             :  *
    1803             :  * @param[in] start_block Scan starting block. If block is not on the active
    1804             :  *                        chain, the scan will return SUCCESS immediately.
    1805             :  * @param[in] start_height Height of start_block
    1806             :  * @param[in] max_height  Optional max scanning height. If unset there is
    1807             :  *                        no maximum and scanning can continue to the tip
    1808             :  *
    1809             :  * @return ScanResult returning scan information and indicating success or
    1810             :  *         failure. Return status will be set to SUCCESS if scan was
    1811             :  *         successful. FAILURE if a complete rescan was not possible (due to
    1812             :  *         pruning or corruption). USER_ABORT if the rescan was aborted before
    1813             :  *         it could complete.
    1814             :  *
    1815             :  * @pre Caller needs to make sure start_block (and the optional stop_block) are on
    1816             :  * the main chain after to the addition of any new keys you want to detect
    1817             :  * transactions for.
    1818             :  */
    1819           0 : CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate, const bool save_progress)
    1820             : {
    1821           0 :     constexpr auto INTERVAL_TIME{60s};
    1822           0 :     auto current_time{reserver.now()};
    1823           0 :     auto start_time{reserver.now()};
    1824             : 
    1825           0 :     assert(reserver.isReserved());
    1826             : 
    1827           0 :     uint256 block_hash = start_block;
    1828           0 :     ScanResult result;
    1829             : 
    1830           0 :     std::unique_ptr<FastWalletRescanFilter> fast_rescan_filter;
    1831           0 :     if (!IsLegacy() && chain().hasBlockFilterIndex(BlockFilterType::BASIC)) fast_rescan_filter = std::make_unique<FastWalletRescanFilter>(*this);
    1832             : 
    1833           0 :     WalletLogPrintf("Rescan started from block %s... (%s)\n", start_block.ToString(),
    1834           0 :                     fast_rescan_filter ? "fast variant using block filters" : "slow variant inspecting all blocks");
    1835             : 
    1836           0 :     fAbortRescan = false;
    1837           0 :     ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if rescan required on startup (e.g. due to corruption)
    1838           0 :     uint256 tip_hash = WITH_LOCK(cs_wallet, return GetLastBlockHash());
    1839           0 :     uint256 end_hash = tip_hash;
    1840           0 :     if (max_height) chain().findAncestorByHeight(tip_hash, *max_height, FoundBlock().hash(end_hash));
    1841           0 :     double progress_begin = chain().guessVerificationProgress(block_hash);
    1842           0 :     double progress_end = chain().guessVerificationProgress(end_hash);
    1843           0 :     double progress_current = progress_begin;
    1844           0 :     int block_height = start_height;
    1845           0 :     while (!fAbortRescan && !chain().shutdownRequested()) {
    1846           0 :         if (progress_end - progress_begin > 0.0) {
    1847           0 :             m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin);
    1848           0 :         } else { // avoid divide-by-zero for single block scan range (i.e. start and stop hashes are equal)
    1849           0 :             m_scanning_progress = 0;
    1850             :         }
    1851           0 :         if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
    1852           0 :             ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), std::max(1, std::min(99, (int)(m_scanning_progress * 100))));
    1853           0 :         }
    1854             : 
    1855           0 :         bool next_interval = reserver.now() >= current_time + INTERVAL_TIME;
    1856           0 :         if (next_interval) {
    1857           0 :             current_time = reserver.now();
    1858           0 :             WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
    1859           0 :         }
    1860             : 
    1861           0 :         bool fetch_block{true};
    1862           0 :         if (fast_rescan_filter) {
    1863           0 :             fast_rescan_filter->UpdateIfNeeded();
    1864           0 :             auto matches_block{fast_rescan_filter->MatchesBlock(block_hash)};
    1865           0 :             if (matches_block.has_value()) {
    1866           0 :                 if (*matches_block) {
    1867           0 :                     LogPrint(BCLog::SCAN, "Fast rescan: inspect block %d [%s] (filter matched)\n", block_height, block_hash.ToString());
    1868           0 :                 } else {
    1869           0 :                     result.last_scanned_block = block_hash;
    1870           0 :                     result.last_scanned_height = block_height;
    1871           0 :                     fetch_block = false;
    1872             :                 }
    1873           0 :             } else {
    1874           0 :                 LogPrint(BCLog::SCAN, "Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.ToString());
    1875             :             }
    1876           0 :         }
    1877             : 
    1878             :         // Find next block separately from reading data above, because reading
    1879             :         // is slow and there might be a reorg while it is read.
    1880           0 :         bool block_still_active = false;
    1881           0 :         bool next_block = false;
    1882           0 :         uint256 next_block_hash;
    1883           0 :         chain().findBlock(block_hash, FoundBlock().inActiveChain(block_still_active).nextBlock(FoundBlock().inActiveChain(next_block).hash(next_block_hash)));
    1884             : 
    1885           0 :         if (fetch_block) {
    1886             :             // Read block data
    1887           0 :             CBlock block;
    1888           0 :             chain().findBlock(block_hash, FoundBlock().data(block));
    1889             : 
    1890           0 :             if (!block.IsNull()) {
    1891           0 :                 LOCK(cs_wallet);
    1892           0 :                 if (!block_still_active) {
    1893             :                     // Abort scan if current block is no longer active, to prevent
    1894             :                     // marking transactions as coming from the wrong block.
    1895           0 :                     result.last_failed_block = block_hash;
    1896           0 :                     result.status = ScanResult::FAILURE;
    1897           0 :                     break;
    1898             :                 }
    1899           0 :                 for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
    1900           0 :                     SyncTransaction(block.vtx[posInBlock], TxStateConfirmed{block_hash, block_height, static_cast<int>(posInBlock)}, fUpdate, /*rescanning_old_block=*/true);
    1901           0 :                 }
    1902             :                 // scan succeeded, record block as most recent successfully scanned
    1903           0 :                 result.last_scanned_block = block_hash;
    1904           0 :                 result.last_scanned_height = block_height;
    1905             : 
    1906           0 :                 if (save_progress && next_interval) {
    1907           0 :                     CBlockLocator loc = m_chain->getActiveChainLocator(block_hash);
    1908             : 
    1909           0 :                     if (!loc.IsNull()) {
    1910           0 :                         WalletLogPrintf("Saving scan progress %d.\n", block_height);
    1911           0 :                         WalletBatch batch(GetDatabase());
    1912           0 :                         batch.WriteBestBlock(loc);
    1913           0 :                     }
    1914           0 :                 }
    1915           0 :             } else {
    1916             :                 // could not scan block, keep scanning but record this block as the most recent failure
    1917           0 :                 result.last_failed_block = block_hash;
    1918           0 :                 result.status = ScanResult::FAILURE;
    1919             :             }
    1920           0 :         }
    1921           0 :         if (max_height && block_height >= *max_height) {
    1922           0 :             break;
    1923             :         }
    1924             :         {
    1925           0 :             if (!next_block) {
    1926             :                 // break successfully when rescan has reached the tip, or
    1927             :                 // previous block is no longer on the chain due to a reorg
    1928           0 :                 break;
    1929             :             }
    1930             : 
    1931             :             // increment block and verification progress
    1932           0 :             block_hash = next_block_hash;
    1933           0 :             ++block_height;
    1934           0 :             progress_current = chain().guessVerificationProgress(block_hash);
    1935             : 
    1936             :             // handle updated tip hash
    1937           0 :             const uint256 prev_tip_hash = tip_hash;
    1938           0 :             tip_hash = WITH_LOCK(cs_wallet, return GetLastBlockHash());
    1939           0 :             if (!max_height && prev_tip_hash != tip_hash) {
    1940             :                 // in case the tip has changed, update progress max
    1941           0 :                 progress_end = chain().guessVerificationProgress(tip_hash);
    1942           0 :             }
    1943             :         }
    1944             :     }
    1945           0 :     if (!max_height) {
    1946           0 :         WalletLogPrintf("Scanning current mempool transactions.\n");
    1947           0 :         WITH_LOCK(cs_wallet, chain().requestMempoolTransactions(*this));
    1948           0 :     }
    1949           0 :     ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), 100); // hide progress dialog in GUI
    1950           0 :     if (block_height && fAbortRescan) {
    1951           0 :         WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", block_height, progress_current);
    1952           0 :         result.status = ScanResult::USER_ABORT;
    1953           0 :     } else if (block_height && chain().shutdownRequested()) {
    1954           0 :         WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height, progress_current);
    1955           0 :         result.status = ScanResult::USER_ABORT;
    1956           0 :     } else {
    1957           0 :         WalletLogPrintf("Rescan completed in %15dms\n", Ticks<std::chrono::milliseconds>(reserver.now() - start_time));
    1958             :     }
    1959             :     return result;
    1960           0 : }
    1961             : 
    1962           0 : bool CWallet::SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string, bool relay) const
    1963             : {
    1964           0 :     AssertLockHeld(cs_wallet);
    1965             : 
    1966             :     // Can't relay if wallet is not broadcasting
    1967           0 :     if (!GetBroadcastTransactions()) return false;
    1968             :     // Don't relay abandoned transactions
    1969           0 :     if (wtx.isAbandoned()) return false;
    1970             :     // Don't try to submit coinbase transactions. These would fail anyway but would
    1971             :     // cause log spam.
    1972           0 :     if (wtx.IsCoinBase()) return false;
    1973             :     // Don't try to submit conflicted or confirmed transactions.
    1974           0 :     if (GetTxDepthInMainChain(wtx) != 0) return false;
    1975             : 
    1976             :     // Submit transaction to mempool for relay
    1977           0 :     WalletLogPrintf("Submitting wtx %s to mempool for relay\n", wtx.GetHash().ToString());
    1978             :     // We must set TxStateInMempool here. Even though it will also be set later by the
    1979             :     // entered-mempool callback, if we did not there would be a race where a
    1980             :     // user could call sendmoney in a loop and hit spurious out of funds errors
    1981             :     // because we think that this newly generated transaction's change is
    1982             :     // unavailable as we're not yet aware that it is in the mempool.
    1983             :     //
    1984             :     // If broadcast fails for any reason, trying to set wtx.m_state here would be incorrect.
    1985             :     // If transaction was previously in the mempool, it should be updated when
    1986             :     // TransactionRemovedFromMempool fires.
    1987           0 :     bool ret = chain().broadcastTransaction(wtx.tx, m_default_max_tx_fee, relay, err_string);
    1988           0 :     if (ret) wtx.m_state = TxStateInMempool{};
    1989           0 :     return ret;
    1990           0 : }
    1991             : 
    1992           0 : std::set<uint256> CWallet::GetTxConflicts(const CWalletTx& wtx) const
    1993             : {
    1994           0 :     AssertLockHeld(cs_wallet);
    1995             : 
    1996           0 :     const uint256 myHash{wtx.GetHash()};
    1997           0 :     std::set<uint256> result{GetConflicts(myHash)};
    1998           0 :     result.erase(myHash);
    1999           0 :     return result;
    2000           0 : }
    2001             : 
    2002           0 : bool CWallet::ShouldResend() const
    2003             : {
    2004             :     // Don't attempt to resubmit if the wallet is configured to not broadcast
    2005           0 :     if (!fBroadcastTransactions) return false;
    2006             : 
    2007             :     // During reindex, importing and IBD, old wallet transactions become
    2008             :     // unconfirmed. Don't resend them as that would spam other nodes.
    2009             :     // We only allow forcing mempool submission when not relaying to avoid this spam.
    2010           0 :     if (!chain().isReadyToBroadcast()) return false;
    2011             : 
    2012             :     // Do this infrequently and randomly to avoid giving away
    2013             :     // that these are our transactions.
    2014           0 :     if (NodeClock::now() < m_next_resend) return false;
    2015             : 
    2016           0 :     return true;
    2017           0 : }
    2018             : 
    2019           0 : NodeClock::time_point CWallet::GetDefaultNextResend() { return FastRandomContext{}.rand_uniform_delay(NodeClock::now() + 12h, 24h); }
    2020             : 
    2021             : // Resubmit transactions from the wallet to the mempool, optionally asking the
    2022             : // mempool to relay them. On startup, we will do this for all unconfirmed
    2023             : // transactions but will not ask the mempool to relay them. We do this on startup
    2024             : // to ensure that our own mempool is aware of our transactions. There
    2025             : // is a privacy side effect here as not broadcasting on startup also means that we won't
    2026             : // inform the world of our wallet's state, particularly if the wallet (or node) is not
    2027             : // yet synced.
    2028             : //
    2029             : // Otherwise this function is called periodically in order to relay our unconfirmed txs.
    2030             : // We do this on a random timer to slightly obfuscate which transactions
    2031             : // come from our wallet.
    2032             : //
    2033             : // TODO: Ideally, we'd only resend transactions that we think should have been
    2034             : // mined in the most recent block. Any transaction that wasn't in the top
    2035             : // blockweight of transactions in the mempool shouldn't have been mined,
    2036             : // and so is probably just sitting in the mempool waiting to be confirmed.
    2037             : // Rebroadcasting does nothing to speed up confirmation and only damages
    2038             : // privacy.
    2039             : //
    2040             : // The `force` option results in all unconfirmed transactions being submitted to
    2041             : // the mempool. This does not necessarily result in those transactions being relayed,
    2042             : // that depends on the `relay` option. Periodic rebroadcast uses the pattern
    2043             : // relay=true force=false, while loading into the mempool
    2044             : // (on start, or after import) uses relay=false force=true.
    2045           0 : void CWallet::ResubmitWalletTransactions(bool relay, bool force)
    2046             : {
    2047             :     // Don't attempt to resubmit if the wallet is configured to not broadcast,
    2048             :     // even if forcing.
    2049           0 :     if (!fBroadcastTransactions) return;
    2050             : 
    2051           0 :     int submitted_tx_count = 0;
    2052             : 
    2053             :     { // cs_wallet scope
    2054           0 :         LOCK(cs_wallet);
    2055             : 
    2056             :         // First filter for the transactions we want to rebroadcast.
    2057             :         // We use a set with WalletTxOrderComparator so that rebroadcasting occurs in insertion order
    2058           0 :         std::set<CWalletTx*, WalletTxOrderComparator> to_submit;
    2059           0 :         for (auto& [txid, wtx] : mapWallet) {
    2060             :             // Only rebroadcast unconfirmed txs
    2061           0 :             if (!wtx.isUnconfirmed()) continue;
    2062             : 
    2063             :             // Attempt to rebroadcast all txes more than 5 minutes older than
    2064             :             // the last block, or all txs if forcing.
    2065           0 :             if (!force && wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;
    2066           0 :             to_submit.insert(&wtx);
    2067             :         }
    2068             :         // Now try submitting the transactions to the memory pool and (optionally) relay them.
    2069           0 :         for (auto wtx : to_submit) {
    2070           0 :             std::string unused_err_string;
    2071           0 :             if (SubmitTxMemoryPoolAndRelay(*wtx, unused_err_string, relay)) ++submitted_tx_count;
    2072           0 :         }
    2073           0 :     } // cs_wallet
    2074             : 
    2075           0 :     if (submitted_tx_count > 0) {
    2076           0 :         WalletLogPrintf("%s: resubmit %u unconfirmed transactions\n", __func__, submitted_tx_count);
    2077           0 :     }
    2078           0 : }
    2079             : 
    2080             : /** @} */ // end of mapWallet
    2081             : 
    2082           0 : void MaybeResendWalletTxs(WalletContext& context)
    2083             : {
    2084           0 :     for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
    2085           0 :         if (!pwallet->ShouldResend()) continue;
    2086           0 :         pwallet->ResubmitWalletTransactions(/*relay=*/true, /*force=*/false);
    2087           0 :         pwallet->SetNextResend();
    2088             :     }
    2089           0 : }
    2090             : 
    2091             : 
    2092             : /** @defgroup Actions
    2093             :  *
    2094             :  * @{
    2095             :  */
    2096             : 
    2097           0 : bool CWallet::SignTransaction(CMutableTransaction& tx) const
    2098             : {
    2099           0 :     AssertLockHeld(cs_wallet);
    2100             : 
    2101             :     // Build coins map
    2102           0 :     std::map<COutPoint, Coin> coins;
    2103           0 :     for (auto& input : tx.vin) {
    2104           0 :         const auto mi = mapWallet.find(input.prevout.hash);
    2105           0 :         if(mi == mapWallet.end() || input.prevout.n >= mi->second.tx->vout.size()) {
    2106           0 :             return false;
    2107             :         }
    2108           0 :         const CWalletTx& wtx = mi->second;
    2109           0 :         int prev_height = wtx.state<TxStateConfirmed>() ? wtx.state<TxStateConfirmed>()->confirmed_block_height : 0;
    2110           0 :         coins[input.prevout] = Coin(wtx.tx->vout[input.prevout.n], prev_height, wtx.IsCoinBase());
    2111             :     }
    2112           0 :     std::map<int, bilingual_str> input_errors;
    2113           0 :     return SignTransaction(tx, coins, SIGHASH_DEFAULT, input_errors);
    2114           0 : }
    2115             : 
    2116           0 : bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const
    2117             : {
    2118             :     // Try to sign with all ScriptPubKeyMans
    2119           0 :     for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {
    2120             :         // spk_man->SignTransaction will return true if the transaction is complete,
    2121             :         // so we can exit early and return true if that happens
    2122           0 :         if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) {
    2123           0 :             return true;
    2124             :         }
    2125             :     }
    2126             : 
    2127             :     // At this point, one input was not fully signed otherwise we would have exited already
    2128           0 :     return false;
    2129           0 : }
    2130             : 
    2131           0 : TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, size_t * n_signed, bool finalize) const
    2132             : {
    2133           0 :     if (n_signed) {
    2134           0 :         *n_signed = 0;
    2135           0 :     }
    2136           0 :     LOCK(cs_wallet);
    2137             :     // Get all of the previous transactions
    2138           0 :     for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
    2139           0 :         const CTxIn& txin = psbtx.tx->vin[i];
    2140           0 :         PSBTInput& input = psbtx.inputs.at(i);
    2141             : 
    2142           0 :         if (PSBTInputSigned(input)) {
    2143           0 :             continue;
    2144             :         }
    2145             : 
    2146             :         // If we have no utxo, grab it from the wallet.
    2147           0 :         if (!input.non_witness_utxo) {
    2148           0 :             const uint256& txhash = txin.prevout.hash;
    2149           0 :             const auto it = mapWallet.find(txhash);
    2150           0 :             if (it != mapWallet.end()) {
    2151           0 :                 const CWalletTx& wtx = it->second;
    2152             :                 // We only need the non_witness_utxo, which is a superset of the witness_utxo.
    2153             :                 //   The signing code will switch to the smaller witness_utxo if this is ok.
    2154           0 :                 input.non_witness_utxo = wtx.tx;
    2155           0 :             }
    2156           0 :         }
    2157           0 :     }
    2158             : 
    2159           0 :     const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
    2160             : 
    2161             :     // Fill in information from ScriptPubKeyMans
    2162           0 :     for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {
    2163           0 :         int n_signed_this_spkm = 0;
    2164           0 :         TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm, finalize);
    2165           0 :         if (res != TransactionError::OK) {
    2166           0 :             return res;
    2167             :         }
    2168             : 
    2169           0 :         if (n_signed) {
    2170           0 :             (*n_signed) += n_signed_this_spkm;
    2171           0 :         }
    2172             :     }
    2173             : 
    2174           0 :     RemoveUnnecessaryTransactions(psbtx, sighash_type);
    2175             : 
    2176             :     // Complete if every input is now signed
    2177           0 :     complete = true;
    2178           0 :     for (const auto& input : psbtx.inputs) {
    2179           0 :         complete &= PSBTInputSigned(input);
    2180             :     }
    2181             : 
    2182           0 :     return TransactionError::OK;
    2183           0 : }
    2184             : 
    2185           0 : SigningResult CWallet::SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const
    2186             : {
    2187           0 :     SignatureData sigdata;
    2188           0 :     CScript script_pub_key = GetScriptForDestination(pkhash);
    2189           0 :     for (const auto& spk_man_pair : m_spk_managers) {
    2190           0 :         if (spk_man_pair.second->CanProvide(script_pub_key, sigdata)) {
    2191           0 :             LOCK(cs_wallet);  // DescriptorScriptPubKeyMan calls IsLocked which can lock cs_wallet in a deadlocking order
    2192           0 :             return spk_man_pair.second->SignMessage(message, pkhash, str_sig);
    2193           0 :         }
    2194             :     }
    2195           0 :     return SigningResult::PRIVATE_KEY_NOT_AVAILABLE;
    2196           0 : }
    2197             : 
    2198           0 : OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const
    2199             : {
    2200             :     // If -changetype is specified, always use that change type.
    2201           0 :     if (change_type) {
    2202           0 :         return *change_type;
    2203             :     }
    2204             : 
    2205             :     // if m_default_address_type is legacy, use legacy address as change.
    2206           0 :     if (m_default_address_type == OutputType::LEGACY) {
    2207           0 :         return OutputType::LEGACY;
    2208             :     }
    2209             : 
    2210           0 :     bool any_tr{false};
    2211           0 :     bool any_wpkh{false};
    2212           0 :     bool any_sh{false};
    2213           0 :     bool any_pkh{false};
    2214             : 
    2215           0 :     for (const auto& recipient : vecSend) {
    2216           0 :         if (std::get_if<WitnessV1Taproot>(&recipient.dest)) {
    2217           0 :             any_tr = true;
    2218           0 :         } else if (std::get_if<WitnessV0KeyHash>(&recipient.dest)) {
    2219           0 :             any_wpkh = true;
    2220           0 :         } else if (std::get_if<ScriptHash>(&recipient.dest)) {
    2221           0 :             any_sh = true;
    2222           0 :         } else if (std::get_if<PKHash>(&recipient.dest)) {
    2223           0 :             any_pkh = true;
    2224           0 :         }
    2225             :     }
    2226             : 
    2227           0 :     const bool has_bech32m_spkman(GetScriptPubKeyMan(OutputType::BECH32M, /*internal=*/true));
    2228           0 :     if (has_bech32m_spkman && any_tr) {
    2229             :         // Currently tr is the only type supported by the BECH32M spkman
    2230           0 :         return OutputType::BECH32M;
    2231             :     }
    2232           0 :     const bool has_bech32_spkman(GetScriptPubKeyMan(OutputType::BECH32, /*internal=*/true));
    2233           0 :     if (has_bech32_spkman && any_wpkh) {
    2234             :         // Currently wpkh is the only type supported by the BECH32 spkman
    2235           0 :         return OutputType::BECH32;
    2236             :     }
    2237           0 :     const bool has_p2sh_segwit_spkman(GetScriptPubKeyMan(OutputType::P2SH_SEGWIT, /*internal=*/true));
    2238           0 :     if (has_p2sh_segwit_spkman && any_sh) {
    2239             :         // Currently sh_wpkh is the only type supported by the P2SH_SEGWIT spkman
    2240             :         // As of 2021 about 80% of all SH are wrapping WPKH, so use that
    2241           0 :         return OutputType::P2SH_SEGWIT;
    2242             :     }
    2243           0 :     const bool has_legacy_spkman(GetScriptPubKeyMan(OutputType::LEGACY, /*internal=*/true));
    2244           0 :     if (has_legacy_spkman && any_pkh) {
    2245             :         // Currently pkh is the only type supported by the LEGACY spkman
    2246           0 :         return OutputType::LEGACY;
    2247             :     }
    2248             : 
    2249           0 :     if (has_bech32m_spkman) {
    2250           0 :         return OutputType::BECH32M;
    2251             :     }
    2252           0 :     if (has_bech32_spkman) {
    2253           0 :         return OutputType::BECH32;
    2254             :     }
    2255             :     // else use m_default_address_type for change
    2256           0 :     return m_default_address_type;
    2257           0 : }
    2258             : 
    2259           0 : void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm)
    2260             : {
    2261           0 :     LOCK(cs_wallet);
    2262           0 :     WalletLogPrintf("CommitTransaction:\n%s", tx->ToString()); // NOLINT(bitcoin-unterminated-logprintf)
    2263             : 
    2264             :     // Add tx to wallet, because if it has change it's also ours,
    2265             :     // otherwise just for transaction history.
    2266           0 :     CWalletTx* wtx = AddToWallet(tx, TxStateInactive{}, [&](CWalletTx& wtx, bool new_tx) {
    2267           0 :         CHECK_NONFATAL(wtx.mapValue.empty());
    2268           0 :         CHECK_NONFATAL(wtx.vOrderForm.empty());
    2269           0 :         wtx.mapValue = std::move(mapValue);
    2270           0 :         wtx.vOrderForm = std::move(orderForm);
    2271           0 :         wtx.fTimeReceivedIsTxTime = true;
    2272           0 :         wtx.fFromMe = true;
    2273           0 :         return true;
    2274             :     });
    2275             : 
    2276             :     // wtx can only be null if the db write failed.
    2277           0 :     if (!wtx) {
    2278           0 :         throw std::runtime_error(std::string(__func__) + ": Wallet db error, transaction commit failed");
    2279             :     }
    2280             : 
    2281             :     // Notify that old coins are spent
    2282           0 :     for (const CTxIn& txin : tx->vin) {
    2283           0 :         CWalletTx &coin = mapWallet.at(txin.prevout.hash);
    2284           0 :         coin.MarkDirty();
    2285           0 :         NotifyTransactionChanged(coin.GetHash(), CT_UPDATED);
    2286             :     }
    2287             : 
    2288           0 :     if (!fBroadcastTransactions) {
    2289             :         // Don't submit tx to the mempool
    2290           0 :         return;
    2291             :     }
    2292             : 
    2293           0 :     std::string err_string;
    2294           0 :     if (!SubmitTxMemoryPoolAndRelay(*wtx, err_string, true)) {
    2295           0 :         WalletLogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
    2296             :         // TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
    2297           0 :     }
    2298           0 : }
    2299             : 
    2300           0 : DBErrors CWallet::LoadWallet()
    2301             : {
    2302           0 :     LOCK(cs_wallet);
    2303             : 
    2304           0 :     DBErrors nLoadWalletRet = WalletBatch(GetDatabase()).LoadWallet(this);
    2305           0 :     if (nLoadWalletRet == DBErrors::NEED_REWRITE)
    2306             :     {
    2307           0 :         if (GetDatabase().Rewrite("\x04pool"))
    2308             :         {
    2309           0 :             for (const auto& spk_man_pair : m_spk_managers) {
    2310           0 :                 spk_man_pair.second->RewriteDB();
    2311             :             }
    2312           0 :         }
    2313           0 :     }
    2314             : 
    2315           0 :     if (m_spk_managers.empty()) {
    2316           0 :         assert(m_external_spk_managers.empty());
    2317           0 :         assert(m_internal_spk_managers.empty());
    2318           0 :     }
    2319             : 
    2320           0 :     return nLoadWalletRet;
    2321           0 : }
    2322             : 
    2323           0 : DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
    2324             : {
    2325           0 :     AssertLockHeld(cs_wallet);
    2326           0 :     DBErrors nZapSelectTxRet = WalletBatch(GetDatabase()).ZapSelectTx(vHashIn, vHashOut);
    2327           0 :     for (const uint256& hash : vHashOut) {
    2328           0 :         const auto& it = mapWallet.find(hash);
    2329           0 :         wtxOrdered.erase(it->second.m_it_wtxOrdered);
    2330           0 :         for (const auto& txin : it->second.tx->vin)
    2331           0 :             mapTxSpends.erase(txin.prevout);
    2332           0 :         mapWallet.erase(it);
    2333           0 :         NotifyTransactionChanged(hash, CT_DELETED);
    2334             :     }
    2335             : 
    2336           0 :     if (nZapSelectTxRet == DBErrors::NEED_REWRITE)
    2337             :     {
    2338           0 :         if (GetDatabase().Rewrite("\x04pool"))
    2339             :         {
    2340           0 :             for (const auto& spk_man_pair : m_spk_managers) {
    2341           0 :                 spk_man_pair.second->RewriteDB();
    2342             :             }
    2343           0 :         }
    2344           0 :     }
    2345             : 
    2346           0 :     if (nZapSelectTxRet != DBErrors::LOAD_OK)
    2347           0 :         return nZapSelectTxRet;
    2348             : 
    2349           0 :     MarkDirty();
    2350             : 
    2351           0 :     return DBErrors::LOAD_OK;
    2352           0 : }
    2353             : 
    2354           0 : bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& new_purpose)
    2355             : {
    2356           0 :     bool fUpdated = false;
    2357             :     bool is_mine;
    2358           0 :     std::optional<AddressPurpose> purpose;
    2359             :     {
    2360           0 :         LOCK(cs_wallet);
    2361           0 :         std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
    2362           0 :         fUpdated = (mi != m_address_book.end() && !mi->second.IsChange());
    2363           0 :         m_address_book[address].SetLabel(strName);
    2364           0 :         is_mine = IsMine(address) != ISMINE_NO;
    2365           0 :         if (new_purpose) { /* update purpose only if requested */
    2366           0 :             purpose = m_address_book[address].purpose = new_purpose;
    2367           0 :         } else {
    2368           0 :             purpose = m_address_book[address].purpose;
    2369             :         }
    2370           0 :     }
    2371             :     // In very old wallets, address purpose may not be recorded so we derive it from IsMine
    2372           0 :     NotifyAddressBookChanged(address, strName, is_mine,
    2373           0 :                              purpose.value_or(is_mine ? AddressPurpose::RECEIVE : AddressPurpose::SEND),
    2374           0 :                              (fUpdated ? CT_UPDATED : CT_NEW));
    2375           0 :     if (new_purpose && !batch.WritePurpose(EncodeDestination(address), PurposeToString(*new_purpose)))
    2376           0 :         return false;
    2377           0 :     return batch.WriteName(EncodeDestination(address), strName);
    2378           0 : }
    2379             : 
    2380           0 : bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& purpose)
    2381             : {
    2382           0 :     WalletBatch batch(GetDatabase());
    2383           0 :     return SetAddressBookWithDB(batch, address, strName, purpose);
    2384           0 : }
    2385             : 
    2386           0 : bool CWallet::DelAddressBook(const CTxDestination& address)
    2387             : {
    2388           0 :     WalletBatch batch(GetDatabase());
    2389             :     {
    2390           0 :         LOCK(cs_wallet);
    2391             :         // If we want to delete receiving addresses, we should avoid calling EraseAddressData because it will delete the previously_spent value. Could instead just erase the label so it becomes a change address, and keep the data.
    2392             :         // NOTE: This isn't a problem for sending addresses because they don't have any data that needs to be kept.
    2393             :         // When adding new address data, it should be considered here whether to retain or delete it.
    2394           0 :         if (IsMine(address)) {
    2395           0 :             WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT);
    2396           0 :             return false;
    2397             :         }
    2398             :         // Delete data rows associated with this address
    2399           0 :         batch.EraseAddressData(address);
    2400           0 :         m_address_book.erase(address);
    2401           0 :     }
    2402             : 
    2403           0 :     NotifyAddressBookChanged(address, "", /*is_mine=*/false, AddressPurpose::SEND, CT_DELETED);
    2404             : 
    2405           0 :     batch.ErasePurpose(EncodeDestination(address));
    2406           0 :     return batch.EraseName(EncodeDestination(address));
    2407           0 : }
    2408             : 
    2409           0 : size_t CWallet::KeypoolCountExternalKeys() const
    2410             : {
    2411           0 :     AssertLockHeld(cs_wallet);
    2412             : 
    2413           0 :     auto legacy_spk_man = GetLegacyScriptPubKeyMan();
    2414           0 :     if (legacy_spk_man) {
    2415           0 :         return legacy_spk_man->KeypoolCountExternalKeys();
    2416             :     }
    2417             : 
    2418           0 :     unsigned int count = 0;
    2419           0 :     for (auto spk_man : m_external_spk_managers) {
    2420           0 :         count += spk_man.second->GetKeyPoolSize();
    2421             :     }
    2422             : 
    2423           0 :     return count;
    2424           0 : }
    2425             : 
    2426           0 : unsigned int CWallet::GetKeyPoolSize() const
    2427             : {
    2428           0 :     AssertLockHeld(cs_wallet);
    2429             : 
    2430           0 :     unsigned int count = 0;
    2431           0 :     for (auto spk_man : GetActiveScriptPubKeyMans()) {
    2432           0 :         count += spk_man->GetKeyPoolSize();
    2433             :     }
    2434           0 :     return count;
    2435           0 : }
    2436             : 
    2437           0 : bool CWallet::TopUpKeyPool(unsigned int kpSize)
    2438             : {
    2439           0 :     LOCK(cs_wallet);
    2440           0 :     bool res = true;
    2441           0 :     for (auto spk_man : GetActiveScriptPubKeyMans()) {
    2442           0 :         res &= spk_man->TopUp(kpSize);
    2443             :     }
    2444           0 :     return res;
    2445           0 : }
    2446             : 
    2447           0 : util::Result<CTxDestination> CWallet::GetNewDestination(const OutputType type, const std::string label)
    2448             : {
    2449           0 :     LOCK(cs_wallet);
    2450           0 :     auto spk_man = GetScriptPubKeyMan(type, /*internal=*/false);
    2451           0 :     if (!spk_man) {
    2452           0 :         return util::Error{strprintf(_("Error: No %s addresses available."), FormatOutputType(type))};
    2453             :     }
    2454             : 
    2455           0 :     auto op_dest = spk_man->GetNewDestination(type);
    2456           0 :     if (op_dest) {
    2457           0 :         SetAddressBook(*op_dest, label, AddressPurpose::RECEIVE);
    2458           0 :     }
    2459             : 
    2460           0 :     return op_dest;
    2461           0 : }
    2462             : 
    2463           0 : util::Result<CTxDestination> CWallet::GetNewChangeDestination(const OutputType type)
    2464             : {
    2465           0 :     LOCK(cs_wallet);
    2466             : 
    2467           0 :     ReserveDestination reservedest(this, type);
    2468           0 :     auto op_dest = reservedest.GetReservedDestination(true);
    2469           0 :     if (op_dest) reservedest.KeepDestination();
    2470             : 
    2471           0 :     return op_dest;
    2472           0 : }
    2473             : 
    2474           0 : std::optional<int64_t> CWallet::GetOldestKeyPoolTime() const
    2475             : {
    2476           0 :     LOCK(cs_wallet);
    2477           0 :     if (m_spk_managers.empty()) {
    2478           0 :         return std::nullopt;
    2479             :     }
    2480             : 
    2481           0 :     std::optional<int64_t> oldest_key{std::numeric_limits<int64_t>::max()};
    2482           0 :     for (const auto& spk_man_pair : m_spk_managers) {
    2483           0 :         oldest_key = std::min(oldest_key, spk_man_pair.second->GetOldestKeyPoolTime());
    2484             :     }
    2485           0 :     return oldest_key;
    2486           0 : }
    2487             : 
    2488           0 : void CWallet::MarkDestinationsDirty(const std::set<CTxDestination>& destinations) {
    2489           0 :     for (auto& entry : mapWallet) {
    2490           0 :         CWalletTx& wtx = entry.second;
    2491           0 :         if (wtx.m_is_cache_empty) continue;
    2492           0 :         for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
    2493           0 :             CTxDestination dst;
    2494           0 :             if (ExtractDestination(wtx.tx->vout[i].scriptPubKey, dst) && destinations.count(dst)) {
    2495           0 :                 wtx.MarkDirty();
    2496           0 :                 break;
    2497             :             }
    2498           0 :         }
    2499             :     }
    2500           0 : }
    2501             : 
    2502           0 : void CWallet::ForEachAddrBookEntry(const ListAddrBookFunc& func) const
    2503             : {
    2504           0 :     AssertLockHeld(cs_wallet);
    2505           0 :     for (const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book) {
    2506           0 :         const auto& entry = item.second;
    2507           0 :         func(item.first, entry.GetLabel(), entry.IsChange(), entry.purpose);
    2508             :     }
    2509           0 : }
    2510             : 
    2511           0 : std::vector<CTxDestination> CWallet::ListAddrBookAddresses(const std::optional<AddrBookFilter>& _filter) const
    2512             : {
    2513           0 :     AssertLockHeld(cs_wallet);
    2514           0 :     std::vector<CTxDestination> result;
    2515           0 :     AddrBookFilter filter = _filter ? *_filter : AddrBookFilter();
    2516           0 :     ForEachAddrBookEntry([&result, &filter](const CTxDestination& dest, const std::string& label, bool is_change, const std::optional<AddressPurpose>& purpose) {
    2517             :         // Filter by change
    2518           0 :         if (filter.ignore_change && is_change) return;
    2519             :         // Filter by label
    2520           0 :         if (filter.m_op_label && *filter.m_op_label != label) return;
    2521             :         // All good
    2522           0 :         result.emplace_back(dest);
    2523           0 :     });
    2524           0 :     return result;
    2525           0 : }
    2526             : 
    2527           0 : std::set<std::string> CWallet::ListAddrBookLabels(const std::optional<AddressPurpose> purpose) const
    2528             : {
    2529           0 :     AssertLockHeld(cs_wallet);
    2530           0 :     std::set<std::string> label_set;
    2531           0 :     ForEachAddrBookEntry([&](const CTxDestination& _dest, const std::string& _label,
    2532             :                              bool _is_change, const std::optional<AddressPurpose>& _purpose) {
    2533           0 :         if (_is_change) return;
    2534           0 :         if (!purpose || purpose == _purpose) {
    2535           0 :             label_set.insert(_label);
    2536           0 :         }
    2537           0 :     });
    2538           0 :     return label_set;
    2539           0 : }
    2540             : 
    2541           0 : util::Result<CTxDestination> ReserveDestination::GetReservedDestination(bool internal)
    2542             : {
    2543           0 :     m_spk_man = pwallet->GetScriptPubKeyMan(type, internal);
    2544           0 :     if (!m_spk_man) {
    2545           0 :         return util::Error{strprintf(_("Error: No %s addresses available."), FormatOutputType(type))};
    2546             :     }
    2547             : 
    2548           0 :     if (nIndex == -1) {
    2549           0 :         CKeyPool keypool;
    2550           0 :         auto op_address = m_spk_man->GetReservedDestination(type, internal, nIndex, keypool);
    2551           0 :         if (!op_address) return op_address;
    2552           0 :         address = *op_address;
    2553           0 :         fInternal = keypool.fInternal;
    2554           0 :     }
    2555           0 :     return address;
    2556           0 : }
    2557             : 
    2558           0 : void ReserveDestination::KeepDestination()
    2559             : {
    2560           0 :     if (nIndex != -1) {
    2561           0 :         m_spk_man->KeepDestination(nIndex, type);
    2562           0 :     }
    2563           0 :     nIndex = -1;
    2564           0 :     address = CNoDestination();
    2565           0 : }
    2566             : 
    2567           0 : void ReserveDestination::ReturnDestination()
    2568             : {
    2569           0 :     if (nIndex != -1) {
    2570           0 :         m_spk_man->ReturnDestination(nIndex, fInternal, address);
    2571           0 :     }
    2572           0 :     nIndex = -1;
    2573           0 :     address = CNoDestination();
    2574           0 : }
    2575             : 
    2576           0 : bool CWallet::DisplayAddress(const CTxDestination& dest)
    2577             : {
    2578           0 :     CScript scriptPubKey = GetScriptForDestination(dest);
    2579           0 :     for (const auto& spk_man : GetScriptPubKeyMans(scriptPubKey)) {
    2580           0 :         auto signer_spk_man = dynamic_cast<ExternalSignerScriptPubKeyMan *>(spk_man);
    2581           0 :         if (signer_spk_man == nullptr) {
    2582           0 :             continue;
    2583             :         }
    2584           0 :         ExternalSigner signer = ExternalSignerScriptPubKeyMan::GetExternalSigner();
    2585           0 :         return signer_spk_man->DisplayAddress(scriptPubKey, signer);
    2586           0 :     }
    2587           0 :     return false;
    2588           0 : }
    2589             : 
    2590           0 : bool CWallet::LockCoin(const COutPoint& output, WalletBatch* batch)
    2591             : {
    2592           0 :     AssertLockHeld(cs_wallet);
    2593           0 :     setLockedCoins.insert(output);
    2594           0 :     if (batch) {
    2595           0 :         return batch->WriteLockedUTXO(output);
    2596             :     }
    2597           0 :     return true;
    2598           0 : }
    2599             : 
    2600           0 : bool CWallet::UnlockCoin(const COutPoint& output, WalletBatch* batch)
    2601             : {
    2602           0 :     AssertLockHeld(cs_wallet);
    2603           0 :     bool was_locked = setLockedCoins.erase(output);
    2604           0 :     if (batch && was_locked) {
    2605           0 :         return batch->EraseLockedUTXO(output);
    2606             :     }
    2607           0 :     return true;
    2608           0 : }
    2609             : 
    2610           0 : bool CWallet::UnlockAllCoins()
    2611             : {
    2612           0 :     AssertLockHeld(cs_wallet);
    2613           0 :     bool success = true;
    2614           0 :     WalletBatch batch(GetDatabase());
    2615           0 :     for (auto it = setLockedCoins.begin(); it != setLockedCoins.end(); ++it) {
    2616           0 :         success &= batch.EraseLockedUTXO(*it);
    2617           0 :     }
    2618           0 :     setLockedCoins.clear();
    2619           0 :     return success;
    2620           0 : }
    2621             : 
    2622           0 : bool CWallet::IsLockedCoin(const COutPoint& output) const
    2623             : {
    2624           0 :     AssertLockHeld(cs_wallet);
    2625           0 :     return setLockedCoins.count(output) > 0;
    2626             : }
    2627             : 
    2628           0 : void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const
    2629             : {
    2630           0 :     AssertLockHeld(cs_wallet);
    2631           0 :     for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
    2632           0 :          it != setLockedCoins.end(); it++) {
    2633           0 :         COutPoint outpt = (*it);
    2634           0 :         vOutpts.push_back(outpt);
    2635           0 :     }
    2636           0 : }
    2637             : 
    2638             : /** @} */ // end of Actions
    2639             : 
    2640           0 : void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t>& mapKeyBirth) const {
    2641           0 :     AssertLockHeld(cs_wallet);
    2642           0 :     mapKeyBirth.clear();
    2643             : 
    2644             :     // map in which we'll infer heights of other keys
    2645           0 :     std::map<CKeyID, const TxStateConfirmed*> mapKeyFirstBlock;
    2646           0 :     TxStateConfirmed max_confirm{uint256{}, /*height=*/-1, /*index=*/-1};
    2647           0 :     max_confirm.confirmed_block_height = GetLastBlockHeight() > 144 ? GetLastBlockHeight() - 144 : 0; // the tip can be reorganized; use a 144-block safety margin
    2648           0 :     CHECK_NONFATAL(chain().findAncestorByHeight(GetLastBlockHash(), max_confirm.confirmed_block_height, FoundBlock().hash(max_confirm.confirmed_block_hash)));
    2649             : 
    2650             :     {
    2651           0 :         LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan();
    2652           0 :         assert(spk_man != nullptr);
    2653           0 :         LOCK(spk_man->cs_KeyStore);
    2654             : 
    2655             :         // get birth times for keys with metadata
    2656           0 :         for (const auto& entry : spk_man->mapKeyMetadata) {
    2657           0 :             if (entry.second.nCreateTime) {
    2658           0 :                 mapKeyBirth[entry.first] = entry.second.nCreateTime;
    2659           0 :             }
    2660             :         }
    2661             : 
    2662             :         // Prepare to infer birth heights for keys without metadata
    2663           0 :         for (const CKeyID &keyid : spk_man->GetKeys()) {
    2664           0 :             if (mapKeyBirth.count(keyid) == 0)
    2665           0 :                 mapKeyFirstBlock[keyid] = &max_confirm;
    2666             :         }
    2667             : 
    2668             :         // if there are no such keys, we're done
    2669           0 :         if (mapKeyFirstBlock.empty())
    2670           0 :             return;
    2671             : 
    2672             :         // find first block that affects those keys, if there are any left
    2673           0 :         for (const auto& entry : mapWallet) {
    2674             :             // iterate over all wallet transactions...
    2675           0 :             const CWalletTx &wtx = entry.second;
    2676           0 :             if (auto* conf = wtx.state<TxStateConfirmed>()) {
    2677             :                 // ... which are already in a block
    2678           0 :                 for (const CTxOut &txout : wtx.tx->vout) {
    2679             :                     // iterate over all their outputs
    2680           0 :                     for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *spk_man)) {
    2681             :                         // ... and all their affected keys
    2682           0 :                         auto rit = mapKeyFirstBlock.find(keyid);
    2683           0 :                         if (rit != mapKeyFirstBlock.end() && conf->confirmed_block_height < rit->second->confirmed_block_height) {
    2684           0 :                             rit->second = conf;
    2685           0 :                         }
    2686             :                     }
    2687             :                 }
    2688           0 :             }
    2689             :         }
    2690           0 :     }
    2691             : 
    2692             :     // Extract block timestamps for those keys
    2693           0 :     for (const auto& entry : mapKeyFirstBlock) {
    2694             :         int64_t block_time;
    2695           0 :         CHECK_NONFATAL(chain().findBlock(entry.second->confirmed_block_hash, FoundBlock().time(block_time)));
    2696           0 :         mapKeyBirth[entry.first] = block_time - TIMESTAMP_WINDOW; // block times can be 2h off
    2697             :     }
    2698           0 : }
    2699             : 
    2700             : /**
    2701             :  * Compute smart timestamp for a transaction being added to the wallet.
    2702             :  *
    2703             :  * Logic:
    2704             :  * - If sending a transaction, assign its timestamp to the current time.
    2705             :  * - If receiving a transaction outside a block, assign its timestamp to the
    2706             :  *   current time.
    2707             :  * - If receiving a transaction during a rescanning process, assign all its
    2708             :  *   (not already known) transactions' timestamps to the block time.
    2709             :  * - If receiving a block with a future timestamp, assign all its (not already
    2710             :  *   known) transactions' timestamps to the current time.
    2711             :  * - If receiving a block with a past timestamp, before the most recent known
    2712             :  *   transaction (that we care about), assign all its (not already known)
    2713             :  *   transactions' timestamps to the same timestamp as that most-recent-known
    2714             :  *   transaction.
    2715             :  * - If receiving a block with a past timestamp, but after the most recent known
    2716             :  *   transaction, assign all its (not already known) transactions' timestamps to
    2717             :  *   the block time.
    2718             :  *
    2719             :  * For more information see CWalletTx::nTimeSmart,
    2720             :  * https://bitcointalk.org/?topic=54527, or
    2721             :  * https://github.com/bitcoin/bitcoin/pull/1393.
    2722             :  */
    2723           0 : unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx, bool rescanning_old_block) const
    2724             : {
    2725           0 :     std::optional<uint256> block_hash;
    2726           0 :     if (auto* conf = wtx.state<TxStateConfirmed>()) {
    2727           0 :         block_hash = conf->confirmed_block_hash;
    2728           0 :     } else if (auto* conf = wtx.state<TxStateConflicted>()) {
    2729           0 :         block_hash = conf->conflicting_block_hash;
    2730           0 :     }
    2731             : 
    2732           0 :     unsigned int nTimeSmart = wtx.nTimeReceived;
    2733           0 :     if (block_hash) {
    2734             :         int64_t blocktime;
    2735             :         int64_t block_max_time;
    2736           0 :         if (chain().findBlock(*block_hash, FoundBlock().time(blocktime).maxTime(block_max_time))) {
    2737           0 :             if (rescanning_old_block) {
    2738           0 :                 nTimeSmart = block_max_time;
    2739           0 :             } else {
    2740           0 :                 int64_t latestNow = wtx.nTimeReceived;
    2741           0 :                 int64_t latestEntry = 0;
    2742             : 
    2743             :                 // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
    2744           0 :                 int64_t latestTolerated = latestNow + 300;
    2745           0 :                 const TxItems& txOrdered = wtxOrdered;
    2746           0 :                 for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
    2747           0 :                     CWalletTx* const pwtx = it->second;
    2748           0 :                     if (pwtx == &wtx) {
    2749           0 :                         continue;
    2750             :                     }
    2751             :                     int64_t nSmartTime;
    2752           0 :                     nSmartTime = pwtx->nTimeSmart;
    2753           0 :                     if (!nSmartTime) {
    2754           0 :                         nSmartTime = pwtx->nTimeReceived;
    2755           0 :                     }
    2756           0 :                     if (nSmartTime <= latestTolerated) {
    2757           0 :                         latestEntry = nSmartTime;
    2758           0 :                         if (nSmartTime > latestNow) {
    2759           0 :                             latestNow = nSmartTime;
    2760           0 :                         }
    2761           0 :                         break;
    2762             :                     }
    2763           0 :                 }
    2764             : 
    2765           0 :                 nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
    2766             :             }
    2767           0 :         } else {
    2768           0 :             WalletLogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), block_hash->ToString());
    2769             :         }
    2770           0 :     }
    2771           0 :     return nTimeSmart;
    2772           0 : }
    2773             : 
    2774           0 : bool CWallet::SetAddressPreviouslySpent(WalletBatch& batch, const CTxDestination& dest, bool used)
    2775             : {
    2776           0 :     if (std::get_if<CNoDestination>(&dest))
    2777           0 :         return false;
    2778             : 
    2779           0 :     if (!used) {
    2780           0 :         if (auto* data{common::FindKey(m_address_book, dest)}) data->previously_spent = false;
    2781           0 :         return batch.WriteAddressPreviouslySpent(dest, false);
    2782             :     }
    2783             : 
    2784           0 :     LoadAddressPreviouslySpent(dest);
    2785           0 :     return batch.WriteAddressPreviouslySpent(dest, true);
    2786           0 : }
    2787             : 
    2788           0 : void CWallet::LoadAddressPreviouslySpent(const CTxDestination& dest)
    2789             : {
    2790           0 :     m_address_book[dest].previously_spent = true;
    2791           0 : }
    2792             : 
    2793           0 : void CWallet::LoadAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& request)
    2794             : {
    2795           0 :     m_address_book[dest].receive_requests[id] = request;
    2796           0 : }
    2797             : 
    2798           0 : bool CWallet::IsAddressPreviouslySpent(const CTxDestination& dest) const
    2799             : {
    2800           0 :     if (auto* data{common::FindKey(m_address_book, dest)}) return data->previously_spent;
    2801           0 :     return false;
    2802           0 : }
    2803             : 
    2804           0 : std::vector<std::string> CWallet::GetAddressReceiveRequests() const
    2805             : {
    2806           0 :     std::vector<std::string> values;
    2807           0 :     for (const auto& [dest, entry] : m_address_book) {
    2808           0 :         for (const auto& [id, request] : entry.receive_requests) {
    2809           0 :             values.emplace_back(request);
    2810             :         }
    2811             :     }
    2812           0 :     return values;
    2813           0 : }
    2814             : 
    2815           0 : bool CWallet::SetAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id, const std::string& value)
    2816             : {
    2817           0 :     if (!batch.WriteAddressReceiveRequest(dest, id, value)) return false;
    2818           0 :     m_address_book[dest].receive_requests[id] = value;
    2819           0 :     return true;
    2820           0 : }
    2821             : 
    2822           0 : bool CWallet::EraseAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id)
    2823             : {
    2824           0 :     if (!batch.EraseAddressReceiveRequest(dest, id)) return false;
    2825           0 :     m_address_book[dest].receive_requests.erase(id);
    2826           0 :     return true;
    2827           0 : }
    2828             : 
    2829           0 : std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error_string)
    2830             : {
    2831             :     // Do some checking on wallet path. It should be either a:
    2832             :     //
    2833             :     // 1. Path where a directory can be created.
    2834             :     // 2. Path to an existing directory.
    2835             :     // 3. Path to a symlink to a directory.
    2836             :     // 4. For backwards compatibility, the name of a data file in -walletdir.
    2837           0 :     const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(name));
    2838           0 :     fs::file_type path_type = fs::symlink_status(wallet_path).type();
    2839           0 :     if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory ||
    2840           0 :           (path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) ||
    2841           0 :           (path_type == fs::file_type::regular && fs::PathFromString(name).filename() == fs::PathFromString(name)))) {
    2842           0 :         error_string = Untranslated(strprintf(
    2843             :               "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
    2844             :               "database/log.?????????? files can be stored, a location where such a directory could be created, "
    2845             :               "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
    2846           0 :               name, fs::quoted(fs::PathToString(GetWalletDir()))));
    2847           0 :         status = DatabaseStatus::FAILED_BAD_PATH;
    2848           0 :         return nullptr;
    2849             :     }
    2850           0 :     return MakeDatabase(wallet_path, options, status, error_string);
    2851           0 : }
    2852             : 
    2853           0 : std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings)
    2854             : {
    2855           0 :     interfaces::Chain* chain = context.chain;
    2856           0 :     ArgsManager& args = *Assert(context.args);
    2857           0 :     const std::string& walletFile = database->Filename();
    2858             : 
    2859           0 :     const auto start{SteadyClock::now()};
    2860             :     // TODO: Can't use std::make_shared because we need a custom deleter but
    2861             :     // should be possible to use std::allocate_shared.
    2862           0 :     std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, std::move(database)), ReleaseWallet);
    2863           0 :     walletInstance->m_keypool_size = std::max(args.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), int64_t{1});
    2864           0 :     walletInstance->m_notify_tx_changed_script = args.GetArg("-walletnotify", "");
    2865             : 
    2866             :     // Load wallet
    2867           0 :     bool rescan_required = false;
    2868           0 :     DBErrors nLoadWalletRet = walletInstance->LoadWallet();
    2869           0 :     if (nLoadWalletRet != DBErrors::LOAD_OK) {
    2870           0 :         if (nLoadWalletRet == DBErrors::CORRUPT) {
    2871           0 :             error = strprintf(_("Error loading %s: Wallet corrupted"), walletFile);
    2872           0 :             return nullptr;
    2873             :         }
    2874           0 :         else if (nLoadWalletRet == DBErrors::NONCRITICAL_ERROR)
    2875             :         {
    2876           0 :             warnings.push_back(strprintf(_("Error reading %s! All keys read correctly, but transaction data"
    2877             :                                            " or address metadata may be missing or incorrect."),
    2878           0 :                 walletFile));
    2879           0 :         }
    2880           0 :         else if (nLoadWalletRet == DBErrors::TOO_NEW) {
    2881           0 :             error = strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, PACKAGE_NAME);
    2882           0 :             return nullptr;
    2883             :         }
    2884           0 :         else if (nLoadWalletRet == DBErrors::EXTERNAL_SIGNER_SUPPORT_REQUIRED) {
    2885           0 :             error = strprintf(_("Error loading %s: External signer wallet being loaded without external signer support compiled"), walletFile);
    2886           0 :             return nullptr;
    2887             :         }
    2888           0 :         else if (nLoadWalletRet == DBErrors::NEED_REWRITE)
    2889             :         {
    2890           0 :             error = strprintf(_("Wallet needed to be rewritten: restart %s to complete"), PACKAGE_NAME);
    2891           0 :             return nullptr;
    2892           0 :         } else if (nLoadWalletRet == DBErrors::NEED_RESCAN) {
    2893           0 :             warnings.push_back(strprintf(_("Error reading %s! Transaction data may be missing or incorrect."
    2894           0 :                                            " Rescanning wallet."), walletFile));
    2895           0 :             rescan_required = true;
    2896           0 :         } else if (nLoadWalletRet == DBErrors::UNKNOWN_DESCRIPTOR) {
    2897           0 :             error = strprintf(_("Unrecognized descriptor found. Loading wallet %s\n\n"
    2898             :                                 "The wallet might had been created on a newer version.\n"
    2899           0 :                                 "Please try running the latest software version.\n"), walletFile);
    2900           0 :             return nullptr;
    2901           0 :         } else if (nLoadWalletRet == DBErrors::UNEXPECTED_LEGACY_ENTRY) {
    2902           0 :             error = strprintf(_("Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
    2903           0 :                                 "The wallet might have been tampered with or created with malicious intent.\n"), walletFile);
    2904           0 :             return nullptr;
    2905             :         } else {
    2906           0 :             error = strprintf(_("Error loading %s"), walletFile);
    2907           0 :             return nullptr;
    2908             :         }
    2909           0 :     }
    2910             : 
    2911             :     // This wallet is in its first run if there are no ScriptPubKeyMans and it isn't blank or no privkeys
    2912           0 :     const bool fFirstRun = walletInstance->m_spk_managers.empty() &&
    2913           0 :                      !walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) &&
    2914           0 :                      !walletInstance->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET);
    2915           0 :     if (fFirstRun)
    2916             :     {
    2917             :         // ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
    2918           0 :         walletInstance->SetMinVersion(FEATURE_LATEST);
    2919             : 
    2920           0 :         walletInstance->InitWalletFlags(wallet_creation_flags);
    2921             : 
    2922             :         // Only create LegacyScriptPubKeyMan when not descriptor wallet
    2923           0 :         if (!walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
    2924           0 :             walletInstance->SetupLegacyScriptPubKeyMan();
    2925           0 :         }
    2926             : 
    2927           0 :         if ((wallet_creation_flags & WALLET_FLAG_EXTERNAL_SIGNER) || !(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
    2928           0 :             LOCK(walletInstance->cs_wallet);
    2929           0 :             if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
    2930           0 :                 walletInstance->SetupDescriptorScriptPubKeyMans();
    2931             :                 // SetupDescriptorScriptPubKeyMans already calls SetupGeneration for us so we don't need to call SetupGeneration separately
    2932           0 :             } else {
    2933             :                 // Legacy wallets need SetupGeneration here.
    2934           0 :                 for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
    2935           0 :                     if (!spk_man->SetupGeneration()) {
    2936           0 :                         error = _("Unable to generate initial keys");
    2937           0 :                         return nullptr;
    2938             :                     }
    2939             :                 }
    2940             :             }
    2941           0 :         }
    2942             : 
    2943           0 :         if (chain) {
    2944           0 :             walletInstance->chainStateFlushed(chain->getTipLocator());
    2945           0 :         }
    2946           0 :     } else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) {
    2947             :         // Make it impossible to disable private keys after creation
    2948           0 :         error = strprintf(_("Error loading %s: Private keys can only be disabled during creation"), walletFile);
    2949           0 :         return nullptr;
    2950           0 :     } else if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
    2951           0 :         for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
    2952           0 :             if (spk_man->HavePrivateKeys()) {
    2953           0 :                 warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
    2954           0 :                 break;
    2955             :             }
    2956             :         }
    2957           0 :     }
    2958             : 
    2959           0 :     if (!args.GetArg("-addresstype", "").empty()) {
    2960           0 :         std::optional<OutputType> parsed = ParseOutputType(args.GetArg("-addresstype", ""));
    2961           0 :         if (!parsed) {
    2962           0 :             error = strprintf(_("Unknown address type '%s'"), args.GetArg("-addresstype", ""));
    2963           0 :             return nullptr;
    2964             :         }
    2965           0 :         walletInstance->m_default_address_type = parsed.value();
    2966           0 :     }
    2967             : 
    2968           0 :     if (!args.GetArg("-changetype", "").empty()) {
    2969           0 :         std::optional<OutputType> parsed = ParseOutputType(args.GetArg("-changetype", ""));
    2970           0 :         if (!parsed) {
    2971           0 :             error = strprintf(_("Unknown change type '%s'"), args.GetArg("-changetype", ""));
    2972           0 :             return nullptr;
    2973             :         }
    2974           0 :         walletInstance->m_default_change_type = parsed.value();
    2975           0 :     }
    2976             : 
    2977           0 :     if (args.IsArgSet("-mintxfee")) {
    2978           0 :         std::optional<CAmount> min_tx_fee = ParseMoney(args.GetArg("-mintxfee", ""));
    2979           0 :         if (!min_tx_fee) {
    2980           0 :             error = AmountErrMsg("mintxfee", args.GetArg("-mintxfee", ""));
    2981           0 :             return nullptr;
    2982           0 :         } else if (min_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
    2983           0 :             warnings.push_back(AmountHighWarn("-mintxfee") + Untranslated(" ") +
    2984           0 :                                _("This is the minimum transaction fee you pay on every transaction."));
    2985           0 :         }
    2986             : 
    2987           0 :         walletInstance->m_min_fee = CFeeRate{min_tx_fee.value()};
    2988           0 :     }
    2989             : 
    2990           0 :     if (args.IsArgSet("-maxapsfee")) {
    2991           0 :         const std::string max_aps_fee{args.GetArg("-maxapsfee", "")};
    2992           0 :         if (max_aps_fee == "-1") {
    2993           0 :             walletInstance->m_max_aps_fee = -1;
    2994           0 :         } else if (std::optional<CAmount> max_fee = ParseMoney(max_aps_fee)) {
    2995           0 :             if (max_fee.value() > HIGH_APS_FEE) {
    2996           0 :                 warnings.push_back(AmountHighWarn("-maxapsfee") + Untranslated(" ") +
    2997           0 :                                   _("This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
    2998           0 :             }
    2999           0 :             walletInstance->m_max_aps_fee = max_fee.value();
    3000           0 :         } else {
    3001           0 :             error = AmountErrMsg("maxapsfee", max_aps_fee);
    3002           0 :             return nullptr;
    3003             :         }
    3004           0 :     }
    3005             : 
    3006           0 :     if (args.IsArgSet("-fallbackfee")) {
    3007           0 :         std::optional<CAmount> fallback_fee = ParseMoney(args.GetArg("-fallbackfee", ""));
    3008           0 :         if (!fallback_fee) {
    3009           0 :             error = strprintf(_("Invalid amount for %s=<amount>: '%s'"), "-fallbackfee", args.GetArg("-fallbackfee", ""));
    3010           0 :             return nullptr;
    3011           0 :         } else if (fallback_fee.value() > HIGH_TX_FEE_PER_KB) {
    3012           0 :             warnings.push_back(AmountHighWarn("-fallbackfee") + Untranslated(" ") +
    3013           0 :                                _("This is the transaction fee you may pay when fee estimates are not available."));
    3014           0 :         }
    3015           0 :         walletInstance->m_fallback_fee = CFeeRate{fallback_fee.value()};
    3016           0 :     }
    3017             : 
    3018             :     // Disable fallback fee in case value was set to 0, enable if non-null value
    3019           0 :     walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.GetFeePerK() != 0;
    3020             : 
    3021           0 :     if (args.IsArgSet("-discardfee")) {
    3022           0 :         std::optional<CAmount> discard_fee = ParseMoney(args.GetArg("-discardfee", ""));
    3023           0 :         if (!discard_fee) {
    3024           0 :             error = strprintf(_("Invalid amount for %s=<amount>: '%s'"), "-discardfee", args.GetArg("-discardfee", ""));
    3025           0 :             return nullptr;
    3026           0 :         } else if (discard_fee.value() > HIGH_TX_FEE_PER_KB) {
    3027           0 :             warnings.push_back(AmountHighWarn("-discardfee") + Untranslated(" ") +
    3028           0 :                                _("This is the transaction fee you may discard if change is smaller than dust at this level"));
    3029           0 :         }
    3030           0 :         walletInstance->m_discard_rate = CFeeRate{discard_fee.value()};
    3031           0 :     }
    3032             : 
    3033           0 :     if (args.IsArgSet("-paytxfee")) {
    3034           0 :         std::optional<CAmount> pay_tx_fee = ParseMoney(args.GetArg("-paytxfee", ""));
    3035           0 :         if (!pay_tx_fee) {
    3036           0 :             error = AmountErrMsg("paytxfee", args.GetArg("-paytxfee", ""));
    3037           0 :             return nullptr;
    3038           0 :         } else if (pay_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
    3039           0 :             warnings.push_back(AmountHighWarn("-paytxfee") + Untranslated(" ") +
    3040           0 :                                _("This is the transaction fee you will pay if you send a transaction."));
    3041           0 :         }
    3042             : 
    3043           0 :         walletInstance->m_pay_tx_fee = CFeeRate{pay_tx_fee.value(), 1000};
    3044             : 
    3045           0 :         if (chain && walletInstance->m_pay_tx_fee < chain->relayMinFee()) {
    3046           0 :             error = strprintf(_("Invalid amount for %s=<amount>: '%s' (must be at least %s)"),
    3047           0 :                 "-paytxfee", args.GetArg("-paytxfee", ""), chain->relayMinFee().ToString());
    3048           0 :             return nullptr;
    3049             :         }
    3050           0 :     }
    3051             : 
    3052           0 :     if (args.IsArgSet("-maxtxfee")) {
    3053           0 :         std::optional<CAmount> max_fee = ParseMoney(args.GetArg("-maxtxfee", ""));
    3054           0 :         if (!max_fee) {
    3055           0 :             error = AmountErrMsg("maxtxfee", args.GetArg("-maxtxfee", ""));
    3056           0 :             return nullptr;
    3057           0 :         } else if (max_fee.value() > HIGH_MAX_TX_FEE) {
    3058           0 :             warnings.push_back(strprintf(_("%s is set very high! Fees this large could be paid on a single transaction."), "-maxtxfee"));
    3059           0 :         }
    3060             : 
    3061           0 :         if (chain && CFeeRate{max_fee.value(), 1000} < chain->relayMinFee()) {
    3062           0 :             error = strprintf(_("Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
    3063           0 :                 "-maxtxfee", args.GetArg("-maxtxfee", ""), chain->relayMinFee().ToString());
    3064           0 :             return nullptr;
    3065             :         }
    3066             : 
    3067           0 :         walletInstance->m_default_max_tx_fee = max_fee.value();
    3068           0 :     }
    3069             : 
    3070           0 :     if (args.IsArgSet("-consolidatefeerate")) {
    3071           0 :         if (std::optional<CAmount> consolidate_feerate = ParseMoney(args.GetArg("-consolidatefeerate", ""))) {
    3072           0 :             walletInstance->m_consolidate_feerate = CFeeRate(*consolidate_feerate);
    3073           0 :         } else {
    3074           0 :             error = AmountErrMsg("consolidatefeerate", args.GetArg("-consolidatefeerate", ""));
    3075           0 :             return nullptr;
    3076             :         }
    3077           0 :     }
    3078             : 
    3079           0 :     if (chain && chain->relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) {
    3080           0 :         warnings.push_back(AmountHighWarn("-minrelaytxfee") + Untranslated(" ") +
    3081           0 :                            _("The wallet will avoid paying less than the minimum relay fee."));
    3082           0 :     }
    3083             : 
    3084           0 :     walletInstance->m_confirm_target = args.GetIntArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
    3085           0 :     walletInstance->m_spend_zero_conf_change = args.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
    3086           0 :     walletInstance->m_signal_rbf = args.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
    3087             : 
    3088           0 :     walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
    3089             : 
    3090             :     // Try to top up keypool. No-op if the wallet is locked.
    3091           0 :     walletInstance->TopUpKeyPool();
    3092             : 
    3093             :     // Cache the first key time
    3094           0 :     std::optional<int64_t> time_first_key;
    3095           0 :     for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
    3096           0 :         int64_t time = spk_man->GetTimeFirstKey();
    3097           0 :         if (!time_first_key || time < *time_first_key) time_first_key = time;
    3098             :     }
    3099           0 :     if (time_first_key) walletInstance->m_birth_time = *time_first_key;
    3100             : 
    3101           0 :     if (chain && !AttachChain(walletInstance, *chain, rescan_required, error, warnings)) {
    3102           0 :         return nullptr;
    3103             :     }
    3104             : 
    3105             :     {
    3106           0 :         LOCK(walletInstance->cs_wallet);
    3107           0 :         walletInstance->SetBroadcastTransactions(args.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
    3108           0 :         walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n",      walletInstance->GetKeyPoolSize());
    3109           0 :         walletInstance->WalletLogPrintf("mapWallet.size() = %u\n",       walletInstance->mapWallet.size());
    3110           0 :         walletInstance->WalletLogPrintf("m_address_book.size() = %u\n",  walletInstance->m_address_book.size());
    3111           0 :     }
    3112             : 
    3113           0 :     return walletInstance;
    3114           0 : }
    3115             : 
    3116           0 : bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interfaces::Chain& chain, const bool rescan_required, bilingual_str& error, std::vector<bilingual_str>& warnings)
    3117             : {
    3118           0 :     LOCK(walletInstance->cs_wallet);
    3119             :     // allow setting the chain if it hasn't been set already but prevent changing it
    3120           0 :     assert(!walletInstance->m_chain || walletInstance->m_chain == &chain);
    3121           0 :     walletInstance->m_chain = &chain;
    3122             : 
    3123             :     // Unless allowed, ensure wallet files are not reused across chains:
    3124           0 :     if (!gArgs.GetBoolArg("-walletcrosschain", DEFAULT_WALLETCROSSCHAIN)) {
    3125           0 :         WalletBatch batch(walletInstance->GetDatabase());
    3126           0 :         CBlockLocator locator;
    3127           0 :         if (batch.ReadBestBlock(locator) && locator.vHave.size() > 0 && chain.getHeight()) {
    3128             :             // Wallet is assumed to be from another chain, if genesis block in the active
    3129             :             // chain differs from the genesis block known to the wallet.
    3130           0 :             if (chain.getBlockHash(0) != locator.vHave.back()) {
    3131           0 :                 error = Untranslated("Wallet files should not be reused across chains. Restart bitcoind with -walletcrosschain to override.");
    3132           0 :                 return false;
    3133             :             }
    3134           0 :         }
    3135           0 :     }
    3136             : 
    3137             :     // Register wallet with validationinterface. It's done before rescan to avoid
    3138             :     // missing block connections between end of rescan and validation subscribing.
    3139             :     // Because of wallet lock being hold, block connection notifications are going to
    3140             :     // be pending on the validation-side until lock release. It's likely to have
    3141             :     // block processing duplicata (if rescan block range overlaps with notification one)
    3142             :     // but we guarantee at least than wallet state is correct after notifications delivery.
    3143             :     // However, chainStateFlushed notifications are ignored until the rescan is finished
    3144             :     // so that in case of a shutdown event, the rescan will be repeated at the next start.
    3145             :     // This is temporary until rescan and notifications delivery are unified under same
    3146             :     // interface.
    3147           0 :     walletInstance->m_attaching_chain = true; //ignores chainStateFlushed notifications
    3148           0 :     walletInstance->m_chain_notifications_handler = walletInstance->chain().handleNotifications(walletInstance);
    3149             : 
    3150             :     // If rescan_required = true, rescan_height remains equal to 0
    3151           0 :     int rescan_height = 0;
    3152           0 :     if (!rescan_required)
    3153             :     {
    3154           0 :         WalletBatch batch(walletInstance->GetDatabase());
    3155           0 :         CBlockLocator locator;
    3156           0 :         if (batch.ReadBestBlock(locator)) {
    3157           0 :             if (const std::optional<int> fork_height = chain.findLocatorFork(locator)) {
    3158           0 :                 rescan_height = *fork_height;
    3159           0 :             }
    3160           0 :         }
    3161           0 :     }
    3162             : 
    3163           0 :     const std::optional<int> tip_height = chain.getHeight();
    3164           0 :     if (tip_height) {
    3165           0 :         walletInstance->m_last_block_processed = chain.getBlockHash(*tip_height);
    3166           0 :         walletInstance->m_last_block_processed_height = *tip_height;
    3167           0 :     } else {
    3168           0 :         walletInstance->m_last_block_processed.SetNull();
    3169           0 :         walletInstance->m_last_block_processed_height = -1;
    3170             :     }
    3171             : 
    3172           0 :     if (tip_height && *tip_height != rescan_height)
    3173             :     {
    3174             :         // No need to read and scan block if block was created before
    3175             :         // our wallet birthday (as adjusted for block time variability)
    3176           0 :         std::optional<int64_t> time_first_key = walletInstance->m_birth_time.load();
    3177           0 :         if (time_first_key) {
    3178           0 :             FoundBlock found = FoundBlock().height(rescan_height);
    3179           0 :             chain.findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height, found);
    3180           0 :             if (!found.found) {
    3181             :                 // We were unable to find a block that had a time more recent than our earliest timestamp
    3182             :                 // or a height higher than the wallet was synced to, indicating that the wallet is newer than the
    3183             :                 // current chain tip. Skip rescanning in this case.
    3184           0 :                 rescan_height = *tip_height;
    3185           0 :             }
    3186           0 :         }
    3187             : 
    3188             :         // Technically we could execute the code below in any case, but performing the
    3189             :         // `while` loop below can make startup very slow, so only check blocks on disk
    3190             :         // if necessary.
    3191           0 :         if (chain.havePruned() || chain.hasAssumedValidChain()) {
    3192           0 :             int block_height = *tip_height;
    3193           0 :             while (block_height > 0 && chain.haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
    3194           0 :                 --block_height;
    3195             :             }
    3196             : 
    3197           0 :             if (rescan_height != block_height) {
    3198             :                 // We can't rescan beyond blocks we don't have data for, stop and throw an error.
    3199             :                 // This might happen if a user uses an old wallet within a pruned node
    3200             :                 // or if they ran -disablewallet for a longer time, then decided to re-enable
    3201             :                 // Exit early and print an error.
    3202             :                 // It also may happen if an assumed-valid chain is in use and therefore not
    3203             :                 // all block data is available.
    3204             :                 // If a block is pruned after this check, we will load the wallet,
    3205             :                 // but fail the rescan with a generic error.
    3206             : 
    3207           0 :                 error = chain.havePruned() ?
    3208           0 :                      _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)") :
    3209           0 :                      strprintf(_(
    3210             :                         "Error loading wallet. Wallet requires blocks to be downloaded, "
    3211             :                         "and software does not currently support loading wallets while "
    3212             :                         "blocks are being downloaded out of order when using assumeutxo "
    3213             :                         "snapshots. Wallet should be able to load successfully after "
    3214             :                         "node sync reaches height %s"), block_height);
    3215           0 :                 return false;
    3216             :             }
    3217           0 :         }
    3218             : 
    3219           0 :         chain.initMessage(_("Rescanning…").translated);
    3220           0 :         walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
    3221             : 
    3222             :         {
    3223           0 :             WalletRescanReserver reserver(*walletInstance);
    3224           0 :             if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(chain.getBlockHash(rescan_height), rescan_height, /*max_height=*/{}, reserver, /*fUpdate=*/true, /*save_progress=*/true).status)) {
    3225           0 :                 error = _("Failed to rescan the wallet during initialization");
    3226           0 :                 return false;
    3227             :             }
    3228           0 :         }
    3229           0 :         walletInstance->m_attaching_chain = false;
    3230           0 :         walletInstance->chainStateFlushed(chain.getTipLocator());
    3231           0 :         walletInstance->GetDatabase().IncrementUpdateCounter();
    3232           0 :     }
    3233           0 :     walletInstance->m_attaching_chain = false;
    3234             : 
    3235           0 :     return true;
    3236           0 : }
    3237             : 
    3238           0 : const CAddressBookData* CWallet::FindAddressBookEntry(const CTxDestination& dest, bool allow_change) const
    3239             : {
    3240           0 :     const auto& address_book_it = m_address_book.find(dest);
    3241           0 :     if (address_book_it == m_address_book.end()) return nullptr;
    3242           0 :     if ((!allow_change) && address_book_it->second.IsChange()) {
    3243           0 :         return nullptr;
    3244             :     }
    3245           0 :     return &address_book_it->second;
    3246           0 : }
    3247             : 
    3248           0 : bool CWallet::UpgradeWallet(int version, bilingual_str& error)
    3249             : {
    3250           0 :     int prev_version = GetVersion();
    3251           0 :     if (version == 0) {
    3252           0 :         WalletLogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
    3253           0 :         version = FEATURE_LATEST;
    3254           0 :     } else {
    3255           0 :         WalletLogPrintf("Allowing wallet upgrade up to %i\n", version);
    3256             :     }
    3257           0 :     if (version < prev_version) {
    3258           0 :         error = strprintf(_("Cannot downgrade wallet from version %i to version %i. Wallet version unchanged."), prev_version, version);
    3259           0 :         return false;
    3260             :     }
    3261             : 
    3262           0 :     LOCK(cs_wallet);
    3263             : 
    3264             :     // Do not upgrade versions to any version between HD_SPLIT and FEATURE_PRE_SPLIT_KEYPOOL unless already supporting HD_SPLIT
    3265           0 :     if (!CanSupportFeature(FEATURE_HD_SPLIT) && version >= FEATURE_HD_SPLIT && version < FEATURE_PRE_SPLIT_KEYPOOL) {
    3266           0 :         error = strprintf(_("Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified."), prev_version, version, FEATURE_PRE_SPLIT_KEYPOOL);
    3267           0 :         return false;
    3268             :     }
    3269             : 
    3270             :     // Permanently upgrade to the version
    3271           0 :     SetMinVersion(GetClosestWalletFeature(version));
    3272             : 
    3273           0 :     for (auto spk_man : GetActiveScriptPubKeyMans()) {
    3274           0 :         if (!spk_man->Upgrade(prev_version, version, error)) {
    3275           0 :             return false;
    3276             :         }
    3277             :     }
    3278           0 :     return true;
    3279           0 : }
    3280             : 
    3281           0 : void CWallet::postInitProcess()
    3282             : {
    3283             :     // Add wallet transactions that aren't already in a block to mempool
    3284             :     // Do this here as mempool requires genesis block to be loaded
    3285           0 :     ResubmitWalletTransactions(/*relay=*/false, /*force=*/true);
    3286             : 
    3287             :     // Update wallet transactions with current mempool transactions.
    3288           0 :     WITH_LOCK(cs_wallet, chain().requestMempoolTransactions(*this));
    3289           0 : }
    3290             : 
    3291           0 : bool CWallet::BackupWallet(const std::string& strDest) const
    3292             : {
    3293           0 :     return GetDatabase().Backup(strDest);
    3294             : }
    3295             : 
    3296           0 : CKeyPool::CKeyPool()
    3297             : {
    3298           0 :     nTime = GetTime();
    3299           0 :     fInternal = false;
    3300           0 :     m_pre_split = false;
    3301           0 : }
    3302             : 
    3303           0 : CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn)
    3304             : {
    3305           0 :     nTime = GetTime();
    3306           0 :     vchPubKey = vchPubKeyIn;
    3307           0 :     fInternal = internalIn;
    3308           0 :     m_pre_split = false;
    3309           0 : }
    3310             : 
    3311           0 : int CWallet::GetTxDepthInMainChain(const CWalletTx& wtx) const
    3312             : {
    3313           0 :     AssertLockHeld(cs_wallet);
    3314           0 :     if (auto* conf = wtx.state<TxStateConfirmed>()) {
    3315           0 :         return GetLastBlockHeight() - conf->confirmed_block_height + 1;
    3316           0 :     } else if (auto* conf = wtx.state<TxStateConflicted>()) {
    3317           0 :         return -1 * (GetLastBlockHeight() - conf->conflicting_block_height + 1);
    3318             :     } else {
    3319           0 :         return 0;
    3320             :     }
    3321           0 : }
    3322             : 
    3323           0 : int CWallet::GetTxBlocksToMaturity(const CWalletTx& wtx) const
    3324             : {
    3325           0 :     AssertLockHeld(cs_wallet);
    3326             : 
    3327           0 :     if (!wtx.IsCoinBase()) {
    3328           0 :         return 0;
    3329             :     }
    3330           0 :     int chain_depth = GetTxDepthInMainChain(wtx);
    3331           0 :     assert(chain_depth >= 0); // coinbase tx should not be conflicted
    3332           0 :     return std::max(0, (COINBASE_MATURITY+1) - chain_depth);
    3333           0 : }
    3334             : 
    3335           0 : bool CWallet::IsTxImmatureCoinBase(const CWalletTx& wtx) const
    3336             : {
    3337           0 :     AssertLockHeld(cs_wallet);
    3338             : 
    3339             :     // note GetBlocksToMaturity is 0 for non-coinbase tx
    3340           0 :     return GetTxBlocksToMaturity(wtx) > 0;
    3341             : }
    3342             : 
    3343           0 : bool CWallet::IsCrypted() const
    3344             : {
    3345           0 :     return HasEncryptionKeys();
    3346             : }
    3347             : 
    3348           0 : bool CWallet::IsLocked() const
    3349             : {
    3350           0 :     if (!IsCrypted()) {
    3351           0 :         return false;
    3352             :     }
    3353           0 :     LOCK(cs_wallet);
    3354           0 :     return vMasterKey.empty();
    3355           0 : }
    3356             : 
    3357           0 : bool CWallet::Lock()
    3358             : {
    3359           0 :     if (!IsCrypted())
    3360           0 :         return false;
    3361             : 
    3362             :     {
    3363           0 :         LOCK2(m_relock_mutex, cs_wallet);
    3364           0 :         if (!vMasterKey.empty()) {
    3365           0 :             memory_cleanse(vMasterKey.data(), vMasterKey.size() * sizeof(decltype(vMasterKey)::value_type));
    3366           0 :             vMasterKey.clear();
    3367           0 :         }
    3368           0 :     }
    3369             : 
    3370           0 :     NotifyStatusChanged(this);
    3371           0 :     return true;
    3372           0 : }
    3373             : 
    3374           0 : bool CWallet::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys)
    3375             : {
    3376             :     {
    3377           0 :         LOCK(cs_wallet);
    3378           0 :         for (const auto& spk_man_pair : m_spk_managers) {
    3379           0 :             if (!spk_man_pair.second->CheckDecryptionKey(vMasterKeyIn, accept_no_keys)) {
    3380           0 :                 return false;
    3381             :             }
    3382             :         }
    3383           0 :         vMasterKey = vMasterKeyIn;
    3384           0 :     }
    3385           0 :     NotifyStatusChanged(this);
    3386           0 :     return true;
    3387           0 : }
    3388             : 
    3389           0 : std::set<ScriptPubKeyMan*> CWallet::GetActiveScriptPubKeyMans() const
    3390             : {
    3391           0 :     std::set<ScriptPubKeyMan*> spk_mans;
    3392           0 :     for (bool internal : {false, true}) {
    3393           0 :         for (OutputType t : OUTPUT_TYPES) {
    3394           0 :             auto spk_man = GetScriptPubKeyMan(t, internal);
    3395           0 :             if (spk_man) {
    3396           0 :                 spk_mans.insert(spk_man);
    3397           0 :             }
    3398             :         }
    3399             :     }
    3400           0 :     return spk_mans;
    3401           0 : }
    3402             : 
    3403           0 : std::set<ScriptPubKeyMan*> CWallet::GetAllScriptPubKeyMans() const
    3404             : {
    3405           0 :     std::set<ScriptPubKeyMan*> spk_mans;
    3406           0 :     for (const auto& spk_man_pair : m_spk_managers) {
    3407           0 :         spk_mans.insert(spk_man_pair.second.get());
    3408             :     }
    3409           0 :     return spk_mans;
    3410           0 : }
    3411             : 
    3412           0 : ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const OutputType& type, bool internal) const
    3413             : {
    3414           0 :     const std::map<OutputType, ScriptPubKeyMan*>& spk_managers = internal ? m_internal_spk_managers : m_external_spk_managers;
    3415           0 :     std::map<OutputType, ScriptPubKeyMan*>::const_iterator it = spk_managers.find(type);
    3416           0 :     if (it == spk_managers.end()) {
    3417           0 :         return nullptr;
    3418             :     }
    3419           0 :     return it->second;
    3420           0 : }
    3421             : 
    3422           0 : std::set<ScriptPubKeyMan*> CWallet::GetScriptPubKeyMans(const CScript& script) const
    3423             : {
    3424           0 :     std::set<ScriptPubKeyMan*> spk_mans;
    3425           0 :     SignatureData sigdata;
    3426           0 :     for (const auto& spk_man_pair : m_spk_managers) {
    3427           0 :         if (spk_man_pair.second->CanProvide(script, sigdata)) {
    3428           0 :             spk_mans.insert(spk_man_pair.second.get());
    3429           0 :         }
    3430             :     }
    3431           0 :     return spk_mans;
    3432           0 : }
    3433             : 
    3434           0 : ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const uint256& id) const
    3435             : {
    3436           0 :     if (m_spk_managers.count(id) > 0) {
    3437           0 :         return m_spk_managers.at(id).get();
    3438             :     }
    3439           0 :     return nullptr;
    3440           0 : }
    3441             : 
    3442           0 : std::unique_ptr<SigningProvider> CWallet::GetSolvingProvider(const CScript& script) const
    3443             : {
    3444           0 :     SignatureData sigdata;
    3445           0 :     return GetSolvingProvider(script, sigdata);
    3446           0 : }
    3447             : 
    3448           0 : std::unique_ptr<SigningProvider> CWallet::GetSolvingProvider(const CScript& script, SignatureData& sigdata) const
    3449             : {
    3450           0 :     for (const auto& spk_man_pair : m_spk_managers) {
    3451           0 :         if (spk_man_pair.second->CanProvide(script, sigdata)) {
    3452           0 :             return spk_man_pair.second->GetSolvingProvider(script);
    3453             :         }
    3454             :     }
    3455           0 :     return nullptr;
    3456           0 : }
    3457             : 
    3458           0 : std::vector<WalletDescriptor> CWallet::GetWalletDescriptors(const CScript& script) const
    3459             : {
    3460           0 :     std::vector<WalletDescriptor> descs;
    3461           0 :     for (const auto spk_man: GetScriptPubKeyMans(script)) {
    3462           0 :         if (const auto desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man)) {
    3463           0 :             LOCK(desc_spk_man->cs_desc_man);
    3464           0 :             descs.push_back(desc_spk_man->GetWalletDescriptor());
    3465           0 :         }
    3466             :     }
    3467           0 :     return descs;
    3468           0 : }
    3469             : 
    3470           0 : LegacyScriptPubKeyMan* CWallet::GetLegacyScriptPubKeyMan() const
    3471             : {
    3472           0 :     if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
    3473           0 :         return nullptr;
    3474             :     }
    3475             :     // Legacy wallets only have one ScriptPubKeyMan which is a LegacyScriptPubKeyMan.
    3476             :     // Everything in m_internal_spk_managers and m_external_spk_managers point to the same legacyScriptPubKeyMan.
    3477           0 :     auto it = m_internal_spk_managers.find(OutputType::LEGACY);
    3478           0 :     if (it == m_internal_spk_managers.end()) return nullptr;
    3479           0 :     return dynamic_cast<LegacyScriptPubKeyMan*>(it->second);
    3480           0 : }
    3481             : 
    3482           0 : LegacyScriptPubKeyMan* CWallet::GetOrCreateLegacyScriptPubKeyMan()
    3483             : {
    3484           0 :     SetupLegacyScriptPubKeyMan();
    3485           0 :     return GetLegacyScriptPubKeyMan();
    3486             : }
    3487             : 
    3488           0 : void CWallet::AddScriptPubKeyMan(const uint256& id, std::unique_ptr<ScriptPubKeyMan> spkm_man)
    3489             : {
    3490           0 :     const auto& spkm = m_spk_managers[id] = std::move(spkm_man);
    3491             : 
    3492             :     // Update birth time if needed
    3493           0 :     FirstKeyTimeChanged(spkm.get(), spkm->GetTimeFirstKey());
    3494           0 : }
    3495             : 
    3496           0 : void CWallet::SetupLegacyScriptPubKeyMan()
    3497             : {
    3498           0 :     if (!m_internal_spk_managers.empty() || !m_external_spk_managers.empty() || !m_spk_managers.empty() || IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
    3499           0 :         return;
    3500             :     }
    3501             : 
    3502           0 :     auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new LegacyScriptPubKeyMan(*this, m_keypool_size));
    3503           0 :     for (const auto& type : LEGACY_OUTPUT_TYPES) {
    3504           0 :         m_internal_spk_managers[type] = spk_manager.get();
    3505           0 :         m_external_spk_managers[type] = spk_manager.get();
    3506             :     }
    3507           0 :     uint256 id = spk_manager->GetID();
    3508           0 :     AddScriptPubKeyMan(id, std::move(spk_manager));
    3509           0 : }
    3510             : 
    3511           0 : const CKeyingMaterial& CWallet::GetEncryptionKey() const
    3512             : {
    3513           0 :     return vMasterKey;
    3514             : }
    3515             : 
    3516           0 : bool CWallet::HasEncryptionKeys() const
    3517             : {
    3518           0 :     return !mapMasterKeys.empty();
    3519             : }
    3520             : 
    3521           0 : void CWallet::ConnectScriptPubKeyManNotifiers()
    3522             : {
    3523           0 :     for (const auto& spk_man : GetActiveScriptPubKeyMans()) {
    3524           0 :         spk_man->NotifyWatchonlyChanged.connect(NotifyWatchonlyChanged);
    3525           0 :         spk_man->NotifyCanGetAddressesChanged.connect(NotifyCanGetAddressesChanged);
    3526           0 :         spk_man->NotifyFirstKeyTimeChanged.connect(std::bind(&CWallet::FirstKeyTimeChanged, this, std::placeholders::_1, std::placeholders::_2));
    3527             :     }
    3528           0 : }
    3529             : 
    3530           0 : void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc)
    3531             : {
    3532           0 :     if (IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
    3533           0 :         auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, desc, m_keypool_size));
    3534           0 :         AddScriptPubKeyMan(id, std::move(spk_manager));
    3535           0 :     } else {
    3536           0 :         auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc, m_keypool_size));
    3537           0 :         AddScriptPubKeyMan(id, std::move(spk_manager));
    3538           0 :     }
    3539           0 : }
    3540             : 
    3541           0 : void CWallet::SetupDescriptorScriptPubKeyMans(const CExtKey& master_key)
    3542             : {
    3543           0 :     AssertLockHeld(cs_wallet);
    3544             : 
    3545           0 :     for (bool internal : {false, true}) {
    3546           0 :         for (OutputType t : OUTPUT_TYPES) {
    3547           0 :             auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, m_keypool_size));
    3548           0 :             if (IsCrypted()) {
    3549           0 :                 if (IsLocked()) {
    3550           0 :                     throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
    3551             :                 }
    3552           0 :                 if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, nullptr)) {
    3553           0 :                     throw std::runtime_error(std::string(__func__) + ": Could not encrypt new descriptors");
    3554             :                 }
    3555           0 :             }
    3556           0 :             spk_manager->SetupDescriptorGeneration(master_key, t, internal);
    3557           0 :             uint256 id = spk_manager->GetID();
    3558           0 :             AddScriptPubKeyMan(id, std::move(spk_manager));
    3559           0 :             AddActiveScriptPubKeyMan(id, t, internal);
    3560           0 :         }
    3561             :     }
    3562           0 : }
    3563             : 
    3564           0 : void CWallet::SetupDescriptorScriptPubKeyMans()
    3565             : {
    3566           0 :     AssertLockHeld(cs_wallet);
    3567             : 
    3568           0 :     if (!IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
    3569             :         // Make a seed
    3570           0 :         CKey seed_key;
    3571           0 :         seed_key.MakeNewKey(true);
    3572           0 :         CPubKey seed = seed_key.GetPubKey();
    3573           0 :         assert(seed_key.VerifyPubKey(seed));
    3574             : 
    3575             :         // Get the extended key
    3576           0 :         CExtKey master_key;
    3577           0 :         master_key.SetSeed(seed_key);
    3578             : 
    3579           0 :         SetupDescriptorScriptPubKeyMans(master_key);
    3580           0 :     } else {
    3581           0 :         ExternalSigner signer = ExternalSignerScriptPubKeyMan::GetExternalSigner();
    3582             : 
    3583             :         // TODO: add account parameter
    3584           0 :         int account = 0;
    3585           0 :         UniValue signer_res = signer.GetDescriptors(account);
    3586             : 
    3587           0 :         if (!signer_res.isObject()) throw std::runtime_error(std::string(__func__) + ": Unexpected result");
    3588           0 :         for (bool internal : {false, true}) {
    3589           0 :             const UniValue& descriptor_vals = signer_res.find_value(internal ? "internal" : "receive");
    3590           0 :             if (!descriptor_vals.isArray()) throw std::runtime_error(std::string(__func__) + ": Unexpected result");
    3591           0 :             for (const UniValue& desc_val : descriptor_vals.get_array().getValues()) {
    3592           0 :                 const std::string& desc_str = desc_val.getValStr();
    3593           0 :                 FlatSigningProvider keys;
    3594           0 :                 std::string desc_error;
    3595           0 :                 std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, desc_error, false);
    3596           0 :                 if (desc == nullptr) {
    3597           0 :                     throw std::runtime_error(std::string(__func__) + ": Invalid descriptor \"" + desc_str + "\" (" + desc_error + ")");
    3598             :                 }
    3599           0 :                 if (!desc->GetOutputType()) {
    3600           0 :                     continue;
    3601             :                 }
    3602           0 :                 OutputType t =  *desc->GetOutputType();
    3603           0 :                 auto spk_manager = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, m_keypool_size));
    3604           0 :                 spk_manager->SetupDescriptor(std::move(desc));
    3605           0 :                 uint256 id = spk_manager->GetID();
    3606           0 :                 AddScriptPubKeyMan(id, std::move(spk_manager));
    3607           0 :                 AddActiveScriptPubKeyMan(id, t, internal);
    3608           0 :             }
    3609             :         }
    3610           0 :     }
    3611           0 : }
    3612             : 
    3613           0 : void CWallet::AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
    3614             : {
    3615           0 :     WalletBatch batch(GetDatabase());
    3616           0 :     if (!batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(type), id, internal)) {
    3617           0 :         throw std::runtime_error(std::string(__func__) + ": writing active ScriptPubKeyMan id failed");
    3618             :     }
    3619           0 :     LoadActiveScriptPubKeyMan(id, type, internal);
    3620           0 : }
    3621             : 
    3622           0 : void CWallet::LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
    3623             : {
    3624             :     // Activating ScriptPubKeyManager for a given output and change type is incompatible with legacy wallets.
    3625             :     // Legacy wallets have only one ScriptPubKeyManager and it's active for all output and change types.
    3626           0 :     Assert(IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
    3627             : 
    3628           0 :     WalletLogPrintf("Setting spkMan to active: id = %s, type = %s, internal = %s\n", id.ToString(), FormatOutputType(type), internal ? "true" : "false");
    3629           0 :     auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;
    3630           0 :     auto& spk_mans_other = internal ? m_external_spk_managers : m_internal_spk_managers;
    3631           0 :     auto spk_man = m_spk_managers.at(id).get();
    3632           0 :     spk_mans[type] = spk_man;
    3633             : 
    3634           0 :     const auto it = spk_mans_other.find(type);
    3635           0 :     if (it != spk_mans_other.end() && it->second == spk_man) {
    3636           0 :         spk_mans_other.erase(type);
    3637           0 :     }
    3638             : 
    3639           0 :     NotifyCanGetAddressesChanged();
    3640           0 : }
    3641             : 
    3642           0 : void CWallet::DeactivateScriptPubKeyMan(uint256 id, OutputType type, bool internal)
    3643             : {
    3644           0 :     auto spk_man = GetScriptPubKeyMan(type, internal);
    3645           0 :     if (spk_man != nullptr && spk_man->GetID() == id) {
    3646           0 :         WalletLogPrintf("Deactivate spkMan: id = %s, type = %s, internal = %s\n", id.ToString(), FormatOutputType(type), internal ? "true" : "false");
    3647           0 :         WalletBatch batch(GetDatabase());
    3648           0 :         if (!batch.EraseActiveScriptPubKeyMan(static_cast<uint8_t>(type), internal)) {
    3649           0 :             throw std::runtime_error(std::string(__func__) + ": erasing active ScriptPubKeyMan id failed");
    3650             :         }
    3651             : 
    3652           0 :         auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;
    3653           0 :         spk_mans.erase(type);
    3654           0 :     }
    3655             : 
    3656           0 :     NotifyCanGetAddressesChanged();
    3657           0 : }
    3658             : 
    3659           0 : bool CWallet::IsLegacy() const
    3660             : {
    3661           0 :     if (m_internal_spk_managers.count(OutputType::LEGACY) == 0) {
    3662           0 :         return false;
    3663             :     }
    3664           0 :     auto spk_man = dynamic_cast<LegacyScriptPubKeyMan*>(m_internal_spk_managers.at(OutputType::LEGACY));
    3665           0 :     return spk_man != nullptr;
    3666           0 : }
    3667             : 
    3668           0 : DescriptorScriptPubKeyMan* CWallet::GetDescriptorScriptPubKeyMan(const WalletDescriptor& desc) const
    3669             : {
    3670           0 :     for (auto& spk_man_pair : m_spk_managers) {
    3671             :         // Try to downcast to DescriptorScriptPubKeyMan then check if the descriptors match
    3672           0 :         DescriptorScriptPubKeyMan* spk_manager = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man_pair.second.get());
    3673           0 :         if (spk_manager != nullptr && spk_manager->HasWalletDescriptor(desc)) {
    3674           0 :             return spk_manager;
    3675             :         }
    3676             :     }
    3677             : 
    3678           0 :     return nullptr;
    3679           0 : }
    3680             : 
    3681           0 : std::optional<bool> CWallet::IsInternalScriptPubKeyMan(ScriptPubKeyMan* spk_man) const
    3682             : {
    3683             :     // Legacy script pubkey man can't be either external or internal
    3684           0 :     if (IsLegacy()) {
    3685           0 :         return std::nullopt;
    3686             :     }
    3687             : 
    3688             :     // only active ScriptPubKeyMan can be internal
    3689           0 :     if (!GetActiveScriptPubKeyMans().count(spk_man)) {
    3690           0 :         return std::nullopt;
    3691             :     }
    3692             : 
    3693           0 :     const auto desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man);
    3694           0 :     if (!desc_spk_man) {
    3695           0 :         throw std::runtime_error(std::string(__func__) + ": unexpected ScriptPubKeyMan type.");
    3696             :     }
    3697             : 
    3698           0 :     LOCK(desc_spk_man->cs_desc_man);
    3699           0 :     const auto& type = desc_spk_man->GetWalletDescriptor().descriptor->GetOutputType();
    3700           0 :     assert(type.has_value());
    3701             : 
    3702           0 :     return GetScriptPubKeyMan(*type, /* internal= */ true) == desc_spk_man;
    3703           0 : }
    3704             : 
    3705           0 : ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label, bool internal)
    3706             : {
    3707           0 :     AssertLockHeld(cs_wallet);
    3708             : 
    3709           0 :     if (!IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
    3710           0 :         WalletLogPrintf("Cannot add WalletDescriptor to a non-descriptor wallet\n");
    3711           0 :         return nullptr;
    3712             :     }
    3713             : 
    3714           0 :     auto spk_man = GetDescriptorScriptPubKeyMan(desc);
    3715           0 :     if (spk_man) {
    3716           0 :         WalletLogPrintf("Update existing descriptor: %s\n", desc.descriptor->ToString());
    3717           0 :         spk_man->UpdateWalletDescriptor(desc);
    3718           0 :     } else {
    3719           0 :         auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc, m_keypool_size));
    3720           0 :         spk_man = new_spk_man.get();
    3721             : 
    3722             :         // Save the descriptor to memory
    3723           0 :         uint256 id = new_spk_man->GetID();
    3724           0 :         AddScriptPubKeyMan(id, std::move(new_spk_man));
    3725           0 :     }
    3726             : 
    3727             :     // Add the private keys to the descriptor
    3728           0 :     for (const auto& entry : signing_provider.keys) {
    3729           0 :         const CKey& key = entry.second;
    3730           0 :         spk_man->AddDescriptorKey(key, key.GetPubKey());
    3731             :     }
    3732             : 
    3733             :     // Top up key pool, the manager will generate new scriptPubKeys internally
    3734           0 :     if (!spk_man->TopUp()) {
    3735           0 :         WalletLogPrintf("Could not top up scriptPubKeys\n");
    3736           0 :         return nullptr;
    3737             :     }
    3738             : 
    3739             :     // Apply the label if necessary
    3740             :     // Note: we disable labels for ranged descriptors
    3741           0 :     if (!desc.descriptor->IsRange()) {
    3742           0 :         auto script_pub_keys = spk_man->GetScriptPubKeys();
    3743           0 :         if (script_pub_keys.empty()) {
    3744           0 :             WalletLogPrintf("Could not generate scriptPubKeys (cache is empty)\n");
    3745           0 :             return nullptr;
    3746             :         }
    3747             : 
    3748           0 :         if (!internal) {
    3749           0 :             for (const auto& script : script_pub_keys) {
    3750           0 :                 CTxDestination dest;
    3751           0 :                 if (ExtractDestination(script, dest)) {
    3752           0 :                     SetAddressBook(dest, label, AddressPurpose::RECEIVE);
    3753           0 :                 }
    3754           0 :             }
    3755           0 :         }
    3756           0 :     }
    3757             : 
    3758             :     // Save the descriptor to DB
    3759           0 :     spk_man->WriteDescriptor();
    3760             : 
    3761           0 :     return spk_man;
    3762           0 : }
    3763             : 
    3764           0 : bool CWallet::MigrateToSQLite(bilingual_str& error)
    3765             : {
    3766           0 :     AssertLockHeld(cs_wallet);
    3767             : 
    3768           0 :     WalletLogPrintf("Migrating wallet storage database from BerkeleyDB to SQLite.\n");
    3769             : 
    3770           0 :     if (m_database->Format() == "sqlite") {
    3771           0 :         error = _("Error: This wallet already uses SQLite");
    3772           0 :         return false;
    3773             :     }
    3774             : 
    3775             :     // Get all of the records for DB type migration
    3776           0 :     std::unique_ptr<DatabaseBatch> batch = m_database->MakeBatch();
    3777           0 :     std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor();
    3778           0 :     std::vector<std::pair<SerializeData, SerializeData>> records;
    3779           0 :     if (!cursor) {
    3780           0 :         error = _("Error: Unable to begin reading all records in the database");
    3781           0 :         return false;
    3782             :     }
    3783           0 :     DatabaseCursor::Status status = DatabaseCursor::Status::FAIL;
    3784           0 :     while (true) {
    3785           0 :         DataStream ss_key{};
    3786           0 :         DataStream ss_value{};
    3787           0 :         status = cursor->Next(ss_key, ss_value);
    3788           0 :         if (status != DatabaseCursor::Status::MORE) {
    3789           0 :             break;
    3790             :         }
    3791           0 :         SerializeData key(ss_key.begin(), ss_key.end());
    3792           0 :         SerializeData value(ss_value.begin(), ss_value.end());
    3793           0 :         records.emplace_back(key, value);
    3794           0 :     }
    3795           0 :     cursor.reset();
    3796           0 :     batch.reset();
    3797           0 :     if (status != DatabaseCursor::Status::DONE) {
    3798           0 :         error = _("Error: Unable to read all records in the database");
    3799           0 :         return false;
    3800             :     }
    3801             : 
    3802             :     // Close this database and delete the file
    3803           0 :     fs::path db_path = fs::PathFromString(m_database->Filename());
    3804           0 :     m_database->Close();
    3805           0 :     fs::remove(db_path);
    3806             : 
    3807             :     // Generate the path for the location of the migrated wallet
    3808             :     // Wallets that are plain files rather than wallet directories will be migrated to be wallet directories.
    3809           0 :     const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(m_name));
    3810             : 
    3811             :     // Make new DB
    3812           0 :     DatabaseOptions opts;
    3813           0 :     opts.require_create = true;
    3814           0 :     opts.require_format = DatabaseFormat::SQLITE;
    3815             :     DatabaseStatus db_status;
    3816           0 :     std::unique_ptr<WalletDatabase> new_db = MakeDatabase(wallet_path, opts, db_status, error);
    3817           0 :     assert(new_db); // This is to prevent doing anything further with this wallet. The original file was deleted, but a backup exists.
    3818           0 :     m_database.reset();
    3819           0 :     m_database = std::move(new_db);
    3820             : 
    3821             :     // Write existing records into the new DB
    3822           0 :     batch = m_database->MakeBatch();
    3823           0 :     bool began = batch->TxnBegin();
    3824           0 :     assert(began); // This is a critical error, the new db could not be written to. The original db exists as a backup, but we should not continue execution.
    3825           0 :     for (const auto& [key, value] : records) {
    3826           0 :         if (!batch->Write(Span{key}, Span{value})) {
    3827           0 :             batch->TxnAbort();
    3828           0 :             m_database->Close();
    3829           0 :             fs::remove(m_database->Filename());
    3830           0 :             assert(false); // This is a critical error, the new db could not be written to. The original db exists as a backup, but we should not continue execution.
    3831             :         }
    3832             :     }
    3833           0 :     bool committed = batch->TxnCommit();
    3834           0 :     assert(committed); // This is a critical error, the new db could not be written to. The original db exists as a backup, but we should not continue execution.
    3835           0 :     return true;
    3836           0 : }
    3837             : 
    3838           0 : std::optional<MigrationData> CWallet::GetDescriptorsForLegacy(bilingual_str& error) const
    3839             : {
    3840           0 :     AssertLockHeld(cs_wallet);
    3841             : 
    3842           0 :     LegacyScriptPubKeyMan* legacy_spkm = GetLegacyScriptPubKeyMan();
    3843           0 :     assert(legacy_spkm);
    3844             : 
    3845           0 :     std::optional<MigrationData> res = legacy_spkm->MigrateToDescriptor();
    3846           0 :     if (res == std::nullopt) {
    3847           0 :         error = _("Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
    3848           0 :         return std::nullopt;
    3849             :     }
    3850           0 :     return res;
    3851           0 : }
    3852             : 
    3853           0 : bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
    3854             : {
    3855           0 :     AssertLockHeld(cs_wallet);
    3856             : 
    3857           0 :     LegacyScriptPubKeyMan* legacy_spkm = GetLegacyScriptPubKeyMan();
    3858           0 :     if (!legacy_spkm) {
    3859           0 :         error = _("Error: This wallet is already a descriptor wallet");
    3860           0 :         return false;
    3861             :     }
    3862             : 
    3863             :     // Get all invalid or non-watched scripts that will not be migrated
    3864           0 :     std::set<CTxDestination> not_migrated_dests;
    3865           0 :     for (const auto& script : legacy_spkm->GetNotMineScriptPubKeys()) {
    3866           0 :         CTxDestination dest;
    3867           0 :         if (ExtractDestination(script, dest)) not_migrated_dests.emplace(dest);
    3868           0 :     }
    3869             : 
    3870           0 :     for (auto& desc_spkm : data.desc_spkms) {
    3871           0 :         if (m_spk_managers.count(desc_spkm->GetID()) > 0) {
    3872           0 :             error = _("Error: Duplicate descriptors created during migration. Your wallet may be corrupted.");
    3873           0 :             return false;
    3874             :         }
    3875           0 :         uint256 id = desc_spkm->GetID();
    3876           0 :         AddScriptPubKeyMan(id, std::move(desc_spkm));
    3877             :     }
    3878             : 
    3879             :     // Remove the LegacyScriptPubKeyMan from disk
    3880           0 :     if (!legacy_spkm->DeleteRecords()) {
    3881           0 :         return false;
    3882             :     }
    3883             : 
    3884             :     // Remove the LegacyScriptPubKeyMan from memory
    3885           0 :     m_spk_managers.erase(legacy_spkm->GetID());
    3886           0 :     m_external_spk_managers.clear();
    3887           0 :     m_internal_spk_managers.clear();
    3888             : 
    3889             :     // Setup new descriptors
    3890           0 :     SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
    3891           0 :     if (!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
    3892             :         // Use the existing master key if we have it
    3893           0 :         if (data.master_key.key.IsValid()) {
    3894           0 :             SetupDescriptorScriptPubKeyMans(data.master_key);
    3895           0 :         } else {
    3896             :             // Setup with a new seed if we don't.
    3897           0 :             SetupDescriptorScriptPubKeyMans();
    3898             :         }
    3899           0 :     }
    3900             : 
    3901             :     // Check if the transactions in the wallet are still ours. Either they belong here, or they belong in the watchonly wallet.
    3902             :     // We need to go through these in the tx insertion order so that lookups to spends works.
    3903           0 :     std::vector<uint256> txids_to_delete;
    3904           0 :     for (const auto& [_pos, wtx] : wtxOrdered) {
    3905           0 :         if (!IsMine(*wtx->tx) && !IsFromMe(*wtx->tx)) {
    3906             :             // Check it is the watchonly wallet's
    3907             :             // solvable_wallet doesn't need to be checked because transactions for those scripts weren't being watched for
    3908           0 :             if (data.watchonly_wallet) {
    3909           0 :                 LOCK(data.watchonly_wallet->cs_wallet);
    3910           0 :                 if (data.watchonly_wallet->IsMine(*wtx->tx) || data.watchonly_wallet->IsFromMe(*wtx->tx)) {
    3911             :                     // Add to watchonly wallet
    3912           0 :                     if (!data.watchonly_wallet->AddToWallet(wtx->tx, wtx->m_state)) {
    3913           0 :                         error = _("Error: Could not add watchonly tx to watchonly wallet");
    3914           0 :                         return false;
    3915             :                     }
    3916             :                     // Mark as to remove from this wallet
    3917           0 :                     txids_to_delete.push_back(wtx->GetHash());
    3918           0 :                     continue;
    3919             :                 }
    3920           0 :             }
    3921             :             // Both not ours and not in the watchonly wallet
    3922           0 :             error = strprintf(_("Error: Transaction %s in wallet cannot be identified to belong to migrated wallets"), wtx->GetHash().GetHex());
    3923           0 :             return false;
    3924             :         }
    3925             :     }
    3926             :     // Do the removes
    3927           0 :     if (txids_to_delete.size() > 0) {
    3928           0 :         std::vector<uint256> deleted_txids;
    3929           0 :         if (ZapSelectTx(txids_to_delete, deleted_txids) != DBErrors::LOAD_OK) {
    3930           0 :             error = _("Error: Could not delete watchonly transactions");
    3931           0 :             return false;
    3932             :         }
    3933           0 :         if (deleted_txids != txids_to_delete) {
    3934           0 :             error = _("Error: Not all watchonly txs could be deleted");
    3935           0 :             return false;
    3936             :         }
    3937             :         // Tell the GUI of each tx
    3938           0 :         for (const uint256& txid : deleted_txids) {
    3939           0 :             NotifyTransactionChanged(txid, CT_UPDATED);
    3940             :         }
    3941           0 :     }
    3942             : 
    3943             :     // Check the address book data in the same way we did for transactions
    3944           0 :     std::vector<CTxDestination> dests_to_delete;
    3945           0 :     for (const auto& addr_pair : m_address_book) {
    3946             :         // Labels applied to receiving addresses should go based on IsMine
    3947           0 :         if (addr_pair.second.purpose == AddressPurpose::RECEIVE) {
    3948           0 :             if (!IsMine(addr_pair.first)) {
    3949             :                 // Check the address book data is the watchonly wallet's
    3950           0 :                 if (data.watchonly_wallet) {
    3951           0 :                     LOCK(data.watchonly_wallet->cs_wallet);
    3952           0 :                     if (data.watchonly_wallet->IsMine(addr_pair.first)) {
    3953             :                         // Add to the watchonly. Preserve the labels, purpose, and change-ness
    3954           0 :                         std::string label = addr_pair.second.GetLabel();
    3955           0 :                         data.watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
    3956           0 :                         if (!addr_pair.second.IsChange()) {
    3957           0 :                             data.watchonly_wallet->m_address_book[addr_pair.first].SetLabel(label);
    3958           0 :                         }
    3959           0 :                         dests_to_delete.push_back(addr_pair.first);
    3960             :                         continue;
    3961           0 :                     }
    3962           0 :                 }
    3963           0 :                 if (data.solvable_wallet) {
    3964           0 :                     LOCK(data.solvable_wallet->cs_wallet);
    3965           0 :                     if (data.solvable_wallet->IsMine(addr_pair.first)) {
    3966             :                         // Add to the solvable. Preserve the labels, purpose, and change-ness
    3967           0 :                         std::string label = addr_pair.second.GetLabel();
    3968           0 :                         data.solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
    3969           0 :                         if (!addr_pair.second.IsChange()) {
    3970           0 :                             data.solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
    3971           0 :                         }
    3972           0 :                         dests_to_delete.push_back(addr_pair.first);
    3973             :                         continue;
    3974           0 :                     }
    3975           0 :                 }
    3976             : 
    3977             :                 // Skip invalid/non-watched scripts that will not be migrated
    3978           0 :                 if (not_migrated_dests.count(addr_pair.first) > 0) {
    3979           0 :                     dests_to_delete.push_back(addr_pair.first);
    3980           0 :                     continue;
    3981             :                 }
    3982             : 
    3983             :                 // Not ours, not in watchonly wallet, and not in solvable
    3984           0 :                 error = _("Error: Address book data in wallet cannot be identified to belong to migrated wallets");
    3985           0 :                 return false;
    3986             :             }
    3987           0 :         } else {
    3988             :             // Labels for everything else ("send") should be cloned to all
    3989           0 :             if (data.watchonly_wallet) {
    3990           0 :                 LOCK(data.watchonly_wallet->cs_wallet);
    3991             :                 // Add to the watchonly. Preserve the labels, purpose, and change-ness
    3992           0 :                 std::string label = addr_pair.second.GetLabel();
    3993           0 :                 data.watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
    3994           0 :                 if (!addr_pair.second.IsChange()) {
    3995           0 :                     data.watchonly_wallet->m_address_book[addr_pair.first].SetLabel(label);
    3996           0 :                 }
    3997           0 :             }
    3998           0 :             if (data.solvable_wallet) {
    3999           0 :                 LOCK(data.solvable_wallet->cs_wallet);
    4000             :                 // Add to the solvable. Preserve the labels, purpose, and change-ness
    4001           0 :                 std::string label = addr_pair.second.GetLabel();
    4002           0 :                 data.solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
    4003           0 :                 if (!addr_pair.second.IsChange()) {
    4004           0 :                     data.solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
    4005           0 :                 }
    4006           0 :             }
    4007             :         }
    4008             :     }
    4009             : 
    4010             :     // Persist added address book entries (labels, purpose) for watchonly and solvable wallets
    4011           0 :     auto persist_address_book = [](const CWallet& wallet) {
    4012           0 :         LOCK(wallet.cs_wallet);
    4013           0 :         WalletBatch batch{wallet.GetDatabase()};
    4014           0 :         for (const auto& [destination, addr_book_data] : wallet.m_address_book) {
    4015           0 :             auto address{EncodeDestination(destination)};
    4016           0 :             std::optional<std::string> label = addr_book_data.IsChange() ? std::nullopt : std::make_optional(addr_book_data.GetLabel());
    4017             :             // don't bother writing default values (unknown purpose)
    4018           0 :             if (addr_book_data.purpose) batch.WritePurpose(address, PurposeToString(*addr_book_data.purpose));
    4019           0 :             if (label) batch.WriteName(address, *label);
    4020           0 :         }
    4021           0 :     };
    4022           0 :     if (data.watchonly_wallet) persist_address_book(*data.watchonly_wallet);
    4023           0 :     if (data.solvable_wallet) persist_address_book(*data.solvable_wallet);
    4024             : 
    4025             :     // Remove the things to delete
    4026           0 :     if (dests_to_delete.size() > 0) {
    4027           0 :         for (const auto& dest : dests_to_delete) {
    4028           0 :             if (!DelAddressBook(dest)) {
    4029           0 :                 error = _("Error: Unable to remove watchonly address book data");
    4030           0 :                 return false;
    4031             :             }
    4032             :         }
    4033           0 :     }
    4034             : 
    4035             :     // Connect the SPKM signals
    4036           0 :     ConnectScriptPubKeyManNotifiers();
    4037           0 :     NotifyCanGetAddressesChanged();
    4038             : 
    4039           0 :     WalletLogPrintf("Wallet migration complete.\n");
    4040             : 
    4041           0 :     return true;
    4042           0 : }
    4043             : 
    4044           0 : bool CWallet::CanGrindR() const
    4045             : {
    4046           0 :     return !IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER);
    4047             : }
    4048             : 
    4049           0 : bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error, MigrationResult& res) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
    4050             : {
    4051           0 :     AssertLockHeld(wallet.cs_wallet);
    4052             : 
    4053             :     // Get all of the descriptors from the legacy wallet
    4054           0 :     std::optional<MigrationData> data = wallet.GetDescriptorsForLegacy(error);
    4055           0 :     if (data == std::nullopt) return false;
    4056             : 
    4057             :     // Create the watchonly and solvable wallets if necessary
    4058           0 :     if (data->watch_descs.size() > 0 || data->solvable_descs.size() > 0) {
    4059           0 :         DatabaseOptions options;
    4060           0 :         options.require_existing = false;
    4061           0 :         options.require_create = true;
    4062             : 
    4063             :         // Make the wallets
    4064           0 :         options.create_flags = WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET | WALLET_FLAG_DESCRIPTORS;
    4065           0 :         if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
    4066           0 :             options.create_flags |= WALLET_FLAG_AVOID_REUSE;
    4067           0 :         }
    4068           0 :         if (wallet.IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) {
    4069           0 :             options.create_flags |= WALLET_FLAG_KEY_ORIGIN_METADATA;
    4070           0 :         }
    4071           0 :         if (data->watch_descs.size() > 0) {
    4072           0 :             wallet.WalletLogPrintf("Making a new watchonly wallet containing the watched scripts\n");
    4073             : 
    4074             :             DatabaseStatus status;
    4075           0 :             std::vector<bilingual_str> warnings;
    4076           0 :             std::string wallet_name = wallet.GetName() + "_watchonly";
    4077           0 :             data->watchonly_wallet = CreateWallet(context, wallet_name, std::nullopt, options, status, error, warnings);
    4078           0 :             if (status != DatabaseStatus::SUCCESS) {
    4079           0 :                 error = _("Error: Failed to create new watchonly wallet");
    4080           0 :                 return false;
    4081             :             }
    4082           0 :             res.watchonly_wallet = data->watchonly_wallet;
    4083           0 :             LOCK(data->watchonly_wallet->cs_wallet);
    4084             : 
    4085             :             // Parse the descriptors and add them to the new wallet
    4086           0 :             for (const auto& [desc_str, creation_time] : data->watch_descs) {
    4087             :                 // Parse the descriptor
    4088           0 :                 FlatSigningProvider keys;
    4089           0 :                 std::string parse_err;
    4090           0 :                 std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, parse_err, /* require_checksum */ true);
    4091           0 :                 assert(desc); // It shouldn't be possible to have the LegacyScriptPubKeyMan make an invalid descriptor
    4092           0 :                 assert(!desc->IsRange()); // It shouldn't be possible to have LegacyScriptPubKeyMan make a ranged watchonly descriptor
    4093             : 
    4094             :                 // Add to the wallet
    4095           0 :                 WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
    4096           0 :                 data->watchonly_wallet->AddWalletDescriptor(w_desc, keys, "", false);
    4097           0 :             }
    4098             : 
    4099             :             // Add the wallet to settings
    4100           0 :             UpdateWalletSetting(*context.chain, wallet_name, /*load_on_startup=*/true, warnings);
    4101           0 :         }
    4102           0 :         if (data->solvable_descs.size() > 0) {
    4103           0 :             wallet.WalletLogPrintf("Making a new watchonly wallet containing the unwatched solvable scripts\n");
    4104             : 
    4105             :             DatabaseStatus status;
    4106           0 :             std::vector<bilingual_str> warnings;
    4107           0 :             std::string wallet_name = wallet.GetName() + "_solvables";
    4108           0 :             data->solvable_wallet = CreateWallet(context, wallet_name, std::nullopt, options, status, error, warnings);
    4109           0 :             if (status != DatabaseStatus::SUCCESS) {
    4110           0 :                 error = _("Error: Failed to create new watchonly wallet");
    4111           0 :                 return false;
    4112             :             }
    4113           0 :             res.solvables_wallet = data->solvable_wallet;
    4114           0 :             LOCK(data->solvable_wallet->cs_wallet);
    4115             : 
    4116             :             // Parse the descriptors and add them to the new wallet
    4117           0 :             for (const auto& [desc_str, creation_time] : data->solvable_descs) {
    4118             :                 // Parse the descriptor
    4119           0 :                 FlatSigningProvider keys;
    4120           0 :                 std::string parse_err;
    4121           0 :                 std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, parse_err, /* require_checksum */ true);
    4122           0 :                 assert(desc); // It shouldn't be possible to have the LegacyScriptPubKeyMan make an invalid descriptor
    4123           0 :                 assert(!desc->IsRange()); // It shouldn't be possible to have LegacyScriptPubKeyMan make a ranged watchonly descriptor
    4124             : 
    4125             :                 // Add to the wallet
    4126           0 :                 WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0);
    4127           0 :                 data->solvable_wallet->AddWalletDescriptor(w_desc, keys, "", false);
    4128           0 :             }
    4129             : 
    4130             :             // Add the wallet to settings
    4131           0 :             UpdateWalletSetting(*context.chain, wallet_name, /*load_on_startup=*/true, warnings);
    4132           0 :         }
    4133           0 :     }
    4134             : 
    4135             :     // Add the descriptors to wallet, remove LegacyScriptPubKeyMan, and cleanup txs and address book data
    4136           0 :     if (!wallet.ApplyMigrationData(*data, error)) {
    4137           0 :         return false;
    4138             :     }
    4139           0 :     return true;
    4140           0 : }
    4141             : 
    4142           0 : util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, const SecureString& passphrase, WalletContext& context)
    4143             : {
    4144           0 :     MigrationResult res;
    4145           0 :     bilingual_str error;
    4146           0 :     std::vector<bilingual_str> warnings;
    4147             : 
    4148             :     // If the wallet is still loaded, unload it so that nothing else tries to use it while we're changing it
    4149           0 :     if (auto wallet = GetWallet(context, wallet_name)) {
    4150           0 :         if (!RemoveWallet(context, wallet, /*load_on_start=*/std::nullopt, warnings)) {
    4151           0 :             return util::Error{_("Unable to unload the wallet before migrating")};
    4152             :         }
    4153           0 :         UnloadWallet(std::move(wallet));
    4154           0 :     }
    4155             : 
    4156             :     // Load the wallet but only in the context of this function.
    4157             :     // No signals should be connected nor should anything else be aware of this wallet
    4158           0 :     WalletContext empty_context;
    4159           0 :     empty_context.args = context.args;
    4160           0 :     DatabaseOptions options;
    4161           0 :     options.require_existing = true;
    4162             :     DatabaseStatus status;
    4163           0 :     std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(wallet_name, options, status, error);
    4164           0 :     if (!database) {
    4165           0 :         return util::Error{Untranslated("Wallet file verification failed.") + Untranslated(" ") + error};
    4166             :     }
    4167             : 
    4168             :     // Make the local wallet
    4169           0 :     std::shared_ptr<CWallet> local_wallet = CWallet::Create(empty_context, wallet_name, std::move(database), options.create_flags, error, warnings);
    4170           0 :     if (!local_wallet) {
    4171           0 :         return util::Error{Untranslated("Wallet loading failed.") + Untranslated(" ") + error};
    4172             :     }
    4173             : 
    4174             :     // Before anything else, check if there is something to migrate.
    4175           0 :     if (!local_wallet->GetLegacyScriptPubKeyMan()) {
    4176           0 :         return util::Error{_("Error: This wallet is already a descriptor wallet")};
    4177             :     }
    4178             : 
    4179             :     // Make a backup of the DB
    4180           0 :     fs::path this_wallet_dir = fs::absolute(fs::PathFromString(local_wallet->GetDatabase().Filename())).parent_path();
    4181           0 :     fs::path backup_filename = fs::PathFromString(strprintf("%s-%d.legacy.bak", wallet_name, GetTime()));
    4182           0 :     fs::path backup_path = this_wallet_dir / backup_filename;
    4183           0 :     if (!local_wallet->BackupWallet(fs::PathToString(backup_path))) {
    4184           0 :         return util::Error{_("Error: Unable to make a backup of your wallet")};
    4185             :     }
    4186           0 :     res.backup_path = backup_path;
    4187             : 
    4188           0 :     bool success = false;
    4189             :     {
    4190           0 :         LOCK(local_wallet->cs_wallet);
    4191             : 
    4192             :         // Unlock the wallet if needed
    4193           0 :         if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
    4194           0 :             if (passphrase.find('\0') == std::string::npos) {
    4195           0 :                 return util::Error{Untranslated("Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
    4196             :             } else {
    4197           0 :                 return util::Error{Untranslated("Error: Wallet decryption failed, the wallet passphrase entered was incorrect. "
    4198             :                                                 "The passphrase contains a null character (ie - a zero byte). "
    4199             :                                                 "If this passphrase was set with a version of this software prior to 25.0, "
    4200             :                                                 "please try again with only the characters up to — but not including — "
    4201             :                                                 "the first null character.")};
    4202             :             }
    4203             :         }
    4204             : 
    4205             :         // First change to using SQLite
    4206           0 :         if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
    4207             : 
    4208             :         // Do the migration, and cleanup if it fails
    4209           0 :         success = DoMigration(*local_wallet, context, error, res);
    4210           0 :     }
    4211             : 
    4212           0 :     if (success) {
    4213             :         // Migration successful, unload the wallet locally, then reload it.
    4214           0 :         assert(local_wallet.use_count() == 1);
    4215           0 :         local_wallet.reset();
    4216           0 :         res.wallet = LoadWallet(context, wallet_name, /*load_on_start=*/std::nullopt, options, status, error, warnings);
    4217           0 :         res.wallet_name = wallet_name;
    4218           0 :     } else {
    4219             :         // Migration failed, cleanup
    4220             :         // Copy the backup to the actual wallet dir
    4221           0 :         fs::path temp_backup_location = fsbridge::AbsPathJoin(GetWalletDir(), backup_filename);
    4222           0 :         fs::copy_file(backup_path, temp_backup_location, fs::copy_options::none);
    4223             : 
    4224             :         // Remember this wallet's walletdir to remove after unloading
    4225           0 :         std::vector<fs::path> wallet_dirs;
    4226           0 :         wallet_dirs.push_back(fs::PathFromString(local_wallet->GetDatabase().Filename()).parent_path());
    4227             : 
    4228             :         // Unload the wallet locally
    4229           0 :         assert(local_wallet.use_count() == 1);
    4230           0 :         local_wallet.reset();
    4231             : 
    4232             :         // Make list of wallets to cleanup
    4233           0 :         std::vector<std::shared_ptr<CWallet>> created_wallets;
    4234           0 :         if (res.watchonly_wallet) created_wallets.push_back(std::move(res.watchonly_wallet));
    4235           0 :         if (res.solvables_wallet) created_wallets.push_back(std::move(res.solvables_wallet));
    4236             : 
    4237             :         // Get the directories to remove after unloading
    4238           0 :         for (std::shared_ptr<CWallet>& w : created_wallets) {
    4239           0 :             wallet_dirs.push_back(fs::PathFromString(w->GetDatabase().Filename()).parent_path());
    4240             :         }
    4241             : 
    4242             :         // Unload the wallets
    4243           0 :         for (std::shared_ptr<CWallet>& w : created_wallets) {
    4244           0 :             if (!RemoveWallet(context, w, /*load_on_start=*/false)) {
    4245           0 :                 error += _("\nUnable to cleanup failed migration");
    4246           0 :                 return util::Error{error};
    4247             :             }
    4248           0 :             UnloadWallet(std::move(w));
    4249             :         }
    4250             : 
    4251             :         // Delete the wallet directories
    4252           0 :         for (fs::path& dir : wallet_dirs) {
    4253           0 :             fs::remove_all(dir);
    4254             :         }
    4255             : 
    4256             :         // Restore the backup
    4257             :         DatabaseStatus status;
    4258           0 :         std::vector<bilingual_str> warnings;
    4259           0 :         if (!RestoreWallet(context, temp_backup_location, wallet_name, /*load_on_start=*/std::nullopt, status, error, warnings)) {
    4260           0 :             error += _("\nUnable to restore backup of wallet.");
    4261           0 :             return util::Error{error};
    4262             :         }
    4263             : 
    4264             :         // Move the backup to the wallet dir
    4265           0 :         fs::copy_file(temp_backup_location, backup_path, fs::copy_options::none);
    4266           0 :         fs::remove(temp_backup_location);
    4267             : 
    4268           0 :         return util::Error{error};
    4269           0 :     }
    4270           0 :     return res;
    4271           0 : }
    4272             : } // namespace wallet

Generated by: LCOV version 1.14