8#include <bitcoin-build-config.h>
11#include <blockfilter.h>
77#include <condition_variable>
102 if (!setting_value.isArray()) setting_value.setArray();
103 for (
const auto& value : setting_value.getValues()) {
106 setting_value.push_back(wallet_name);
115 if (!setting_value.isArray()) {
116 if (wallet_name.empty() && setting_value.isNull()) {
118 setting_value.setArray();
124 for (
const auto& value : setting_value.getValues()) {
125 if (!value.isStr() || value.get_str() != wallet_name) new_value.
push_back(value);
128 setting_value = std::move(new_value);
135 const std::string& wallet_name,
136 std::optional<bool> load_on_startup,
137 std::vector<bilingual_str>& warnings)
139 if (!load_on_startup)
return;
141 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
143 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));
165 std::vector<std::shared_ptr<CWallet>>::const_iterator i = std::find(context.wallets.begin(), context.wallets.end(),
wallet);
166 if (i != context.wallets.end())
return false;
167 context.wallets.push_back(
wallet);
168 wallet->ConnectScriptPubKeyManNotifiers();
169 wallet->NotifyCanGetAddressesChanged();
178 std::string name =
wallet->GetName();
182 wallet->DisconnectChainNotifications();
185 std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(context.wallets.begin(), context.wallets.end(),
wallet);
186 if (i == context.wallets.end())
return false;
187 context.wallets.erase(i);
200 std::vector<bilingual_str> warnings;
207 return context.wallets;
213 count = context.wallets.size();
214 return count == 1 ? context.wallets[0] :
nullptr;
220 for (
const std::shared_ptr<CWallet>&
wallet : context.wallets) {
229 auto it = context.wallet_load_fns.emplace(context.wallet_load_fns.end(), std::move(load_wallet));
236 for (
auto& load_wallet : context.wallet_load_fns) {
250 const std::string name =
wallet->GetName();
251 wallet->WalletLogPrintf(
"Releasing wallet %s..\n", name);
256 if (g_unloading_wallet_set.erase(name) == 0) {
267 const std::string name =
wallet->GetName();
270 g_unloading_wallet_set.insert(name);
279 while (g_unloading_wallet_set.contains(name)) {
289 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(name, options, status, error);
296 std::shared_ptr<CWallet> wallet =
CWallet::LoadExisting(context, name, std::move(database), error, warnings);
305 wallet->postInitProcess();
311 }
catch (
const std::runtime_error& e) {
318class FastWalletRescanFilter
321 FastWalletRescanFilter(
const CWallet& wallet) : m_wallet(wallet)
324 for (
auto spkm : m_wallet.GetAllScriptPubKeyMans()) {
325 auto desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(spkm)};
326 assert(desc_spkm !=
nullptr);
327 AddScriptPubKeys(desc_spkm);
329 if (desc_spkm->IsHDEnabled()) {
330 m_last_range_ends.emplace(desc_spkm->GetID(), desc_spkm->GetEndRange());
335 void UpdateIfNeeded()
338 for (
const auto& [desc_spkm_id, last_range_end] : m_last_range_ends) {
340 assert(desc_spkm !=
nullptr);
341 int32_t current_range_end{desc_spkm->GetEndRange()};
342 if (current_range_end > last_range_end) {
343 AddScriptPubKeys(desc_spkm, last_range_end);
344 m_last_range_ends.at(desc_spkm->GetID()) = current_range_end;
349 std::optional<bool> MatchesBlock(
const uint256& block_hash)
const
362 std::map<uint256, int32_t> m_last_range_ends;
367 for (
const auto& script_pub_key : desc_spkm->GetScriptPubKeys(last_range_end)) {
368 m_filter_set.emplace(script_pub_key.begin(), script_pub_key.end());
377 if (!result.second) {
382 auto wallet = LoadWalletInternal(context, name, load_on_start, options, status, error, warnings);
398 bool born_encrypted = !passphrase.empty();
407 error =
Untranslated(
"Private keys must be disabled when using an external signer");
414 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.");
420 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(name, options, status, error);
429 std::shared_ptr<CWallet>
wallet =
CWallet::CreateNew(context, name, std::move(database), wallet_creation_flags, born_encrypted, error, warnings);
437 if (born_encrypted) {
438 if (!
wallet->EncryptWallet(passphrase)) {
439 error =
Untranslated(
"Error: Wallet created but failed to encrypt.");
448 wallet->postInitProcess();
459std::shared_ptr<CWallet>
RestoreWallet(
WalletContext& context,
const fs::path& backup_file,
const std::string& wallet_name, std::optional<bool> load_on_start,
DatabaseStatus& status,
bilingual_str& error, std::vector<bilingual_str>& warnings,
bool load_after_restore,
bool allow_unnamed)
463 if (!allow_unnamed && wallet_name.empty()) {
474 auto wallet_file = wallet_path /
"wallet.dat";
475 std::shared_ptr<CWallet>
wallet;
476 bool wallet_file_copied =
false;
477 bool created_parent_dir =
false;
480 if (!fs::exists(backup_file)) {
488 if (fs::exists(wallet_path)) {
490 if (!fs::is_directory(wallet_path)) {
491 error =
Untranslated(
strprintf(
"Failed to restore wallet. Database file exists '%s'.", fs::PathToString(wallet_path)));
497 if (fs::exists(wallet_file)) {
498 error =
Untranslated(
strprintf(
"Failed to restore wallet. Database file exists in '%s'.", fs::PathToString(wallet_file)));
505 error =
Untranslated(
strprintf(
"Failed to restore database path '%s'.", fs::PathToString(wallet_path)));
509 created_parent_dir =
true;
512 fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
513 wallet_file_copied =
true;
515 if (load_after_restore) {
516 wallet =
LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
518 }
catch (
const std::exception& e) {
525 if (load_after_restore && !
wallet) {
526 if (wallet_file_copied) fs::remove(wallet_file);
529 if (created_parent_dir) {
530 Assume(fs::is_empty(wallet_path));
531 fs::remove(wallet_path);
546 const auto it = mapWallet.find(hash);
547 if (it == mapWallet.end())
549 return &(it->second);
574 for (
int i = 0; i < 2; i++){
582 if (elapsed_time <= 0s) {
589 const double target_iterations{updated_master_key.
nDeriveIterations * target_time / elapsed_time};
590 if (target_iterations < 1 || target_iterations > std::numeric_limits<unsigned int>::max()) {
609 master_key = std::move(updated_master_key);
637 if (
Unlock(plain_master_key)) {
658 if (!
DecryptMasterKey(strOldWalletPassphrase, master_key, plain_master_key)) {
661 if (
Unlock(plain_master_key))
663 if (!
EncryptMasterKey(strNewWalletPassphrase, plain_master_key, master_key)) {
666 WalletLogPrintf(
"Wallet passphrase changed to an nDeriveIterations of %i\n", master_key.nDeriveIterations);
683 m_last_block_processed = block_hash;
684 m_last_block_processed_height = block_height;
697 std::set<Txid> result;
700 const auto it = mapWallet.find(txid);
701 if (it == mapWallet.end())
705 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
709 if (mapTxSpends.count(txin.prevout) <= 1)
711 range = mapTxSpends.equal_range(txin.prevout);
712 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
713 result.insert(_it->second);
721 const Txid& txid = tx->GetHash();
722 for (
unsigned int i = 0; i < tx->vout.size(); ++i) {
738 std::set<CWalletTx*, WalletTxOrderComparator> txs;
744 if (std::ranges::none_of(wtx.
GetTx()->vin, [](
const CTxIn& in) { return in.scriptWitness.IsNull(); })) {
749 bool found_self =
false;
750 const auto [begin, end] = mapTxSpends.equal_range(wtx.
GetTx()->vin.front().prevout);
751 for (
auto it = begin; it != end; ++it) {
752 auto entry = mapWallet.find(it->second);
753 if (!
Assume(entry != mapWallet.end()))
continue;
754 const bool is_self = &entry->second == &wtx;
755 found_self |= is_self;
757 Assume(txs.insert(&entry->second).second);
768 if (txs.size() <= 1)
return;
771 const CWalletTx* copyFrom = *txs.begin();
775 const auto metadata = [](
auto& tx) {
776 return std::tie(tx.m_from, tx.m_message, tx.m_comment, tx.m_comment_to,
777 tx.m_replaces_txid, tx.m_replaced_by_txid,
778 tx.m_messages, tx.m_payment_requests, tx.nTimeSmart);
783 if (copyTo == copyFrom)
continue;
784 metadata(*copyTo) = metadata(*copyFrom);
795 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
796 range = mapTxSpends.equal_range(outpoint);
798 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
799 const Txid& txid = it->second;
800 const auto mit = mapWallet.find(txid);
801 if (mit != mapWallet.end()) {
802 const auto& wtx = mit->second;
803 if (!wtx.isAbandoned() && !wtx.isBlockConflicted() && !wtx.isMempoolConflicted())
814 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
815 range = mapTxSpends.equal_range(outpoint);
817 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
818 const Txid& txid = it->second;
819 const auto mit = mapWallet.find(txid);
820 if (mit != mapWallet.end()) {
821 const auto& wtx = mit->second;
823 if (wtx.InMempool()) {
825 }
else if (!wtx.isAbandoned() && !wtx.isBlockConflicted() && !wtx.isMempoolConflicted()) {
835 mapTxSpends.insert(std::make_pair(outpoint, txid));
878 delete encrypted_batch;
879 encrypted_batch =
nullptr;
885 auto spk_man = spk_man_pair.second.get();
886 if (!spk_man->Encrypt(plain_master_key, encrypted_batch)) {
888 delete encrypted_batch;
889 encrypted_batch =
nullptr;
897 delete encrypted_batch;
898 encrypted_batch =
nullptr;
904 delete encrypted_batch;
905 encrypted_batch =
nullptr;
908 if (!
Unlock(strWalletPassphrase)) {
934 typedef std::multimap<int64_t, CWalletTx*>
TxItems;
937 for (
auto& entry : mapWallet)
944 std::vector<int64_t> nOrderPosOffsets;
945 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
952 nOrderPos = nOrderPosNext++;
953 nOrderPosOffsets.push_back(nOrderPos);
960 int64_t nOrderPosOff = 0;
961 for (
const int64_t& nOffsetStart : nOrderPosOffsets)
963 if (nOrderPos >= nOffsetStart)
966 nOrderPos += nOrderPosOff;
967 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
985 int64_t nRet = nOrderPosNext++;
998 for (
auto& [
_, wtx] : mapWallet)
1007 auto mi = mapWallet.find(originalHash);
1010 assert(mi != mapWallet.end());
1024 bool success =
true;
1033 if (variant == &wtx)
continue;
1034 variant->m_replaced_by_txid = newHash;
1036 WalletLogPrintf(
"%s: Updating variant tx %s failed\n", __func__, variant->GetHash().ToString());
1057 tx_destinations.insert(dst);
1084 Txid hash = tx->GetHash();
1088 std::set<CTxDestination> tx_destinations;
1090 for (
const CTxIn& txin : tx->vin) {
1099 auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(tx, state));
1101 bool fInsertedNew =
ret.second;
1102 bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
1122 fUpdated |= wtx.
Update(tx, state, batch, fUpdated);
1123 }
catch (
const std::ios_base::failure& e) {
1131 std::vector<CWalletTx*> txs{&wtx};
1135 while (!txs.empty()) {
1138 desc_tx->
m_state = inactive_state;
1143 for (
unsigned int i = 0; i < desc_tx->
GetTx()->vout.size(); ++i) {
1145 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(outpoint);
1146 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
1147 const auto wit = mapWallet.find(it->second);
1148 if (wit != mapWallet.end()) {
1149 txs.push_back(&wit->second);
1157 std::string status{
"no-change"};
1158 if (fInsertedNew || fUpdated) {
1159 status = fInsertedNew ? (fUpdated ?
"new, update" :
"new") :
"update";
1176 if (!strCmd.empty())
1181 ReplaceAll(strCmd,
"%b", conf->confirmed_block_hash.GetHex());
1195 std::thread
t(runCommand, strCmd);
1205 const auto& ins = mapWallet.emplace(wtx_in.GetHash(), std::move(wtx_in));
1218 auto it = mapWallet.find(txin.prevout.hash);
1219 if (it != mapWallet.end()) {
1241 if (
auto* conf = std::get_if<TxStateConfirmed>(&state)) {
1243 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.
prevout);
1244 while (range.first != range.second) {
1245 if (range.first->second != tx.
GetHash()) {
1246 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);
1247 MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
1254 bool fExisted = mapWallet.contains(tx.
GetHash());
1266 for (
auto &dest : spk_man->MarkUnusedAddresses(txout.
scriptPubKey)) {
1268 if (!dest.internal.has_value()) {
1273 if (!dest.internal.has_value())
continue;
1287 TxState tx_state = std::visit([](
auto&& s) ->
TxState {
return s; }, state);
1292 throw std::runtime_error(
"DB error adding transaction to wallet, write failed");
1311 for (
long unsigned int i = 0; i < parent_wtx.GetTx()->vout.size(); i++) {
1312 for (
auto range = mapTxSpends.equal_range(
COutPoint(parent_wtx.GetTx()->GetHash(), i)); range.first != range.second; range.first++) {
1313 const Txid& sibling_txid = range.first->second;
1315 if (sibling_txid == child_txid)
continue;
1326 for (
const CTxIn& txin : tx->vin) {
1328 if (it != mapWallet.end()) {
1329 it->second.MarkDirty();
1337 auto it = mapWallet.find(hashTx);
1338 assert(it != mapWallet.end());
1351 assert(!wtx.isConfirmed());
1352 assert(!wtx.InMempool());
1354 if (!wtx.isBlockConflicted() && !wtx.isAbandoned()) {
1380 if (m_last_block_processed_height < 0 || conflicting_height < 0) {
1383 int conflictconfirms = (m_last_block_processed_height - conflicting_height + 1) * -1;
1384 if (conflictconfirms >= 0)
1408 std::set<Txid> todo;
1409 std::set<Txid> done;
1411 todo.insert(tx_hash);
1413 while (!todo.empty()) {
1417 auto it = mapWallet.find(now);
1418 assert(it != mapWallet.end());
1421 TxUpdate update_state = try_updating_state(wtx);
1426 for (
unsigned int i = 0; i < wtx.
GetTx()->vout.size(); ++i) {
1427 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(
COutPoint(now, i));
1428 for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
1429 if (!done.contains(iter->second)) {
1430 todo.insert(iter->second);
1462 auto it = mapWallet.find(tx->GetHash());
1463 if (it != mapWallet.end()) {
1467 const Txid& txid = tx->GetHash();
1469 for (
const CTxIn& tx_in : tx->vin) {
1471 for (
auto range = mapTxSpends.equal_range(tx_in.
prevout); range.first != range.second; range.first++) {
1472 const Txid& spent_id = range.first->second;
1474 if (spent_id == txid)
continue;
1486 for (
const CTxIn& tx_in : tx->vin) {
1487 auto parent_it = mapWallet.find(tx_in.
prevout.
hash);
1488 if (parent_it != mapWallet.end()) {
1489 CWalletTx& parent_wtx = parent_it->second;
1503 auto it = mapWallet.find(tx->GetHash());
1504 if (it != mapWallet.end()) {
1537 const Txid& txid = tx->GetHash();
1539 for (
const CTxIn& tx_in : tx->vin) {
1543 for (
auto range = mapTxSpends.equal_range(tx_in.
prevout); range.first != range.second; range.first++) {
1544 const Txid& spent_id = range.first->second;
1557 for (
const CTxIn& tx_in : tx->vin) {
1558 auto parent_it = mapWallet.find(tx_in.
prevout.
hash);
1559 if (parent_it != mapWallet.end()) {
1560 CWalletTx& parent_wtx = parent_it->second;
1587 bool wallet_updated =
false;
1588 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1594 if (wallet_updated || block.
height % 144 == 0) {
1608 int disconnect_height = block.
height;
1610 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1616 for (
const CTxIn& tx_in : ptx->vin) {
1618 if (!mapTxSpends.contains(tx_in.
prevout))
continue;
1620 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(tx_in.
prevout);
1623 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) {
1624 CWalletTx& wtx = mapWallet.find(_it->second)->second;
1628 auto try_updating_state = [&](
CWalletTx& tx) {
1651void CWallet::BlockUntilSyncedToCurrentChain()
const {
1668 return txo->GetTxOut().nValue;
1693 for (
const auto& spkm : it->second) {
1694 res = res || spkm->IsMine(
script);
1719 if (outpoint.
n >= wtx->GetTx()->vout.size()) {
1722 return IsMine(wtx->GetTx()->vout[outpoint.
n]);
1741 throw std::runtime_error(std::string(__func__) +
": value out of range");
1749 bool result =
false;
1751 if (!spk_man->IsHDEnabled())
return false;
1763 if (spk_man && spk_man->CanGetAddresses(internal)) {
1781 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1795 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1830 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1844 if (time < birthtime) {
1862 int start_height = 0;
1902 constexpr auto INTERVAL_TIME{60s};
1903 auto current_time{reserver.
now()};
1904 auto start_time{reserver.
now()};
1908 uint256 block_hash = start_block;
1911 std::unique_ptr<FastWalletRescanFilter> fast_rescan_filter;
1915 fast_rescan_filter ?
"fast variant using block filters" :
"slow variant inspecting all blocks");
1923 double progress_current = progress_begin;
1924 int block_height = start_height;
1926 if (progress_end - progress_begin > 0.0) {
1927 m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin);
1931 if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
1935 bool next_interval = reserver.
now() >= current_time + INTERVAL_TIME;
1936 if (next_interval) {
1937 current_time = reserver.
now();
1938 WalletLogPrintf(
"Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
1941 bool fetch_block{
true};
1942 if (fast_rescan_filter) {
1943 fast_rescan_filter->UpdateIfNeeded();
1944 auto matches_block{fast_rescan_filter->MatchesBlock(block_hash)};
1945 if (matches_block.has_value()) {
1946 if (*matches_block) {
1951 fetch_block =
false;
1954 LogDebug(
BCLog::SCAN,
"Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.
ToString());
1960 bool block_still_active =
false;
1961 bool next_block =
false;
1971 if (save_progress && next_interval) found_block.
locator(loc);
1976 if (!block_still_active) {
1983 for (
size_t posInBlock = 0; posInBlock < block.
vtx.size(); ++posInBlock) {
2001 if (max_height && block_height >= *max_height) {
2020 block_hash = next_block_hash;
2025 const uint256 prev_tip_hash = tip_hash;
2027 if (!max_height && prev_tip_hash != tip_hash) {
2039 WalletLogPrintf(
"Rescan aborted at block %d. Progress=%f\n", block_height, progress_current);
2041 }
else if (
chain().shutdownRequested()) {
2042 WalletLogPrintf(
"Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height, progress_current);
2051 std::string& err_string,
2066 const char* what{
""};
2067 switch (broadcast_method) {
2069 what =
"to mempool and for broadcast to peers";
2072 what =
"to mempool without broadcast";
2075 what =
"for private broadcast without adding to the mempool";
2099 result.erase(myHash);
2111 if (!
chain().isReadyToBroadcast())
return false;
2153 int submitted_tx_count = 0;
2160 std::set<CWalletTx*, WalletTxOrderComparator> to_submit;
2161 for (
auto& [txid, wtx] : mapWallet) {
2163 if (!wtx.isUnconfirmed())
continue;
2168 to_submit.insert(&wtx);
2171 for (
auto wtx : to_submit) {
2172 std::string unused_err_string;
2177 if (submitted_tx_count > 0) {
2178 WalletLogPrintf(
"%s: resubmit %u unconfirmed transactions\n", __func__, submitted_tx_count);
2186 for (
const std::shared_ptr<CWallet>& pwallet :
GetWallets(context)) {
2187 if (!pwallet->ShouldResend())
continue;
2189 pwallet->SetNextResend();
2199 std::map<COutPoint, Coin> coins;
2200 for (
auto& input : tx.
vin) {
2201 const auto mi = mapWallet.find(input.prevout.hash);
2202 if(mi == mapWallet.end() || input.prevout.n >= mi->second.GetTx()->vout.size()) {
2207 coins[input.prevout] =
Coin(wtx.
GetTx()->vout[input.prevout.n], prev_height, wtx.
IsCoinBase());
2209 std::map<int, bilingual_str> input_errors;
2219 if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) {
2243 const auto it = mapWallet.find(txhash);
2244 if (it != mapWallet.end()) {
2261 int n_signed_this_spkm = 0;
2262 const auto error{spk_man->FillPSBT(psbtx, txdata, options, &n_signed_this_spkm)};
2268 (*n_signed) += n_signed_this_spkm;
2276 for (
size_t i = 0; i < psbtx.
inputs.size(); ++i) {
2288 if (spk_man_pair.second->CanProvide(script_pub_key, sigdata)) {
2290 return spk_man_pair.second->SignMessage(message, pkhash, str_sig);
2300 return *change_type;
2309 bool any_wpkh{
false};
2311 bool any_pkh{
false};
2313 for (
const auto& recipient : vecSend) {
2314 if (std::get_if<WitnessV1Taproot>(&recipient.dest)) {
2316 }
else if (std::get_if<WitnessV0KeyHash>(&recipient.dest)) {
2318 }
else if (std::get_if<ScriptHash>(&recipient.dest)) {
2320 }
else if (std::get_if<PKHash>(&recipient.dest)) {
2326 if (has_bech32m_spkman && any_tr) {
2331 if (has_bech32_spkman && any_wpkh) {
2336 if (has_p2sh_segwit_spkman && any_sh) {
2342 if (has_legacy_spkman && any_pkh) {
2347 if (has_bech32m_spkman) {
2350 if (has_bech32_spkman) {
2359 std::optional<Txid> replaces_txid,
2360 std::optional<std::string> comment,
2361 std::optional<std::string> comment_to,
2362 const std::vector<std::string>& messages,
2363 const std::vector<std::string>& payment_requests
2375 if (!messages.empty()) wtx.
m_messages = messages;
2382 throw std::runtime_error(std::string(__func__) +
": Wallet db error, transaction commit failed");
2386 for (
const CTxIn& txin : tx->vin) {
2397 std::string err_string;
2399 WalletLogPrintf(
"CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
2417 const auto wallet_file =
m_database->Filename();
2418 switch (nLoadWalletRet) {
2422 warnings.push_back(
strprintf(
_(
"Error reading %s! All keys read correctly, but transaction data"
2423 " or address metadata may be missing or incorrect."),
2427 warnings.push_back(
strprintf(
_(
"Error reading %s! Transaction data may be missing or incorrect."
2428 " Rescanning wallet."), wallet_file));
2431 error =
strprintf(
_(
"Error loading %s: Wallet corrupted"), wallet_file);
2434 error =
strprintf(
_(
"Error loading %s: Wallet requires newer version of %s"), wallet_file, CLIENT_NAME);
2437 error =
strprintf(
_(
"Error loading %s: External signer wallet being loaded without external signer support compiled"), wallet_file);
2440 error =
strprintf(
_(
"Unrecognized descriptor found. Loading wallet %s\n\n"
2441 "The wallet might have been created on a newer version.\n"
2442 "Please try running the latest software version.\n"), wallet_file);
2445 error =
strprintf(
_(
"Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
2446 "The wallet might have been tampered with or created with malicious intent.\n"), wallet_file);
2449 error =
strprintf(
_(
"Error loading %s: Wallet is a legacy wallet. Please migrate to a descriptor wallet using the migration tool (migratewallet RPC)."), wallet_file);
2452 error =
strprintf(
_(
"Error loading %s"), wallet_file);
2455 return nLoadWalletRet;
2468 if (!was_txn_committed)
return util::Error{
_(
"Error starting/committing db txn for wallet transactions removal process")};
2478 std::vector<
decltype(mapWallet)::const_iterator> erased_txs;
2480 for (
const Txid& hash : txs_to_remove) {
2481 auto it_wtx = mapWallet.find(hash);
2482 if (it_wtx == mapWallet.end()) {
2488 erased_txs.emplace_back(it_wtx);
2494 for (
const auto& it : erased_txs) {
2495 const Txid hash{it->first};
2496 wtxOrdered.erase(it->second.m_it_wtxOrdered);
2497 for (
const auto& txin : it->second.GetTx()->vin) {
2498 auto range = mapTxSpends.equal_range(txin.prevout);
2499 for (
auto iter = range.first; iter != range.second; ++iter) {
2500 if (iter->second == hash) {
2501 mapTxSpends.erase(iter);
2506 for (
unsigned int i = 0; i < it->second.GetTx()->vout.size(); ++i) {
2509 mapWallet.erase(it);
2521 bool fUpdated =
false;
2523 std::optional<AddressPurpose> purpose;
2526 std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
2527 fUpdated = mi != m_address_book.end() && !mi->second.IsChange();
2529 CAddressBookData& record = mi != m_address_book.end() ? mi->second : m_address_book[address];
2531 is_mine =
IsMine(address);
2540 WalletLogPrintf(
"Error: fail to write address book 'purpose' entry\n");
2543 if (!batch.
WriteName(encoded_dest, strName)) {
2577 WalletLogPrintf(
"%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, CLIENT_BUGREPORT);
2599 m_address_book.erase(address);
2611 unsigned int count = 0;
2613 count += spk_man.second->GetKeyPoolSize();
2623 unsigned int count = 0;
2625 count += spk_man->GetKeyPoolSize();
2635 res &= spk_man->TopUp(kpSize);
2648 auto op_dest = spk_man->GetNewDestination(type);
2668 for (
auto& entry : mapWallet) {
2671 for (
unsigned int i = 0; i < wtx.
GetTx()->vout.size(); i++) {
2684 for (
const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book) {
2685 const auto& entry = item.second;
2686 func(item.first, entry.GetLabel(), entry.IsChange(), entry.purpose);
2693 std::vector<CTxDestination> result;
2701 result.emplace_back(dest);
2709 std::set<std::string> label_set;
2711 bool _is_change,
const std::optional<AddressPurpose>& _purpose) {
2712 if (_is_change)
return;
2713 if (!purpose || purpose == _purpose) {
2714 label_set.insert(_label);
2729 auto op_address =
m_spk_man->GetReservedDestination(
type, internal, index);
2730 if (!op_address)
return op_address;
2760 if (signer_spk_man ==
nullptr) {
2765 return signer_spk_man->DisplayAddress(dest, *
signer);
2767 return util::Error{
_(
"There is no ScriptPubKeyManager for this address")};
2773 m_locked_coins.emplace(coin, persistent);
2790 auto locked_coin_it = m_locked_coins.find(output);
2791 if (locked_coin_it != m_locked_coins.end()) {
2792 bool persisted = locked_coin_it->second;
2793 m_locked_coins.erase(locked_coin_it);
2805 bool success =
true;
2807 for (
const auto& [coin, persistent] : m_locked_coins) {
2810 m_locked_coins.clear();
2817 return m_locked_coins.contains(output);
2823 for (
const auto& [coin,
_] : m_locked_coins) {
2824 vOutpts.push_back(coin);
2853 std::optional<uint256> block_hash;
2855 block_hash = conf->confirmed_block_hash;
2857 block_hash = conf->conflicting_block_hash;
2863 int64_t block_max_time;
2864 if (
chain().findBlock(*block_hash,
FoundBlock().time(blocktime).maxTime(block_max_time))) {
2865 if (rescanning_old_block) {
2866 nTimeSmart = block_max_time;
2869 int64_t latestEntry = 0;
2872 int64_t latestTolerated = latestNow + 300;
2874 for (
auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
2884 if (nSmartTime <= latestTolerated) {
2885 latestEntry = nSmartTime;
2886 if (nSmartTime > latestNow) {
2887 latestNow = nSmartTime;
2893 nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
2904 if (std::get_if<CNoDestination>(&dest))
2908 if (
auto* data{
common::FindKey(m_address_book, dest)}) data->previously_spent =
false;
2918 m_address_book[dest].previously_spent =
true;
2923 m_address_book[dest].receive_requests[id] =
request;
2928 if (
auto* data{
common::FindKey(m_address_book, dest)})
return data->previously_spent;
2934 std::vector<std::string> values;
2935 for (
const auto& [dest, entry] : m_address_book) {
2936 for (
const auto& [
id,
request] : entry.receive_requests) {
2946 m_address_book[dest].receive_requests[id] = value;
2953 m_address_book[dest].receive_requests.erase(
id);
2959 const fs::path name_path = fs::PathFromString(name);
2962 if (name_path != name_path.lexically_normal()) {
2967 if (!name_path.empty() && (*name_path.begin() == fs::PathFromString(
".") || *name_path.begin() == fs::PathFromString(
".."))) {
2968 return util::Error{
Untranslated(
"Wallet name given as a relative path cannot begin with ./ or ../, for wallets not in the walletdir, please use an absolute path.")};
2972 if (name_path.has_root_path() && name_path.root_path() == name_path) {
2983 fs::file_type path_type = fs::symlink_status(wallet_path).type();
2984 if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory ||
2985 (path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) ||
2986 (path_type == fs::file_type::regular && name_path.filename() == name_path))) {
2988 "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
2989 "database/log.?????????? files can be stored, a location where such a directory could be created, "
2990 "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
3004 return MakeDatabase(*wallet_path, options, status, error_string);
3012 if (!
args.
GetArg(
"-addresstype",
"").empty()) {
3018 wallet->m_default_address_type = parsed.value();
3021 if (!
args.
GetArg(
"-changetype",
"").empty()) {
3027 wallet->m_default_change_type = parsed.value();
3030 if (
const auto arg{
args.
GetArg(
"-mintxfee")}) {
3031 std::optional<CAmount> min_tx_fee =
ParseMoney(*arg);
3037 _(
"This is the minimum transaction fee you pay on every transaction."));
3043 if (
const auto arg{
args.
GetArg(
"-maxapsfee")}) {
3044 const std::string& max_aps_fee{*arg};
3045 if (max_aps_fee ==
"-1") {
3046 wallet->m_max_aps_fee = -1;
3047 }
else if (std::optional<CAmount> max_fee =
ParseMoney(max_aps_fee)) {
3050 _(
"This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
3052 wallet->m_max_aps_fee = max_fee.value();
3059 if (
const auto arg{
args.
GetArg(
"-fallbackfee")}) {
3060 std::optional<CAmount> fallback_fee =
ParseMoney(*arg);
3061 if (!fallback_fee) {
3062 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s'"),
"-fallbackfee", *arg);
3066 _(
"This is the transaction fee you may pay when fee estimates are not available."));
3072 wallet->m_allow_fallback_fee =
wallet->m_fallback_fee.GetFeePerK() != 0;
3074 if (
const auto arg{
args.
GetArg(
"-discardfee")}) {
3075 std::optional<CAmount> discard_fee =
ParseMoney(*arg);
3077 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s'"),
"-discardfee", *arg);
3081 _(
"This is the transaction fee you may discard if change is smaller than dust at this level"));
3086 if (
const auto arg{
args.
GetArg(
"-maxtxfee")}) {
3087 std::optional<CAmount> max_fee =
ParseMoney(*arg);
3092 warnings.push_back(
strprintf(
_(
"%s is set very high! Fees this large could be paid on a single transaction."),
"-maxtxfee"));
3096 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
3101 wallet->m_default_max_tx_fee = max_fee.value();
3104 if (
const auto arg{
args.
GetArg(
"-consolidatefeerate")}) {
3105 if (std::optional<CAmount> consolidate_feerate =
ParseMoney(*arg)) {
3115 _(
"The wallet will avoid paying less than the minimum relay fee."));
3122 warnings.push_back(
_(
"-walletrbf is deprecated and will be fully removed in the next release."));
3123 wallet->m_signal_rbf = *value;
3133std::shared_ptr<CWallet>
CWallet::CreateNew(
WalletContext& context,
const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags,
bool born_encrypted,
bilingual_str& error, std::vector<bilingual_str>& warnings)
3136 const std::string& walletFile = database->Filename();
3138 const auto start{SteadyClock::now()};
3149 error =
strprintf(
_(
"Error creating %s: Could not write version metadata."), walletFile);
3153 LOCK(walletInstance->cs_wallet);
3163 if (!born_encrypted) {
3164 walletInstance->SetupWalletGeneration();
3170 walletInstance->SetLastBlockProcessed(*tip_height,
chain->
getBlockHash(*tip_height));
3178 walletInstance->TopUpKeyPool();
3181 walletInstance->DisconnectChainNotifications();
3185 return walletInstance;
3191 const std::string& walletFile = database->Filename();
3193 const auto start{SteadyClock::now()};
3201 auto nLoadWalletRet = walletInstance->PopulateWalletFromDB(error, warnings);
3208 for (
auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
3209 if (spk_man->HavePrivateKeys()) {
3210 warnings.push_back(
strprintf(
_(
"Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
3219 walletInstance->TopUpKeyPool();
3222 walletInstance->DisconnectChainNotifications();
3226 WITH_LOCK(walletInstance->cs_wallet, walletInstance->LogStats());
3228 return walletInstance;
3234 LOCK(walletInstance->cs_wallet);
3236 assert(!walletInstance->m_chain || walletInstance->m_chain == &
chain);
3237 walletInstance->m_chain = &
chain;
3247 error =
Untranslated(
"Wallet files should not be reused across chains. Restart bitcoind with -walletcrosschain to override.");
3259 walletInstance->m_chain_notifications_handler = walletInstance->chain().
handleNotifications(walletInstance);
3262 int rescan_height = 0;
3263 if (!rescan_required)
3269 rescan_height = *fork_height;
3276 walletInstance->SetLastBlockProcessedInMem(*tip_height,
chain.
getBlockHash(*tip_height));
3278 walletInstance->SetLastBlockProcessedInMem(-1,
uint256());
3281 if (tip_height && *tip_height != rescan_height)
3285 std::optional<int64_t> time_first_key = walletInstance->m_birth_time.load();
3286 if (time_first_key) {
3293 rescan_height = *tip_height;
3301 int block_height = *tip_height;
3302 while (block_height > 0 &&
chain.
haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
3306 if (rescan_height != block_height) {
3317 _(
"Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of a pruned node)") :
3319 "Error loading wallet. Wallet requires blocks to be downloaded, "
3320 "and software does not currently support loading wallets while "
3321 "blocks are being downloaded out of order when using assumeutxo "
3322 "snapshots. Wallet should be able to load successfully after "
3323 "node sync reaches height %s"), block_height);
3329 walletInstance->WalletLogPrintf(
"Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
3334 error =
_(
"Failed to acquire rescan reserver during wallet initialization");
3337 ScanResult scan_res = walletInstance->ScanForWalletTransactions(
chain.
getBlockHash(rescan_height), rescan_height, {}, reserver,
true);
3339 error =
_(
"Failed to rescan the wallet during initialization");
3354 const auto& address_book_it = m_address_book.find(dest);
3355 if (address_book_it == m_address_book.end())
return nullptr;
3356 if ((!allow_change) && address_book_it->second.IsChange()) {
3359 return &address_book_it->second;
3382 assert(conf->confirmed_block_height >= 0);
3385 assert(conf->conflicting_block_height >= 0);
3400 assert(chain_depth >= 0);
3418 return vMasterKey.empty();
3428 if (!vMasterKey.empty()) {
3429 memory_cleanse(vMasterKey.data(), vMasterKey.size() *
sizeof(
decltype(vMasterKey)::value_type));
3443 if (!spk_man_pair.second->CheckDecryptionKey(vMasterKeyIn)) {
3447 vMasterKey = vMasterKeyIn;
3455 std::set<ScriptPubKeyMan*> spk_mans;
3456 for (
bool internal : {
false,
true}) {
3460 spk_mans.insert(spk_man);
3470 if (ext_spkm == &spkm)
return true;
3473 if (int_spkm == &spkm)
return true;
3480 std::set<ScriptPubKeyMan*> spk_mans;
3482 spk_mans.insert(spk_man_pair.second.get());
3490 std::map<OutputType, ScriptPubKeyMan*>::const_iterator it = spk_managers.find(type);
3491 if (it == spk_managers.end()) {
3499 std::set<ScriptPubKeyMan*> spk_mans;
3504 spk_mans.insert(it->second.begin(), it->second.end());
3507 Assume(std::all_of(spk_mans.begin(), spk_mans.end(), [&
script, &sigdata](
ScriptPubKeyMan* spkm) { return spkm->CanProvide(script, sigdata); }));
3533 return it->second.at(0)->GetSolvingProvider(
script);
3541 std::vector<WalletDescriptor> descs;
3544 LOCK(desc_spk_man->cs_desc_man);
3545 descs.push_back(desc_spk_man->GetWalletDescriptor());
3584 std::unique_ptr<ScriptPubKeyMan> spk_manager = std::make_unique<LegacyDataSPKM>(*
this);
3590 uint256 id = spk_manager->GetID();
3597 return cb(vMasterKey);
3608 if (spkm->HaveCryptedKeys())
return true;
3616 spk_man->NotifyCanGetAddressesChanged.connect([
this] {
3619 spk_man->NotifyFirstKeyTimeChanged.connect([
this](
const ScriptPubKeyMan*, int64_t time) {
3627 std::unique_ptr<DescriptorScriptPubKeyMan> spk_manager;
3640 throw std::runtime_error(std::string(__func__) +
": Wallet is locked, cannot setup new descriptors");
3644 uint256 id = spk_manager->GetID();
3653 for (
bool internal : {
false,
true}) {
3684 }))
throw std::runtime_error(
"Error: cannot process db transaction for descriptors setup");
3693 if (!signer_res.
isObject())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3696 if (!batch.
TxnBegin())
throw std::runtime_error(
"Error: cannot create db transaction for descriptors import");
3698 for (
bool internal : {
false,
true}) {
3699 const UniValue& descriptor_vals = signer_res.
find_value(internal ?
"internal" :
"receive");
3700 if (!descriptor_vals.
isArray())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3702 const std::string& desc_str = desc_val.getValStr();
3704 std::string desc_error;
3705 auto descs =
Parse(desc_str,
keys, desc_error,
false);
3706 if (descs.empty()) {
3707 throw std::runtime_error(std::string(__func__) +
": Invalid descriptor \"" + desc_str +
"\" (" + desc_error +
")");
3709 auto& desc = descs.at(0);
3710 if (!desc->GetOutputType()) {
3715 uint256 id = spk_manager->GetID();
3722 if (!batch.
TxnCommit())
throw std::runtime_error(
"Error: cannot commit db transaction for descriptors import");
3747 throw std::runtime_error(std::string(__func__) +
": writing active ScriptPubKeyMan id failed");
3762 spk_mans[type] = spk_man;
3764 const auto it = spk_mans_other.find(type);
3765 if (it != spk_mans_other.end() && it->second == spk_man) {
3766 spk_mans_other.erase(type);
3775 if (spk_man !=
nullptr && spk_man->GetID() ==
id) {
3779 throw std::runtime_error(std::string(__func__) +
": erasing active ScriptPubKeyMan id failed");
3783 spk_mans.erase(type);
3792 DescriptorScriptPubKeyMan* spk_manager = dynamic_cast<DescriptorScriptPubKeyMan*>(item.second.get());
3793 return spk_manager != nullptr && spk_manager->HasWalletDescriptor(desc);
3807 return std::nullopt;
3811 if (!desc_spk_man) {
3812 throw std::runtime_error(std::string(__func__) +
": unexpected ScriptPubKeyMan type.");
3815 LOCK(desc_spk_man->cs_desc_man);
3816 const auto& type = desc_spk_man->GetWalletDescriptor().descriptor->GetOutputType();
3817 assert(type.has_value());
3831 if (
auto spkm_res = spk_man->UpdateWalletDescriptor(desc, signing_provider); !spkm_res) {
3836 spk_man = new_spk_man.get();
3839 uint256 id = new_spk_man->GetID();
3845 return util::Error{
_(
"Unable to write descriptor cache")};
3852 auto script_pub_keys = spk_man->GetScriptPubKeys();
3853 if (script_pub_keys.empty()) {
3854 return util::Error{
_(
"Could not generate scriptPubKeys (cache is empty)")};
3858 for (
const auto&
script : script_pub_keys) {
3868 spk_man->WriteDescriptor();
3873 return std::reference_wrapper(*spk_man);
3880 WalletLogPrintf(
"Migrating wallet storage database from BerkeleyDB to SQLite.\n");
3883 error =
_(
"Error: This wallet already uses SQLite");
3888 std::unique_ptr<DatabaseBatch> batch =
m_database->MakeBatch();
3889 std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor();
3890 std::vector<std::pair<SerializeData, SerializeData>> records;
3892 error =
_(
"Error: Unable to begin reading all records in the database");
3899 status = cursor->Next(ss_key, ss_value);
3905 records.emplace_back(key, value);
3910 error =
_(
"Error: Unable to read all records in the database");
3915 fs::path db_path = fs::PathFromString(
m_database->Filename());
3917 fs::remove(db_path);
3928 std::unique_ptr<WalletDatabase> new_db =
MakeDatabase(wallet_path, opts, db_status, error);
3935 bool began = batch->TxnBegin();
3937 for (
const auto& [key, value] : records) {
3938 if (!batch->Write(std::span{key}, std::span{value})) {
3945 bool committed = batch->TxnCommit();
3955 if (!
Assume(legacy_spkm)) {
3958 return std::nullopt;
3962 if (res == std::nullopt) {
3963 error =
_(
"Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
3964 return std::nullopt;
3974 if (!
Assume(legacy_spkm)) {
3980 bool has_spendable_material = !data.desc_spkms.empty() || data.master_key.key.IsValid();
3983 std::set<CTxDestination> not_migrated_dests;
3992 if (!data.watch_descs.empty())
Assume(!data.watchonly_wallet->m_cached_spks.empty());
3993 if (!data.solvable_descs.empty())
Assume(!data.solvable_wallet->m_cached_spks.empty());
3995 for (
auto& desc_spkm : data.desc_spkms) {
3997 return util::Error{
_(
"Error: Duplicate descriptors created during migration. Your wallet may be corrupted.")};
3999 uint256 id = desc_spkm->GetID();
4005 return util::Error{
_(
"Error: cannot remove legacy wallet records")};
4017 if (data.master_key.key.IsValid()) {
4036 std::vector<Txid> txids_to_delete;
4037 std::unique_ptr<WalletBatch> watchonly_batch;
4038 if (data.watchonly_wallet) {
4039 watchonly_batch = std::make_unique<WalletBatch>(data.watchonly_wallet->GetDatabase());
4040 if (!watchonly_batch->TxnBegin())
return util::Error{
strprintf(
_(
"Error: database transaction cannot be executed for wallet %s"), data.watchonly_wallet->GetName())};
4042 LOCK(data.watchonly_wallet->cs_wallet);
4043 data.watchonly_wallet->nOrderPosNext = nOrderPosNext;
4044 watchonly_batch->WriteOrderPosNext(data.watchonly_wallet->nOrderPosNext);
4046 if (!watchonly_batch->WriteBestBlock(best_block_locator)) {
4047 return util::Error{
_(
"Error: Unable to write watchonly wallet best block locator record")};
4050 std::unique_ptr<WalletBatch> solvables_batch;
4051 if (data.solvable_wallet) {
4052 solvables_batch = std::make_unique<WalletBatch>(data.solvable_wallet->GetDatabase());
4053 if (!solvables_batch->TxnBegin())
return util::Error{
strprintf(
_(
"Error: database transaction cannot be executed for wallet %s"), data.solvable_wallet->GetName())};
4055 if (!solvables_batch->WriteBestBlock(best_block_locator)) {
4056 return util::Error{
_(
"Error: Unable to write solvable wallet best block locator record")};
4063 if (data.watchonly_wallet) {
4064 LOCK(data.watchonly_wallet->cs_wallet);
4065 if (data.watchonly_wallet->IsMine(*wtx->GetTx()) || data.watchonly_wallet->IsFromMe(*wtx->GetTx())) {
4067 const Txid& hash = wtx->GetHash();
4071 if (!data.watchonly_wallet->LoadToWallet(std::move(copy_wtx))) {
4072 return util::Error{
strprintf(
_(
"Error: Could not add watchonly tx %s to watchonly wallet"), wtx->GetHash().GetHex())};
4074 watchonly_batch->WriteFullTx(data.watchonly_wallet->mapWallet.at(hash));
4077 txids_to_delete.push_back(hash);
4084 return util::Error{
strprintf(
_(
"Error: Transaction %s in wallet cannot be identified to belong to migrated wallets"), wtx->GetHash().GetHex())};
4091 if (txids_to_delete.size() > 0) {
4092 if (
auto res =
RemoveTxs(local_wallet_batch, txids_to_delete); !res) {
4098 std::vector<std::pair<std::shared_ptr<CWallet>, std::unique_ptr<WalletBatch>>> wallets_vec;
4099 if (data.watchonly_wallet) wallets_vec.emplace_back(data.watchonly_wallet, std::move(watchonly_batch));
4100 if (data.solvable_wallet) wallets_vec.emplace_back(data.solvable_wallet, std::move(solvables_batch));
4106 if (entry.label) batch.
WriteName(address, *entry.label);
4107 for (
const auto& [
id,
request] : entry.receive_requests) {
4114 std::vector<CTxDestination> dests_to_delete;
4115 for (
const auto& [dest, record] : m_address_book) {
4119 bool copied =
false;
4120 for (
auto& [
wallet, batch] : wallets_vec) {
4122 if (require_transfer && !
wallet->IsMine(dest))
continue;
4125 wallet->m_address_book[dest] = record;
4126 func_store_addr(*batch, dest, record);
4130 if (require_transfer) {
4131 dests_to_delete.push_back(dest);
4139 if (require_transfer && !copied) {
4142 if (not_migrated_dests.contains(dest)) {
4143 dests_to_delete.push_back(dest);
4147 return util::Error{
_(
"Error: Address book data in wallet cannot be identified to belong to migrated wallets")};
4152 for (
auto& [
wallet, batch] : wallets_vec) {
4159 if (dests_to_delete.size() > 0) {
4160 for (
const auto& dest : dests_to_delete) {
4162 return util::Error{
_(
"Error: Unable to remove watchonly address book data")};
4170 if (!has_spendable_material) {
4171 if (!m_address_book.empty())
return util::Error{
_(
"Error: Not all address book records were migrated")};
4172 if (!mapWallet.empty())
return util::Error{
_(
"Error: Not all transaction records were migrated")};
4188 const std::string& name{
wallet.GetName()};
4189 return name.empty() ?
"default_wallet" : name;
4197 std::optional<MigrationData> data =
wallet.GetDescriptorsForLegacy(error);
4198 if (data == std::nullopt)
return false;
4201 if (data->watch_descs.size() > 0 || data->solvable_descs.size() > 0) {
4218 if (data->watch_descs.size() > 0) {
4219 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the watched scripts\n");
4222 std::vector<bilingual_str> warnings;
4224 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4226 error =
strprintf(
_(
"Wallet file creation failed: %s"), error);
4231 if (!data->watchonly_wallet) {
4232 error =
_(
"Error: Failed to create new watchonly wallet");
4236 LOCK(data->watchonly_wallet->cs_wallet);
4239 for (
const auto& [desc_str, creation_time] : data->watch_descs) {
4242 std::string parse_err;
4243 std::vector<std::unique_ptr<Descriptor>> descs =
Parse(desc_str,
keys, parse_err,
true);
4245 assert(descs.size() == 1);
4246 assert(!descs.at(0)->IsRange());
4250 if (
auto spkm_res = data->watchonly_wallet->AddWalletDescriptor(w_desc,
keys,
"",
false); !spkm_res) {
4258 if (data->solvable_descs.size() > 0) {
4259 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the unwatched solvable scripts\n");
4262 std::vector<bilingual_str> warnings;
4264 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4266 error =
strprintf(
_(
"Wallet file creation failed: %s"), error);
4271 if (!data->solvable_wallet) {
4272 error =
_(
"Error: Failed to create new watchonly wallet");
4276 LOCK(data->solvable_wallet->cs_wallet);
4279 for (
const auto& [desc_str, creation_time] : data->solvable_descs) {
4282 std::string parse_err;
4283 std::vector<std::unique_ptr<Descriptor>> descs =
Parse(desc_str,
keys, parse_err,
true);
4285 assert(descs.size() == 1);
4286 assert(!descs.at(0)->IsRange());
4290 if (
auto spkm_res = data->solvable_wallet->AddWalletDescriptor(w_desc,
keys,
"",
false); !spkm_res) {
4302 if (auto res_migration = wallet.ApplyMigrationData(batch, *data); !res_migration) {
4303 error = util::ErrorString(res_migration);
4306 wallet.WalletLogPrintf(
"Wallet migration complete.\n");
4313 std::vector<bilingual_str> warnings;
4319 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4326 if (!fs::exists(*wallet_path)) {
4330 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4342 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4348 std::shared_ptr<CWallet> local_wallet =
CWallet::LoadExisting(empty_context, wallet_name, std::move(database), error, warnings);
4349 if (!local_wallet) {
4360 std::vector<bilingual_str> warnings;
4366 const std::string wallet_name = local_wallet->GetName();
4370 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4379 const std::string backup_prefix = wallet_name.empty() ?
MigrationPrefixName(*local_wallet) : [&] {
4381 const auto legacy_wallet_path = fs::weakly_canonical(
GetWalletDir() / fs::PathFromString(wallet_name));
4382 return fs::PathToString(legacy_wallet_path.filename());
4385 fs::path backup_filename = fs::PathFromString(
strprintf(
"%s_%d.legacy.bak", backup_prefix,
GetTime()));
4387 if (!local_wallet->BackupWallet(fs::PathToString(backup_path))) {
4388 return util::Error{
_(
"Error: Unable to make a backup of your wallet")};
4392 bool success =
false;
4395 if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
4396 if (passphrase.find(
'\0') == std::string::npos) {
4397 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
4399 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase entered was incorrect. "
4400 "The passphrase contains a null character (ie - a zero byte). "
4401 "If this passphrase was set with a version of this software prior to 25.0, "
4402 "please try again with only the characters up to — but not including — "
4403 "the first null character.")};
4413 bool empty_local_wallet =
false;
4416 LOCK(local_wallet->cs_wallet);
4418 if (!local_wallet->MigrateToSQLite(error))
return util::Error{error};
4422 success =
DoMigration(*local_wallet, context, error, res, load_wallet);
4424 empty_local_wallet = local_wallet->GetAllScriptPubKeyMans().empty();
4436 std::set<fs::path> wallet_files_to_remove;
4437 std::set<fs::path> wallet_empty_dirs_to_remove;
4442 const auto files =
wallet.GetDatabase().Files();
4443 wallet_files_to_remove.insert(files.begin(), files.end());
4444 if (
wallet.GetName() != wallet_name) {
4449 wallet_empty_dirs_to_remove.insert(fs::PathFromString(
wallet.GetDatabase().Filename()).parent_path());
4457 if (empty_local_wallet) {
4459 std::vector<fs::path> paths_to_remove = local_wallet->GetDatabase().Files();
4460 local_wallet.reset();
4461 for (
const auto& path_to_remove : paths_to_remove) fs::remove(path_to_remove);
4465 LogInfo(
"Loading new wallets after migration...\n");
4472 bool main_wallet_set{
false};
4474 if (success && *wallet_ptr) {
4475 std::shared_ptr<CWallet>&
wallet = *wallet_ptr;
4477 track_for_cleanup(*
wallet);
4479 std::string wallet_name =
wallet->GetName();
4482 wallet =
LoadWallet(context, wallet_name, std::nullopt, options, status, error, warnings);
4484 LogError(
"Failed to load wallet '%s' after migration. Rolling back migration to preserve consistency. "
4485 "Error cause: %s\n", wallet_name, error.
original);
4492 if (!main_wallet_set) {
4495 main_wallet_set =
true;
4507 std::vector<std::shared_ptr<CWallet>> created_wallets;
4508 if (local_wallet) created_wallets.push_back(std::move(local_wallet));
4513 for (std::shared_ptr<CWallet>&
wallet : created_wallets) {
4514 track_for_cleanup(*
wallet);
4518 for (std::shared_ptr<CWallet>& w : created_wallets) {
4519 if (w->HaveChain()) {
4522 error +=
_(
"\nUnable to cleanup failed migration");
4528 assert(w.use_count() == 1);
4534 for (
const fs::path& file : wallet_files_to_remove) {
4539 for (
const fs::path& dir : wallet_empty_dirs_to_remove) {
4540 Assume(fs::is_empty(dir));
4547 const auto& ptr_wallet =
RestoreWallet(context, backup_path, wallet_name, std::nullopt, status, restore_error, warnings,
false,
true);
4548 if (!restore_error.
empty()) {
4549 error += restore_error +
_(
"\nUnable to restore backup of wallet.");
4562 for (
const auto&
script : spks) {
4582 LOCK(desc_spkm->cs_desc_man);
4584 if (filter == HDKeyFilter::UnusedKey && w_desc.
descriptor->HasScripts())
continue;
4586 std::set<CPubKey> desc_pubkeys;
4587 std::set<CExtPubKey> desc_xpubs;
4588 w_desc.
descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
4590 xpubs[xpub].insert(desc_spkm);
4604 if (std::optional<CKey> key = desc_spkm->
GetKey(keyid)) {
4608 return std::nullopt;
4616 return std::nullopt;
4623 if (!m_last_block_processed.IsNull()) {
4637 for (uint32_t i = 0; i < wtx.
GetTx()->vout.size(); ++i) {
4639 if (!
IsMine(txout))
continue;
4641 if (m_txos.contains(outpoint)) {
4643 m_txos.emplace(outpoint,
WalletTXO{wtx, txout});
4651 for (
const auto& [
_, wtx] : mapWallet) {
4659 const auto& it = m_txos.find(outpoint);
4660 if (it == m_txos.end()) {
4661 return std::nullopt;
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a scriptPubKey for the destination.
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)
int64_t CAmount
Amount in satoshis (Can be negative).
std::string ToString(const T &t)
Locale-independent version of std::to_string.
constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
#define CHECK_NONFATAL(condition)
Identity function.
#define Assert(val)
Identity function.
#define STR_INTERNAL_BUG(msg)
#define Assume(val)
Assume is the identity function.
std::string GetArg(const std::string &strArg, const std::string &strDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return string argument or default value.
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
bool GetBoolArg(const std::string &strArg, bool fDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return boolean argument or default value.
std::vector< CTransactionRef > vtx
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
std::string ToString(FeeRateFormat fee_rate_format=FeeRateFormat::BTC_KVB) const
CFeeRate()=default
Fee rate of 0 satoshis per 0 vB.
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
An encapsulated private key.
CPubKey GetPubKey() const
Compute the public key from a private key.
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
A reference to a CKey: the Hash160 of its serialized public key.
An outpoint - a combination of a transaction hash and an index n into its vout.
An encapsulated public key.
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization).
Serialized script, used inside transaction inputs and outputs.
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.
An output of a transaction.
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 ...
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::optional< AddressPurpose > &purpose)
bool TopUpKeyPool(unsigned int kpSize=0)
DBErrors PopulateWalletFromDB(bilingual_str &error, std::vector< bilingual_str > &warnings)
unsigned int GetKeyPoolSize() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::optional< WalletTXO > GetTXO(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool IsActiveScriptPubKeyMan(const ScriptPubKeyMan &spkm) const
static bool AttachChain(const std::shared_ptr< CWallet > &wallet, interfaces::Chain &chain, 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...
static std::shared_ptr< CWallet > LoadExisting(WalletContext &context, const std::string &name, std::unique_ptr< WalletDatabase > database, bilingual_str &error, std::vector< bilingual_str > &warnings)
void AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
void LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
bool IsLockedCoin(const COutPoint &output) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool SignTransaction(CMutableTransaction &tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Fetch the inputs and sign with SIGHASH_ALL.
CWallet(interfaces::Chain *chain, const std::string &name, std::unique_ptr< WalletDatabase > database)
Construct wallet with specified name and database implementation.
std::unique_ptr< SigningProvider > GetSolvingProvider(const CScript &script) const
Get the SigningProvider for a script.
bool IsTxImmatureCoinBase(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void RefreshAllTXOs() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Cache outputs that belong to the wallet for all transactions in the wallet.
void AddActiveScriptPubKeyManWithDb(WalletBatch &batch, uint256 id, OutputType type, bool internal)
void TopUpCallback(const std::set< CScript > &spks, ScriptPubKeyMan *spkm) override
std::set< ScriptPubKeyMan * > GetActiveScriptPubKeyMans() const
Returns all unique ScriptPubKeyMans in m_internal_spk_managers and m_external_spk_managers.
const CAddressBookData * FindAddressBookEntry(const CTxDestination &, bool allow_change=false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void postInitProcess()
Wallet post-init setup Gives the wallet a chance to register repetitive tasks and complete post-init ...
std::optional< CExtKey > GetExtKey(const CExtPubKey &xpub) const
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...
bool SetAddressReceiveRequest(WalletBatch &batch, const CTxDestination &dest, const std::string &id, const std::string &value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
LegacyDataSPKM * GetLegacyDataSPKM() const
Get the LegacyDataSPKM used for all legacy output types and both internal and external chains.
void DisconnectChainNotifications()
Disconnect chain notifications and wait for all notifications to be processed.
std::optional< common::PSBTError > FillPSBT(PartiallySignedTransaction &psbtx, const common::PSBTFillOptions &options, bool &complete, size_t *n_signed=nullptr) const
Fills out a PSBT with information from the wallet.
void SetupWalletGeneration() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Setup new descriptors or seed for new address generation.
std::vector< CTxDestination > ListAddrBookAddresses(const std::optional< AddrBookFilter > &filter) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Filter and retrieve destinations stored in the addressbook.
DescriptorScriptPubKeyMan * GetDescriptorScriptPubKeyMan(const WalletDescriptor &desc) const
Return the DescriptorScriptPubKeyMan for a WalletDescriptor if it is already in the wallet.
std::optional< MigrationData > GetDescriptorsForLegacy(bilingual_str &error) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get all of the descriptors from a legacy wallet.
bool HaveCryptedKeys() const
LegacyDataSPKM * GetOrCreateLegacyDataSPKM()
interfaces::Chain & chain() const
Interface for accessing chain state.
bool Unlock(const CKeyingMaterial &vMasterKeyIn)
bool MigrateToSQLite(bilingual_str &error) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Move all records from the BDB database to a new SQLite database for storage.
bool BackupWallet(const std::string &strDest) const
bool SetAddressPreviouslySpent(WalletBatch &batch, const CTxDestination &dest, bool used) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor &desc, const KeyMap &keys, const CryptedKeyMap &ckeys)
Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it.
util::Result< void > RemoveTxs(std::vector< Txid > &txs_to_remove) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Erases the provided transactions from the wallet.
std::vector< std::string > GetAddressReceiveRequests() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::vector< WalletDescriptor > GetWalletDescriptors(const CScript &script) const
Get the wallet descriptors for a script.
size_t KeypoolCountExternalKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void CacheNewScriptPubKeys(const std::set< CScript > &spks, ScriptPubKeyMan *spkm)
Add scriptPubKeys for this ScriptPubKeyMan into the scriptPubKey cache.
int GetTxBlocksToMaturity(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool HasEncryptionKeys() const override
bool CanGrindR() const
Whether the (external) signer performs R-value signature grinding.
void CommitTransaction(CTransactionRef tx, std::optional< Txid > replaces_txid=std::nullopt, std::optional< std::string > comment=std::nullopt, std::optional< std::string > comment_to=std::nullopt, const std::vector< std::string > &messages={}, const std::vector< std::string > &payment_requests={})
Submit the transaction to the node's mempool and then relay to peers.
util::Result< CTxDestination > GetNewChangeDestination(OutputType type)
std::optional< bool > IsInternalScriptPubKeyMan(ScriptPubKeyMan *spk_man) const
void LoadLockedCoin(const COutPoint &coin, bool persistent) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void SetupLegacyDataSPKM()
Create a LegacyDataSPKM and set it for all legacy output types and both internal and external chains.
static std::shared_ptr< CWallet > CreateNew(WalletContext &context, const std::string &name, std::unique_ptr< WalletDatabase > database, uint64_t wallet_creation_flags, bool born_encrypted, bilingual_str &error, std::vector< bilingual_str > &warnings)
SigningResult SignMessage(const std::string &message, const PKHash &pkhash, std::string &str_sig) const
util::Result< void > ApplyMigrationData(WalletBatch &local_wallet_batch, MigrationData &data) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::optional< CKey > GetKey(const CKeyID &keyid) const
bool EraseAddressReceiveRequest(WalletBatch &batch, const CTxDestination &dest, const std::string &id) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool SetAddressBookWithDB(WalletBatch &batch, const CTxDestination &address, const std::string &strName, const std::optional< AddressPurpose > &strPurpose)
void WriteBestBlock() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Write the current best block to database.
bool DelAddressBookWithDB(WalletBatch &batch, const CTxDestination &address)
void LoadAddressReceiveRequest(const CTxDestination &dest, const std::string &id, const std::string &request) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Appends payment request to destination.
void AddScriptPubKeyMan(const uint256 &id, std::unique_ptr< ScriptPubKeyMan > spkm_man)
void DeactivateScriptPubKeyMan(uint256 id, OutputType type, bool internal)
bool LockCoin(const COutPoint &output, bool persist) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool IsLocked() const override
OutputType TransactionChangeType(const std::optional< OutputType > &change_type, const std::vector< CRecipient > &vecSend) const
std::set< ScriptPubKeyMan * > GetAllScriptPubKeyMans() const
Returns all unique ScriptPubKeyMans.
void RefreshTXOsFromTx(const CWalletTx &wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Cache outputs that belong to the wallet from a single transaction.
unsigned int ComputeTimeSmart(const CWalletTx &wtx, bool rescanning_old_block) const
Compute smart timestamp for a transaction being added to the wallet.
std::set< std::string > ListAddrBookLabels(std::optional< AddressPurpose > purpose) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Retrieve all the known labels in the address book.
void ListLockedCoins(std::vector< COutPoint > &vOutpts) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool UnlockAllCoins() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
util::Result< CTxDestination > GetNewDestination(OutputType type, const std::string &label)
ScriptPubKeyMan * GetScriptPubKeyMan(const OutputType &type, bool internal) const
Get the ScriptPubKeyMan for the given OutputType and internal/external chain.
bool IsAddressPreviouslySpent(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool WithEncryptionKey(std::function< bool(const CKeyingMaterial &)> cb) const override
RecursiveMutex cs_wallet
Main wallet lock.
void ForEachAddrBookEntry(const ListAddrBookFunc &func) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void ConnectScriptPubKeyManNotifiers()
Connect the signals from ScriptPubKeyMans to the signals in CWallet.
bool DelAddressBook(const CTxDestination &address)
void SetupOwnDescriptorScriptPubKeyMans(WalletBatch &batch) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Create new seed and default DescriptorScriptPubKeyMans for this wallet.
void SetupDescriptorScriptPubKeyMans() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
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.
bool UnlockCoin(const COutPoint &output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void LoadAddressPreviouslySpent(const CTxDestination &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Marks destination as previously spent.
util::Result< std::reference_wrapper< DescriptorScriptPubKeyMan > > 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.
static bool LoadWalletArgs(std::shared_ptr< CWallet > wallet, const WalletContext &context, bilingual_str &error, std::vector< bilingual_str > &warnings)
HDPubKeyMap GetHDPubKeys(HDKeyFilter filter) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Retrieve descriptor xpubs matching the requested filter.
std::set< ScriptPubKeyMan * > GetScriptPubKeyMans(const CScript &script) const
Get all the ScriptPubKeyMans for a script.
util::Result< void > DisplayAddress(const CTxDestination &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Display address on an external signer.
Double ended buffer combining vector and stream-like interfaces.
const_iterator begin() const
const_iterator end() const
std::unordered_set< Element, ByteVectorHash > ElementSet
Different type to mark Mutex at global scope.
A version of CTransaction with the PSBT format.
std::vector< PSBTInput > inputs
Tp rand_uniform_delay(const Tp &time, typename Tp::duration range) noexcept
Return the time point advanced by a uniform random duration.
void push_back(UniValue val)
const UniValue & find_value(std::string_view key) const
const std::vector< UniValue > & getValues() const
const UniValue & get_array() const
std::string ToString() const
virtual std::optional< int > getHeight()=0
virtual std::unique_ptr< Handler > handleNotifications(std::shared_ptr< Notifications > notifications)=0
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
virtual bool havePruned()=0
Check if any block has been pruned.
virtual bool updateRwSetting(const std::string &name, const SettingsUpdate &update_function)=0
virtual void waitForNotifications()=0
Wait for all pending notifications up to this point to be processed.
virtual bool hasAssumedValidChain()=0
virtual bool isInMempool(const Txid &txid)=0
Check if transaction is in mempool.
virtual bool findAncestorByHeight(const uint256 &block_hash, int ancestor_height, const FoundBlock &ancestor_out={})=0
virtual bool findBlock(const uint256 &hash, const FoundBlock &block={})=0
virtual double guessVerificationProgress(const uint256 &block_hash)=0
virtual void waitForNotificationsIfTipChanged(const uint256 &old_tip)=0
virtual void initMessage(const std::string &message)=0
Send init message.
virtual std::optional< int > findLocatorFork(const CBlockLocator &locator)=0
virtual bool haveBlockOnDisk(int height)=0
virtual bool broadcastTransaction(const CTransactionRef &tx, const CAmount &max_tx_fee, node::TxBroadcast broadcast_method, std::string &err_string)=0
virtual CFeeRate relayMinFee()=0
Relay current minimum fee (from -minrelaytxfee and -incrementalrelayfee settings).
FoundBlock & locator(CBlockLocator &locator)
Return locator if block is in the active chain.
FoundBlock & height(int &height)
FoundBlock & data(CBlock &data)
std::string ToString() const
constexpr const std::byte * begin() const
std::string GetHex() const
constexpr uint256()=default
bool has_value() const noexcept
Encryption/decryption context with key information.
bool Decrypt(std::span< const unsigned char > ciphertext, CKeyingMaterial &plaintext) const
bool SetKeyFromPassphrase(const SecureString &key_data, std::span< const unsigned char > salt, unsigned int rounds, unsigned int derivation_method)
bool Encrypt(const CKeyingMaterial &vchPlaintext, std::vector< unsigned char > &vchCiphertext) const
Private key encryption is done based on a CMasterKey, which holds a salt and random encryption key.
std::vector< unsigned char > vchSalt
unsigned int nDerivationMethod
0 = EVP_sha512()
std::vector< unsigned char > vchCryptedKey
unsigned int nDeriveIterations
static constexpr unsigned int DEFAULT_DERIVE_ITERATIONS
Default/minimum number of key derivation rounds.
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
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 ...
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::optional< AddressPurpose > &purpose)
std::atomic< bool > fAbortRescan
bool HaveChain() const
Interface to assert chain access.
bool GetBroadcastTransactions() const
Inquire whether this wallet broadcasts transactions.
std::function< bool(CWalletTx &wtx, bool new_tx)> UpdateWalletTxFn
CAmount m_default_max_tx_fee
Absolute maximum transaction fee (in satoshis) used by default for the wallet.
std::optional< WalletTXO > GetTXO(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
static bool AttachChain(const std::shared_ptr< CWallet > &wallet, interfaces::Chain &chain, 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...
OutputType m_default_address_type
static std::shared_ptr< CWallet > LoadExisting(WalletContext &context, const std::string &name, std::unique_ptr< WalletDatabase > database, bilingual_str &error, std::vector< bilingual_str > &warnings)
btcsignals::signal< void(const CTxDestination &address, const std::string &label, bool isMine, AddressPurpose purpose, ChangeType status)> NotifyAddressBookChanged
Address book entry changed.
void LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
std::unique_ptr< WalletDatabase > m_database
Internal database handle.
bool SignTransaction(CMutableTransaction &tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Fetch the inputs and sign with SIGHASH_ALL.
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.
std::unique_ptr< SigningProvider > GetSolvingProvider(const CScript &script) const
Get the SigningProvider for a script.
void RefreshAllTXOs() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Cache outputs that belong to the wallet for all transactions in the wallet.
void AddActiveScriptPubKeyManWithDb(WalletBatch &batch, uint256 id, OutputType type, bool internal)
std::set< ScriptPubKeyMan * > GetActiveScriptPubKeyMans() const
Returns all unique ScriptPubKeyMans in m_internal_spk_managers and m_external_spk_managers.
const CAddressBookData * FindAddressBookEntry(const CTxDestination &, bool allow_change=false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
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...
unsigned int nMasterKeyMaxID
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get last block processed height.
std::atomic< double > m_scanning_progress
LegacyDataSPKM * GetLegacyDataSPKM() const
Get the LegacyDataSPKM used for all legacy output types and both internal and external chains.
void SetupWalletGeneration() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Setup new descriptors or seed for new address generation.
DescriptorScriptPubKeyMan * GetDescriptorScriptPubKeyMan(const WalletDescriptor &desc) const
Return the DescriptorScriptPubKeyMan for a WalletDescriptor if it is already in the wallet.
btcsignals::signal< void(CWallet *wallet)> NotifyStatusChanged
Wallet status (encrypted, locked) changed.
btcsignals::signal< void()> NotifyCanGetAddressesChanged
Keypool has new keys.
std::map< OutputType, ScriptPubKeyMan * > m_external_spk_managers
interfaces::Chain & chain() const
Interface for accessing chain state.
const std::string & GetName() const
Get a name for this wallet for logging/debugging purposes.
std::map< CExtPubKey, std::set< DescriptorScriptPubKeyMan * > > HDPubKeyMap
bool Unlock(const CKeyingMaterial &vMasterKeyIn)
std::unique_ptr< interfaces::Handler > m_chain_notifications_handler
Registered interfaces::Chain::Notifications handler.
std::map< OutputType, ScriptPubKeyMan * > m_internal_spk_managers
std::string m_name
Wallet name: relative directory name or "" for default wallet.
bool SetAddressPreviouslySpent(WalletBatch &batch, const CTxDestination &dest, bool used) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
util::Result< void > RemoveTxs(std::vector< Txid > &txs_to_remove) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Erases the provided transactions from the wallet.
RecursiveMutex m_relock_mutex
btcsignals::signal< void(const Txid &hashTx, ChangeType status)> NotifyTransactionChanged
Wallet transaction added, removed or updated.
std::string m_notify_tx_changed_script
Notify external script when a wallet transaction comes in or is updated (handled by -walletnotify).
bool fBroadcastTransactions
Whether this wallet will submit newly created transactions to the node's mempool and prompt rebroadca...
void CacheNewScriptPubKeys(const std::set< CScript > &spks, ScriptPubKeyMan *spkm)
Add scriptPubKeys for this ScriptPubKeyMan into the scriptPubKey cache.
int GetTxBlocksToMaturity(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void WalletLogPrintf(util::ConstevalFormatString< sizeof...(Params)> wallet_fmt, const Params &... params) const
Prepends the wallet name in logging output to ease debugging in multi-wallet use cases.
bool HasEncryptionKeys() const override
std::optional< bool > IsInternalScriptPubKeyMan(ScriptPubKeyMan *spk_man) const
void SetupDescriptorScriptPubKeyMans(WalletBatch &batch, const CExtKey &master_key) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Create new DescriptorScriptPubKeyMans and add them to the wallet.
void LoadLockedCoin(const COutPoint &coin, bool persistent) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void SetupLegacyDataSPKM()
Create a LegacyDataSPKM and set it for all legacy output types and both internal and external chains.
MasterKeyMap mapMasterKeys
btcsignals::signal< void(const std::string &title, int nProgress)> ShowProgress
Show progress e.g.
NodeClock::time_point m_next_resend
The next scheduled rebroadcast of wallet transactions.
HDKeyFilter
Which descriptors GetHDPubKeys() should consider.
WalletDatabase & GetDatabase() const override
std::optional< CKey > GetKey(const CKeyID &keyid) const
bool SetAddressBookWithDB(WalletBatch &batch, const CTxDestination &address, const std::string &strName, const std::optional< AddressPurpose > &strPurpose)
void WriteBestBlock() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Write the current best block to database.
bool DelAddressBookWithDB(WalletBatch &batch, const CTxDestination &address)
std::string DisplayName() const
Return wallet name for display, like LogName() but translates "default wallet" string.
void AddScriptPubKeyMan(const uint256 &id, std::unique_ptr< ScriptPubKeyMan > spkm_man)
std::atomic< uint64_t > m_wallet_flags
WalletFlags set on this wallet.
bool IsLocked() const override
std::set< ScriptPubKeyMan * > GetAllScriptPubKeyMans() const
Returns all unique ScriptPubKeyMans.
void RefreshTXOsFromTx(const CWalletTx &wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Cache outputs that belong to the wallet from a single transaction.
unsigned int ComputeTimeSmart(const CWalletTx &wtx, bool rescanning_old_block) const
Compute smart timestamp for a transaction being added to the wallet.
ScriptPubKeyMan * GetScriptPubKeyMan(const OutputType &type, bool internal) const
Get the ScriptPubKeyMan for the given OutputType and internal/external chain.
bool IsAddressPreviouslySpent(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
uint256 GetLastBlockHash() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
int64_t m_keypool_size
Number of pre-generated keys/scripts by each spkm (part of the look-ahead process,...
RecursiveMutex cs_wallet
Main wallet lock.
void ForEachAddrBookEntry(const ListAddrBookFunc &func) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
friend class WalletRescanReserver
std::atomic< int64_t > m_best_block_time
std::unordered_map< CScript, std::vector< ScriptPubKeyMan * >, SaltedSipHasher > m_cached_spks
Cache of descriptor ScriptPubKeys used for IsMine. Maps ScriptPubKey to set of spkms.
std::multimap< int64_t, CWalletTx * > TxItems
void SetupOwnDescriptorScriptPubKeyMans(WalletBatch &batch) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Create new seed and default DescriptorScriptPubKeyMans for this wallet.
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.
std::map< uint256, std::unique_ptr< ScriptPubKeyMan > > m_spk_managers
std::function< TxUpdate(CWalletTx &wtx)> TryUpdatingStateFn
bool UnlockCoin(const COutPoint &output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::atomic< int64_t > m_birth_time
void LoadAddressPreviouslySpent(const CTxDestination &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Marks destination as previously spent.
static bool LoadWalletArgs(std::shared_ptr< CWallet > wallet, const WalletContext &context, bilingual_str &error, std::vector< bilingual_str > &warnings)
std::set< ScriptPubKeyMan * > GetScriptPubKeyMans(const CScript &script) const
Get all the ScriptPubKeyMans for a script.
A transaction with a bunch of additional info that only the owner cares about.
bool Update(CTransactionRef tx, const TxState &new_state, WalletBatch &batch, bool metadata_changed)
bool isBlockConflicted() const
std::vector< std::string > m_messages
const Txid & GetHash() const LIFETIMEBOUND
std::set< Txid > mempool_conflicts
std::optional< Txid > m_replaces_txid
void updateState(interfaces::Chain &chain)
std::optional< std::string > m_comment_to
int64_t nOrderPos
position in ordered transaction list
bool isUnconfirmed() const
std::optional< std::string > m_comment
unsigned int nTimeReceived
time received by this node
std::optional< Txid > m_replaced_by_txid
std::optional< Txid > truc_child_in_mempool
std::vector< std::string > m_payment_requests
int64_t GetTxTime() const
CTransactionRef GetTx() const
bool IsMalleation(const CWalletTx &tx) const
True if tx is a malleation of this, i.e.
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
void UpgradeDescriptorCache()
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,...
static std::unique_ptr< DescriptorScriptPubKeyMan > LoadFromStorage(WalletStorage &storage, const uint256 &id, WalletDescriptor &descriptor, int64_t keypool_size, const KeyMap &keys, const CryptedKeyMap &ckeys)
static std::unique_ptr< DescriptorScriptPubKeyMan > CreateFromImport(WalletStorage &storage, WalletDescriptor &descriptor, int64_t keypool_size, const FlatSigningProvider &provider)
RecursiveMutex cs_desc_man
static std::unique_ptr< DescriptorScriptPubKeyMan > GenerateNewSingleSig(WalletStorage &storage, WalletBatch &batch, int64_t keypool_size, const CExtKey &master_key, OutputType addr_type, bool internal)
static std::unique_ptr< ExternalSignerScriptPubKeyMan > CreateNew(WalletStorage &storage, WalletBatch &batch, int64_t keypool_size, std::unique_ptr< Descriptor > desc)
static std::unique_ptr< ExternalSignerScriptPubKeyMan > LoadFromStorage(WalletStorage &storage, const uint256 &id, WalletDescriptor &descriptor, int64_t keypool_size, const KeyMap &keys, const CryptedKeyMap &ckeys)
static util::Result< ExternalSigner > GetExternalSigner()
bool DeleteRecordsWithDB(WalletBatch &batch)
Delete the legacy wallet records from disk.
std::optional< MigrationData > MigrateToDescriptor()
Get the DescriptorScriptPubKeyMans (with private keys) that have the same scriptPubKeys as this Legac...
uint256 GetID() const override
std::unordered_set< CScript, SaltedSipHasher > GetNotMineScriptPubKeys() const
Retrieves scripts that were imported by bugs into the legacy spkm and are simply invalid,...
A wrapper to reserve an address from a wallet.
const CWallet *const pwallet
The wallet to reserve from.
void KeepDestination()
Keep the address. Do not return its key to the keypool when this object goes out of scope.
CTxDestination address
The destination.
bool fInternal
Whether this is from the internal (change output) keypool.
void ReturnDestination()
Return reserved address.
ScriptPubKeyMan * m_spk_man
The ScriptPubKeyMan to reserve from. Based on type when GetReservedDestination is called.
int64_t nIndex
The index of the address's key in the keypool.
util::Result< CTxDestination > GetReservedDestination(bool internal)
Reserve an address.
Access to the wallet database.
bool TxnAbort()
Abort current transaction.
bool EraseName(const std::string &strAddress)
DBErrors LoadWallet(CWallet *pwallet)
bool WriteBestBlock(const CBlockLocator &locator)
void RegisterTxnListener(const DbTxnListener &l)
Registers db txn callback functions.
bool ReadBestBlock(CBlockLocator &locator)
bool WriteDescriptorCacheItems(const uint256 &desc_id, const DescriptorCache &cache)
bool WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
bool WriteWalletFlags(uint64_t flags)
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)
bool WritePurpose(const std::string &strAddress, const std::string &purpose)
bool EraseAddressData(const CTxDestination &dest)
bool WriteOrderPosNext(int64_t nOrderPosNext)
bool WriteFullTx(const CWalletTx &wtx)
bool ErasePurpose(const std::string &strAddress)
bool EraseLockedUTXO(const COutPoint &output)
bool WriteTxMetadata(const CWalletTx &wtx)
bool WriteLockedUTXO(const COutPoint &output)
bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256 &id, bool internal)
bool WriteVersion(int client_version)
Write the given client_version to m_batch, indicating the last version of client software to load thi...
bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal)
bool WriteAddressReceiveRequest(const CTxDestination &dest, const std::string &id, const std::string &receive_request)
Descriptor with some wallet metadata.
const std::shared_ptr< const Descriptor > descriptor
Clock::time_point now() const
bool reserve(bool with_passphrase=false)
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
constexpr int CLIENT_VERSION
void ReplaceAll(std::string &in_out, std::string_view search, std::string_view substitute)
Replace every non-overlapping occurrence of search with substitute, treating both literally; the repl...
std::string ShellEscape(const std::string &arg)
constexpr int COINBASE_MATURITY
Coinbase transaction outputs can only be spent after this number of new blocks (network rule).
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by create_directories if the requested directory exists.
bool IsSpentKey(const CScript &scriptPubKey) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
int64_t IncOrderPosNext(WalletBatch *batch=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Increment the next transaction order id.
void RecursiveUpdateTxState(const Txid &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.
void MarkInputsDirty(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed.
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.
bool ChangeWalletPassphrase(const SecureString &strOldWalletPassphrase, const SecureString &strNewWalletPassphrase)
bool AbandonTransaction(const Txid &hashTx)
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver)
Scan active chain for relevant transactions after importing keys.
void SetWalletFlagWithDB(WalletBatch &batch, uint64_t flags)
Store wallet flags.
static bool EncryptMasterKey(const SecureString &wallet_passphrase, const CKeyingMaterial &plain_master_key, CMasterKey &master_key)
uint64_t GetWalletFlags() const
Retrieve all of the wallet's flags.
void updatedBlockTip() override
bool TransactionCanBeAbandoned(const Txid &hashTx) const
Return whether transaction can be abandoned.
void SyncMalleatedTxMetadata(WalletBatch &batch, const CWalletTx &wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
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...
bool AddToWalletIfInvolvingMe(const CTransactionRef &tx, const SyncTxState &state, bool rescanning_old_block) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Add a transaction to the wallet, or update it.
ScanResult ScanForWalletTransactions(const uint256 &start_block, int start_height, std::optional< int > max_height, const WalletRescanReserver &reserver, bool save_progress)
Scan the block chain (starting in start_block) for transactions from or to us.
void MaybeUpdateBirthTime(int64_t time)
Updates wallet birth time if 'time' is below it.
void blockDisconnected(const interfaces::BlockInfo &block) override
std::set< Txid > GetConflicts(const Txid &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get wallet transactions that conflict with given transaction (spend same outputs).
bool IsWalletFlagSet(uint64_t flag) const override
check if a certain wallet flag is set
SpendType HowSpent(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
static bool DecryptMasterKey(const SecureString &wallet_passphrase, const CMasterKey &master_key, CKeyingMaterial &plain_master_key)
void AddToSpends(const COutPoint &outpoint, const Txid &txid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void SetLastBlockProcessedInMem(int block_height, uint256 block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UnsetWalletFlagWithDB(WalletBatch &batch, uint64_t flag)
Unsets a wallet flag and saves it to disk.
bool IsSpent(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Outpoint is spent if any non-conflicted transaction spends it:
void ResubmitWalletTransactions(node::TxBroadcast broadcast_method, bool force)
std::set< Txid > GetTxConflicts(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UnsetBlankWalletFlag(WalletBatch &batch) override
Unset the blank wallet flag and saves it to disk.
CWalletTx * AddToWallet(CTransactionRef tx, const TxState &state, const UpdateWalletTxFn &update_wtx=nullptr, bool rescanning_old_block=false)
Add the transaction to the wallet, wrapping it up inside a CWalletTx.
bool MarkReplaced(const Txid &originalHash, const Txid &newHash)
Mark a transaction as replaced by another transaction.
bool CanGetAddresses(bool internal=false) const
bool LoadToWallet(CWalletTx &&wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UpdateTrucSiblingConflicts(const CWalletTx &parent_wtx, const Txid &child_txid, bool add_conflict) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Update mempool conflicts for TRUC sibling transactions.
bool LoadWalletFlags(uint64_t flags)
Loads the flags into the wallet.
bool SubmitTxMemoryPoolAndRelay(CWalletTx &wtx, std::string &err_string, node::TxBroadcast broadcast_method) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Pass this transaction to node for optional mempool insertion and relay to peers.
void blockConnected(const kernel::ChainstateRole &role, const interfaces::BlockInfo &block) override
void transactionRemovedFromMempool(const CTransactionRef &tx, MemPoolRemovalReason reason) override
static NodeClock::time_point GetDefaultNextResend()
bool ShouldResend() const
Return true if all conditions for periodically resending transactions are met.
bool SyncTransaction(const CTransactionRef &tx, const SyncTxState &state, bool rescanning_old_block=false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
const CWalletTx * GetWalletTx(const Txid &hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void InitWalletFlags(uint64_t flags)
overwrite all flags by the given uint64_t flags must be uninitialised (or 0) only known flags may be ...
void UnsetWalletFlag(uint64_t flag)
Unsets a single wallet flag.
std::set< CWalletTx *, WalletTxOrderComparator > GetMalleatedVariants(const CWalletTx &wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Collects all wallet txs that differ from wtx only in their scriptSigs (i.e.
bool EncryptWallet(const SecureString &strWalletPassphrase)
void SetLastBlockProcessed(int block_height, uint256 block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Set last block processed height, and write to database.
bool IsFromMe(const CTransaction &tx) const
should probably be renamed to IsRelevantToMe
DBErrors ReorderTransactions()
bool IsMine(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UpgradeDescriptorCache() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Upgrade DescriptorCaches.
void SetSpentKeyState(WalletBatch &batch, const Txid &hash, unsigned int n, bool used, std::set< CTxDestination > &tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
CAmount GetDebit(const CTxIn &txin) const
Returns amount of debit, i.e.
void MarkConflicted(const uint256 &hashBlock, int conflicting_height, const Txid &hashTx)
Mark a transaction (and its in-wallet descendants) as conflicting with a particular block.
void transactionAddedToMempool(const CTransactionRef &tx) override
void Close()
Close wallet database.
const std::string request
@ SIGHASH_DEFAULT
Taproot only; implied when sighash byte is missing, and equivalent to SIGHASH_ALL.
CKey GenerateRandomKey(bool compressed) noexcept
std::string EncodeDestination(const CTxDestination &dest)
#define LogDebug(category,...)
bilingual_str AmountErrMsg(const std::string &optname, const std::string &strValue)
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.
std::optional< CAmount > ParseMoney(const std::string &money_string)
Parse an amount denoted in full coins.
auto FindKey(Map &&map, Key &&key) -> decltype(&map.at(key))
Map lookup helper.
bilingual_str AmountErrMsg(const std::string &optname, const std::string &strValue)
bilingual_str AmountHighWarn(const std::string &optname)
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
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)
TxBroadcast
How to broadcast a local transaction.
@ MEMPOOL_AND_BROADCAST_TO_ALL
Add the transaction to the mempool and broadcast to all peers for which tx relay is enabled.
@ MEMPOOL_NO_BROADCAST
Add the transaction to the mempool, but don't broadcast to anybody.
@ NO_MEMPOOL_PRIVATE_BROADCAST
Omit the mempool and directly send the transaction via a few dedicated connections to peers on privac...
bilingual_str ErrorString(const Result< T > &result)
std::string_view RemoveSuffixView(std::string_view str LIFETIMEBOUND, std::string_view suffix)
void ReplaceAll(std::string &in_out, std::string_view search, std::string_view substitute)
Replace every non-overlapping occurrence of search with substitute, treating both literally; the repl...
std::string ToString(const T &t)
Locale-independent version of std::to_string.
constexpr bool DEFAULT_WALLET_RBF
-walletrbf default
constexpr bool DEFAULT_WALLETCROSSCHAIN
std::variant< TxStateConfirmed, TxStateInMempool, TxStateInactive > SyncTxState
Subset of states transaction sync logic is implemented to handle.
constexpr CAmount HIGH_APS_FEE
discourage APS fee higher than this amount
void ReadDatabaseArgs(const ArgsManager &args, DatabaseOptions &options)
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)
static std::set< std::string > g_loading_wallet_set GUARDED_BY(g_loading_wallet_mutex)
constexpr unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
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.
bool RunWithinTxn(WalletDatabase &database, std::string_view process_desc, const std::function< bool(WalletBatch &)> &func)
Executes the provided function 'func' within a database transaction context.
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
util::Result< MigrationResult > MigrateLegacyToDescriptor(const std::string &wallet_name, const SecureString &passphrase, WalletContext &context, bool load_wallet)
Do all steps to migrate a legacy wallet to a descriptor wallet.
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
DBErrors
Overview of wallet database classes:
@ UNEXPECTED_LEGACY_ENTRY
@ EXTERNAL_SIGNER_SUPPORT_REQUIRED
bool AddWalletSetting(interfaces::Chain &chain, const std::string &wallet_name)
Add wallet name to persistent configuration so it will be loaded on startup.
static GlobalMutex g_wallet_release_mutex
bool RemoveWalletSetting(interfaces::Chain &chain, const std::string &wallet_name)
Remove wallet name from persistent configuration so it will not be loaded on startup.
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...
std::unique_ptr< interfaces::Handler > HandleLoadWallet(WalletContext &context, LoadWalletFn load_wallet)
bool HasLegacyRecords(CWallet &wallet)
Returns true if there are any DBKeys::LEGACY_TYPES record in the wallet db.
fs::path GetWalletDir()
Get the path of the wallet directory.
const std::unordered_set< OutputType > LEGACY_OUTPUT_TYPES
Output types associated with LegacyDataSPKM.
constexpr CAmount HIGH_TX_FEE_PER_KB
Discourage users to set fees higher than this amount (in satoshis) per kB.
static std::condition_variable g_wallet_release_cv
std::unique_ptr< WalletDatabase > MakeWalletDatabase(const std::string &name, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error_string)
bool IsBDBFile(const fs::path &path)
void NotifyWalletLoaded(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
fs::path BDBDataFile(const fs::path &wallet_path)
constexpr CAmount HIGH_MAX_TX_FEE
-maxtxfee will warn if called with a higher fee than this amount (in satoshis)
std::shared_ptr< CWallet > RestoreWallet(WalletContext &context, const fs::path &backup_file, const std::string &wallet_name, std::optional< bool > load_on_start, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings, bool load_after_restore, bool allow_unnamed)
std::string PurposeToString(AddressPurpose p)
std::function< void(std::unique_ptr< interfaces::Wallet > wallet)> LoadWalletFn
std::map< CKeyID, CKey > KeyMap
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
constexpr uint64_t KNOWN_WALLET_FLAGS
std::variant< TxStateConfirmed, TxStateInMempool, TxStateBlockConflicted, TxStateInactive, TxStateUnrecognized > TxState
All possible CWalletTx states.
static void UpdateWalletSetting(interfaces::Chain &chain, const std::string &wallet_name, std::optional< bool > load_on_startup, std::vector< bilingual_str > &warnings)
static std::string MigrationPrefixName(CWallet &wallet)
static GlobalMutex g_loading_wallet_mutex
bool DoMigration(CWallet &wallet, WalletContext &context, bilingual_str &error, MigrationResult &res, const bool load_on_startup=true) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
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)
static void FlushAndDeleteWallet(CWallet *wallet)
@ WALLET_FLAG_EXTERNAL_SIGNER
Indicates that the wallet needs an external signer.
@ WALLET_FLAG_LAST_HARDENED_XPUB_CACHED
@ WALLET_FLAG_KEY_ORIGIN_METADATA
@ WALLET_FLAG_AVOID_REUSE
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
@ WALLET_FLAG_BLANK_WALLET
void WaitForDeleteWallet(std::shared_ptr< CWallet > &&wallet)
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)
util::Result< fs::path > GetWalletPath(const std::string &name)
Determine the path that the wallet is stored in.
constexpr unsigned int WALLET_CRYPTO_KEY_SIZE
constexpr bool DEFAULT_WALLETBROADCAST
constexpr unsigned int WALLET_CRYPTO_SALT_SIZE
@ FAILED_INVALID_BACKUP_FILE
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
std::shared_ptr< CWallet > GetDefaultWallet(WalletContext &context, size_t &count)
constexpr bool DEFAULT_SPEND_ZEROCONF_CHANGE
Default for -spendzeroconfchange.
constexpr unsigned int DEFAULT_TX_CONFIRM_TARGET
-txconfirmtarget default
std::map< CKeyID, std::pair< CPubKey, std::vector< unsigned char > > > CryptedKeyMap
std::optional< OutputType > ParseOutputType(std::string_view type)
const std::string & FormatOutputType(OutputType type)
constexpr auto OUTPUT_TYPES
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.
void RemoveUnnecessaryTransactions(PartiallySignedTransaction &psbtx)
Reduces the size of the PSBT by dropping unnecessary non_witness_utxos (i.e.
std::optional< PrecomputedTransactionData > PrecomputePSBTData(const PartiallySignedTransaction &psbt)
Compute a PrecomputedTransactionData object from a psbt.
bool PSBTInputSigned(const PSBTInput &input)
Checks whether a PSBTInput is already signed by checking for non-null finalized fields.
void GetStrongRandBytes(std::span< unsigned char > bytes) noexcept
Gather entropy from various sources, feed it into the internal PRNG, and generate random data using i...
std::vector< std::unique_ptr< Descriptor > > Parse(std::string_view descriptor, FlatSigningProvider &out, std::string &error, bool require_checksum)
Parse a descriptor string.
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
constexpr deserialize_type deserialize
@ 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...
std::vector< uint256 > vHave
void SetSeed(std::span< const std::byte > seed)
A mutable version of CTransaction.
static time_point now() noexcept
Return current system time or mocked time, if set.
std::chrono::time_point< NodeClock > time_point
interfaces::Chain * chain
Instructions for how a PSBT should be signed or filled with information.
Block data sent with blockConnected, blockDisconnected notifications.
const uint256 * prev_hash
unsigned int chain_time_max
Information about chainstate that notifications are sent from.
std::optional< AddressPurpose > purpose
Address purpose which was originally recorded for payment protocol support but now serves as a cached...
void SetLabel(std::string name)
std::optional< std::string > m_op_label
std::optional< int > last_scanned_height
uint256 last_scanned_block
uint256 last_failed_block
enum wallet::CWallet::ScanResult::@273233031336335332015254221053060000163044056224 status
SecureString create_passphrase
std::optional< DatabaseFormat > require_format
struct containing information needed for migrating legacy wallets to descriptor wallets
std::optional< std::string > solvables_wallet_name
std::optional< std::string > watchonly_wallet_name
std::shared_ptr< CWallet > watchonly_wallet
std::shared_ptr< CWallet > solvables_wallet
std::shared_ptr< CWallet > wallet
State of rejected transaction that conflicts with a confirmed block.
int conflicting_block_height
State of transaction confirmed in a block.
int confirmed_block_height
State of transaction added to mempool.
TxStateInactive(bool abandoned=false)
interfaces::Chain * chain
#define WAIT_LOCK(cs, name)
#define AssertLockNotHeld(cs)
#define WITH_LOCK(cs, code)
#define AssertLockHeld(cs)
std::vector< uint16_t > keys
bilingual_str AmountHighWarn(const std::string &optname)
#define EXCLUSIVE_LOCKS_REQUIRED(...)
transaction_identifier< false > Txid
Txid commits to all transaction fields except the witness.
consteval auto _(util::TranslatedLiteral str)
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
constexpr decltype(CTransaction::version) TRUC_VERSION
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
std::chrono::duration< double, std::chrono::milliseconds::period > MillisecondsDouble
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.