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