Coverage Report

Created: 2026-08-05 14:35

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