8#include <bitcoin-build-config.h>
10#include <blockfilter.h>
76#include <condition_variable>
98 if (!setting_value.isArray()) setting_value.setArray();
99 for (
const auto& value : setting_value.getValues()) {
102 setting_value.push_back(wallet_name);
113 for (
const auto& value : setting_value.getValues()) {
114 if (!value.isStr() || value.get_str() != wallet_name) new_value.
push_back(value);
117 setting_value = std::move(new_value);
124 const std::string& wallet_name,
125 std::optional<bool> load_on_startup,
126 std::vector<bilingual_str>& warnings)
128 if (!load_on_startup)
return;
130 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
132 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));
154 std::vector<std::shared_ptr<CWallet>>::const_iterator i = std::find(context.wallets.begin(), context.wallets.end(),
wallet);
155 if (i != context.wallets.end())
return false;
156 context.wallets.push_back(
wallet);
157 wallet->ConnectScriptPubKeyManNotifiers();
158 wallet->NotifyCanGetAddressesChanged();
171 wallet->m_chain_notifications_handler.reset();
174 std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(context.wallets.begin(), context.wallets.end(),
wallet);
175 if (i == context.wallets.end())
return false;
176 context.wallets.erase(i);
189 std::vector<bilingual_str> warnings;
196 return context.wallets;
202 count = context.wallets.size();
203 return count == 1 ? context.wallets[0] :
nullptr;
209 for (
const std::shared_ptr<CWallet>&
wallet : context.wallets) {
218 auto it = context.wallet_load_fns.emplace(context.wallet_load_fns.end(), std::move(load_wallet));
225 for (
auto& load_wallet : context.wallet_load_fns) {
240 wallet->WalletLogPrintf(
"Releasing wallet %s..\n",
name);
245 if (g_unloading_wallet_set.erase(
name) == 0) {
259 g_unloading_wallet_set.insert(
name);
268 while (g_unloading_wallet_set.count(
name) == 1) {
275std::shared_ptr<CWallet> LoadWalletInternal(WalletContext& context,
const std::string&
name, std::optional<bool> load_on_start,
const DatabaseOptions& options,
DatabaseStatus& status,
bilingual_str& error, std::vector<bilingual_str>& warnings)
284 context.chain->initMessage(
_(
"Loading wallet…"));
285 std::shared_ptr<CWallet>
wallet =
CWallet::Create(context,
name, std::move(database), options.create_flags, error, warnings);
294 wallet->postInitProcess();
300 }
catch (
const std::runtime_error& e) {
307class FastWalletRescanFilter
313 for (
auto spkm :
m_wallet.GetAllScriptPubKeyMans()) {
314 auto desc_spkm{
dynamic_cast<DescriptorScriptPubKeyMan*
>(spkm)};
315 assert(desc_spkm !=
nullptr);
316 AddScriptPubKeys(desc_spkm);
318 if (desc_spkm->IsHDEnabled()) {
324 void UpdateIfNeeded()
328 auto desc_spkm{
dynamic_cast<DescriptorScriptPubKeyMan*
>(
m_wallet.GetScriptPubKeyMan(desc_spkm_id))};
329 assert(desc_spkm !=
nullptr);
330 int32_t current_range_end{desc_spkm->GetEndRange()};
331 if (current_range_end > last_range_end) {
332 AddScriptPubKeys(desc_spkm, last_range_end);
338 std::optional<bool> MatchesBlock(
const uint256& block_hash)
const
354 void AddScriptPubKeys(
const DescriptorScriptPubKeyMan* desc_spkm, int32_t last_range_end = 0)
356 for (
const auto& script_pub_key : desc_spkm->GetScriptPubKeys(last_range_end)) {
357 m_filter_set.emplace(script_pub_key.begin(), script_pub_key.end());
366 if (!result.second) {
371 auto wallet = LoadWalletInternal(context,
name, load_on_start, options, status, error, warnings);
389 if (!passphrase.empty()) {
395 error =
Untranslated(
"Private keys must be disabled when using an external signer");
402 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.");
417 std::shared_ptr<CWallet>
wallet =
CWallet::Create(context,
name, std::move(database), wallet_creation_flags, error, warnings);
426 if (!
wallet->EncryptWallet(passphrase)) {
427 error =
Untranslated(
"Error: Wallet created but failed to encrypt.");
433 if (!
wallet->Unlock(passphrase)) {
434 error =
Untranslated(
"Error: Wallet was encrypted but could not be unlocked");
442 wallet->SetupDescriptorScriptPubKeyMans();
452 wallet->postInitProcess();
470 auto wallet_file = wallet_path /
"wallet.dat";
471 std::shared_ptr<CWallet>
wallet;
486 fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
488 if (load_after_restore) {
489 wallet =
LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
491 }
catch (
const std::exception& e) {
498 if (load_after_restore && !
wallet) {
499 fs::remove_all(wallet_path);
513 const auto it = mapWallet.find(hash);
514 if (it == mapWallet.end())
516 return &(it->second);
537 auto start{SteadyClock::now()};
543 start = SteadyClock::now();
585 if (
Unlock(plain_master_key)) {
606 if (!
DecryptMasterKey(strOldWalletPassphrase, master_key, plain_master_key)) {
609 if (
Unlock(plain_master_key))
611 if (!
EncryptMasterKey(strNewWalletPassphrase, plain_master_key, master_key)) {
614 WalletLogPrintf(
"Wallet passphrase changed to an nDeriveIterations of %i\n", master_key.nDeriveIterations);
631 m_last_block_processed = block_hash;
632 m_last_block_processed_height = block_height;
645 std::set<Txid> result;
648 const auto it = mapWallet.find(txid);
649 if (it == mapWallet.end())
653 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
655 for (
const CTxIn& txin : wtx.
tx->vin)
657 if (mapTxSpends.count(txin.
prevout) <= 1)
659 range = mapTxSpends.equal_range(txin.
prevout);
660 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
661 result.insert(_it->second);
669 const Txid& txid = tx->GetHash();
670 for (
unsigned int i = 0; i < tx->vout.size(); ++i) {
689 int nMinOrderPos = std::numeric_limits<int>::max();
691 for (TxSpends::iterator it = range.first; it != range.second; ++it) {
692 const CWalletTx* wtx = &mapWallet.at(it->second);
704 for (TxSpends::iterator it = range.first; it != range.second; ++it)
706 const Txid& hash = it->second;
708 if (copyFrom == copyTo)
continue;
709 assert(copyFrom &&
"Oldest wallet transaction in range assumed to have been found.");
726 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
727 range = mapTxSpends.equal_range(outpoint);
729 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
730 const Txid& txid = it->second;
731 const auto mit = mapWallet.find(txid);
732 if (mit != mapWallet.end()) {
733 const auto& wtx = mit->second;
734 if (!wtx.isAbandoned() && !wtx.isBlockConflicted() && !wtx.isMempoolConflicted())
743 mapTxSpends.insert(std::make_pair(outpoint, txid));
747 std::pair<TxSpends::iterator, TxSpends::iterator> range;
748 range = mapTxSpends.equal_range(outpoint);
758 for (
const CTxIn& txin : wtx.
tx->vin)
790 delete encrypted_batch;
791 encrypted_batch =
nullptr;
797 auto spk_man = spk_man_pair.second.get();
798 if (!spk_man->Encrypt(plain_master_key, encrypted_batch)) {
800 delete encrypted_batch;
801 encrypted_batch =
nullptr;
809 delete encrypted_batch;
810 encrypted_batch =
nullptr;
816 delete encrypted_batch;
817 encrypted_batch =
nullptr;
820 Unlock(strWalletPassphrase);
846 typedef std::multimap<int64_t, CWalletTx*>
TxItems;
849 for (
auto& entry : mapWallet)
856 std::vector<int64_t> nOrderPosOffsets;
857 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
864 nOrderPos = nOrderPosNext++;
865 nOrderPosOffsets.push_back(nOrderPos);
872 int64_t nOrderPosOff = 0;
873 for (
const int64_t& nOffsetStart : nOrderPosOffsets)
875 if (nOrderPos >= nOffsetStart)
878 nOrderPos += nOrderPosOff;
879 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
897 int64_t nRet = nOrderPosNext++;
910 for (
auto& [
_, wtx] : mapWallet)
919 auto mi = mapWallet.find(originalHash);
922 assert(mi != mapWallet.end());
958 tx_destinations.insert(dst);
985 Txid hash = tx->GetHash();
989 std::set<CTxDestination> tx_destinations;
991 for (
const CTxIn& txin : tx->vin) {
1000 auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(tx, state));
1002 bool fInsertedNew =
ret.second;
1003 bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
1017 if (state.index() != wtx.
m_state.index()) {
1029 if (tx->HasWitness() && !wtx.
tx->HasWitness()) {
1037 std::vector<CWalletTx*> txs{&wtx};
1041 while (!txs.empty()) {
1044 desc_tx->
m_state = inactive_state;
1049 for (
unsigned int i = 0; i < desc_tx->
tx->vout.size(); ++i) {
1051 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(outpoint);
1052 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
1053 const auto wit = mapWallet.find(it->second);
1054 if (wit != mapWallet.end()) {
1055 txs.push_back(&wit->second);
1066 if (fInsertedNew || fUpdated)
1083 if (!strCmd.empty())
1088 ReplaceAll(strCmd,
"%b", conf->confirmed_block_hash.GetHex());
1102 std::thread
t(runCommand, strCmd);
1112 const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(
nullptr,
TxStateInactive{}));
1114 if (!fill_wtx(wtx, ins.second)) {
1126 for (
const CTxIn& txin : wtx.
tx->vin) {
1128 if (it != mapWallet.end()) {
1150 if (
auto* conf = std::get_if<TxStateConfirmed>(&state)) {
1152 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.
prevout);
1153 while (range.first != range.second) {
1154 if (range.first->second != tx.
GetHash()) {
1155 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);
1156 MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
1163 bool fExisted = mapWallet.count(tx.
GetHash()) != 0;
1164 if (fExisted && !fUpdate)
return false;
1176 for (
auto &dest : spk_man->MarkUnusedAddresses(txout.
scriptPubKey)) {
1178 if (!dest.internal.has_value()) {
1183 if (!dest.internal.has_value())
continue;
1197 TxState tx_state = std::visit([](
auto&&
s) ->
TxState {
return s; }, state);
1202 throw std::runtime_error(
"DB error adding transaction to wallet, write failed");
1221 for (
long unsigned int i = 0; i < parent_wtx.tx->vout.size(); i++) {
1222 for (
auto range = mapTxSpends.equal_range(
COutPoint(parent_wtx.tx->GetHash(), i)); range.first != range.second; range.first++) {
1223 const Txid& sibling_txid = range.first->second;
1225 if (sibling_txid == child_txid)
continue;
1227 return add_conflict ? (wtx.
mempool_conflicts.insert(child_txid).second ? TxUpdate::CHANGED : TxUpdate::UNCHANGED)
1228 : (wtx.
mempool_conflicts.erase(child_txid) ? TxUpdate::CHANGED : TxUpdate::UNCHANGED);
1236 for (
const CTxIn& txin : tx->vin) {
1238 if (it != mapWallet.end()) {
1239 it->second.MarkDirty();
1247 auto it = mapWallet.find(hashTx);
1248 assert(it != mapWallet.end());
1261 assert(!wtx.isConfirmed());
1262 assert(!wtx.InMempool());
1264 if (!wtx.isBlockConflicted() && !wtx.isAbandoned()) {
1290 if (m_last_block_processed_height < 0 || conflicting_height < 0) {
1293 int conflictconfirms = (m_last_block_processed_height - conflicting_height + 1) * -1;
1294 if (conflictconfirms >= 0)
1318 std::set<Txid> todo;
1319 std::set<Txid> done;
1321 todo.insert(tx_hash);
1323 while (!todo.empty()) {
1327 auto it = mapWallet.find(now);
1328 assert(it != mapWallet.end());
1331 TxUpdate update_state = try_updating_state(wtx);
1334 if (batch) batch->
WriteTx(wtx);
1336 for (
unsigned int i = 0; i < wtx.
tx->vout.size(); ++i) {
1337 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(
COutPoint(now, i));
1338 for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
1339 if (!done.count(iter->second)) {
1340 todo.insert(iter->second);
1372 auto it = mapWallet.find(tx->GetHash());
1373 if (it != mapWallet.end()) {
1377 const Txid& txid = tx->GetHash();
1379 for (
const CTxIn& tx_in : tx->vin) {
1381 for (
auto range = mapTxSpends.equal_range(tx_in.
prevout); range.first != range.second; range.first++) {
1382 const Txid& spent_id = range.first->second;
1384 if (spent_id == txid)
continue;
1396 for (
const CTxIn& tx_in : tx->vin) {
1397 auto parent_it = mapWallet.find(tx_in.
prevout.
hash);
1398 if (parent_it != mapWallet.end()) {
1399 CWalletTx& parent_wtx = parent_it->second;
1413 auto it = mapWallet.find(tx->GetHash());
1414 if (it != mapWallet.end()) {
1447 const Txid& txid = tx->GetHash();
1449 for (
const CTxIn& tx_in : tx->vin) {
1453 for (
auto range = mapTxSpends.equal_range(tx_in.
prevout); range.first != range.second; range.first++) {
1454 const Txid& spent_id = range.first->second;
1467 for (
const CTxIn& tx_in : tx->vin) {
1468 auto parent_it = mapWallet.find(tx_in.
prevout.
hash);
1469 if (parent_it != mapWallet.end()) {
1470 CWalletTx& parent_wtx = parent_it->second;
1497 bool wallet_updated =
false;
1498 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1504 if (wallet_updated || block.
height % 144 == 0) {
1518 int disconnect_height = block.
height;
1520 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1526 for (
const CTxIn& tx_in : ptx->vin) {
1528 if (mapTxSpends.count(tx_in.
prevout) < 1)
continue;
1530 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(tx_in.
prevout);
1533 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) {
1534 CWalletTx& wtx = mapWallet.find(_it->second)->second;
1538 auto try_updating_state = [&](
CWalletTx& tx) {
1561void CWallet::BlockUntilSyncedToCurrentChain()
const {
1578 return txo->GetTxOut().nValue;
1603 for (
const auto& spkm : it->second) {
1604 res = res || spkm->IsMine(
script);
1629 if (outpoint.
n >= wtx->tx->vout.size()) {
1632 return IsMine(wtx->tx->vout[outpoint.
n]);
1651 throw std::runtime_error(std::string(__func__) +
": value out of range");
1659 bool result =
false;
1661 if (!spk_man->IsHDEnabled())
return false;
1673 if (spk_man && spk_man->CanGetAddresses(internal)) {
1691 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1705 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1740 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1754 if (time < birthtime) {
1772 int start_height = 0;
1813 constexpr auto INTERVAL_TIME{60
s};
1814 auto current_time{reserver.
now()};
1815 auto start_time{reserver.
now()};
1819 uint256 block_hash = start_block;
1822 std::unique_ptr<FastWalletRescanFilter> fast_rescan_filter;
1826 fast_rescan_filter ?
"fast variant using block filters" :
"slow variant inspecting all blocks");
1835 double progress_current = progress_begin;
1836 int block_height = start_height;
1838 if (progress_end - progress_begin > 0.0) {
1839 m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin);
1843 if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
1847 bool next_interval = reserver.
now() >= current_time + INTERVAL_TIME;
1848 if (next_interval) {
1849 current_time = reserver.
now();
1850 WalletLogPrintf(
"Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
1853 bool fetch_block{
true};
1854 if (fast_rescan_filter) {
1855 fast_rescan_filter->UpdateIfNeeded();
1856 auto matches_block{fast_rescan_filter->MatchesBlock(block_hash)};
1857 if (matches_block.has_value()) {
1858 if (*matches_block) {
1863 fetch_block =
false;
1866 LogDebug(
BCLog::SCAN,
"Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.
ToString());
1872 bool block_still_active =
false;
1873 bool next_block =
false;
1883 if (save_progress && next_interval) found_block.
locator(loc);
1888 if (!block_still_active) {
1895 for (
size_t posInBlock = 0; posInBlock < block.
vtx.size(); ++posInBlock) {
1913 if (max_height && block_height >= *max_height) {
1932 block_hash = next_block_hash;
1937 const uint256 prev_tip_hash = tip_hash;
1939 if (!max_height && prev_tip_hash != tip_hash) {
1951 WalletLogPrintf(
"Rescan aborted at block %d. Progress=%f\n", block_height, progress_current);
1953 }
else if (block_height &&
chain().shutdownRequested()) {
1954 WalletLogPrintf(
"Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height, progress_current);
1957 WalletLogPrintf(
"Rescan completed in %15dms\n", Ticks<std::chrono::milliseconds>(reserver.
now() - start_time));
1998 result.erase(myHash);
2010 if (!
chain().isReadyToBroadcast())
return false;
2051 int submitted_tx_count = 0;
2058 std::set<CWalletTx*, WalletTxOrderComparator> to_submit;
2059 for (
auto& [txid, wtx] : mapWallet) {
2061 if (!wtx.isUnconfirmed())
continue;
2066 to_submit.insert(&wtx);
2069 for (
auto wtx : to_submit) {
2070 std::string unused_err_string;
2075 if (submitted_tx_count > 0) {
2076 WalletLogPrintf(
"%s: resubmit %u unconfirmed transactions\n", __func__, submitted_tx_count);
2084 for (
const std::shared_ptr<CWallet>& pwallet :
GetWallets(context)) {
2085 if (!pwallet->ShouldResend())
continue;
2086 pwallet->ResubmitWalletTransactions(
true,
false);
2087 pwallet->SetNextResend();
2097 std::map<COutPoint, Coin> coins;
2098 for (
auto& input : tx.
vin) {
2099 const auto mi = mapWallet.find(input.prevout.hash);
2100 if(mi == mapWallet.end() || input.prevout.n >= mi->second.tx->vout.size()) {
2105 coins[input.prevout] =
Coin(wtx.
tx->vout[input.prevout.n], prev_height, wtx.
IsCoinBase());
2107 std::map<int, bilingual_str> input_errors;
2117 if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) {
2133 for (
unsigned int i = 0; i < psbtx.
tx->vin.size(); ++i) {
2134 const CTxIn& txin = psbtx.
tx->vin[i];
2144 const auto it = mapWallet.find(txhash);
2145 if (it != mapWallet.end()) {
2158 int n_signed_this_spkm = 0;
2159 const auto error{spk_man->FillPSBT(psbtx, txdata, sighash_type,
sign, bip32derivs, &n_signed_this_spkm, finalize)};
2165 (*n_signed) += n_signed_this_spkm;
2173 for (
size_t i = 0; i < psbtx.
inputs.size(); ++i) {
2185 if (spk_man_pair.second->CanProvide(script_pub_key, sigdata)) {
2187 return spk_man_pair.second->SignMessage(message, pkhash, str_sig);
2197 return *change_type;
2206 bool any_wpkh{
false};
2208 bool any_pkh{
false};
2210 for (
const auto& recipient : vecSend) {
2211 if (std::get_if<WitnessV1Taproot>(&recipient.dest)) {
2213 }
else if (std::get_if<WitnessV0KeyHash>(&recipient.dest)) {
2215 }
else if (std::get_if<ScriptHash>(&recipient.dest)) {
2217 }
else if (std::get_if<PKHash>(&recipient.dest)) {
2223 if (has_bech32m_spkman && any_tr) {
2228 if (has_bech32_spkman && any_wpkh) {
2233 if (has_p2sh_segwit_spkman && any_sh) {
2239 if (has_legacy_spkman && any_pkh) {
2244 if (has_bech32m_spkman) {
2247 if (has_bech32_spkman) {
2264 wtx.
mapValue = std::move(mapValue);
2271 throw std::runtime_error(std::string(__func__) +
": Wallet db error, transaction commit failed");
2275 for (
const CTxIn& txin : tx->vin) {
2286 std::string err_string;
2288 WalletLogPrintf(
"CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
2305 spk_man_pair.second->RewriteDB();
2315 return nLoadWalletRet;
2325 return result.has_value();
2328 if (!was_txn_committed)
return util::Error{
_(
"Error starting/committing db txn for wallet transactions removal process")};
2338 std::vector<
decltype(mapWallet)::const_iterator> erased_txs;
2340 for (
const Txid& hash : txs_to_remove) {
2341 auto it_wtx = mapWallet.find(hash);
2342 if (it_wtx == mapWallet.end()) {
2348 erased_txs.emplace_back(it_wtx);
2354 for (
const auto& it : erased_txs) {
2355 const Txid hash{it->first};
2356 wtxOrdered.erase(it->second.m_it_wtxOrdered);
2357 for (
const auto& txin : it->second.tx->vin)
2358 mapTxSpends.erase(txin.prevout);
2359 for (
unsigned int i = 0; i < it->second.tx->vout.size(); ++i) {
2362 mapWallet.erase(it);
2374 bool fUpdated =
false;
2376 std::optional<AddressPurpose> purpose;
2379 std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
2380 fUpdated = mi != m_address_book.end() && !mi->second.IsChange();
2382 CAddressBookData& record = mi != m_address_book.end() ? mi->second : m_address_book[address];
2384 is_mine =
IsMine(address);
2393 WalletLogPrintf(
"Error: fail to write address book 'purpose' entry\n");
2396 if (!batch.
WriteName(encoded_dest, strName)) {
2430 WalletLogPrintf(
"%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, CLIENT_BUGREPORT);
2452 m_address_book.erase(address);
2464 unsigned int count = 0;
2466 count += spk_man.second->GetKeyPoolSize();
2476 unsigned int count = 0;
2478 count += spk_man->GetKeyPoolSize();
2488 res &= spk_man->TopUp(kpSize);
2501 auto op_dest = spk_man->GetNewDestination(type);
2521 for (
auto& entry : mapWallet) {
2524 for (
unsigned int i = 0; i < wtx.
tx->vout.size(); i++) {
2537 for (
const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book) {
2538 const auto& entry = item.second;
2539 func(item.first, entry.GetLabel(), entry.IsChange(), entry.purpose);
2546 std::vector<CTxDestination> result;
2554 result.emplace_back(dest);
2562 std::set<std::string> label_set;
2564 bool _is_change,
const std::optional<AddressPurpose>& _purpose) {
2565 if (_is_change)
return;
2566 if (!purpose || purpose == _purpose) {
2567 label_set.insert(_label);
2583 if (!op_address)
return op_address;
2613 if (signer_spk_man ==
nullptr) {
2618 return signer_spk_man->DisplayAddress(dest, *
signer);
2620 return util::Error{
_(
"There is no ScriptPubKeyManager for this address")};
2626 m_locked_coins.emplace(coin, persistent);
2643 auto locked_coin_it = m_locked_coins.find(output);
2644 if (locked_coin_it != m_locked_coins.end()) {
2645 bool persisted = locked_coin_it->second;
2646 m_locked_coins.erase(locked_coin_it);
2658 bool success =
true;
2660 for (
const auto& [coin, persistent] : m_locked_coins) {
2663 m_locked_coins.clear();
2670 return m_locked_coins.count(output) > 0;
2676 for (
const auto& [coin,
_] : m_locked_coins) {
2677 vOutpts.push_back(coin);
2706 std::optional<uint256> block_hash;
2708 block_hash = conf->confirmed_block_hash;
2710 block_hash = conf->conflicting_block_hash;
2716 int64_t block_max_time;
2717 if (
chain().findBlock(*block_hash,
FoundBlock().time(blocktime).maxTime(block_max_time))) {
2718 if (rescanning_old_block) {
2719 nTimeSmart = block_max_time;
2722 int64_t latestEntry = 0;
2725 int64_t latestTolerated = latestNow + 300;
2727 for (
auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
2737 if (nSmartTime <= latestTolerated) {
2738 latestEntry = nSmartTime;
2739 if (nSmartTime > latestNow) {
2740 latestNow = nSmartTime;
2746 nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
2757 if (std::get_if<CNoDestination>(&dest))
2771 m_address_book[dest].previously_spent =
true;
2776 m_address_book[dest].receive_requests[id] = request;
2787 std::vector<std::string>
values;
2788 for (
const auto& [dest, entry] : m_address_book) {
2789 for (
const auto& [
id, request] : entry.receive_requests) {
2790 values.emplace_back(request);
2799 m_address_book[dest].receive_requests[id] = value;
2806 m_address_book[dest].receive_requests.erase(
id);
2819 fs::file_type path_type = fs::symlink_status(wallet_path).type();
2820 if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory ||
2821 (path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) ||
2824 "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
2825 "database/log.?????????? files can be stored, a location where such a directory could be created, "
2826 "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
2840 return MakeDatabase(*wallet_path, options, status, error_string);
2847 const std::string& walletFile = database->Filename();
2849 const auto start{SteadyClock::now()};
2854 walletInstance->m_notify_tx_changed_script =
args.
GetArg(
"-walletnotify",
"");
2857 bool rescan_required =
false;
2858 DBErrors nLoadWalletRet = walletInstance->LoadWallet();
2861 error =
strprintf(
_(
"Error loading %s: Wallet corrupted"), walletFile);
2866 warnings.push_back(
strprintf(
_(
"Error reading %s! All keys read correctly, but transaction data"
2867 " or address metadata may be missing or incorrect."),
2871 error =
strprintf(
_(
"Error loading %s: Wallet requires newer version of %s"), walletFile, CLIENT_NAME);
2875 error =
strprintf(
_(
"Error loading %s: External signer wallet being loaded without external signer support compiled"), walletFile);
2880 error =
strprintf(
_(
"Wallet needed to be rewritten: restart %s to complete"), CLIENT_NAME);
2883 warnings.push_back(
strprintf(
_(
"Error reading %s! Transaction data may be missing or incorrect."
2884 " Rescanning wallet."), walletFile));
2885 rescan_required =
true;
2887 error =
strprintf(
_(
"Unrecognized descriptor found. Loading wallet %s\n\n"
2888 "The wallet might have been created on a newer version.\n"
2889 "Please try running the latest software version.\n"), walletFile);
2892 error =
strprintf(
_(
"Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
2893 "The wallet might have been tampered with or created with malicious intent.\n"), walletFile);
2896 error =
strprintf(
_(
"Error loading %s: Wallet is a legacy wallet. Please migrate to a descriptor wallet using the migration tool (migratewallet RPC)."), walletFile);
2899 error =
strprintf(
_(
"Error loading %s"), walletFile);
2905 const bool fFirstRun = walletInstance->m_spk_managers.empty() &&
2910 LOCK(walletInstance->cs_wallet);
2920 walletInstance->SetupDescriptorScriptPubKeyMans();
2926 walletInstance->SetLastBlockProcessed(*tip_height,
chain->
getBlockHash(*tip_height));
2931 error =
strprintf(
_(
"Error loading %s: Private keys can only be disabled during creation"), walletFile);
2934 for (
auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
2935 if (spk_man->HavePrivateKeys()) {
2936 warnings.push_back(
strprintf(
_(
"Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
2942 if (!
args.
GetArg(
"-addresstype",
"").empty()) {
2948 walletInstance->m_default_address_type = parsed.value();
2951 if (!
args.
GetArg(
"-changetype",
"").empty()) {
2957 walletInstance->m_default_change_type = parsed.value();
2960 if (
const auto arg{
args.
GetArg(
"-mintxfee")}) {
2961 std::optional<CAmount> min_tx_fee =
ParseMoney(*arg);
2967 _(
"This is the minimum transaction fee you pay on every transaction."));
2970 walletInstance->m_min_fee =
CFeeRate{min_tx_fee.value()};
2973 if (
const auto arg{
args.
GetArg(
"-maxapsfee")}) {
2974 const std::string& max_aps_fee{*arg};
2975 if (max_aps_fee ==
"-1") {
2976 walletInstance->m_max_aps_fee = -1;
2977 }
else if (std::optional<CAmount> max_fee =
ParseMoney(max_aps_fee)) {
2980 _(
"This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
2982 walletInstance->m_max_aps_fee = max_fee.value();
2989 if (
const auto arg{
args.
GetArg(
"-fallbackfee")}) {
2990 std::optional<CAmount> fallback_fee =
ParseMoney(*arg);
2991 if (!fallback_fee) {
2992 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s'"),
"-fallbackfee", *arg);
2996 _(
"This is the transaction fee you may pay when fee estimates are not available."));
2998 walletInstance->m_fallback_fee =
CFeeRate{fallback_fee.value()};
3002 walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.
GetFeePerK() != 0;
3004 if (
const auto arg{
args.
GetArg(
"-discardfee")}) {
3005 std::optional<CAmount> discard_fee =
ParseMoney(*arg);
3007 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s'"),
"-discardfee", *arg);
3011 _(
"This is the transaction fee you may discard if change is smaller than dust at this level"));
3013 walletInstance->m_discard_rate =
CFeeRate{discard_fee.value()};
3016 if (
const auto arg{
args.
GetArg(
"-paytxfee")}) {
3017 warnings.push_back(
_(
"-paytxfee is deprecated and will be fully removed in v31.0."));
3019 std::optional<CAmount> pay_tx_fee =
ParseMoney(*arg);
3025 _(
"This is the transaction fee you will pay if you send a transaction."));
3028 walletInstance->m_pay_tx_fee =
CFeeRate{pay_tx_fee.value(), 1000};
3031 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' (must be at least %s)"),
3037 if (
const auto arg{
args.
GetArg(
"-maxtxfee")}) {
3038 std::optional<CAmount> max_fee =
ParseMoney(*arg);
3043 warnings.push_back(
strprintf(
_(
"%s is set very high! Fees this large could be paid on a single transaction."),
"-maxtxfee"));
3047 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
3052 walletInstance->m_default_max_tx_fee = max_fee.value();
3055 if (
const auto arg{
args.
GetArg(
"-consolidatefeerate")}) {
3056 if (std::optional<CAmount> consolidate_feerate =
ParseMoney(*arg)) {
3057 walletInstance->m_consolidate_feerate =
CFeeRate(*consolidate_feerate);
3066 _(
"The wallet will avoid paying less than the minimum relay fee."));
3073 walletInstance->WalletLogPrintf(
"Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
3076 walletInstance->TopUpKeyPool();
3079 std::optional<int64_t> time_first_key;
3080 for (
auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
3081 int64_t time = spk_man->GetTimeFirstKey();
3082 if (!time_first_key || time < *time_first_key) time_first_key = time;
3084 if (time_first_key) walletInstance->MaybeUpdateBirthTime(*time_first_key);
3087 walletInstance->m_chain_notifications_handler.reset();
3092 LOCK(walletInstance->cs_wallet);
3094 walletInstance->WalletLogPrintf(
"setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
3095 walletInstance->WalletLogPrintf(
"mapWallet.size() = %u\n", walletInstance->mapWallet.size());
3096 walletInstance->WalletLogPrintf(
"m_address_book.size() = %u\n", walletInstance->m_address_book.size());
3099 return walletInstance;
3104 LOCK(walletInstance->cs_wallet);
3106 assert(!walletInstance->m_chain || walletInstance->m_chain == &
chain);
3107 walletInstance->m_chain = &
chain;
3117 error =
Untranslated(
"Wallet files should not be reused across chains. Restart bitcoind with -walletcrosschain to override.");
3129 walletInstance->m_chain_notifications_handler = walletInstance->chain().handleNotifications(walletInstance);
3132 int rescan_height = 0;
3133 if (!rescan_required)
3139 rescan_height = *fork_height;
3146 walletInstance->SetLastBlockProcessedInMem(*tip_height,
chain.
getBlockHash(*tip_height));
3148 walletInstance->SetLastBlockProcessedInMem(-1,
uint256());
3151 if (tip_height && *tip_height != rescan_height)
3155 std::optional<int64_t> time_first_key = walletInstance->m_birth_time.load();
3156 if (time_first_key) {
3163 rescan_height = *tip_height;
3171 int block_height = *tip_height;
3172 while (block_height > 0 &&
chain.
haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
3176 if (rescan_height != block_height) {
3187 _(
"Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of a pruned node)") :
3189 "Error loading wallet. Wallet requires blocks to be downloaded, "
3190 "and software does not currently support loading wallets while "
3191 "blocks are being downloaded out of order when using assumeutxo "
3192 "snapshots. Wallet should be able to load successfully after "
3193 "node sync reaches height %s"), block_height);
3199 walletInstance->WalletLogPrintf(
"Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
3204 error =
_(
"Failed to acquire rescan reserver during wallet initialization");
3207 ScanResult scan_res = walletInstance->ScanForWalletTransactions(
chain.
getBlockHash(rescan_height), rescan_height, {}, reserver,
true,
true);
3209 error =
_(
"Failed to rescan the wallet during initialization");
3224 const auto& address_book_it = m_address_book.find(dest);
3225 if (address_book_it == m_address_book.end())
return nullptr;
3226 if ((!allow_change) && address_book_it->second.IsChange()) {
3229 return &address_book_it->second;
3252 assert(conf->confirmed_block_height >= 0);
3255 assert(conf->conflicting_block_height >= 0);
3270 assert(chain_depth >= 0);
3293 return vMasterKey.empty();
3303 if (!vMasterKey.empty()) {
3304 memory_cleanse(vMasterKey.data(), vMasterKey.size() *
sizeof(
decltype(vMasterKey)::value_type));
3318 if (!spk_man_pair.second->CheckDecryptionKey(vMasterKeyIn)) {
3322 vMasterKey = vMasterKeyIn;
3330 std::set<ScriptPubKeyMan*> spk_mans;
3331 for (
bool internal : {
false,
true}) {
3335 spk_mans.insert(spk_man);
3345 if (ext_spkm == &spkm)
return true;
3348 if (int_spkm == &spkm)
return true;
3355 std::set<ScriptPubKeyMan*> spk_mans;
3357 spk_mans.insert(spk_man_pair.second.get());
3365 std::map<OutputType, ScriptPubKeyMan*>::const_iterator it = spk_managers.find(type);
3366 if (it == spk_managers.end()) {
3374 std::set<ScriptPubKeyMan*> spk_mans;
3379 spk_mans.insert(it->second.begin(), it->second.end());
3382 Assume(std::all_of(spk_mans.begin(), spk_mans.end(), [&
script, &sigdata](
ScriptPubKeyMan* spkm) { return spkm->CanProvide(script, sigdata); }));
3408 return it->second.at(0)->GetSolvingProvider(
script);
3416 std::vector<WalletDescriptor> descs;
3419 LOCK(desc_spk_man->cs_desc_man);
3420 descs.push_back(desc_spk_man->GetWalletDescriptor());
3459 std::unique_ptr<ScriptPubKeyMan> spk_manager = std::make_unique<LegacyDataSPKM>(*
this);
3465 uint256 id = spk_manager->GetID();
3472 return cb(vMasterKey);
3483 if (spkm->HaveCryptedKeys())
return true;
3505 return *spk_manager;
3514 throw std::runtime_error(std::string(__func__) +
": Wallet is locked, cannot setup new descriptors");
3516 if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, &batch)) {
3517 throw std::runtime_error(std::string(__func__) +
": Could not encrypt new descriptors");
3520 spk_manager->SetupDescriptorGeneration(batch, master_key, output_type, internal);
3522 uint256 id = spk_manager->GetID();
3531 for (
bool internal : {
false,
true}) {
3562 }))
throw std::runtime_error(
"Error: cannot process db transaction for descriptors setup");
3571 if (!signer_res.
isObject())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3574 if (!batch.
TxnBegin())
throw std::runtime_error(
"Error: cannot create db transaction for descriptors import");
3576 for (
bool internal : {
false,
true}) {
3577 const UniValue& descriptor_vals = signer_res.
find_value(internal ?
"internal" :
"receive");
3578 if (!descriptor_vals.
isArray())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3580 const std::string& desc_str = desc_val.getValStr();
3582 std::string desc_error;
3583 auto descs =
Parse(desc_str, keys, desc_error,
false);
3584 if (descs.empty()) {
3585 throw std::runtime_error(std::string(__func__) +
": Invalid descriptor \"" + desc_str +
"\" (" + desc_error +
")");
3587 auto& desc = descs.at(0);
3588 if (!desc->GetOutputType()) {
3593 spk_manager->SetupDescriptor(batch, std::move(desc));
3594 uint256 id = spk_manager->GetID();
3601 if (!batch.
TxnCommit())
throw std::runtime_error(
"Error: cannot commit db transaction for descriptors import");
3614 throw std::runtime_error(std::string(__func__) +
": writing active ScriptPubKeyMan id failed");
3629 spk_mans[type] = spk_man;
3631 const auto it = spk_mans_other.find(type);
3632 if (it != spk_mans_other.end() && it->second == spk_man) {
3633 spk_mans_other.erase(type);
3642 if (spk_man !=
nullptr && spk_man->GetID() ==
id) {
3646 throw std::runtime_error(std::string(__func__) +
": erasing active ScriptPubKeyMan id failed");
3650 spk_mans.erase(type);
3675 return std::nullopt;
3679 if (!desc_spk_man) {
3680 throw std::runtime_error(std::string(__func__) +
": unexpected ScriptPubKeyMan type.");
3683 LOCK(desc_spk_man->cs_desc_man);
3684 const auto& type = desc_spk_man->GetWalletDescriptor().descriptor->GetOutputType();
3685 assert(type.has_value());
3699 if (
auto spkm_res = spk_man->UpdateWalletDescriptor(desc); !spkm_res) {
3704 spk_man = new_spk_man.get();
3707 uint256 id = new_spk_man->GetID();
3712 for (
const auto& entry : signing_provider.
keys) {
3713 const CKey& key = entry.second;
3714 spk_man->AddDescriptorKey(key, key.
GetPubKey());
3718 if (!spk_man->TopUp()) {
3719 return util::Error{
_(
"Could not top up scriptPubKeys")};
3725 auto script_pub_keys = spk_man->GetScriptPubKeys();
3726 if (script_pub_keys.empty()) {
3727 return util::Error{
_(
"Could not generate scriptPubKeys (cache is empty)")};
3731 for (
const auto&
script : script_pub_keys) {
3741 spk_man->WriteDescriptor();
3746 return std::reference_wrapper(*spk_man);
3753 WalletLogPrintf(
"Migrating wallet storage database from BerkeleyDB to SQLite.\n");
3756 error =
_(
"Error: This wallet already uses SQLite");
3761 std::unique_ptr<DatabaseBatch> batch =
m_database->MakeBatch();
3762 std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor();
3763 std::vector<std::pair<SerializeData, SerializeData>> records;
3765 error =
_(
"Error: Unable to begin reading all records in the database");
3772 status = cursor->Next(ss_key, ss_value);
3778 records.emplace_back(key, value);
3783 error =
_(
"Error: Unable to read all records in the database");
3790 fs::remove(db_path);
3801 std::unique_ptr<WalletDatabase> new_db =
MakeDatabase(wallet_path, opts, db_status, error);
3808 bool began = batch->TxnBegin();
3810 for (
const auto& [key, value] : records) {
3811 if (!batch->Write(std::span{key}, std::span{value})) {
3818 bool committed = batch->TxnCommit();
3828 if (!
Assume(legacy_spkm)) {
3831 return std::nullopt;
3835 if (res == std::nullopt) {
3836 error =
_(
"Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
3837 return std::nullopt;
3847 if (!
Assume(legacy_spkm)) {
3853 bool has_spendable_material = !
data.desc_spkms.empty() ||
data.master_key.key.IsValid();
3856 std::set<CTxDestination> not_migrated_dests;
3865 if (!
data.watch_descs.empty())
Assume(!
data.watchonly_wallet->m_cached_spks.empty());
3866 if (!
data.solvable_descs.empty())
Assume(!
data.solvable_wallet->m_cached_spks.empty());
3868 for (
auto& desc_spkm :
data.desc_spkms) {
3870 return util::Error{
_(
"Error: Duplicate descriptors created during migration. Your wallet may be corrupted.")};
3872 uint256 id = desc_spkm->GetID();
3878 return util::Error{
_(
"Error: cannot remove legacy wallet records")};
3890 if (
data.master_key.key.IsValid()) {
3900 if (!local_wallet_batch.
ReadBestBlock(best_block_locator)) {
3901 return util::Error{
_(
"Error: Unable to read wallet's best block locator record")};
3910 std::vector<Txid> txids_to_delete;
3911 std::unique_ptr<WalletBatch> watchonly_batch;
3912 if (
data.watchonly_wallet) {
3913 watchonly_batch = std::make_unique<WalletBatch>(
data.watchonly_wallet->GetDatabase());
3914 if (!watchonly_batch->TxnBegin())
return util::Error{
strprintf(
_(
"Error: database transaction cannot be executed for wallet %s"),
data.watchonly_wallet->GetName())};
3916 LOCK(
data.watchonly_wallet->cs_wallet);
3917 data.watchonly_wallet->nOrderPosNext = nOrderPosNext;
3918 watchonly_batch->WriteOrderPosNext(
data.watchonly_wallet->nOrderPosNext);
3920 if (!watchonly_batch->WriteBestBlock(best_block_locator)) {
3921 return util::Error{
_(
"Error: Unable to write watchonly wallet best block locator record")};
3924 std::unique_ptr<WalletBatch> solvables_batch;
3925 if (
data.solvable_wallet) {
3926 solvables_batch = std::make_unique<WalletBatch>(
data.solvable_wallet->GetDatabase());
3927 if (!solvables_batch->TxnBegin())
return util::Error{
strprintf(
_(
"Error: database transaction cannot be executed for wallet %s"),
data.solvable_wallet->GetName())};
3929 if (!solvables_batch->WriteBestBlock(best_block_locator)) {
3930 return util::Error{
_(
"Error: Unable to write solvable wallet best block locator record")};
3937 if (
data.watchonly_wallet) {
3938 LOCK(
data.watchonly_wallet->cs_wallet);
3939 if (
data.watchonly_wallet->IsMine(*wtx->tx) ||
data.watchonly_wallet->IsFromMe(*wtx->tx)) {
3941 const Txid& hash = wtx->GetHash();
3944 if (!new_tx) return false;
3945 ins_wtx.SetTx(to_copy_wtx.tx);
3946 ins_wtx.CopyFrom(to_copy_wtx);
3949 return util::Error{
strprintf(
_(
"Error: Could not add watchonly tx %s to watchonly wallet"), wtx->GetHash().GetHex())};
3951 watchonly_batch->WriteTx(
data.watchonly_wallet->mapWallet.at(hash));
3954 txids_to_delete.push_back(hash);
3961 return util::Error{
strprintf(
_(
"Error: Transaction %s in wallet cannot be identified to belong to migrated wallets"), wtx->GetHash().GetHex())};
3966 if (txids_to_delete.size() > 0) {
3967 if (
auto res =
RemoveTxs(local_wallet_batch, txids_to_delete); !res) {
3973 std::vector<std::pair<std::shared_ptr<CWallet>, std::unique_ptr<WalletBatch>>> wallets_vec;
3974 if (
data.watchonly_wallet) wallets_vec.emplace_back(
data.watchonly_wallet, std::move(watchonly_batch));
3975 if (
data.solvable_wallet) wallets_vec.emplace_back(
data.solvable_wallet, std::move(solvables_batch));
3981 if (entry.label) batch.
WriteName(address, *entry.label);
3982 for (
const auto& [
id, request] : entry.receive_requests) {
3989 std::vector<CTxDestination> dests_to_delete;
3990 for (
const auto& [dest, record] : m_address_book) {
3994 bool copied =
false;
3995 for (
auto& [
wallet, batch] : wallets_vec) {
3997 if (require_transfer && !
wallet->IsMine(dest))
continue;
4000 wallet->m_address_book[dest] = record;
4001 func_store_addr(*batch, dest, record);
4005 if (require_transfer) {
4006 dests_to_delete.push_back(dest);
4014 if (require_transfer && !copied) {
4017 if (not_migrated_dests.count(dest) > 0) {
4018 dests_to_delete.push_back(dest);
4022 return util::Error{
_(
"Error: Address book data in wallet cannot be identified to belong to migrated wallets")};
4027 for (
auto& [
wallet, batch] : wallets_vec) {
4034 if (dests_to_delete.size() > 0) {
4035 for (
const auto& dest : dests_to_delete) {
4037 return util::Error{
_(
"Error: Unable to remove watchonly address book data")};
4045 if (!has_spendable_material) {
4046 if (!m_address_book.empty())
return util::Error{
_(
"Error: Not all address book records were migrated")};
4047 if (!mapWallet.empty())
return util::Error{
_(
"Error: Not all transaction records were migrated")};
4063 std::optional<MigrationData>
data =
wallet.GetDescriptorsForLegacy(error);
4064 if (
data == std::nullopt)
return false;
4067 if (
data->watch_descs.size() > 0 ||
data->solvable_descs.size() > 0) {
4074 empty_context.
args = context.args;
4084 if (
data->watch_descs.size() > 0) {
4085 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the watched scripts\n");
4088 std::vector<bilingual_str> warnings;
4089 std::string wallet_name =
wallet.GetName() +
"_watchonly";
4090 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4092 error =
strprintf(
_(
"Wallet file creation failed: %s"), error);
4097 if (!
data->watchonly_wallet) {
4098 error =
_(
"Error: Failed to create new watchonly wallet");
4101 res.watchonly_wallet =
data->watchonly_wallet;
4102 LOCK(
data->watchonly_wallet->cs_wallet);
4105 for (
const auto& [desc_str, creation_time] :
data->watch_descs) {
4108 std::string parse_err;
4109 std::vector<std::unique_ptr<Descriptor>> descs =
Parse(desc_str, keys, parse_err,
true);
4110 assert(descs.size() == 1);
4111 assert(!descs.at(0)->IsRange());
4115 if (
auto spkm_res =
data->watchonly_wallet->AddWalletDescriptor(w_desc, keys,
"",
false); !spkm_res) {
4123 if (
data->solvable_descs.size() > 0) {
4124 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the unwatched solvable scripts\n");
4127 std::vector<bilingual_str> warnings;
4128 std::string wallet_name =
wallet.GetName() +
"_solvables";
4129 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4131 error =
strprintf(
_(
"Wallet file creation failed: %s"), error);
4136 if (!
data->solvable_wallet) {
4137 error =
_(
"Error: Failed to create new watchonly wallet");
4140 res.solvables_wallet =
data->solvable_wallet;
4141 LOCK(
data->solvable_wallet->cs_wallet);
4144 for (
const auto& [desc_str, creation_time] :
data->solvable_descs) {
4147 std::string parse_err;
4148 std::vector<std::unique_ptr<Descriptor>> descs =
Parse(desc_str, keys, parse_err,
true);
4149 assert(descs.size() == 1);
4150 assert(!descs.at(0)->IsRange());
4154 if (
auto spkm_res =
data->solvable_wallet->AddWalletDescriptor(w_desc, keys,
"",
false); !spkm_res) {
4166 if (auto res_migration = wallet.ApplyMigrationData(batch, *data); !res_migration) {
4167 error = util::ErrorString(res_migration);
4170 wallet.WalletLogPrintf(
"Wallet migration complete.\n");
4177 std::vector<bilingual_str> warnings;
4183 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4194 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4206 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4212 std::shared_ptr<CWallet> local_wallet = CWallet::Create(empty_context, wallet_name, std::move(database), options.
create_flags, error, warnings);
4213 if (!local_wallet) {
4224 std::vector<bilingual_str> warnings;
4230 const std::string wallet_name = local_wallet->GetName();
4234 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4243 const std::string backup_prefix = wallet_name.empty() ?
"default_wallet" : [&] {
4252 return util::Error{
_(
"Error: Unable to make a backup of your wallet")};
4256 bool success =
false;
4259 if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
4260 if (passphrase.find(
'\0') == std::string::npos) {
4261 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
4263 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase entered was incorrect. "
4264 "The passphrase contains a null character (ie - a zero byte). "
4265 "If this passphrase was set with a version of this software prior to 25.0, "
4266 "please try again with only the characters up to — but not including — "
4267 "the first null character.")};
4277 bool empty_local_wallet =
false;
4280 LOCK(local_wallet->cs_wallet);
4282 if (!local_wallet->MigrateToSQLite(error))
return util::Error{error};
4286 success =
DoMigration(*local_wallet, context, error, res);
4288 empty_local_wallet = local_wallet->GetAllScriptPubKeyMans().empty();
4300 std::set<fs::path> wallet_dirs;
4304 if (empty_local_wallet) {
4306 std::vector<fs::path> paths_to_remove = local_wallet->GetDatabase().Files();
4307 local_wallet.reset();
4308 for (
const auto& path_to_remove : paths_to_remove) fs::remove_all(path_to_remove);
4313 if (success && *wallet_ptr) {
4314 std::shared_ptr<CWallet>&
wallet = *wallet_ptr;
4318 std::string wallet_name =
wallet->GetName();
4320 wallet =
LoadWallet(context, wallet_name, std::nullopt, options, status, error, warnings);
4321 success = (
wallet !=
nullptr);
4324 if (success && !res.
wallet) {
4333 std::vector<std::shared_ptr<CWallet>> created_wallets;
4334 if (local_wallet) created_wallets.push_back(std::move(local_wallet));
4339 for (std::shared_ptr<CWallet>& w : created_wallets) {
4344 for (std::shared_ptr<CWallet>& w : created_wallets) {
4345 if (w->HaveChain()) {
4348 error +=
_(
"\nUnable to cleanup failed migration");
4354 assert(w.use_count() == 1);
4360 for (
const fs::path& dir : wallet_dirs) {
4361 fs::remove_all(dir);
4367 const auto& ptr_wallet =
RestoreWallet(context, backup_path, wallet_name, std::nullopt, status, restore_error, warnings,
false);
4368 if (!restore_error.
empty()) {
4369 error += restore_error +
_(
"\nUnable to restore backup of wallet.");
4382 for (
const auto&
script : spks) {
4383 m_cached_spks[
script].push_back(spkm);
4390 CacheNewScriptPubKeys(spks, spkm);
4393std::set<CExtPubKey> CWallet::GetActiveHDPubKeys()
const
4399 std::set<CExtPubKey> active_xpubs;
4400 for (
const auto& spkm : GetActiveScriptPubKeyMans()) {
4406 std::set<CPubKey> desc_pubkeys;
4407 std::set<CExtPubKey> desc_xpubs;
4408 w_desc.
descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
4409 active_xpubs.merge(std::move(desc_xpubs));
4411 return active_xpubs;
4414std::optional<CKey> CWallet::GetKey(
const CKeyID& keyid)
const
4418 for (
const auto& spkm : GetAllScriptPubKeyMans()) {
4422 if (std::optional<CKey> key = desc_spkm->
GetKey(keyid)) {
4426 return std::nullopt;
4429void CWallet::WriteBestBlock()
const
4433 if (!m_last_block_processed.IsNull()) {
4435 chain().findBlock(m_last_block_processed,
FoundBlock().locator(loc));
4447 for (uint32_t i = 0; i < wtx.
tx->vout.size(); ++i) {
4448 const CTxOut& txout = wtx.
tx->vout.at(i);
4449 if (!IsMine(txout))
continue;
4451 if (m_txos.contains(outpoint)) {
4453 m_txos.emplace(outpoint,
WalletTXO{wtx, txout});
4458void CWallet::RefreshAllTXOs()
4461 for (
const auto& [
_, wtx] : mapWallet) {
4462 RefreshTXOsFromTx(wtx);
4466std::optional<WalletTXO> CWallet::GetTXO(
const COutPoint& outpoint)
const
4469 const auto& it = m_txos.find(outpoint);
4470 if (it == m_txos.end()) {
4471 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)
static 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.
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
bool GetBoolArg(const std::string &strArg, bool fDefault) const
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(const FeeEstimateMode &fee_estimate_mode=FeeEstimateMode::BTC_KVB) const
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.
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.
Double ended buffer combining vector and stream-like interfaces.
std::unordered_set< Element, ByteVectorHash > ElementSet
Different type to mark Mutex at global scope.
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
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
virtual std::optional< int > getHeight()=0
Get current chain height, not including genesis block (returns 0 if chain only contains genesis block...
virtual uint256 getBlockHash(int height)=0
Get block hash. Height must be valid or this function will abort.
virtual bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock &block={})=0
Find first block in the chain with timestamp >= the given time and height >= than the given height,...
virtual bool havePruned()=0
Check if any block has been pruned.
virtual bool updateRwSetting(const std::string &name, const SettingsUpdate &update_function)=0
Updates a setting in <datadir>/settings.json.
virtual bool hasAssumedValidChain()=0
Return true if an assumed-valid chain is in use.
virtual bool 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
Find ancestor of block at specified height and optionally return ancestor information.
virtual bool findBlock(const uint256 &hash, const FoundBlock &block={})=0
Return whether node has the block and optionally return block metadata or contents.
virtual double guessVerificationProgress(const uint256 &block_hash)=0
Estimate fraction of total transactions verified if blocks up to the specified block hash are verifie...
virtual void waitForNotificationsIfTipChanged(const uint256 &old_tip)=0
Wait for pending notifications to be processed unless block hash points to the current chain tip.
virtual void initMessage(const std::string &message)=0
Send init message.
virtual bool broadcastTransaction(const CTransactionRef &tx, const CAmount &max_tx_fee, bool relay, std::string &err_string)=0
Transaction is added to memory pool, if the transaction fee is below the amount specified by max_tx_f...
virtual std::optional< int > findLocatorFork(const CBlockLocator &locator)=0
Return height of the highest block on chain in common with the locator, which will either be the orig...
virtual bool haveBlockOnDisk(int height)=0
Check that the block is available on disk (i.e.
virtual CFeeRate relayMinFee()=0
Relay current minimum fee (from -minrelaytxfee and -incrementalrelayfee settings).
Helper for findBlock to selectively return pieces of block data.
FoundBlock & locator(CBlockLocator &locator)
Return locator if block is in the active chain.
FoundBlock & height(int &height)
FoundBlock & data(CBlock &data)
Read block data from disk.
std::string ToString() const
constexpr const std::byte * begin() const
std::string GetHex() const
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, const unsigned int rounds, const 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 TopUpKeyPool(unsigned int kpSize=0)
bool HaveChain() const
Interface to assert chain access.
bool GetBroadcastTransactions() const
Inquire whether this wallet broadcasts transactions.
unsigned int GetKeyPoolSize() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::function< bool(CWalletTx &wtx, bool new_tx)> UpdateWalletTxFn
Callback for updating transaction metadata in mapWallet.
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)
bool IsActiveScriptPubKeyMan(const ScriptPubKeyMan &spkm) const
OutputType m_default_address_type
void AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
Adds the active ScriptPubKeyMan for the specified type and internal.
void LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
Loads an active ScriptPubKeyMan for the specified type and internal.
std::unique_ptr< WalletDatabase > m_database
Internal database handle.
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::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.
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)
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 ...
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...
std::optional< common::PSBTError > FillPSBT(PartiallySignedTransaction &psbtx, bool &complete, std::optional< int > sighash_type=std::nullopt, bool sign=true, bool bip32derivs=true, size_t *n_signed=nullptr, bool finalize=true) const
Fills out a PSBT with information from the wallet.
unsigned int nMasterKeyMaxID
bool SetAddressReceiveRequest(WalletBatch &batch, const CTxDestination &dest, const std::string &id, const std::string &value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get last block processed height.
std::atomic< double > m_scanning_progress
LegacyDataSPKM * GetLegacyDataSPKM() const
Get the LegacyScriptPubKeyMan which is used for all types, internal, and external.
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::map< OutputType, ScriptPubKeyMan * > m_external_spk_managers
DescriptorScriptPubKeyMan & LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor &desc)
Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it.
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.
const std::string & GetName() const
Get a name for this wallet for logging/debugging purposes.
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
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.
util::Result< CTxDestination > GetNewDestination(const OutputType type, const std::string label)
RecursiveMutex m_relock_mutex
std::string m_notify_tx_changed_script
Notify external script when a wallet transaction comes in or is updated (handled by -walletnotify)
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.
bool fBroadcastTransactions
Whether this wallet will submit newly created transactions to the node's mempool and prompt rebroadca...
size_t KeypoolCountExternalKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
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
static std::shared_ptr< CWallet > Create(WalletContext &context, const std::string &name, std::unique_ptr< WalletDatabase > database, uint64_t wallet_creation_flags, bilingual_str &error, std::vector< bilingual_str > &warnings)
bool CanGrindR() const
Whether the (external) signer performs R-value signature grinding.
std::optional< bool > IsInternalScriptPubKeyMan(ScriptPubKeyMan *spk_man) const
Returns whether the provided ScriptPubKeyMan is internal.
void LoadLockedCoin(const COutPoint &coin, bool persistent) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
SigningResult SignMessage(const std::string &message, const PKHash &pkhash, std::string &str_sig) const
MasterKeyMap mapMasterKeys
boost::signals2::signal< void(const Txid &hashTx, ChangeType status)> NotifyTransactionChanged
Wallet transaction added, removed or updated.
util::Result< void > ApplyMigrationData(WalletBatch &local_wallet_batch, MigrationData &data) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Adds the ScriptPubKeyMans given in MigrationData to this wallet, removes LegacyScriptPubKeyMan,...
NodeClock::time_point m_next_resend
The next scheduled rebroadcast of wallet transactions.
WalletDatabase & GetDatabase() const override
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.
boost::signals2::signal< void(const std::string &title, int nProgress)> ShowProgress
Show progress e.g.
bool DelAddressBookWithDB(WalletBatch &batch, const CTxDestination &address)
std::string DisplayName() const
Return wallet name for display, like LogName() but translates "default wallet" string.
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)
Remove specified ScriptPubKeyMan from set of active SPK managers.
std::atomic< uint64_t > m_wallet_flags
WalletFlags set on this wallet.
bool LockCoin(const COutPoint &output, bool persist) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::set< std::string > ListAddrBookLabels(const std::optional< AddressPurpose > purpose) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Retrieve all the known labels in the address book.
bool IsLocked() const override
OutputType TransactionChangeType(const std::optional< OutputType > &change_type, const std::vector< CRecipient > &vecSend) const
boost::signals2::signal< void()> NotifyCanGetAddressesChanged
Keypool has new keys.
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.
void ListLockedCoins(std::vector< COutPoint > &vOutpts) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector< std::pair< std::string, std::string > > orderForm)
Submit the transaction to the node's mempool and then relay to peers.
bool UnlockAllCoins() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
util::Result< CTxDestination > GetNewChangeDestination(const OutputType type)
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
Pass the encryption key to cb().
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)
void ConnectScriptPubKeyManNotifiers()
Connect the signals from ScriptPubKeyMans to the signals in CWallet.
bool DelAddressBook(const CTxDestination &address)
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.
void SetupLegacyScriptPubKeyMan()
Make a Legacy(Data)SPKM and set it for all types, internal, and external.
static bool AttachChain(const std::shared_ptr< CWallet > &wallet, interfaces::Chain &chain, const bool rescan_required, bilingual_str &error, std::vector< bilingual_str > &warnings)
Catch wallet up to current chain, scanning new blocks, updating the best block locator and m_last_blo...
boost::signals2::signal< void(const CTxDestination &address, const std::string &label, bool isMine, AddressPurpose purpose, ChangeType status)> NotifyAddressBookChanged
Address book entry changed.
std::multimap< int64_t, CWalletTx * > TxItems
void SetupOwnDescriptorScriptPubKeyMans(WalletBatch &batch) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Create new seed and default DescriptorScriptPubKeyMans for this wallet.
boost::signals2::signal< void(CWallet *wallet)> NotifyStatusChanged
Wallet status (encrypted, locked) changed.
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.
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.
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.
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.
A transaction with a bunch of additional info that only the owner cares about.
bool isBlockConflicted() const
const Txid & GetHash() const LIFETIMEBOUND
bool IsEquivalentTo(const CWalletTx &tx) const
True if only scriptSigs are different.
std::vector< std::pair< std::string, std::string > > vOrderForm
std::set< Txid > mempool_conflicts
mapValue_t mapValue
Key/value map with information about the transaction.
void updateState(interfaces::Chain &chain)
Update transaction state when attaching to a chain, filling in heights of conflicted and confirmed bl...
int64_t nOrderPos
position in ordered transaction list
bool isUnconfirmed() const
unsigned int nTimeReceived
time received by this node
void SetTx(CTransactionRef arg)
std::optional< Txid > truc_child_in_mempool
int64_t GetTxTime() const
bool m_is_cache_empty
This flag is true if all m_amounts caches are empty.
std::multimap< int64_t, CWalletTx * >::const_iterator m_it_wtxOrdered
unsigned int nTimeSmart
Stable timestamp that never changes, and reflects the order a transaction was added to the wallet.
void MarkDirty()
make sure balances are recalculated
void UpgradeDescriptorCache()
WalletDescriptor GetWalletDescriptor() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man)
std::optional< CKey > GetKey(const CKeyID &keyid) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man)
Retrieve the particular key if it is available. Returns nullopt if the key is not in the wallet,...
bool HasWalletDescriptor(const WalletDescriptor &desc) const
RecursiveMutex cs_desc_man
static util::Result< ExternalSigner > GetExternalSigner()
bool DeleteRecordsWithDB(WalletBatch &batch)
Delete all the records of this LegacyScriptPubKeyMan 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.
virtual void KeepDestination(int64_t index, const OutputType &type)
virtual void ReturnDestination(int64_t index, bool internal, const CTxDestination &addr)
virtual util::Result< CTxDestination > GetReservedDestination(const OutputType type, bool internal, int64_t &index)
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 WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
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 WriteWalletFlags(const uint64_t flags)
bool EraseAddressData(const CTxDestination &dest)
bool WriteOrderPosNext(int64_t nOrderPosNext)
bool WriteTx(const CWalletTx &wtx)
bool ErasePurpose(const std::string &strAddress)
bool EraseLockedUTXO(const COutPoint &output)
bool WriteLockedUTXO(const COutPoint &output)
bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256 &id, bool internal)
bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal)
bool WriteAddressReceiveRequest(const CTxDestination &dest, const std::string &id, const std::string &receive_request)
virtual void Close()=0
Flush to the database file and close the database.
virtual bool Backup(const std::string &strDest) const =0
Back up the entire database to a file.
virtual bool Rewrite()=0
Rewrite the entire database on disk.
Descriptor with some wallet metadata.
std::shared_ptr< Descriptor > descriptor
RAII object to check and reserve a wallet rescan.
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.
static UniValue Parse(std::string_view raw)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
std::string ShellEscape(const std::string &arg)
static const int COINBASE_MATURITY
Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
static path u8path(const std::string &utf8_str)
static auto quoted(const std::string &s)
static bool exists(const path &p)
static bool copy_file(const path &from, const path &to, copy_options options)
static std::string PathToString(const path &path)
Convert path object to a byte string.
static path PathFromString(const std::string &string)
Convert byte string to path object.
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)
void SyncMetaData(std::pair< TxSpends::iterator, TxSpends::iterator >) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
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 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...
void blockConnected(ChainstateRole role, const interfaces::BlockInfo &block) override
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
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:
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.
void ResubmitWalletTransactions(bool relay, bool force)
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
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.
ScanResult ScanForWalletTransactions(const uint256 &start_block, int start_height, std::optional< int > max_height, const WalletRescanReserver &reserver, bool fUpdate, const bool save_progress)
Scan the block chain (starting in start_block) for transactions from or to us.
bool LoadWalletFlags(uint64_t flags)
Loads the flags into the wallet.
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.
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 ...
bool SyncTransaction(const CTransactionRef &tx, const SyncTxState &state, bool update_tx=true, bool rescanning_old_block=false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UnsetWalletFlag(uint64_t flag)
Unsets a single wallet flag.
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 LoadToWallet(const Txid &hash, const UpdateWalletTxFn &fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver, bool update)
Scan active chain for relevant transactions after importing keys.
bool IsFromMe(const CTransaction &tx) const
should probably be renamed to IsRelevantToMe
DBErrors ReorderTransactions()
bool AddToWalletIfInvolvingMe(const CTransactionRef &tx, const SyncTxState &state, bool fUpdate, bool rescanning_old_block) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Add a transaction to the wallet, or update it.
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.
bool SubmitTxMemoryPoolAndRelay(CWalletTx &wtx, std::string &err_string, bool relay) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Pass this transaction to node for mempool insertion and relay to peers if flag set to true.
@ SIGHASH_DEFAULT
Taproot only; implied when sighash byte is missing, and equivalent to SIGHASH_ALL.
ChainstateRole
This enum describes the various roles a specific Chainstate instance can take.
CKey GenerateRandomKey(bool compressed) noexcept
std::string EncodeDestination(const CTxDestination &dest)
#define LogDebug(category,...)
MemPoolRemovalReason
Reason why a transaction was removed from the mempool, this is passed to the notification signal.
@ BLOCK
Removed for block.
@ CONFLICT
Removed for conflict with in-block transaction.
is a home for simple string functions returning descriptive messages that are used in RPC and GUI int...
std::optional< CAmount > ParseMoney(const std::string &money_string)
Parse an amount denoted in full coins.
static int sign(const secp256k1_context *ctx, struct signer_secrets *signer_secrets, struct signer *signer, const secp256k1_musig_keyagg_cache *cache, const unsigned char *msg32, unsigned char *sig64)
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)
Return implementation of Wallet interface.
bilingual_str ErrorString(const Result< T > &result)
std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix)
std::string ToString(const T &t)
Locale-independent version of std::to_string.
void ReplaceAll(std::string &in_out, const std::string &search, const std::string &substitute)
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)
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.
std::variant< TxStateConfirmed, TxStateInMempool, TxStateInactive > SyncTxState
Subset of states transaction sync logic is implemented to handle.
std::function< void(std::unique_ptr< interfaces::Wallet > wallet)> LoadWalletFn
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
static bool RunWithinTxn(WalletBatch &batch, std::string_view process_desc, const std::function< bool(WalletBatch &)> &func)
std::variant< TxStateConfirmed, TxStateInMempool, TxStateBlockConflicted, TxStateInactive, TxStateUnrecognized > TxState
All possible CWalletTx states.
std::map< std::string, std::string > mapValue_t
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
DBErrors
Overview of wallet database classes:
@ UNEXPECTED_LEGACY_ENTRY
@ EXTERNAL_SIGNER_SUPPORT_REQUIRED
util::Result< MigrationResult > MigrateLegacyToDescriptor(std::shared_ptr< CWallet > local_wallet, const SecureString &passphrase, WalletContext &context)
Requirement: The wallet provided to this function must be isolated, with no attachment to the node's ...
static int TxStateSerializedIndex(const TxState &state)
Get TxState serialized block index. Inverse of TxStateInterpretSerialized.
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.
const unsigned int WALLET_CRYPTO_KEY_SIZE
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)
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...
static const bool DEFAULT_WALLETCROSSCHAIN
std::unique_ptr< interfaces::Handler > HandleLoadWallet(WalletContext &context, LoadWalletFn load_wallet)
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start)
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.
static const unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
static const std::unordered_set< OutputType > LEGACY_OUTPUT_TYPES
OutputTypes supported by the LegacyScriptPubKeyMan.
static const bool DEFAULT_WALLET_RBF
-walletrbf default
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)
static const unsigned int DEFAULT_TX_CONFIRM_TARGET
-txconfirmtarget default
std::string PurposeToString(AddressPurpose p)
static const bool DEFAULT_WALLETBROADCAST
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
bool DoMigration(CWallet &wallet, WalletContext &context, bilingual_str &error, MigrationResult &res) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
static uint256 TxStateSerializedBlockHash(const TxState &state)
Get TxState serialized block hash. Inverse of TxStateInterpretSerialized.
static constexpr uint64_t KNOWN_WALLET_FLAGS
static void UpdateWalletSetting(interfaces::Chain &chain, const std::string &wallet_name, std::optional< bool > load_on_startup, std::vector< bilingual_str > &warnings)
static GlobalMutex g_loading_wallet_mutex
const unsigned int WALLET_CRYPTO_SALT_SIZE
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
Flag set when a wallet contains no HD seed and no private keys, scripts, addresses,...
void WaitForDeleteWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly delete the 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)
static const bool DEFAULT_SPEND_ZEROCONF_CHANGE
Default for -spendzeroconfchange.
static util::Result< fs::path > GetWalletPath(const std::string &name)
@ 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)
is a home for public enum and struct type definitions that are used internally by node code,...
std::optional< OutputType > ParseOutputType(const std::string &type)
const std::string & FormatOutputType(OutputType type)
static constexpr auto OUTPUT_TYPES
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::shared_ptr< const CTransaction > CTransactionRef
bool PSBTInputSignedAndVerified(const PartiallySignedTransaction psbt, unsigned int input_index, const PrecomputedTransactionData *txdata)
Checks whether a PSBTInput is already signed by doing script verification using final fields.
void RemoveUnnecessaryTransactions(PartiallySignedTransaction &psbtx)
Reduces the size of the PSBT by dropping unnecessary non_witness_utxos (i.e.
bool PSBTInputSigned(const PSBTInput &input)
Checks whether a PSBTInput is already signed by checking for non-null finalized fields.
PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction &psbt)
Compute a PrecomputedTransactionData object from a psbt.
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...
static const int64_t values[]
A selection of numbers that do not trigger int64_t overflow when added/subtracted.
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
@ 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.
std::map< CKeyID, CKey > keys
static time_point now() noexcept
Return current system time or mocked time, if set.
std::chrono::time_point< NodeClock > time_point
A version of CTransaction with the PSBT format.
std::vector< PSBTInput > inputs
std::optional< CMutableTransaction > tx
Block data sent with blockConnected, blockDisconnected notifications.
const uint256 * prev_hash
unsigned int chain_time_max
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
enum wallet::CWallet::ScanResult::@19 status
uint256 last_scanned_block
Hash and height of most recent block that was successfully scanned.
uint256 last_failed_block
Height of the most recent block that could not be scanned due to read errors or pruning.
SecureString create_passphrase
std::optional< DatabaseFormat > require_format
struct containing information needed for migrating legacy wallets to descriptor wallets
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.
State of transaction not confirmed or conflicting with a known block and not in the mempool.
WalletContext struct containing references to state shared between CWallet instances,...
interfaces::Chain * chain
#define WAIT_LOCK(cs, name)
#define AssertLockNotHeld(cs)
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
#define EXCLUSIVE_LOCKS_REQUIRED(...)
consteval auto _(util::TranslatedLiteral str)
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
static 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
is a home for public enum and struct type definitions that are used by internally by wallet code,...
GCSFilter::ElementSet m_filter_set
std::map< uint256, int32_t > m_last_range_ends
Map for keeping track of each range descriptor's last seen end range.
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.