8#include <bitcoin-build-config.h>
10#include <blockfilter.h>
76#include <condition_variable>
99 if (!setting_value.isArray()) setting_value.setArray();
100 for (
const auto& value : setting_value.getValues()) {
103 setting_value.push_back(wallet_name);
114 for (
const auto& value : setting_value.getValues()) {
115 if (!value.isStr() || value.get_str() != wallet_name) new_value.
push_back(value);
118 setting_value = std::move(new_value);
125 const std::string& wallet_name,
126 std::optional<bool> load_on_startup,
127 std::vector<bilingual_str>& warnings)
129 if (!load_on_startup)
return;
131 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
133 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));
155 std::vector<std::shared_ptr<CWallet>>::const_iterator i = std::find(context.wallets.begin(), context.wallets.end(),
wallet);
156 if (i != context.wallets.end())
return false;
157 context.wallets.push_back(
wallet);
158 wallet->ConnectScriptPubKeyManNotifiers();
159 wallet->NotifyCanGetAddressesChanged();
172 wallet->DisconnectChainNotifications();
175 std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(context.wallets.begin(), context.wallets.end(),
wallet);
176 if (i == context.wallets.end())
return false;
177 context.wallets.erase(i);
190 std::vector<bilingual_str> warnings;
197 return context.wallets;
203 count = context.wallets.size();
204 return count == 1 ? context.wallets[0] :
nullptr;
210 for (
const std::shared_ptr<CWallet>&
wallet : context.wallets) {
219 auto it = context.wallet_load_fns.emplace(context.wallet_load_fns.end(), std::move(load_wallet));
226 for (
auto& load_wallet : context.wallet_load_fns) {
241 wallet->WalletLogPrintf(
"Releasing wallet %s..\n",
name);
246 if (g_unloading_wallet_set.erase(
name) == 0) {
260 g_unloading_wallet_set.insert(
name);
269 while (g_unloading_wallet_set.contains(
name)) {
276std::shared_ptr<CWallet> LoadWalletInternal(WalletContext& context,
const std::string&
name, std::optional<bool> load_on_start,
const DatabaseOptions& options,
DatabaseStatus& status,
bilingual_str& error, std::vector<bilingual_str>& warnings)
285 context.chain->initMessage(
_(
"Loading wallet…"));
295 wallet->postInitProcess();
301 }
catch (
const std::runtime_error& e) {
308class FastWalletRescanFilter
314 for (
auto spkm :
m_wallet.GetAllScriptPubKeyMans()) {
315 auto desc_spkm{
dynamic_cast<DescriptorScriptPubKeyMan*
>(spkm)};
316 assert(desc_spkm !=
nullptr);
317 AddScriptPubKeys(desc_spkm);
319 if (desc_spkm->IsHDEnabled()) {
325 void UpdateIfNeeded()
329 auto desc_spkm{
dynamic_cast<DescriptorScriptPubKeyMan*
>(
m_wallet.GetScriptPubKeyMan(desc_spkm_id))};
330 assert(desc_spkm !=
nullptr);
331 int32_t current_range_end{desc_spkm->GetEndRange()};
332 if (current_range_end > last_range_end) {
333 AddScriptPubKeys(desc_spkm, last_range_end);
339 std::optional<bool> MatchesBlock(
const uint256& block_hash)
const
355 void AddScriptPubKeys(
const DescriptorScriptPubKeyMan* desc_spkm, int32_t last_range_end = 0)
357 for (
const auto& script_pub_key : desc_spkm->GetScriptPubKeys(last_range_end)) {
358 m_filter_set.emplace(script_pub_key.begin(), script_pub_key.end());
367 if (!result.second) {
372 auto wallet = LoadWalletInternal(context,
name, load_on_start, options, status, error, warnings);
397 if (!passphrase.empty()) {
403 error =
Untranslated(
"Private keys must be disabled when using an external signer");
410 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.");
434 if (!
wallet->EncryptWallet(passphrase)) {
435 error =
Untranslated(
"Error: Wallet created but failed to encrypt.");
441 if (!
wallet->Unlock(passphrase)) {
442 error =
Untranslated(
"Error: Wallet was encrypted but could not be unlocked");
450 wallet->SetupDescriptorScriptPubKeyMans();
461 wallet->postInitProcess();
472std::shared_ptr<CWallet>
RestoreWallet(
WalletContext& context,
const fs::path& backup_file,
const std::string& wallet_name, std::optional<bool> load_on_start,
DatabaseStatus& status,
bilingual_str& error, std::vector<bilingual_str>& warnings,
bool load_after_restore,
bool allow_unnamed)
476 if (!allow_unnamed && wallet_name.empty()) {
487 auto wallet_file = wallet_path /
"wallet.dat";
488 std::shared_ptr<CWallet>
wallet;
489 bool wallet_file_copied =
false;
490 bool created_parent_dir =
false;
503 if (!fs::is_directory(wallet_path)) {
522 created_parent_dir =
true;
525 fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
526 wallet_file_copied =
true;
528 if (load_after_restore) {
529 wallet =
LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
531 }
catch (
const std::exception& e) {
538 if (load_after_restore && !
wallet) {
539 if (wallet_file_copied) fs::remove(wallet_file);
542 if (created_parent_dir) {
543 Assume(fs::is_empty(wallet_path));
544 fs::remove(wallet_path);
559 const auto it = mapWallet.find(hash);
560 if (it == mapWallet.end())
562 return &(it->second);
586 for (
int i = 0; i < 2; i++){
591 if (elapsed_time <= 0
s) {
598 unsigned int target_iterations = master_key.
nDeriveIterations * target_time / elapsed_time;
641 if (
Unlock(plain_master_key)) {
662 if (!
DecryptMasterKey(strOldWalletPassphrase, master_key, plain_master_key)) {
665 if (
Unlock(plain_master_key))
667 if (!
EncryptMasterKey(strNewWalletPassphrase, plain_master_key, master_key)) {
670 WalletLogPrintf(
"Wallet passphrase changed to an nDeriveIterations of %i\n", master_key.nDeriveIterations);
687 m_last_block_processed = block_hash;
688 m_last_block_processed_height = block_height;
701 std::set<Txid> result;
704 const auto it = mapWallet.find(txid);
705 if (it == mapWallet.end())
709 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
711 for (
const CTxIn& txin : wtx.
tx->vin)
713 if (mapTxSpends.count(txin.
prevout) <= 1)
715 range = mapTxSpends.equal_range(txin.
prevout);
716 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
717 result.insert(_it->second);
725 const Txid& txid = tx->GetHash();
726 for (
unsigned int i = 0; i < tx->vout.size(); ++i) {
745 int nMinOrderPos = std::numeric_limits<int>::max();
747 for (TxSpends::iterator it = range.first; it != range.second; ++it) {
748 const CWalletTx* wtx = &mapWallet.at(it->second);
760 for (TxSpends::iterator it = range.first; it != range.second; ++it)
762 const Txid& hash = it->second;
764 if (copyFrom == copyTo)
continue;
765 assert(copyFrom &&
"Oldest wallet transaction in range assumed to have been found.");
782 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
783 range = mapTxSpends.equal_range(outpoint);
785 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
786 const Txid& txid = it->second;
787 const auto mit = mapWallet.find(txid);
788 if (mit != mapWallet.end()) {
789 const auto& wtx = mit->second;
790 if (!wtx.isAbandoned() && !wtx.isBlockConflicted() && !wtx.isMempoolConflicted())
801 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
802 range = mapTxSpends.equal_range(outpoint);
804 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
805 const Txid& txid = it->second;
806 const auto mit = mapWallet.find(txid);
807 if (mit != mapWallet.end()) {
808 const auto& wtx = mit->second;
810 if (wtx.InMempool()) {
812 }
else if (!wtx.isAbandoned() && !wtx.isBlockConflicted() && !wtx.isMempoolConflicted()) {
822 mapTxSpends.insert(std::make_pair(outpoint, txid));
826 std::pair<TxSpends::iterator, TxSpends::iterator> range;
827 range = mapTxSpends.equal_range(outpoint);
837 for (
const CTxIn& txin : wtx.
tx->vin)
869 delete encrypted_batch;
870 encrypted_batch =
nullptr;
876 auto spk_man = spk_man_pair.second.get();
877 if (!spk_man->Encrypt(plain_master_key, encrypted_batch)) {
879 delete encrypted_batch;
880 encrypted_batch =
nullptr;
888 delete encrypted_batch;
889 encrypted_batch =
nullptr;
895 delete encrypted_batch;
896 encrypted_batch =
nullptr;
899 Unlock(strWalletPassphrase);
925 typedef std::multimap<int64_t, CWalletTx*>
TxItems;
928 for (
auto& entry : mapWallet)
935 std::vector<int64_t> nOrderPosOffsets;
936 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
943 nOrderPos = nOrderPosNext++;
944 nOrderPosOffsets.push_back(nOrderPos);
951 int64_t nOrderPosOff = 0;
952 for (
const int64_t& nOffsetStart : nOrderPosOffsets)
954 if (nOrderPos >= nOffsetStart)
957 nOrderPos += nOrderPosOff;
958 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
976 int64_t nRet = nOrderPosNext++;
989 for (
auto& [
_, wtx] : mapWallet)
998 auto mi = mapWallet.find(originalHash);
1001 assert(mi != mapWallet.end());
1015 bool success =
true;
1037 tx_destinations.insert(dst);
1064 Txid hash = tx->GetHash();
1068 std::set<CTxDestination> tx_destinations;
1070 for (
const CTxIn& txin : tx->vin) {
1079 auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(tx, state));
1081 bool fInsertedNew =
ret.second;
1082 bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
1096 if (state.index() != wtx.
m_state.index()) {
1108 if (tx->HasWitness() && !wtx.
tx->HasWitness()) {
1116 std::vector<CWalletTx*> txs{&wtx};
1120 while (!txs.empty()) {
1123 desc_tx->
m_state = inactive_state;
1128 for (
unsigned int i = 0; i < desc_tx->
tx->vout.size(); ++i) {
1130 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(outpoint);
1131 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
1132 const auto wit = mapWallet.find(it->second);
1133 if (wit != mapWallet.end()) {
1134 txs.push_back(&wit->second);
1142 std::string status{
"no-change"};
1143 if (fInsertedNew || fUpdated) {
1144 status = fInsertedNew ? (fUpdated ?
"new, update" :
"new") :
"update";
1149 if (fInsertedNew || fUpdated)
1166 if (!strCmd.empty())
1171 ReplaceAll(strCmd,
"%b", conf->confirmed_block_hash.GetHex());
1185 std::thread
t(runCommand, strCmd);
1195 const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(
nullptr,
TxStateInactive{}));
1197 if (!fill_wtx(wtx, ins.second)) {
1209 for (
const CTxIn& txin : wtx.
tx->vin) {
1211 if (it != mapWallet.end()) {
1233 if (
auto* conf = std::get_if<TxStateConfirmed>(&state)) {
1235 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.
prevout);
1236 while (range.first != range.second) {
1237 if (range.first->second != tx.
GetHash()) {
1238 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);
1239 MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
1246 bool fExisted = mapWallet.contains(tx.
GetHash());
1247 if (fExisted && !fUpdate)
return false;
1259 for (
auto &dest : spk_man->MarkUnusedAddresses(txout.
scriptPubKey)) {
1261 if (!dest.internal.has_value()) {
1266 if (!dest.internal.has_value())
continue;
1280 TxState tx_state = std::visit([](
auto&&
s) ->
TxState {
return s; }, state);
1285 throw std::runtime_error(
"DB error adding transaction to wallet, write failed");
1304 for (
long unsigned int i = 0; i < parent_wtx.tx->vout.size(); i++) {
1305 for (
auto range = mapTxSpends.equal_range(
COutPoint(parent_wtx.tx->GetHash(), i)); range.first != range.second; range.first++) {
1306 const Txid& sibling_txid = range.first->second;
1308 if (sibling_txid == child_txid)
continue;
1310 return add_conflict ? (wtx.
mempool_conflicts.insert(child_txid).second ? TxUpdate::CHANGED : TxUpdate::UNCHANGED)
1311 : (wtx.
mempool_conflicts.erase(child_txid) ? TxUpdate::CHANGED : TxUpdate::UNCHANGED);
1319 for (
const CTxIn& txin : tx->vin) {
1321 if (it != mapWallet.end()) {
1322 it->second.MarkDirty();
1330 auto it = mapWallet.find(hashTx);
1331 assert(it != mapWallet.end());
1344 assert(!wtx.isConfirmed());
1345 assert(!wtx.InMempool());
1347 if (!wtx.isBlockConflicted() && !wtx.isAbandoned()) {
1373 if (m_last_block_processed_height < 0 || conflicting_height < 0) {
1376 int conflictconfirms = (m_last_block_processed_height - conflicting_height + 1) * -1;
1377 if (conflictconfirms >= 0)
1401 std::set<Txid> todo;
1402 std::set<Txid> done;
1404 todo.insert(tx_hash);
1406 while (!todo.empty()) {
1410 auto it = mapWallet.find(now);
1411 assert(it != mapWallet.end());
1414 TxUpdate update_state = try_updating_state(wtx);
1417 if (batch) batch->
WriteTx(wtx);
1419 for (
unsigned int i = 0; i < wtx.
tx->vout.size(); ++i) {
1420 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(
COutPoint(now, i));
1421 for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
1422 if (!done.contains(iter->second)) {
1423 todo.insert(iter->second);
1455 auto it = mapWallet.find(tx->GetHash());
1456 if (it != mapWallet.end()) {
1460 const Txid& txid = tx->GetHash();
1462 for (
const CTxIn& tx_in : tx->vin) {
1464 for (
auto range = mapTxSpends.equal_range(tx_in.
prevout); range.first != range.second; range.first++) {
1465 const Txid& spent_id = range.first->second;
1467 if (spent_id == txid)
continue;
1479 for (
const CTxIn& tx_in : tx->vin) {
1480 auto parent_it = mapWallet.find(tx_in.
prevout.
hash);
1481 if (parent_it != mapWallet.end()) {
1482 CWalletTx& parent_wtx = parent_it->second;
1496 auto it = mapWallet.find(tx->GetHash());
1497 if (it != mapWallet.end()) {
1530 const Txid& txid = tx->GetHash();
1532 for (
const CTxIn& tx_in : tx->vin) {
1536 for (
auto range = mapTxSpends.equal_range(tx_in.
prevout); range.first != range.second; range.first++) {
1537 const Txid& spent_id = range.first->second;
1550 for (
const CTxIn& tx_in : tx->vin) {
1551 auto parent_it = mapWallet.find(tx_in.
prevout.
hash);
1552 if (parent_it != mapWallet.end()) {
1553 CWalletTx& parent_wtx = parent_it->second;
1580 bool wallet_updated =
false;
1581 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1587 if (wallet_updated || block.
height % 144 == 0) {
1601 int disconnect_height = block.
height;
1603 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1609 for (
const CTxIn& tx_in : ptx->vin) {
1611 if (!mapTxSpends.contains(tx_in.
prevout))
continue;
1613 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(tx_in.
prevout);
1616 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) {
1617 CWalletTx& wtx = mapWallet.find(_it->second)->second;
1621 auto try_updating_state = [&](
CWalletTx& tx) {
1644void CWallet::BlockUntilSyncedToCurrentChain()
const {
1661 return txo->GetTxOut().nValue;
1686 for (
const auto& spkm : it->second) {
1687 res = res || spkm->IsMine(
script);
1712 if (outpoint.
n >= wtx->tx->vout.size()) {
1715 return IsMine(wtx->tx->vout[outpoint.
n]);
1734 throw std::runtime_error(std::string(__func__) +
": value out of range");
1742 bool result =
false;
1744 if (!spk_man->IsHDEnabled())
return false;
1756 if (spk_man && spk_man->CanGetAddresses(internal)) {
1774 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1788 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1823 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1837 if (time < birthtime) {
1855 int start_height = 0;
1896 constexpr auto INTERVAL_TIME{60
s};
1897 auto current_time{reserver.
now()};
1898 auto start_time{reserver.
now()};
1902 uint256 block_hash = start_block;
1905 std::unique_ptr<FastWalletRescanFilter> fast_rescan_filter;
1909 fast_rescan_filter ?
"fast variant using block filters" :
"slow variant inspecting all blocks");
1918 double progress_current = progress_begin;
1919 int block_height = start_height;
1921 if (progress_end - progress_begin > 0.0) {
1922 m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin);
1926 if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
1930 bool next_interval = reserver.
now() >= current_time + INTERVAL_TIME;
1931 if (next_interval) {
1932 current_time = reserver.
now();
1933 WalletLogPrintf(
"Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
1936 bool fetch_block{
true};
1937 if (fast_rescan_filter) {
1938 fast_rescan_filter->UpdateIfNeeded();
1939 auto matches_block{fast_rescan_filter->MatchesBlock(block_hash)};
1940 if (matches_block.has_value()) {
1941 if (*matches_block) {
1946 fetch_block =
false;
1949 LogDebug(
BCLog::SCAN,
"Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.
ToString());
1955 bool block_still_active =
false;
1956 bool next_block =
false;
1966 if (save_progress && next_interval) found_block.
locator(loc);
1971 if (!block_still_active) {
1978 for (
size_t posInBlock = 0; posInBlock < block.
vtx.size(); ++posInBlock) {
1996 if (max_height && block_height >= *max_height) {
2015 block_hash = next_block_hash;
2020 const uint256 prev_tip_hash = tip_hash;
2022 if (!max_height && prev_tip_hash != tip_hash) {
2034 WalletLogPrintf(
"Rescan aborted at block %d. Progress=%f\n", block_height, progress_current);
2036 }
else if (block_height &&
chain().shutdownRequested()) {
2037 WalletLogPrintf(
"Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height, progress_current);
2040 WalletLogPrintf(
"Rescan completed in %15dms\n", Ticks<std::chrono::milliseconds>(reserver.
now() - start_time));
2046 std::string& err_string,
2061 const char* what{
""};
2062 switch (broadcast_method) {
2064 what =
"to mempool and for broadcast to peers";
2067 what =
"to mempool without broadcast";
2070 what =
"for private broadcast without adding to the mempool";
2094 result.erase(myHash);
2106 if (!
chain().isReadyToBroadcast())
return false;
2148 int submitted_tx_count = 0;
2155 std::set<CWalletTx*, WalletTxOrderComparator> to_submit;
2156 for (
auto& [txid, wtx] : mapWallet) {
2158 if (!wtx.isUnconfirmed())
continue;
2163 to_submit.insert(&wtx);
2166 for (
auto wtx : to_submit) {
2167 std::string unused_err_string;
2172 if (submitted_tx_count > 0) {
2173 WalletLogPrintf(
"%s: resubmit %u unconfirmed transactions\n", __func__, submitted_tx_count);
2181 for (
const std::shared_ptr<CWallet>& pwallet :
GetWallets(context)) {
2182 if (!pwallet->ShouldResend())
continue;
2184 pwallet->SetNextResend();
2194 std::map<COutPoint, Coin> coins;
2195 for (
auto& input : tx.
vin) {
2196 const auto mi = mapWallet.find(input.prevout.hash);
2197 if(mi == mapWallet.end() || input.prevout.n >= mi->second.tx->vout.size()) {
2202 coins[input.prevout] =
Coin(wtx.
tx->vout[input.prevout.n], prev_height, wtx.
IsCoinBase());
2204 std::map<int, bilingual_str> input_errors;
2214 if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) {
2238 const auto it = mapWallet.find(txhash);
2239 if (it != mapWallet.end()) {
2250 return PSBTError::INVALID_TX;
2256 int n_signed_this_spkm = 0;
2257 const auto error{spk_man->FillPSBT(psbtx, txdata, options, &n_signed_this_spkm)};
2263 (*n_signed) += n_signed_this_spkm;
2271 for (
size_t i = 0; i < psbtx.
inputs.size(); ++i) {
2283 if (spk_man_pair.second->CanProvide(script_pub_key, sigdata)) {
2285 return spk_man_pair.second->SignMessage(message, pkhash, str_sig);
2295 return *change_type;
2304 bool any_wpkh{
false};
2306 bool any_pkh{
false};
2308 for (
const auto& recipient : vecSend) {
2309 if (std::get_if<WitnessV1Taproot>(&recipient.dest)) {
2311 }
else if (std::get_if<WitnessV0KeyHash>(&recipient.dest)) {
2313 }
else if (std::get_if<ScriptHash>(&recipient.dest)) {
2315 }
else if (std::get_if<PKHash>(&recipient.dest)) {
2321 if (has_bech32m_spkman && any_tr) {
2326 if (has_bech32_spkman && any_wpkh) {
2331 if (has_p2sh_segwit_spkman && any_sh) {
2337 if (has_legacy_spkman && any_pkh) {
2342 if (has_bech32m_spkman) {
2345 if (has_bech32_spkman) {
2362 wtx.
mapValue = std::move(mapValue);
2369 throw std::runtime_error(std::string(__func__) +
": Wallet db error, transaction commit failed");
2373 for (
const CTxIn& txin : tx->vin) {
2384 std::string err_string;
2386 WalletLogPrintf(
"CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
2404 const auto wallet_file =
m_database->Filename();
2405 switch (nLoadWalletRet) {
2409 warnings.push_back(
strprintf(
_(
"Error reading %s! All keys read correctly, but transaction data"
2410 " or address metadata may be missing or incorrect."),
2414 warnings.push_back(
strprintf(
_(
"Error reading %s! Transaction data may be missing or incorrect."
2415 " Rescanning wallet."), wallet_file));
2418 error =
strprintf(
_(
"Error loading %s: Wallet corrupted"), wallet_file);
2421 error =
strprintf(
_(
"Error loading %s: Wallet requires newer version of %s"), wallet_file, CLIENT_NAME);
2424 error =
strprintf(
_(
"Error loading %s: External signer wallet being loaded without external signer support compiled"), wallet_file);
2427 error =
strprintf(
_(
"Unrecognized descriptor found. Loading wallet %s\n\n"
2428 "The wallet might have been created on a newer version.\n"
2429 "Please try running the latest software version.\n"), wallet_file);
2432 error =
strprintf(
_(
"Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
2433 "The wallet might have been tampered with or created with malicious intent.\n"), wallet_file);
2436 error =
strprintf(
_(
"Error loading %s: Wallet is a legacy wallet. Please migrate to a descriptor wallet using the migration tool (migratewallet RPC)."), wallet_file);
2439 error =
strprintf(
_(
"Error loading %s"), wallet_file);
2442 return nLoadWalletRet;
2452 return result.has_value();
2455 if (!was_txn_committed)
return util::Error{
_(
"Error starting/committing db txn for wallet transactions removal process")};
2465 std::vector<
decltype(mapWallet)::const_iterator> erased_txs;
2467 for (
const Txid& hash : txs_to_remove) {
2468 auto it_wtx = mapWallet.find(hash);
2469 if (it_wtx == mapWallet.end()) {
2475 erased_txs.emplace_back(it_wtx);
2481 for (
const auto& it : erased_txs) {
2482 const Txid hash{it->first};
2483 wtxOrdered.erase(it->second.m_it_wtxOrdered);
2484 for (
const auto& txin : it->second.tx->vin) {
2485 auto range = mapTxSpends.equal_range(txin.prevout);
2486 for (
auto iter = range.first; iter != range.second; ++iter) {
2487 if (iter->second == hash) {
2488 mapTxSpends.erase(iter);
2493 for (
unsigned int i = 0; i < it->second.tx->vout.size(); ++i) {
2496 mapWallet.erase(it);
2508 bool fUpdated =
false;
2510 std::optional<AddressPurpose> purpose;
2513 std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
2514 fUpdated = mi != m_address_book.end() && !mi->second.IsChange();
2516 CAddressBookData& record = mi != m_address_book.end() ? mi->second : m_address_book[address];
2518 is_mine =
IsMine(address);
2527 WalletLogPrintf(
"Error: fail to write address book 'purpose' entry\n");
2530 if (!batch.
WriteName(encoded_dest, strName)) {
2564 WalletLogPrintf(
"%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, CLIENT_BUGREPORT);
2586 m_address_book.erase(address);
2598 unsigned int count = 0;
2600 count += spk_man.second->GetKeyPoolSize();
2610 unsigned int count = 0;
2612 count += spk_man->GetKeyPoolSize();
2622 res &= spk_man->TopUp(kpSize);
2635 auto op_dest = spk_man->GetNewDestination(type);
2655 for (
auto& entry : mapWallet) {
2658 for (
unsigned int i = 0; i < wtx.
tx->vout.size(); i++) {
2671 for (
const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book) {
2672 const auto& entry = item.second;
2673 func(item.first, entry.GetLabel(), entry.IsChange(), entry.purpose);
2680 std::vector<CTxDestination> result;
2688 result.emplace_back(dest);
2696 std::set<std::string> label_set;
2698 bool _is_change,
const std::optional<AddressPurpose>& _purpose) {
2699 if (_is_change)
return;
2700 if (!purpose || purpose == _purpose) {
2701 label_set.insert(_label);
2717 if (!op_address)
return op_address;
2747 if (signer_spk_man ==
nullptr) {
2752 return signer_spk_man->DisplayAddress(dest, *
signer);
2754 return util::Error{
_(
"There is no ScriptPubKeyManager for this address")};
2760 m_locked_coins.emplace(coin, persistent);
2777 auto locked_coin_it = m_locked_coins.find(output);
2778 if (locked_coin_it != m_locked_coins.end()) {
2779 bool persisted = locked_coin_it->second;
2780 m_locked_coins.erase(locked_coin_it);
2792 bool success =
true;
2794 for (
const auto& [coin, persistent] : m_locked_coins) {
2797 m_locked_coins.clear();
2804 return m_locked_coins.contains(output);
2810 for (
const auto& [coin,
_] : m_locked_coins) {
2811 vOutpts.push_back(coin);
2840 std::optional<uint256> block_hash;
2842 block_hash = conf->confirmed_block_hash;
2844 block_hash = conf->conflicting_block_hash;
2850 int64_t block_max_time;
2851 if (
chain().findBlock(*block_hash,
FoundBlock().time(blocktime).maxTime(block_max_time))) {
2852 if (rescanning_old_block) {
2853 nTimeSmart = block_max_time;
2856 int64_t latestEntry = 0;
2859 int64_t latestTolerated = latestNow + 300;
2861 for (
auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
2871 if (nSmartTime <= latestTolerated) {
2872 latestEntry = nSmartTime;
2873 if (nSmartTime > latestNow) {
2874 latestNow = nSmartTime;
2880 nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
2891 if (std::get_if<CNoDestination>(&dest))
2905 m_address_book[dest].previously_spent =
true;
2910 m_address_book[dest].receive_requests[id] = request;
2921 std::vector<std::string>
values;
2922 for (
const auto& [dest, entry] : m_address_book) {
2923 for (
const auto& [
id, request] : entry.receive_requests) {
2924 values.emplace_back(request);
2933 m_address_book[dest].receive_requests[id] = value;
2940 m_address_book[dest].receive_requests.erase(
id);
2949 if (name_path != name_path.lexically_normal()) {
2955 return util::Error{
Untranslated(
"Wallet name given as a relative path cannot begin with ./ or ../, for wallets not in the walletdir, please use an absolute path.")};
2959 if (name_path.has_root_path() && name_path.root_path() == name_path) {
2970 fs::file_type path_type = fs::symlink_status(wallet_path).type();
2971 if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory ||
2972 (path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) ||
2973 (path_type == fs::file_type::regular && name_path.filename() == name_path))) {
2975 "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
2976 "database/log.?????????? files can be stored, a location where such a directory could be created, "
2977 "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
2991 return MakeDatabase(*wallet_path, options, status, error_string);
2999 if (!
args.
GetArg(
"-addresstype",
"").empty()) {
3005 wallet->m_default_address_type = parsed.value();
3008 if (!
args.
GetArg(
"-changetype",
"").empty()) {
3014 wallet->m_default_change_type = parsed.value();
3017 if (
const auto arg{
args.
GetArg(
"-mintxfee")}) {
3018 std::optional<CAmount> min_tx_fee =
ParseMoney(*arg);
3024 _(
"This is the minimum transaction fee you pay on every transaction."));
3030 if (
const auto arg{
args.
GetArg(
"-maxapsfee")}) {
3031 const std::string& max_aps_fee{*arg};
3032 if (max_aps_fee ==
"-1") {
3033 wallet->m_max_aps_fee = -1;
3034 }
else if (std::optional<CAmount> max_fee =
ParseMoney(max_aps_fee)) {
3037 _(
"This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
3039 wallet->m_max_aps_fee = max_fee.value();
3046 if (
const auto arg{
args.
GetArg(
"-fallbackfee")}) {
3047 std::optional<CAmount> fallback_fee =
ParseMoney(*arg);
3048 if (!fallback_fee) {
3049 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s'"),
"-fallbackfee", *arg);
3053 _(
"This is the transaction fee you may pay when fee estimates are not available."));
3059 wallet->m_allow_fallback_fee =
wallet->m_fallback_fee.GetFeePerK() != 0;
3061 if (
const auto arg{
args.
GetArg(
"-discardfee")}) {
3062 std::optional<CAmount> discard_fee =
ParseMoney(*arg);
3064 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s'"),
"-discardfee", *arg);
3068 _(
"This is the transaction fee you may discard if change is smaller than dust at this level"));
3073 if (
const auto arg{
args.
GetArg(
"-maxtxfee")}) {
3074 std::optional<CAmount> max_fee =
ParseMoney(*arg);
3079 warnings.push_back(
strprintf(
_(
"%s is set very high! Fees this large could be paid on a single transaction."),
"-maxtxfee"));
3083 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
3088 wallet->m_default_max_tx_fee = max_fee.value();
3091 if (
const auto arg{
args.
GetArg(
"-consolidatefeerate")}) {
3092 if (std::optional<CAmount> consolidate_feerate =
ParseMoney(*arg)) {
3102 _(
"The wallet will avoid paying less than the minimum relay fee."));
3119 const std::string& walletFile = database->Filename();
3121 const auto start{SteadyClock::now()};
3132 error =
strprintf(
_(
"Error creating %s: Could not write version metadata."), walletFile);
3136 LOCK(walletInstance->cs_wallet);
3146 walletInstance->SetupDescriptorScriptPubKeyMans();
3152 walletInstance->SetLastBlockProcessed(*tip_height,
chain->
getBlockHash(*tip_height));
3157 walletInstance->WalletLogPrintf(
"Wallet completed creation in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
3160 walletInstance->TopUpKeyPool();
3163 walletInstance->DisconnectChainNotifications();
3167 return walletInstance;
3173 const std::string& walletFile = database->Filename();
3175 const auto start{SteadyClock::now()};
3183 auto nLoadWalletRet = walletInstance->PopulateWalletFromDB(error, warnings);
3190 for (
auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
3191 if (spk_man->HavePrivateKeys()) {
3192 warnings.push_back(
strprintf(
_(
"Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
3198 walletInstance->WalletLogPrintf(
"Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
3201 walletInstance->TopUpKeyPool();
3204 walletInstance->DisconnectChainNotifications();
3208 WITH_LOCK(walletInstance->cs_wallet, walletInstance->LogStats());
3210 return walletInstance;
3216 LOCK(walletInstance->cs_wallet);
3218 assert(!walletInstance->m_chain || walletInstance->m_chain == &
chain);
3219 walletInstance->m_chain = &
chain;
3229 error =
Untranslated(
"Wallet files should not be reused across chains. Restart bitcoind with -walletcrosschain to override.");
3241 walletInstance->m_chain_notifications_handler = walletInstance->chain().handleNotifications(walletInstance);
3244 int rescan_height = 0;
3245 if (!rescan_required)
3251 rescan_height = *fork_height;
3258 walletInstance->SetLastBlockProcessedInMem(*tip_height,
chain.
getBlockHash(*tip_height));
3260 walletInstance->SetLastBlockProcessedInMem(-1,
uint256());
3263 if (tip_height && *tip_height != rescan_height)
3267 std::optional<int64_t> time_first_key = walletInstance->m_birth_time.load();
3268 if (time_first_key) {
3275 rescan_height = *tip_height;
3283 int block_height = *tip_height;
3284 while (block_height > 0 &&
chain.
haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
3288 if (rescan_height != block_height) {
3299 _(
"Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of a pruned node)") :
3301 "Error loading wallet. Wallet requires blocks to be downloaded, "
3302 "and software does not currently support loading wallets while "
3303 "blocks are being downloaded out of order when using assumeutxo "
3304 "snapshots. Wallet should be able to load successfully after "
3305 "node sync reaches height %s"), block_height);
3311 walletInstance->WalletLogPrintf(
"Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
3316 error =
_(
"Failed to acquire rescan reserver during wallet initialization");
3319 ScanResult scan_res = walletInstance->ScanForWalletTransactions(
chain.
getBlockHash(rescan_height), rescan_height, {}, reserver,
true,
true);
3321 error =
_(
"Failed to rescan the wallet during initialization");
3336 const auto& address_book_it = m_address_book.find(dest);
3337 if (address_book_it == m_address_book.end())
return nullptr;
3338 if ((!allow_change) && address_book_it->second.IsChange()) {
3341 return &address_book_it->second;
3364 assert(conf->confirmed_block_height >= 0);
3367 assert(conf->conflicting_block_height >= 0);
3382 assert(chain_depth >= 0);
3400 return vMasterKey.empty();
3410 if (!vMasterKey.empty()) {
3411 memory_cleanse(vMasterKey.data(), vMasterKey.size() *
sizeof(
decltype(vMasterKey)::value_type));
3425 if (!spk_man_pair.second->CheckDecryptionKey(vMasterKeyIn)) {
3429 vMasterKey = vMasterKeyIn;
3437 std::set<ScriptPubKeyMan*> spk_mans;
3438 for (
bool internal : {
false,
true}) {
3442 spk_mans.insert(spk_man);
3452 if (ext_spkm == &spkm)
return true;
3455 if (int_spkm == &spkm)
return true;
3462 std::set<ScriptPubKeyMan*> spk_mans;
3464 spk_mans.insert(spk_man_pair.second.get());
3472 std::map<OutputType, ScriptPubKeyMan*>::const_iterator it = spk_managers.find(type);
3473 if (it == spk_managers.end()) {
3481 std::set<ScriptPubKeyMan*> spk_mans;
3486 spk_mans.insert(it->second.begin(), it->second.end());
3489 Assume(std::all_of(spk_mans.begin(), spk_mans.end(), [&
script, &sigdata](
ScriptPubKeyMan* spkm) { return spkm->CanProvide(script, sigdata); }));
3515 return it->second.at(0)->GetSolvingProvider(
script);
3523 std::vector<WalletDescriptor> descs;
3526 LOCK(desc_spk_man->cs_desc_man);
3527 descs.push_back(desc_spk_man->GetWalletDescriptor());
3566 std::unique_ptr<ScriptPubKeyMan> spk_manager = std::make_unique<LegacyDataSPKM>(*
this);
3572 uint256 id = spk_manager->GetID();
3579 return cb(vMasterKey);
3590 if (spkm->HaveCryptedKeys())
return true;
3598 spk_man->NotifyCanGetAddressesChanged.connect([
this] {
3601 spk_man->NotifyFirstKeyTimeChanged.connect([
this](
const ScriptPubKeyMan*, int64_t time) {
3616 return *spk_manager;
3625 throw std::runtime_error(std::string(__func__) +
": Wallet is locked, cannot setup new descriptors");
3627 if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey, &batch)) {
3628 throw std::runtime_error(std::string(__func__) +
": Could not encrypt new descriptors");
3631 spk_manager->SetupDescriptorGeneration(batch, master_key, output_type, internal);
3633 uint256 id = spk_manager->GetID();
3642 for (
bool internal : {
false,
true}) {
3673 }))
throw std::runtime_error(
"Error: cannot process db transaction for descriptors setup");
3682 if (!signer_res.
isObject())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3685 if (!batch.
TxnBegin())
throw std::runtime_error(
"Error: cannot create db transaction for descriptors import");
3687 for (
bool internal : {
false,
true}) {
3688 const UniValue& descriptor_vals = signer_res.
find_value(internal ?
"internal" :
"receive");
3689 if (!descriptor_vals.
isArray())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3691 const std::string& desc_str = desc_val.getValStr();
3693 std::string desc_error;
3694 auto descs =
Parse(desc_str, keys, desc_error,
false);
3695 if (descs.empty()) {
3696 throw std::runtime_error(std::string(__func__) +
": Invalid descriptor \"" + desc_str +
"\" (" + desc_error +
")");
3698 auto& desc = descs.at(0);
3699 if (!desc->GetOutputType()) {
3704 spk_manager->SetupDescriptor(batch, std::move(desc));
3705 uint256 id = spk_manager->GetID();
3712 if (!batch.
TxnCommit())
throw std::runtime_error(
"Error: cannot commit db transaction for descriptors import");
3725 throw std::runtime_error(std::string(__func__) +
": writing active ScriptPubKeyMan id failed");
3740 spk_mans[type] = spk_man;
3742 const auto it = spk_mans_other.find(type);
3743 if (it != spk_mans_other.end() && it->second == spk_man) {
3744 spk_mans_other.erase(type);
3753 if (spk_man !=
nullptr && spk_man->GetID() ==
id) {
3757 throw std::runtime_error(std::string(__func__) +
": erasing active ScriptPubKeyMan id failed");
3761 spk_mans.erase(type);
3786 return std::nullopt;
3790 if (!desc_spk_man) {
3791 throw std::runtime_error(std::string(__func__) +
": unexpected ScriptPubKeyMan type.");
3794 LOCK(desc_spk_man->cs_desc_man);
3795 const auto& type = desc_spk_man->GetWalletDescriptor().descriptor->GetOutputType();
3796 assert(type.has_value());
3810 if (
auto spkm_res = spk_man->UpdateWalletDescriptor(desc); !spkm_res) {
3815 spk_man = new_spk_man.get();
3818 uint256 id = new_spk_man->GetID();
3823 for (
const auto& entry : signing_provider.
keys) {
3824 const CKey& key = entry.second;
3825 spk_man->AddDescriptorKey(key, key.
GetPubKey());
3829 if (!spk_man->TopUp()) {
3830 return util::Error{
_(
"Could not top up scriptPubKeys")};
3836 auto script_pub_keys = spk_man->GetScriptPubKeys();
3837 if (script_pub_keys.empty()) {
3838 return util::Error{
_(
"Could not generate scriptPubKeys (cache is empty)")};
3842 for (
const auto&
script : script_pub_keys) {
3852 spk_man->WriteDescriptor();
3857 return std::reference_wrapper(*spk_man);
3864 WalletLogPrintf(
"Migrating wallet storage database from BerkeleyDB to SQLite.\n");
3867 error =
_(
"Error: This wallet already uses SQLite");
3872 std::unique_ptr<DatabaseBatch> batch =
m_database->MakeBatch();
3873 std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor();
3874 std::vector<std::pair<SerializeData, SerializeData>> records;
3876 error =
_(
"Error: Unable to begin reading all records in the database");
3883 status = cursor->Next(ss_key, ss_value);
3889 records.emplace_back(key, value);
3894 error =
_(
"Error: Unable to read all records in the database");
3901 fs::remove(db_path);
3912 std::unique_ptr<WalletDatabase> new_db =
MakeDatabase(wallet_path, opts, db_status, error);
3919 bool began = batch->TxnBegin();
3921 for (
const auto& [key, value] : records) {
3922 if (!batch->Write(std::span{key}, std::span{value})) {
3929 bool committed = batch->TxnCommit();
3939 if (!
Assume(legacy_spkm)) {
3942 return std::nullopt;
3946 if (res == std::nullopt) {
3947 error =
_(
"Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
3948 return std::nullopt;
3958 if (!
Assume(legacy_spkm)) {
3964 bool has_spendable_material = !
data.desc_spkms.empty() ||
data.master_key.key.IsValid();
3967 std::set<CTxDestination> not_migrated_dests;
3976 if (!
data.watch_descs.empty())
Assume(!
data.watchonly_wallet->m_cached_spks.empty());
3977 if (!
data.solvable_descs.empty())
Assume(!
data.solvable_wallet->m_cached_spks.empty());
3979 for (
auto& desc_spkm :
data.desc_spkms) {
3981 return util::Error{
_(
"Error: Duplicate descriptors created during migration. Your wallet may be corrupted.")};
3983 uint256 id = desc_spkm->GetID();
3989 return util::Error{
_(
"Error: cannot remove legacy wallet records")};
4001 if (
data.master_key.key.IsValid()) {
4011 if (!local_wallet_batch.
ReadBestBlock(best_block_locator)) {
4012 return util::Error{
_(
"Error: Unable to read wallet's best block locator record")};
4021 std::vector<Txid> txids_to_delete;
4022 std::unique_ptr<WalletBatch> watchonly_batch;
4023 if (
data.watchonly_wallet) {
4024 watchonly_batch = std::make_unique<WalletBatch>(
data.watchonly_wallet->GetDatabase());
4025 if (!watchonly_batch->TxnBegin())
return util::Error{
strprintf(
_(
"Error: database transaction cannot be executed for wallet %s"),
data.watchonly_wallet->GetName())};
4027 LOCK(
data.watchonly_wallet->cs_wallet);
4028 data.watchonly_wallet->nOrderPosNext = nOrderPosNext;
4029 watchonly_batch->WriteOrderPosNext(
data.watchonly_wallet->nOrderPosNext);
4031 if (!watchonly_batch->WriteBestBlock(best_block_locator)) {
4032 return util::Error{
_(
"Error: Unable to write watchonly wallet best block locator record")};
4035 std::unique_ptr<WalletBatch> solvables_batch;
4036 if (
data.solvable_wallet) {
4037 solvables_batch = std::make_unique<WalletBatch>(
data.solvable_wallet->GetDatabase());
4038 if (!solvables_batch->TxnBegin())
return util::Error{
strprintf(
_(
"Error: database transaction cannot be executed for wallet %s"),
data.solvable_wallet->GetName())};
4040 if (!solvables_batch->WriteBestBlock(best_block_locator)) {
4041 return util::Error{
_(
"Error: Unable to write solvable wallet best block locator record")};
4048 if (
data.watchonly_wallet) {
4049 LOCK(
data.watchonly_wallet->cs_wallet);
4050 if (
data.watchonly_wallet->IsMine(*wtx->tx) ||
data.watchonly_wallet->IsFromMe(*wtx->tx)) {
4052 const Txid& hash = wtx->GetHash();
4055 if (!new_tx) return false;
4056 ins_wtx.SetTx(to_copy_wtx.tx);
4057 ins_wtx.CopyFrom(to_copy_wtx);
4060 return util::Error{
strprintf(
_(
"Error: Could not add watchonly tx %s to watchonly wallet"), wtx->GetHash().GetHex())};
4062 watchonly_batch->WriteTx(
data.watchonly_wallet->mapWallet.at(hash));
4065 txids_to_delete.push_back(hash);
4072 return util::Error{
strprintf(
_(
"Error: Transaction %s in wallet cannot be identified to belong to migrated wallets"), wtx->GetHash().GetHex())};
4075 local_wallet_batch.
WriteTx(*wtx);
4079 if (txids_to_delete.size() > 0) {
4080 if (
auto res =
RemoveTxs(local_wallet_batch, txids_to_delete); !res) {
4086 std::vector<std::pair<std::shared_ptr<CWallet>, std::unique_ptr<WalletBatch>>> wallets_vec;
4087 if (
data.watchonly_wallet) wallets_vec.emplace_back(
data.watchonly_wallet, std::move(watchonly_batch));
4088 if (
data.solvable_wallet) wallets_vec.emplace_back(
data.solvable_wallet, std::move(solvables_batch));
4094 if (entry.label) batch.
WriteName(address, *entry.label);
4095 for (
const auto& [
id, request] : entry.receive_requests) {
4102 std::vector<CTxDestination> dests_to_delete;
4103 for (
const auto& [dest, record] : m_address_book) {
4107 bool copied =
false;
4108 for (
auto& [
wallet, batch] : wallets_vec) {
4110 if (require_transfer && !
wallet->IsMine(dest))
continue;
4113 wallet->m_address_book[dest] = record;
4114 func_store_addr(*batch, dest, record);
4118 if (require_transfer) {
4119 dests_to_delete.push_back(dest);
4127 if (require_transfer && !copied) {
4130 if (not_migrated_dests.contains(dest)) {
4131 dests_to_delete.push_back(dest);
4135 return util::Error{
_(
"Error: Address book data in wallet cannot be identified to belong to migrated wallets")};
4140 for (
auto& [
wallet, batch] : wallets_vec) {
4147 if (dests_to_delete.size() > 0) {
4148 for (
const auto& dest : dests_to_delete) {
4150 return util::Error{
_(
"Error: Unable to remove watchonly address book data")};
4158 if (!has_spendable_material) {
4159 if (!m_address_book.empty())
return util::Error{
_(
"Error: Not all address book records were migrated")};
4160 if (!mapWallet.empty())
return util::Error{
_(
"Error: Not all transaction records were migrated")};
4177 return name.empty() ?
"default_wallet" :
name;
4185 std::optional<MigrationData>
data =
wallet.GetDescriptorsForLegacy(error);
4186 if (
data == std::nullopt)
return false;
4189 if (
data->watch_descs.size() > 0 ||
data->solvable_descs.size() > 0) {
4196 empty_context.
args = context.args;
4206 if (
data->watch_descs.size() > 0) {
4207 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the watched scripts\n");
4210 std::vector<bilingual_str> warnings;
4212 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4214 error =
strprintf(
_(
"Wallet file creation failed: %s"), error);
4219 if (!
data->watchonly_wallet) {
4220 error =
_(
"Error: Failed to create new watchonly wallet");
4223 res.watchonly_wallet =
data->watchonly_wallet;
4224 LOCK(
data->watchonly_wallet->cs_wallet);
4227 for (
const auto& [desc_str, creation_time] :
data->watch_descs) {
4230 std::string parse_err;
4231 std::vector<std::unique_ptr<Descriptor>> descs =
Parse(desc_str, keys, parse_err,
true);
4232 assert(descs.size() == 1);
4233 assert(!descs.at(0)->IsRange());
4237 if (
auto spkm_res =
data->watchonly_wallet->AddWalletDescriptor(w_desc, keys,
"",
false); !spkm_res) {
4245 if (
data->solvable_descs.size() > 0) {
4246 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the unwatched solvable scripts\n");
4249 std::vector<bilingual_str> warnings;
4251 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4253 error =
strprintf(
_(
"Wallet file creation failed: %s"), error);
4258 if (!
data->solvable_wallet) {
4259 error =
_(
"Error: Failed to create new watchonly wallet");
4262 res.solvables_wallet =
data->solvable_wallet;
4263 LOCK(
data->solvable_wallet->cs_wallet);
4266 for (
const auto& [desc_str, creation_time] :
data->solvable_descs) {
4269 std::string parse_err;
4270 std::vector<std::unique_ptr<Descriptor>> descs =
Parse(desc_str, keys, parse_err,
true);
4271 assert(descs.size() == 1);
4272 assert(!descs.at(0)->IsRange());
4276 if (
auto spkm_res =
data->solvable_wallet->AddWalletDescriptor(w_desc, keys,
"",
false); !spkm_res) {
4288 if (auto res_migration = wallet.ApplyMigrationData(batch, *data); !res_migration) {
4289 error = util::ErrorString(res_migration);
4292 wallet.WalletLogPrintf(
"Wallet migration complete.\n");
4299 std::vector<bilingual_str> warnings;
4305 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4316 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4328 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4334 std::shared_ptr<CWallet> local_wallet = CWallet::LoadExisting(empty_context, wallet_name, std::move(database), error, warnings);
4335 if (!local_wallet) {
4346 std::vector<bilingual_str> warnings;
4352 const std::string wallet_name = local_wallet->GetName();
4356 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4365 const std::string backup_prefix = wallet_name.empty() ?
MigrationPrefixName(*local_wallet) : [&] {
4374 return util::Error{
_(
"Error: Unable to make a backup of your wallet")};
4378 bool success =
false;
4381 if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
4382 if (passphrase.find(
'\0') == std::string::npos) {
4383 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
4385 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase entered was incorrect. "
4386 "The passphrase contains a null character (ie - a zero byte). "
4387 "If this passphrase was set with a version of this software prior to 25.0, "
4388 "please try again with only the characters up to — but not including — "
4389 "the first null character.")};
4399 bool empty_local_wallet =
false;
4402 LOCK(local_wallet->cs_wallet);
4404 if (!local_wallet->MigrateToSQLite(error))
return util::Error{error};
4408 success =
DoMigration(*local_wallet, context, error, res);
4410 empty_local_wallet = local_wallet->GetAllScriptPubKeyMans().empty();
4422 std::set<fs::path> wallet_files_to_remove;
4423 std::set<fs::path> wallet_empty_dirs_to_remove;
4428 const auto files =
wallet.GetDatabase().Files();
4429 wallet_files_to_remove.insert(files.begin(), files.end());
4430 if (
wallet.GetName() != wallet_name) {
4443 if (empty_local_wallet) {
4445 std::vector<fs::path> paths_to_remove = local_wallet->GetDatabase().Files();
4446 local_wallet.reset();
4447 for (
const auto& path_to_remove : paths_to_remove) fs::remove(path_to_remove);
4450 LogInfo(
"Loading new wallets after migration...\n");
4453 if (success && *wallet_ptr) {
4454 std::shared_ptr<CWallet>&
wallet = *wallet_ptr;
4456 track_for_cleanup(*
wallet);
4458 std::string wallet_name =
wallet->GetName();
4460 wallet =
LoadWallet(context, wallet_name, std::nullopt, options, status, error, warnings);
4462 LogError(
"Failed to load wallet '%s' after migration. Rolling back migration to preserve consistency. "
4463 "Error cause: %s\n", wallet_name, error.
original);
4479 std::vector<std::shared_ptr<CWallet>> created_wallets;
4480 if (local_wallet) created_wallets.push_back(std::move(local_wallet));
4485 for (std::shared_ptr<CWallet>&
wallet : created_wallets) {
4486 track_for_cleanup(*
wallet);
4490 for (std::shared_ptr<CWallet>& w : created_wallets) {
4491 if (w->HaveChain()) {
4494 error +=
_(
"\nUnable to cleanup failed migration");
4500 assert(w.use_count() == 1);
4506 for (
const fs::path& file : wallet_files_to_remove) {
4511 for (
const fs::path& dir : wallet_empty_dirs_to_remove) {
4512 Assume(fs::is_empty(dir));
4519 const auto& ptr_wallet =
RestoreWallet(context, backup_path, wallet_name, std::nullopt, status, restore_error, warnings,
false,
true);
4520 if (!restore_error.
empty()) {
4521 error += restore_error +
_(
"\nUnable to restore backup of wallet.");
4534 for (
const auto&
script : spks) {
4535 m_cached_spks[
script].push_back(spkm);
4542 CacheNewScriptPubKeys(spks, spkm);
4545std::set<CExtPubKey> CWallet::GetActiveHDPubKeys()
const
4551 std::set<CExtPubKey> active_xpubs;
4552 for (
const auto& spkm : GetActiveScriptPubKeyMans()) {
4558 std::set<CPubKey> desc_pubkeys;
4559 std::set<CExtPubKey> desc_xpubs;
4560 w_desc.
descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
4561 active_xpubs.merge(std::move(desc_xpubs));
4563 return active_xpubs;
4566std::optional<CKey> CWallet::GetKey(
const CKeyID& keyid)
const
4570 for (
const auto& spkm : GetAllScriptPubKeyMans()) {
4574 if (std::optional<CKey> key = desc_spkm->
GetKey(keyid)) {
4578 return std::nullopt;
4581void CWallet::WriteBestBlock()
const
4585 if (!m_last_block_processed.IsNull()) {
4587 chain().findBlock(m_last_block_processed,
FoundBlock().locator(loc));
4599 for (uint32_t i = 0; i < wtx.
tx->vout.size(); ++i) {
4600 const CTxOut& txout = wtx.
tx->vout.at(i);
4601 if (!IsMine(txout))
continue;
4603 if (m_txos.contains(outpoint)) {
4605 m_txos.emplace(outpoint,
WalletTXO{wtx, txout});
4610void CWallet::RefreshAllTXOs()
4613 for (
const auto& [
_, wtx] : mapWallet) {
4614 RefreshTXOsFromTx(wtx);
4618std::optional<WalletTXO> CWallet::GetTXO(
const COutPoint& outpoint)
const
4621 const auto& it = m_txos.find(outpoint);
4622 if (it == m_txos.end()) {
4623 return std::nullopt;
4628void CWallet::DisconnectChainNotifications()
4630 if (m_chain_notifications_handler) {
4631 m_chain_notifications_handler->disconnect();
4632 chain().waitForNotifications();
4633 m_chain_notifications_handler.reset();
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.
std::string GetArg(const std::string &strArg, const std::string &strDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return string argument or default value.
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
bool GetBoolArg(const std::string &strArg, bool fDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return boolean argument or default value.
std::vector< CTransactionRef > vtx
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
std::string ToString(FeeRateFormat fee_rate_format=FeeRateFormat::BTC_KVB) const
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.
A version of CTransaction with the PSBT format.
std::vector< PSBTInput > inputs
Tp rand_uniform_delay(const Tp &time, typename Tp::duration range) noexcept
Return the time point advanced by a uniform random duration.
void push_back(UniValue val)
const UniValue & find_value(std::string_view key) const
const std::vector< UniValue > & getValues() const
const UniValue & get_array() const
std::string ToString() const
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 snapshot 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 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 bool broadcastTransaction(const CTransactionRef &tx, const CAmount &max_tx_fee, node::TxBroadcast broadcast_method, std::string &err_string)=0
Process a local transaction, optionally adding it to the mempool and optionally broadcasting it to th...
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, unsigned int rounds, unsigned int derivation_method)
bool Encrypt(const CKeyingMaterial &vchPlaintext, std::vector< unsigned char > &vchCiphertext) const
Private key encryption is done based on a CMasterKey, which holds a salt and random encryption key.
std::vector< unsigned char > vchSalt
unsigned int nDerivationMethod
0 = EVP_sha512()
std::vector< unsigned char > vchCryptedKey
unsigned int nDeriveIterations
static constexpr unsigned int DEFAULT_DERIVE_ITERATIONS
Default/minimum number of key derivation rounds.
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
void MarkDestinationsDirty(const std::set< CTxDestination > &destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Marks all outputs in each one of the destinations dirty, so their cache is reset and does not return ...
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::optional< AddressPurpose > &purpose)
std::atomic< bool > fAbortRescan
bool TopUpKeyPool(unsigned int kpSize=0)
bool HaveChain() const
Interface to assert chain access.
bool GetBroadcastTransactions() const
Inquire whether this wallet broadcasts transactions.
DBErrors PopulateWalletFromDB(bilingual_str &error, std::vector< bilingual_str > &warnings)
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
static bool AttachChain(const std::shared_ptr< CWallet > &wallet, interfaces::Chain &chain, bool rescan_required, bilingual_str &error, std::vector< bilingual_str > &warnings)
Catch wallet up to current chain, scanning new blocks, updating the best block locator and m_last_blo...
OutputType m_default_address_type
static std::shared_ptr< CWallet > LoadExisting(WalletContext &context, const std::string &name, std::unique_ptr< WalletDatabase > database, bilingual_str &error, std::vector< bilingual_str > &warnings)
void AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
Adds the active ScriptPubKeyMan for the specified type and internal.
btcsignals::signal< void(const CTxDestination &address, const std::string &label, bool isMine, AddressPurpose purpose, ChangeType status)> NotifyAddressBookChanged
Address book entry changed.
void LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
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...
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::optional< common::PSBTError > FillPSBT(PartiallySignedTransaction &psbtx, const common::PSBTFillOptions &options, bool &complete, size_t *n_signed=nullptr) const
Fills out a PSBT with information from the wallet.
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.
btcsignals::signal< void(CWallet *wallet)> NotifyStatusChanged
Wallet status (encrypted, locked) changed.
btcsignals::signal< void()> NotifyCanGetAddressesChanged
Keypool has new keys.
std::map< OutputType, ScriptPubKeyMan * > m_external_spk_managers
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.
RecursiveMutex m_relock_mutex
btcsignals::signal< void(const Txid &hashTx, ChangeType status)> NotifyTransactionChanged
Wallet transaction added, removed or updated.
std::string m_notify_tx_changed_script
Notify external script when a wallet transaction comes in or is updated (handled by -walletnotify)
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
bool CanGrindR() const
Whether the (external) signer performs R-value signature grinding.
util::Result< CTxDestination > GetNewChangeDestination(OutputType type)
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
btcsignals::signal< void(const std::string &title, int nProgress)> ShowProgress
Show progress e.g.
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.
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)
bool IsLocked() const override
OutputType TransactionChangeType(const std::optional< OutputType > &change_type, const std::vector< CRecipient > &vecSend) const
std::set< ScriptPubKeyMan * > GetAllScriptPubKeyMans() const
Returns all unique ScriptPubKeyMans.
void RefreshTXOsFromTx(const CWalletTx &wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Cache outputs that belong to the wallet from a single transaction.
unsigned int ComputeTimeSmart(const CWalletTx &wtx, bool rescanning_old_block) const
Compute smart timestamp for a transaction being added to the wallet.
std::set< std::string > ListAddrBookLabels(std::optional< AddressPurpose > purpose) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Retrieve all the known labels in the address book.
void ListLockedCoins(std::vector< COutPoint > &vOutpts) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
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 > GetNewDestination(OutputType type, const std::string &label)
ScriptPubKeyMan * GetScriptPubKeyMan(const OutputType &type, bool internal) const
Get the ScriptPubKeyMan for the given OutputType and internal/external chain.
bool IsAddressPreviouslySpent(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool WithEncryptionKey(std::function< bool(const CKeyingMaterial &)> cb) const override
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.
static std::shared_ptr< CWallet > CreateNew(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 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.
std::multimap< int64_t, CWalletTx * > TxItems
void SetupOwnDescriptorScriptPubKeyMans(WalletBatch &batch) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Create new seed and default DescriptorScriptPubKeyMans for this wallet.
void SetupDescriptorScriptPubKeyMans() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
DescriptorScriptPubKeyMan & SetupDescriptorScriptPubKeyMan(WalletBatch &batch, const CExtKey &master_key, const OutputType &output_type, bool internal) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Create new DescriptorScriptPubKeyMan and add it to the wallet.
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.
static bool LoadWalletArgs(std::shared_ptr< CWallet > wallet, const WalletContext &context, bilingual_str &error, std::vector< bilingual_str > &warnings)
std::set< ScriptPubKeyMan * > GetScriptPubKeyMans(const CScript &script) const
Get all the ScriptPubKeyMans for a script.
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 WriteWalletFlags(uint64_t flags)
bool TxnBegin()
Begin a new transaction.
bool WriteAddressPreviouslySpent(const CTxDestination &dest, bool previously_spent)
bool EraseAddressReceiveRequest(const CTxDestination &dest, const std::string &id)
bool TxnCommit()
Commit current transaction.
bool WriteName(const std::string &strAddress, const std::string &strName)
bool WritePurpose(const std::string &strAddress, const std::string &purpose)
bool EraseAddressData(const CTxDestination &dest)
bool WriteOrderPosNext(int64_t nOrderPosNext)
bool 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 WriteVersion(int client_version)
Write the given client_version.
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, ParamFormat format=ParamFormat::JSON)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
static const int CLIENT_VERSION
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(std::string_view 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 MaybeUpdateBirthTime(int64_t time)
Updates wallet birth time if 'time' is below it.
void blockDisconnected(const interfaces::BlockInfo &block) override
ScanResult ScanForWalletTransactions(const uint256 &start_block, int start_height, std::optional< int > max_height, const WalletRescanReserver &reserver, bool fUpdate, bool save_progress)
Scan the block chain (starting in start_block) for transactions from or to us.
std::set< Txid > GetConflicts(const Txid &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get wallet transactions that conflict with given transaction (spend same outputs)
bool IsWalletFlagSet(uint64_t flag) const override
check if a certain wallet flag is set
SpendType HowSpent(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
static bool DecryptMasterKey(const SecureString &wallet_passphrase, const CMasterKey &master_key, CKeyingMaterial &plain_master_key)
void AddToSpends(const COutPoint &outpoint, const Txid &txid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void SetLastBlockProcessedInMem(int block_height, uint256 block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UnsetWalletFlagWithDB(WalletBatch &batch, uint64_t flag)
Unsets a wallet flag and saves it to disk.
bool IsSpent(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Outpoint is spent if any non-conflicted transaction spends it:
void ResubmitWalletTransactions(node::TxBroadcast broadcast_method, bool force)
std::set< Txid > GetTxConflicts(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UnsetBlankWalletFlag(WalletBatch &batch) override
Unset the blank wallet flag and saves it to disk.
CWalletTx * AddToWallet(CTransactionRef tx, const TxState &state, const UpdateWalletTxFn &update_wtx=nullptr, bool rescanning_old_block=false)
Add the transaction to the wallet, wrapping it up inside a CWalletTx.
bool MarkReplaced(const Txid &originalHash, const Txid &newHash)
Mark a transaction as replaced by another transaction.
bool CanGetAddresses(bool internal=false) const
void UpdateTrucSiblingConflicts(const CWalletTx &parent_wtx, const Txid &child_txid, bool add_conflict) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Update mempool conflicts for TRUC sibling transactions.
bool LoadWalletFlags(uint64_t flags)
Loads the flags into the wallet.
bool SubmitTxMemoryPoolAndRelay(CWalletTx &wtx, std::string &err_string, node::TxBroadcast broadcast_method) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Pass this transaction to node for optional mempool insertion and relay to peers.
void blockConnected(const kernel::ChainstateRole &role, const interfaces::BlockInfo &block) override
void transactionRemovedFromMempool(const CTransactionRef &tx, MemPoolRemovalReason reason) override
static NodeClock::time_point GetDefaultNextResend()
bool ShouldResend() const
Return true if all conditions for periodically resending transactions are met.
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.
@ SIGHASH_DEFAULT
Taproot only; implied when sighash byte is missing, and equivalent to SIGHASH_ALL.
is a home for simple enum and struct type definitions that can be used internally by functions in the...
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.
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.
TxBroadcast
How to broadcast a local transaction.
@ MEMPOOL_AND_BROADCAST_TO_ALL
Add the transaction to the mempool and broadcast to all peers for which tx relay is enabled.
@ MEMPOOL_NO_BROADCAST
Add the transaction to the mempool, but don't broadcast to anybody.
@ NO_MEMPOOL_PRIVATE_BROADCAST
Omit the mempool and directly send the transaction via a few dedicated connections to peers on privac...
bilingual_str ErrorString(const Result< T > &result)
std::string_view RemoveSuffixView(std::string_view str, 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
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::shared_ptr< CWallet > RestoreWallet(WalletContext &context, const fs::path &backup_file, const std::string &wallet_name, std::optional< bool > load_on_start, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings, bool load_after_restore, bool allow_unnamed)
std::string PurposeToString(AddressPurpose p)
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 std::string MigrationPrefixName(CWallet &wallet)
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.
util::Result< fs::path > GetWalletPath(const std::string &name)
Determine the path that the wallet is stored in.
@ 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(std::string_view 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.
std::optional< PrecomputedTransactionData > PrecomputePSBTData(const PartiallySignedTransaction &psbt)
Compute a PrecomputedTransactionData object from a psbt.
bool PSBTInputSigned(const PSBTInput &input)
Checks whether a PSBTInput is already signed by checking for non-null finalized fields.
void GetStrongRandBytes(std::span< unsigned char > bytes) noexcept
Gather entropy from various sources, feed it into the internal PRNG, and generate random data using i...
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
Instructions for how a PSBT should be signed or filled with information.
Block data sent with blockConnected, blockDisconnected notifications.
const uint256 * prev_hash
unsigned int chain_time_max
Information about chainstate that notifications are sent from.
bool historical
Whether this is a historical chainstate downloading old blocks to validate an assumeutxo snapshot,...
std::optional< AddressPurpose > purpose
Address purpose which was originally recorded for payment protocol support but now serves as a cached...
void SetLabel(std::string name)
std::optional< std::string > m_op_label
std::optional< int > last_scanned_height
uint256 last_scanned_block
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.
enum wallet::CWallet::ScanResult::@18 status
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.