8#include <bitcoin-build-config.h>
11#include <blockfilter.h>
77#include <condition_variable>
102 if (!setting_value.isArray()) setting_value.setArray();
103 for (
const auto& value : setting_value.getValues()) {
106 setting_value.push_back(wallet_name);
115 if (!setting_value.isArray()) {
116 if (wallet_name.empty() && setting_value.isNull()) {
118 setting_value.setArray();
124 for (
const auto& value : setting_value.getValues()) {
125 if (!value.isStr() || value.get_str() != wallet_name) new_value.
push_back(value);
128 setting_value = std::move(new_value);
135 const std::string& wallet_name,
136 std::optional<bool> load_on_startup,
137 std::vector<bilingual_str>& warnings)
139 if (!load_on_startup)
return;
141 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
143 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));
165 std::vector<std::shared_ptr<CWallet>>::const_iterator i = std::find(context.wallets.begin(), context.wallets.end(),
wallet);
166 if (i != context.wallets.end())
return false;
167 context.wallets.push_back(
wallet);
168 wallet->ConnectScriptPubKeyManNotifiers();
169 wallet->NotifyCanGetAddressesChanged();
182 wallet->DisconnectChainNotifications();
185 std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(context.wallets.begin(), context.wallets.end(),
wallet);
186 if (i == context.wallets.end())
return false;
187 context.wallets.erase(i);
200 std::vector<bilingual_str> warnings;
207 return context.wallets;
213 count = context.wallets.size();
214 return count == 1 ? context.wallets[0] :
nullptr;
220 for (
const std::shared_ptr<CWallet>&
wallet : context.wallets) {
229 auto it = context.wallet_load_fns.emplace(context.wallet_load_fns.end(), std::move(load_wallet));
236 for (
auto& load_wallet : context.wallet_load_fns) {
251 wallet->WalletLogPrintf(
"Releasing wallet %s..\n",
name);
256 if (g_unloading_wallet_set.erase(
name) == 0) {
270 g_unloading_wallet_set.insert(
name);
279 while (g_unloading_wallet_set.contains(
name)) {
286std::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)
295 context.chain->initMessage(
_(
"Loading wallet…"));
305 wallet->postInitProcess();
311 }
catch (
const std::runtime_error& e) {
318class FastWalletRescanFilter
324 for (
auto spkm :
m_wallet.GetAllScriptPubKeyMans()) {
325 auto desc_spkm{
dynamic_cast<DescriptorScriptPubKeyMan*
>(spkm)};
326 assert(desc_spkm !=
nullptr);
327 AddScriptPubKeys(desc_spkm);
329 if (desc_spkm->IsHDEnabled()) {
335 void UpdateIfNeeded()
339 auto desc_spkm{
dynamic_cast<DescriptorScriptPubKeyMan*
>(
m_wallet.GetScriptPubKeyMan(desc_spkm_id))};
340 assert(desc_spkm !=
nullptr);
341 int32_t current_range_end{desc_spkm->GetEndRange()};
342 if (current_range_end > last_range_end) {
343 AddScriptPubKeys(desc_spkm, last_range_end);
349 std::optional<bool> MatchesBlock(
const uint256& block_hash)
const
365 void AddScriptPubKeys(
const DescriptorScriptPubKeyMan* desc_spkm, int32_t last_range_end = 0)
367 for (
const auto& script_pub_key : desc_spkm->GetScriptPubKeys(last_range_end)) {
368 m_filter_set.emplace(script_pub_key.begin(), script_pub_key.end());
377 if (!result.second) {
382 auto wallet = LoadWalletInternal(context,
name, load_on_start, options, status, error, warnings);
398 bool born_encrypted = !passphrase.empty();
407 error =
Untranslated(
"Private keys must be disabled when using an external signer");
414 error =
Untranslated(
"Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.");
429 std::shared_ptr<CWallet>
wallet =
CWallet::CreateNew(context,
name, std::move(database), wallet_creation_flags, born_encrypted, error, warnings);
437 if (born_encrypted) {
438 if (!
wallet->EncryptWallet(passphrase)) {
439 error =
Untranslated(
"Error: Wallet created but failed to encrypt.");
448 wallet->postInitProcess();
459std::shared_ptr<CWallet>
RestoreWallet(
WalletContext& context,
const fs::path& backup_file,
const std::string& wallet_name, std::optional<bool> load_on_start,
DatabaseStatus& status,
bilingual_str& error, std::vector<bilingual_str>& warnings,
bool load_after_restore,
bool allow_unnamed)
463 if (!allow_unnamed && wallet_name.empty()) {
474 auto wallet_file = wallet_path /
"wallet.dat";
475 std::shared_ptr<CWallet>
wallet;
476 bool wallet_file_copied =
false;
477 bool created_parent_dir =
false;
490 if (!fs::is_directory(wallet_path)) {
509 created_parent_dir =
true;
512 fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
513 wallet_file_copied =
true;
515 if (load_after_restore) {
516 wallet =
LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
518 }
catch (
const std::exception& e) {
525 if (load_after_restore && !
wallet) {
526 if (wallet_file_copied) fs::remove(wallet_file);
529 if (created_parent_dir) {
530 Assume(fs::is_empty(wallet_path));
531 fs::remove(wallet_path);
546 const auto it = mapWallet.find(hash);
547 if (it == mapWallet.end())
549 return &(it->second);
574 for (
int i = 0; i < 2; i++){
576 const bool key_set{crypter.
SetKeyFromPassphrase(wallet_passphrase, updated_master_key.vchSalt, updated_master_key.nDeriveIterations, updated_master_key.nDerivationMethod)};
582 if (elapsed_time <= 0
s) {
589 const double target_iterations{updated_master_key.nDeriveIterations * target_time / elapsed_time};
590 if (target_iterations < 1 || target_iterations > std::numeric_limits<unsigned int>::max()) {
595 updated_master_key.nDeriveIterations = (uint64_t{updated_master_key.nDeriveIterations} * i +
static_cast<unsigned int>(target_iterations)) / (i + 1);
602 if (!crypter.
SetKeyFromPassphrase(wallet_passphrase, updated_master_key.vchSalt, updated_master_key.nDeriveIterations, updated_master_key.nDerivationMethod)) {
605 if (!crypter.
Encrypt(plain_master_key, updated_master_key.vchCryptedKey)) {
609 master_key = std::move(updated_master_key);
637 if (
Unlock(plain_master_key)) {
658 if (!
DecryptMasterKey(strOldWalletPassphrase, master_key, plain_master_key)) {
661 if (
Unlock(plain_master_key))
663 if (!
EncryptMasterKey(strNewWalletPassphrase, plain_master_key, master_key)) {
666 WalletLogPrintf(
"Wallet passphrase changed to an nDeriveIterations of %i\n", master_key.nDeriveIterations);
683 m_last_block_processed = block_hash;
684 m_last_block_processed_height = block_height;
697 std::set<Txid> result;
700 const auto it = mapWallet.find(txid);
701 if (it == mapWallet.end())
705 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
709 if (mapTxSpends.count(txin.prevout) <= 1)
711 range = mapTxSpends.equal_range(txin.prevout);
712 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
713 result.insert(_it->second);
721 const Txid& txid = tx->GetHash();
722 for (
unsigned int i = 0; i < tx->vout.size(); ++i) {
741 int nMinOrderPos = std::numeric_limits<int>::max();
743 for (TxSpends::iterator it = range.first; it != range.second; ++it) {
744 const CWalletTx* wtx = &mapWallet.at(it->second);
756 for (TxSpends::iterator it = range.first; it != range.second; ++it)
758 const Txid& hash = it->second;
760 if (copyFrom == copyTo)
continue;
761 assert(copyFrom &&
"Oldest wallet transaction in range assumed to have been found.");
784 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
785 range = mapTxSpends.equal_range(outpoint);
787 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
788 const Txid& txid = it->second;
789 const auto mit = mapWallet.find(txid);
790 if (mit != mapWallet.end()) {
791 const auto& wtx = mit->second;
792 if (!wtx.isAbandoned() && !wtx.isBlockConflicted() && !wtx.isMempoolConflicted())
803 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
804 range = mapTxSpends.equal_range(outpoint);
806 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
807 const Txid& txid = it->second;
808 const auto mit = mapWallet.find(txid);
809 if (mit != mapWallet.end()) {
810 const auto& wtx = mit->second;
812 if (wtx.InMempool()) {
814 }
else if (!wtx.isAbandoned() && !wtx.isBlockConflicted() && !wtx.isMempoolConflicted()) {
824 mapTxSpends.insert(std::make_pair(outpoint, txid));
828 std::pair<TxSpends::iterator, TxSpends::iterator> range;
829 range = mapTxSpends.equal_range(outpoint);
871 delete encrypted_batch;
872 encrypted_batch =
nullptr;
878 auto spk_man = spk_man_pair.second.get();
879 if (!spk_man->Encrypt(plain_master_key, encrypted_batch)) {
881 delete encrypted_batch;
882 encrypted_batch =
nullptr;
890 delete encrypted_batch;
891 encrypted_batch =
nullptr;
897 delete encrypted_batch;
898 encrypted_batch =
nullptr;
901 if (!
Unlock(strWalletPassphrase)) {
927 typedef std::multimap<int64_t, CWalletTx*>
TxItems;
930 for (
auto& entry : mapWallet)
937 std::vector<int64_t> nOrderPosOffsets;
938 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
945 nOrderPos = nOrderPosNext++;
946 nOrderPosOffsets.push_back(nOrderPos);
953 int64_t nOrderPosOff = 0;
954 for (
const int64_t& nOffsetStart : nOrderPosOffsets)
956 if (nOrderPos >= nOffsetStart)
959 nOrderPos += nOrderPosOff;
960 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
978 int64_t nRet = nOrderPosNext++;
991 for (
auto& [
_, wtx] : mapWallet)
1000 auto mi = mapWallet.find(originalHash);
1003 assert(mi != mapWallet.end());
1017 bool success =
true;
1039 tx_destinations.insert(dst);
1066 Txid hash = tx->GetHash();
1070 std::set<CTxDestination> tx_destinations;
1072 for (
const CTxIn& txin : tx->vin) {
1081 auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(tx, state));
1083 bool fInsertedNew =
ret.second;
1084 bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
1098 fUpdated |= wtx.
Update(tx, state);
1103 std::vector<CWalletTx*> txs{&wtx};
1107 while (!txs.empty()) {
1110 desc_tx->
m_state = inactive_state;
1115 for (
unsigned int i = 0; i < desc_tx->
GetTx()->vout.size(); ++i) {
1117 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(outpoint);
1118 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
1119 const auto wit = mapWallet.find(it->second);
1120 if (wit != mapWallet.end()) {
1121 txs.push_back(&wit->second);
1129 std::string status{
"no-change"};
1130 if (fInsertedNew || fUpdated) {
1131 status = fInsertedNew ? (fUpdated ?
"new, update" :
"new") :
"update";
1136 if (fInsertedNew || fUpdated)
1153 if (!strCmd.empty())
1158 ReplaceAll(strCmd,
"%b", conf->confirmed_block_hash.GetHex());
1182 const auto& ins = mapWallet.emplace(wtx_in.GetHash(), std::move(wtx_in));
1195 auto it = mapWallet.find(txin.prevout.hash);
1196 if (it != mapWallet.end()) {
1218 if (
auto* conf = std::get_if<TxStateConfirmed>(&state)) {
1220 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.
prevout);
1221 while (range.first != range.second) {
1222 if (range.first->second != tx.
GetHash()) {
1223 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);
1224 MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
1231 bool fExisted = mapWallet.contains(tx.
GetHash());
1243 for (
auto &dest : spk_man->MarkUnusedAddresses(txout.
scriptPubKey)) {
1245 if (!dest.internal.has_value()) {
1250 if (!dest.internal.has_value())
continue;
1264 TxState tx_state = std::visit([](
auto&&
s) ->
TxState {
return s; }, state);
1269 throw std::runtime_error(
"DB error adding transaction to wallet, write failed");
1288 for (
long unsigned int i = 0; i < parent_wtx.GetTx()->vout.size(); i++) {
1289 for (
auto range = mapTxSpends.equal_range(
COutPoint(parent_wtx.GetTx()->GetHash(), i)); range.first != range.second; range.first++) {
1290 const Txid& sibling_txid = range.first->second;
1292 if (sibling_txid == child_txid)
continue;
1294 return add_conflict ? (wtx.
mempool_conflicts.insert(child_txid).second ? TxUpdate::CHANGED : TxUpdate::UNCHANGED)
1295 : (wtx.
mempool_conflicts.erase(child_txid) ? TxUpdate::CHANGED : TxUpdate::UNCHANGED);
1303 for (
const CTxIn& txin : tx->vin) {
1305 if (it != mapWallet.end()) {
1306 it->second.MarkDirty();
1314 auto it = mapWallet.find(hashTx);
1315 assert(it != mapWallet.end());
1328 assert(!wtx.isConfirmed());
1329 assert(!wtx.InMempool());
1331 if (!wtx.isBlockConflicted() && !wtx.isAbandoned()) {
1357 if (m_last_block_processed_height < 0 || conflicting_height < 0) {
1360 int conflictconfirms = (m_last_block_processed_height - conflicting_height + 1) * -1;
1361 if (conflictconfirms >= 0)
1385 std::set<Txid> todo;
1386 std::set<Txid> done;
1388 todo.insert(tx_hash);
1390 while (!todo.empty()) {
1394 auto it = mapWallet.find(now);
1395 assert(it != mapWallet.end());
1398 TxUpdate update_state = try_updating_state(wtx);
1401 if (batch) batch->
WriteTx(wtx);
1403 for (
unsigned int i = 0; i < wtx.
GetTx()->vout.size(); ++i) {
1404 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(
COutPoint(now, i));
1405 for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
1406 if (!done.contains(iter->second)) {
1407 todo.insert(iter->second);
1439 auto it = mapWallet.find(tx->GetHash());
1440 if (it != mapWallet.end()) {
1444 const Txid& txid = tx->GetHash();
1446 for (
const CTxIn& tx_in : tx->vin) {
1448 for (
auto range = mapTxSpends.equal_range(tx_in.
prevout); range.first != range.second; range.first++) {
1449 const Txid& spent_id = range.first->second;
1451 if (spent_id == txid)
continue;
1463 for (
const CTxIn& tx_in : tx->vin) {
1464 auto parent_it = mapWallet.find(tx_in.
prevout.
hash);
1465 if (parent_it != mapWallet.end()) {
1466 CWalletTx& parent_wtx = parent_it->second;
1480 auto it = mapWallet.find(tx->GetHash());
1481 if (it != mapWallet.end()) {
1514 const Txid& txid = tx->GetHash();
1516 for (
const CTxIn& tx_in : tx->vin) {
1520 for (
auto range = mapTxSpends.equal_range(tx_in.
prevout); range.first != range.second; range.first++) {
1521 const Txid& spent_id = range.first->second;
1534 for (
const CTxIn& tx_in : tx->vin) {
1535 auto parent_it = mapWallet.find(tx_in.
prevout.
hash);
1536 if (parent_it != mapWallet.end()) {
1537 CWalletTx& parent_wtx = parent_it->second;
1564 bool wallet_updated =
false;
1565 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1571 if (wallet_updated || block.
height % 144 == 0) {
1585 int disconnect_height = block.
height;
1587 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1593 for (
const CTxIn& tx_in : ptx->vin) {
1595 if (!mapTxSpends.contains(tx_in.
prevout))
continue;
1597 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(tx_in.
prevout);
1600 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) {
1601 CWalletTx& wtx = mapWallet.find(_it->second)->second;
1605 auto try_updating_state = [&](
CWalletTx& tx) {
1628void CWallet::BlockUntilSyncedToCurrentChain()
const {
1645 return txo->GetTxOut().nValue;
1670 for (
const auto& spkm : it->second) {
1671 res = res || spkm->IsMine(
script);
1696 if (outpoint.
n >= wtx->GetTx()->vout.size()) {
1699 return IsMine(wtx->GetTx()->vout[outpoint.
n]);
1718 throw std::runtime_error(std::string(__func__) +
": value out of range");
1726 bool result =
false;
1728 if (!spk_man->IsHDEnabled())
return false;
1740 if (spk_man && spk_man->CanGetAddresses(internal)) {
1758 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1772 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1807 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1821 if (time < birthtime) {
1839 int start_height = 0;
1879 constexpr auto INTERVAL_TIME{60
s};
1880 auto current_time{reserver.
now()};
1881 auto start_time{reserver.
now()};
1885 uint256 block_hash = start_block;
1888 std::unique_ptr<FastWalletRescanFilter> fast_rescan_filter;
1892 fast_rescan_filter ?
"fast variant using block filters" :
"slow variant inspecting all blocks");
1900 double progress_current = progress_begin;
1901 int block_height = start_height;
1903 if (progress_end - progress_begin > 0.0) {
1904 m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin);
1908 if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
1912 bool next_interval = reserver.
now() >= current_time + INTERVAL_TIME;
1913 if (next_interval) {
1914 current_time = reserver.
now();
1915 WalletLogPrintf(
"Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
1918 bool fetch_block{
true};
1919 if (fast_rescan_filter) {
1920 fast_rescan_filter->UpdateIfNeeded();
1921 auto matches_block{fast_rescan_filter->MatchesBlock(block_hash)};
1922 if (matches_block.has_value()) {
1923 if (*matches_block) {
1928 fetch_block =
false;
1931 LogDebug(
BCLog::SCAN,
"Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.
ToString());
1937 bool block_still_active =
false;
1938 bool next_block =
false;
1948 if (save_progress && next_interval) found_block.
locator(loc);
1953 if (!block_still_active) {
1960 for (
size_t posInBlock = 0; posInBlock < block.
vtx.size(); ++posInBlock) {
1978 if (max_height && block_height >= *max_height) {
1997 block_hash = next_block_hash;
2002 const uint256 prev_tip_hash = tip_hash;
2004 if (!max_height && prev_tip_hash != tip_hash) {
2016 WalletLogPrintf(
"Rescan aborted at block %d. Progress=%f\n", block_height, progress_current);
2018 }
else if (
chain().shutdownRequested()) {
2019 WalletLogPrintf(
"Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height, progress_current);
2022 WalletLogPrintf(
"Rescan completed in %15dms\n", Ticks<std::chrono::milliseconds>(reserver.
now() - start_time));
2028 std::string& err_string,
2043 const char* what{
""};
2044 switch (broadcast_method) {
2046 what =
"to mempool and for broadcast to peers";
2049 what =
"to mempool without broadcast";
2052 what =
"for private broadcast without adding to the mempool";
2076 result.erase(myHash);
2088 if (!
chain().isReadyToBroadcast())
return false;
2130 int submitted_tx_count = 0;
2137 std::set<CWalletTx*, WalletTxOrderComparator> to_submit;
2138 for (
auto& [txid, wtx] : mapWallet) {
2140 if (!wtx.isUnconfirmed())
continue;
2145 to_submit.insert(&wtx);
2148 for (
auto wtx : to_submit) {
2149 std::string unused_err_string;
2154 if (submitted_tx_count > 0) {
2155 WalletLogPrintf(
"%s: resubmit %u unconfirmed transactions\n", __func__, submitted_tx_count);
2163 for (
const std::shared_ptr<CWallet>& pwallet :
GetWallets(context)) {
2164 if (!pwallet->ShouldResend())
continue;
2166 pwallet->SetNextResend();
2176 std::map<COutPoint, Coin> coins;
2177 for (
auto& input : tx.
vin) {
2178 const auto mi = mapWallet.find(input.prevout.hash);
2179 if(mi == mapWallet.end() || input.prevout.n >= mi->second.GetTx()->vout.size()) {
2184 coins[input.prevout] =
Coin(wtx.
GetTx()->vout[input.prevout.n], prev_height, wtx.
IsCoinBase());
2186 std::map<int, bilingual_str> input_errors;
2196 if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) {
2220 const auto it = mapWallet.find(txhash);
2221 if (it != mapWallet.end()) {
2232 return PSBTError::INVALID_TX;
2238 int n_signed_this_spkm = 0;
2239 const auto error{spk_man->FillPSBT(psbtx, txdata, options, &n_signed_this_spkm)};
2245 (*n_signed) += n_signed_this_spkm;
2253 for (
size_t i = 0; i < psbtx.
inputs.size(); ++i) {
2265 if (spk_man_pair.second->CanProvide(script_pub_key, sigdata)) {
2267 return spk_man_pair.second->SignMessage(message, pkhash, str_sig);
2277 return *change_type;
2286 bool any_wpkh{
false};
2288 bool any_pkh{
false};
2290 for (
const auto& recipient : vecSend) {
2291 if (std::get_if<WitnessV1Taproot>(&recipient.dest)) {
2293 }
else if (std::get_if<WitnessV0KeyHash>(&recipient.dest)) {
2295 }
else if (std::get_if<ScriptHash>(&recipient.dest)) {
2297 }
else if (std::get_if<PKHash>(&recipient.dest)) {
2303 if (has_bech32m_spkman && any_tr) {
2308 if (has_bech32_spkman && any_wpkh) {
2313 if (has_p2sh_segwit_spkman && any_sh) {
2319 if (has_legacy_spkman && any_pkh) {
2324 if (has_bech32m_spkman) {
2327 if (has_bech32_spkman) {
2336 std::optional<Txid> replaces_txid,
2337 std::optional<std::string> comment,
2338 std::optional<std::string> comment_to,
2339 const std::vector<std::string>&
messages,
2340 const std::vector<std::string>& payment_requests
2359 throw std::runtime_error(std::string(__func__) +
": Wallet db error, transaction commit failed");
2363 for (
const CTxIn& txin : tx->vin) {
2374 std::string err_string;
2376 WalletLogPrintf(
"CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
2394 const auto wallet_file =
m_database->Filename();
2395 switch (nLoadWalletRet) {
2399 warnings.push_back(
strprintf(
_(
"Error reading %s! All keys read correctly, but transaction data"
2400 " or address metadata may be missing or incorrect."),
2404 warnings.push_back(
strprintf(
_(
"Error reading %s! Transaction data may be missing or incorrect."
2405 " Rescanning wallet."), wallet_file));
2408 error =
strprintf(
_(
"Error loading %s: Wallet corrupted"), wallet_file);
2411 error =
strprintf(
_(
"Error loading %s: Wallet requires newer version of %s"), wallet_file, CLIENT_NAME);
2414 error =
strprintf(
_(
"Error loading %s: External signer wallet being loaded without external signer support compiled"), wallet_file);
2417 error =
strprintf(
_(
"Unrecognized descriptor found. Loading wallet %s\n\n"
2418 "The wallet might have been created on a newer version.\n"
2419 "Please try running the latest software version.\n"), wallet_file);
2422 error =
strprintf(
_(
"Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
2423 "The wallet might have been tampered with or created with malicious intent.\n"), wallet_file);
2426 error =
strprintf(
_(
"Error loading %s: Wallet is a legacy wallet. Please migrate to a descriptor wallet using the migration tool (migratewallet RPC)."), wallet_file);
2429 error =
strprintf(
_(
"Error loading %s"), wallet_file);
2432 return nLoadWalletRet;
2442 return result.has_value();
2445 if (!was_txn_committed)
return util::Error{
_(
"Error starting/committing db txn for wallet transactions removal process")};
2455 std::vector<
decltype(mapWallet)::const_iterator> erased_txs;
2457 for (
const Txid& hash : txs_to_remove) {
2458 auto it_wtx = mapWallet.find(hash);
2459 if (it_wtx == mapWallet.end()) {
2465 erased_txs.emplace_back(it_wtx);
2471 for (
const auto& it : erased_txs) {
2472 const Txid hash{it->first};
2473 wtxOrdered.erase(it->second.m_it_wtxOrdered);
2474 for (
const auto& txin : it->second.GetTx()->vin) {
2475 auto range = mapTxSpends.equal_range(txin.prevout);
2476 for (
auto iter = range.first; iter != range.second; ++iter) {
2477 if (iter->second == hash) {
2478 mapTxSpends.erase(iter);
2483 for (
unsigned int i = 0; i < it->second.GetTx()->vout.size(); ++i) {
2486 mapWallet.erase(it);
2498 bool fUpdated =
false;
2500 std::optional<AddressPurpose> purpose;
2503 std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
2504 fUpdated = mi != m_address_book.end() && !mi->second.IsChange();
2506 CAddressBookData& record = mi != m_address_book.end() ? mi->second : m_address_book[address];
2508 is_mine =
IsMine(address);
2517 WalletLogPrintf(
"Error: fail to write address book 'purpose' entry\n");
2520 if (!batch.
WriteName(encoded_dest, strName)) {
2554 WalletLogPrintf(
"%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, CLIENT_BUGREPORT);
2576 m_address_book.erase(address);
2588 unsigned int count = 0;
2590 count += spk_man.second->GetKeyPoolSize();
2600 unsigned int count = 0;
2602 count += spk_man->GetKeyPoolSize();
2612 res &= spk_man->TopUp(kpSize);
2625 auto op_dest = spk_man->GetNewDestination(type);
2645 for (
auto& entry : mapWallet) {
2648 for (
unsigned int i = 0; i < wtx.
GetTx()->vout.size(); i++) {
2661 for (
const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book) {
2662 const auto& entry = item.second;
2663 func(item.first, entry.GetLabel(), entry.IsChange(), entry.purpose);
2670 std::vector<CTxDestination> result;
2678 result.emplace_back(dest);
2686 std::set<std::string> label_set;
2688 bool _is_change,
const std::optional<AddressPurpose>& _purpose) {
2689 if (_is_change)
return;
2690 if (!purpose || purpose == _purpose) {
2691 label_set.insert(_label);
2707 if (!op_address)
return op_address;
2737 if (signer_spk_man ==
nullptr) {
2742 return signer_spk_man->DisplayAddress(dest, *
signer);
2744 return util::Error{
_(
"There is no ScriptPubKeyManager for this address")};
2750 m_locked_coins.emplace(coin, persistent);
2767 auto locked_coin_it = m_locked_coins.find(output);
2768 if (locked_coin_it != m_locked_coins.end()) {
2769 bool persisted = locked_coin_it->second;
2770 m_locked_coins.erase(locked_coin_it);
2782 bool success =
true;
2784 for (
const auto& [coin, persistent] : m_locked_coins) {
2787 m_locked_coins.clear();
2794 return m_locked_coins.contains(output);
2800 for (
const auto& [coin,
_] : m_locked_coins) {
2801 vOutpts.push_back(coin);
2830 std::optional<uint256> block_hash;
2832 block_hash = conf->confirmed_block_hash;
2834 block_hash = conf->conflicting_block_hash;
2840 int64_t block_max_time;
2841 if (
chain().findBlock(*block_hash,
FoundBlock().time(blocktime).maxTime(block_max_time))) {
2842 if (rescanning_old_block) {
2843 nTimeSmart = block_max_time;
2846 int64_t latestEntry = 0;
2849 int64_t latestTolerated = latestNow + 300;
2851 for (
auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
2861 if (nSmartTime <= latestTolerated) {
2862 latestEntry = nSmartTime;
2863 if (nSmartTime > latestNow) {
2864 latestNow = nSmartTime;
2870 nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
2881 if (std::get_if<CNoDestination>(&dest))
2895 m_address_book[dest].previously_spent =
true;
2900 m_address_book[dest].receive_requests[id] = request;
2911 std::vector<std::string>
values;
2912 for (
const auto& [dest, entry] : m_address_book) {
2913 for (
const auto& [
id, request] : entry.receive_requests) {
2914 values.emplace_back(request);
2923 m_address_book[dest].receive_requests[id] = value;
2930 m_address_book[dest].receive_requests.erase(
id);
2939 if (name_path != name_path.lexically_normal()) {
2945 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.")};
2949 if (name_path.has_root_path() && name_path.root_path() == name_path) {
2960 fs::file_type path_type = fs::symlink_status(wallet_path).type();
2961 if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory ||
2962 (path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) ||
2963 (path_type == fs::file_type::regular && name_path.filename() == name_path))) {
2965 "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
2966 "database/log.?????????? files can be stored, a location where such a directory could be created, "
2967 "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
2981 return MakeDatabase(*wallet_path, options, status, error_string);
2989 if (!
args.
GetArg(
"-addresstype",
"").empty()) {
2995 wallet->m_default_address_type = parsed.value();
2998 if (!
args.
GetArg(
"-changetype",
"").empty()) {
3004 wallet->m_default_change_type = parsed.value();
3007 if (
const auto arg{
args.
GetArg(
"-mintxfee")}) {
3008 std::optional<CAmount> min_tx_fee =
ParseMoney(*arg);
3014 _(
"This is the minimum transaction fee you pay on every transaction."));
3020 if (
const auto arg{
args.
GetArg(
"-maxapsfee")}) {
3021 const std::string& max_aps_fee{*arg};
3022 if (max_aps_fee ==
"-1") {
3023 wallet->m_max_aps_fee = -1;
3024 }
else if (std::optional<CAmount> max_fee =
ParseMoney(max_aps_fee)) {
3027 _(
"This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
3029 wallet->m_max_aps_fee = max_fee.value();
3036 if (
const auto arg{
args.
GetArg(
"-fallbackfee")}) {
3037 std::optional<CAmount> fallback_fee =
ParseMoney(*arg);
3038 if (!fallback_fee) {
3039 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s'"),
"-fallbackfee", *arg);
3043 _(
"This is the transaction fee you may pay when fee estimates are not available."));
3049 wallet->m_allow_fallback_fee =
wallet->m_fallback_fee.GetFeePerK() != 0;
3051 if (
const auto arg{
args.
GetArg(
"-discardfee")}) {
3052 std::optional<CAmount> discard_fee =
ParseMoney(*arg);
3054 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s'"),
"-discardfee", *arg);
3058 _(
"This is the transaction fee you may discard if change is smaller than dust at this level"));
3063 if (
const auto arg{
args.
GetArg(
"-maxtxfee")}) {
3064 std::optional<CAmount> max_fee =
ParseMoney(*arg);
3069 warnings.push_back(
strprintf(
_(
"%s is set very high! Fees this large could be paid on a single transaction."),
"-maxtxfee"));
3073 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
3078 wallet->m_default_max_tx_fee = max_fee.value();
3081 if (
const auto arg{
args.
GetArg(
"-consolidatefeerate")}) {
3082 if (std::optional<CAmount> consolidate_feerate =
ParseMoney(*arg)) {
3092 _(
"The wallet will avoid paying less than the minimum relay fee."));
3099 warnings.push_back(
_(
"-walletrbf is deprecated and will be fully removed in the next release."));
3100 wallet->m_signal_rbf = *value;
3113 const std::string& walletFile = database->Filename();
3115 const auto start{SteadyClock::now()};
3126 error =
strprintf(
_(
"Error creating %s: Could not write version metadata."), walletFile);
3130 LOCK(walletInstance->cs_wallet);
3140 if (!born_encrypted) {
3141 walletInstance->SetupWalletGeneration();
3147 walletInstance->SetLastBlockProcessed(*tip_height,
chain->
getBlockHash(*tip_height));
3152 walletInstance->WalletLogPrintf(
"Wallet completed creation in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
3155 walletInstance->TopUpKeyPool();
3158 walletInstance->DisconnectChainNotifications();
3162 return walletInstance;
3168 const std::string& walletFile = database->Filename();
3170 const auto start{SteadyClock::now()};
3178 auto nLoadWalletRet = walletInstance->PopulateWalletFromDB(error, warnings);
3185 for (
auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
3186 if (spk_man->HavePrivateKeys()) {
3187 warnings.push_back(
strprintf(
_(
"Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
3193 walletInstance->WalletLogPrintf(
"Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
3196 walletInstance->TopUpKeyPool();
3199 walletInstance->DisconnectChainNotifications();
3203 WITH_LOCK(walletInstance->cs_wallet, walletInstance->LogStats());
3205 return walletInstance;
3211 LOCK(walletInstance->cs_wallet);
3213 assert(!walletInstance->m_chain || walletInstance->m_chain == &
chain);
3214 walletInstance->m_chain = &
chain;
3224 error =
Untranslated(
"Wallet files should not be reused across chains. Restart bitcoind with -walletcrosschain to override.");
3236 walletInstance->m_chain_notifications_handler = walletInstance->chain().handleNotifications(walletInstance);
3239 int rescan_height = 0;
3240 if (!rescan_required)
3246 rescan_height = *fork_height;
3253 walletInstance->SetLastBlockProcessedInMem(*tip_height,
chain.
getBlockHash(*tip_height));
3255 walletInstance->SetLastBlockProcessedInMem(-1,
uint256());
3258 if (tip_height && *tip_height != rescan_height)
3262 std::optional<int64_t> time_first_key = walletInstance->m_birth_time.load();
3263 if (time_first_key) {
3270 rescan_height = *tip_height;
3278 int block_height = *tip_height;
3279 while (block_height > 0 &&
chain.
haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
3283 if (rescan_height != block_height) {
3294 _(
"Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of a pruned node)") :
3296 "Error loading wallet. Wallet requires blocks to be downloaded, "
3297 "and software does not currently support loading wallets while "
3298 "blocks are being downloaded out of order when using assumeutxo "
3299 "snapshots. Wallet should be able to load successfully after "
3300 "node sync reaches height %s"), block_height);
3306 walletInstance->WalletLogPrintf(
"Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
3311 error =
_(
"Failed to acquire rescan reserver during wallet initialization");
3314 ScanResult scan_res = walletInstance->ScanForWalletTransactions(
chain.
getBlockHash(rescan_height), rescan_height, {}, reserver,
true);
3316 error =
_(
"Failed to rescan the wallet during initialization");
3331 const auto& address_book_it = m_address_book.find(dest);
3332 if (address_book_it == m_address_book.end())
return nullptr;
3333 if ((!allow_change) && address_book_it->second.IsChange()) {
3336 return &address_book_it->second;
3359 assert(conf->confirmed_block_height >= 0);
3362 assert(conf->conflicting_block_height >= 0);
3377 assert(chain_depth >= 0);
3395 return vMasterKey.empty();
3405 if (!vMasterKey.empty()) {
3406 memory_cleanse(vMasterKey.data(), vMasterKey.size() *
sizeof(
decltype(vMasterKey)::value_type));
3420 if (!spk_man_pair.second->CheckDecryptionKey(vMasterKeyIn)) {
3424 vMasterKey = vMasterKeyIn;
3432 std::set<ScriptPubKeyMan*> spk_mans;
3433 for (
bool internal : {
false,
true}) {
3437 spk_mans.insert(spk_man);
3447 if (ext_spkm == &spkm)
return true;
3450 if (int_spkm == &spkm)
return true;
3457 std::set<ScriptPubKeyMan*> spk_mans;
3459 spk_mans.insert(spk_man_pair.second.get());
3467 std::map<OutputType, ScriptPubKeyMan*>::const_iterator it = spk_managers.find(type);
3468 if (it == spk_managers.end()) {
3476 std::set<ScriptPubKeyMan*> spk_mans;
3481 spk_mans.insert(it->second.begin(), it->second.end());
3484 Assume(std::all_of(spk_mans.begin(), spk_mans.end(), [&
script, &sigdata](
ScriptPubKeyMan* spkm) { return spkm->CanProvide(script, sigdata); }));
3510 return it->second.at(0)->GetSolvingProvider(
script);
3518 std::vector<WalletDescriptor> descs;
3521 LOCK(desc_spk_man->cs_desc_man);
3522 descs.push_back(desc_spk_man->GetWalletDescriptor());
3561 std::unique_ptr<ScriptPubKeyMan> spk_manager = std::make_unique<LegacyDataSPKM>(*
this);
3567 uint256 id = spk_manager->GetID();
3574 return cb(vMasterKey);
3585 if (spkm->HaveCryptedKeys())
return true;
3593 spk_man->NotifyCanGetAddressesChanged.connect([
this] {
3596 spk_man->NotifyFirstKeyTimeChanged.connect([
this](
const ScriptPubKeyMan*, int64_t time) {
3604 std::unique_ptr<DescriptorScriptPubKeyMan> spk_manager;
3617 throw std::runtime_error(std::string(__func__) +
": Wallet is locked, cannot setup new descriptors");
3621 uint256 id = spk_manager->GetID();
3630 for (
bool internal : {
false,
true}) {
3661 }))
throw std::runtime_error(
"Error: cannot process db transaction for descriptors setup");
3670 if (!signer_res.
isObject())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3673 if (!batch.
TxnBegin())
throw std::runtime_error(
"Error: cannot create db transaction for descriptors import");
3675 for (
bool internal : {
false,
true}) {
3676 const UniValue& descriptor_vals = signer_res.
find_value(internal ?
"internal" :
"receive");
3677 if (!descriptor_vals.
isArray())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3679 const std::string& desc_str = desc_val.getValStr();
3681 std::string desc_error;
3682 auto descs =
Parse(desc_str,
keys, desc_error,
false);
3683 if (descs.empty()) {
3684 throw std::runtime_error(std::string(__func__) +
": Invalid descriptor \"" + desc_str +
"\" (" + desc_error +
")");
3686 auto& desc = descs.at(0);
3687 if (!desc->GetOutputType()) {
3692 uint256 id = spk_manager->GetID();
3699 if (!batch.
TxnCommit())
throw std::runtime_error(
"Error: cannot commit db transaction for descriptors import");
3724 throw std::runtime_error(std::string(__func__) +
": writing active ScriptPubKeyMan id failed");
3739 spk_mans[type] = spk_man;
3741 const auto it = spk_mans_other.find(type);
3742 if (it != spk_mans_other.end() && it->second == spk_man) {
3743 spk_mans_other.erase(type);
3752 if (spk_man !=
nullptr && spk_man->GetID() ==
id) {
3756 throw std::runtime_error(std::string(__func__) +
": erasing active ScriptPubKeyMan id failed");
3760 spk_mans.erase(type);
3785 return std::nullopt;
3789 if (!desc_spk_man) {
3790 throw std::runtime_error(std::string(__func__) +
": unexpected ScriptPubKeyMan type.");
3793 LOCK(desc_spk_man->cs_desc_man);
3794 const auto& type = desc_spk_man->GetWalletDescriptor().descriptor->GetOutputType();
3795 assert(type.has_value());
3809 if (
auto spkm_res = spk_man->UpdateWalletDescriptor(desc, signing_provider); !spkm_res) {
3814 spk_man = new_spk_man.get();
3817 uint256 id = new_spk_man->GetID();
3823 return util::Error{
_(
"Unable to write descriptor cache")};
3830 auto script_pub_keys = spk_man->GetScriptPubKeys();
3831 if (script_pub_keys.empty()) {
3832 return util::Error{
_(
"Could not generate scriptPubKeys (cache is empty)")};
3836 for (
const auto&
script : script_pub_keys) {
3846 spk_man->WriteDescriptor();
3851 return std::reference_wrapper(*spk_man);
3858 WalletLogPrintf(
"Migrating wallet storage database from BerkeleyDB to SQLite.\n");
3861 error =
_(
"Error: This wallet already uses SQLite");
3866 std::unique_ptr<DatabaseBatch> batch =
m_database->MakeBatch();
3867 std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor();
3868 std::vector<std::pair<SerializeData, SerializeData>> records;
3870 error =
_(
"Error: Unable to begin reading all records in the database");
3877 status = cursor->Next(ss_key, ss_value);
3883 records.emplace_back(key, value);
3888 error =
_(
"Error: Unable to read all records in the database");
3895 fs::remove(db_path);
3906 std::unique_ptr<WalletDatabase> new_db =
MakeDatabase(wallet_path, opts, db_status, error);
3913 bool began = batch->TxnBegin();
3915 for (
const auto& [key, value] : records) {
3916 if (!batch->Write(std::span{key}, std::span{value})) {
3923 bool committed = batch->TxnCommit();
3933 if (!
Assume(legacy_spkm)) {
3936 return std::nullopt;
3940 if (res == std::nullopt) {
3941 error =
_(
"Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
3942 return std::nullopt;
3952 if (!
Assume(legacy_spkm)) {
3958 bool has_spendable_material = !
data.desc_spkms.empty() ||
data.master_key.key.IsValid();
3961 std::set<CTxDestination> not_migrated_dests;
3970 if (!
data.watch_descs.empty())
Assume(!
data.watchonly_wallet->m_cached_spks.empty());
3971 if (!
data.solvable_descs.empty())
Assume(!
data.solvable_wallet->m_cached_spks.empty());
3973 for (
auto& desc_spkm :
data.desc_spkms) {
3975 return util::Error{
_(
"Error: Duplicate descriptors created during migration. Your wallet may be corrupted.")};
3977 uint256 id = desc_spkm->GetID();
3983 return util::Error{
_(
"Error: cannot remove legacy wallet records")};
3995 if (
data.master_key.key.IsValid()) {
4014 std::vector<Txid> txids_to_delete;
4015 std::unique_ptr<WalletBatch> watchonly_batch;
4016 if (
data.watchonly_wallet) {
4017 watchonly_batch = std::make_unique<WalletBatch>(
data.watchonly_wallet->GetDatabase());
4018 if (!watchonly_batch->TxnBegin())
return util::Error{
strprintf(
_(
"Error: database transaction cannot be executed for wallet %s"),
data.watchonly_wallet->GetName())};
4020 LOCK(
data.watchonly_wallet->cs_wallet);
4021 data.watchonly_wallet->nOrderPosNext = nOrderPosNext;
4022 watchonly_batch->WriteOrderPosNext(
data.watchonly_wallet->nOrderPosNext);
4024 if (!watchonly_batch->WriteBestBlock(best_block_locator)) {
4025 return util::Error{
_(
"Error: Unable to write watchonly wallet best block locator record")};
4028 std::unique_ptr<WalletBatch> solvables_batch;
4029 if (
data.solvable_wallet) {
4030 solvables_batch = std::make_unique<WalletBatch>(
data.solvable_wallet->GetDatabase());
4031 if (!solvables_batch->TxnBegin())
return util::Error{
strprintf(
_(
"Error: database transaction cannot be executed for wallet %s"),
data.solvable_wallet->GetName())};
4033 if (!solvables_batch->WriteBestBlock(best_block_locator)) {
4034 return util::Error{
_(
"Error: Unable to write solvable wallet best block locator record")};
4041 if (
data.watchonly_wallet) {
4042 LOCK(
data.watchonly_wallet->cs_wallet);
4043 if (
data.watchonly_wallet->IsMine(*wtx->GetTx()) ||
data.watchonly_wallet->IsFromMe(*wtx->GetTx())) {
4045 const Txid& hash = wtx->GetHash();
4049 if (!
data.watchonly_wallet->LoadToWallet(std::move(copy_wtx))) {
4050 return util::Error{
strprintf(
_(
"Error: Could not add watchonly tx %s to watchonly wallet"), wtx->GetHash().GetHex())};
4052 watchonly_batch->WriteTx(
data.watchonly_wallet->mapWallet.at(hash));
4055 txids_to_delete.push_back(hash);
4062 return util::Error{
strprintf(
_(
"Error: Transaction %s in wallet cannot be identified to belong to migrated wallets"), wtx->GetHash().GetHex())};
4065 local_wallet_batch.
WriteTx(*wtx);
4069 if (txids_to_delete.size() > 0) {
4070 if (
auto res =
RemoveTxs(local_wallet_batch, txids_to_delete); !res) {
4076 std::vector<std::pair<std::shared_ptr<CWallet>, std::unique_ptr<WalletBatch>>> wallets_vec;
4077 if (
data.watchonly_wallet) wallets_vec.emplace_back(
data.watchonly_wallet, std::move(watchonly_batch));
4078 if (
data.solvable_wallet) wallets_vec.emplace_back(
data.solvable_wallet, std::move(solvables_batch));
4084 if (entry.label) batch.
WriteName(address, *entry.label);
4085 for (
const auto& [
id, request] : entry.receive_requests) {
4092 std::vector<CTxDestination> dests_to_delete;
4093 for (
const auto& [dest, record] : m_address_book) {
4097 bool copied =
false;
4098 for (
auto& [
wallet, batch] : wallets_vec) {
4100 if (require_transfer && !
wallet->IsMine(dest))
continue;
4103 wallet->m_address_book[dest] = record;
4104 func_store_addr(*batch, dest, record);
4108 if (require_transfer) {
4109 dests_to_delete.push_back(dest);
4117 if (require_transfer && !copied) {
4120 if (not_migrated_dests.contains(dest)) {
4121 dests_to_delete.push_back(dest);
4125 return util::Error{
_(
"Error: Address book data in wallet cannot be identified to belong to migrated wallets")};
4130 for (
auto& [
wallet, batch] : wallets_vec) {
4137 if (dests_to_delete.size() > 0) {
4138 for (
const auto& dest : dests_to_delete) {
4140 return util::Error{
_(
"Error: Unable to remove watchonly address book data")};
4148 if (!has_spendable_material) {
4149 if (!m_address_book.empty())
return util::Error{
_(
"Error: Not all address book records were migrated")};
4150 if (!mapWallet.empty())
return util::Error{
_(
"Error: Not all transaction records were migrated")};
4167 return name.empty() ?
"default_wallet" :
name;
4175 std::optional<MigrationData>
data =
wallet.GetDescriptorsForLegacy(error);
4176 if (
data == std::nullopt)
return false;
4179 if (
data->watch_descs.size() > 0 ||
data->solvable_descs.size() > 0) {
4196 if (
data->watch_descs.size() > 0) {
4197 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the watched scripts\n");
4200 std::vector<bilingual_str> warnings;
4202 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4204 error =
strprintf(
_(
"Wallet file creation failed: %s"), error);
4209 if (!
data->watchonly_wallet) {
4210 error =
_(
"Error: Failed to create new watchonly wallet");
4214 LOCK(
data->watchonly_wallet->cs_wallet);
4217 for (
const auto& [desc_str, creation_time] :
data->watch_descs) {
4220 std::string parse_err;
4221 std::vector<std::unique_ptr<Descriptor>> descs =
Parse(desc_str,
keys, parse_err,
true);
4223 assert(descs.size() == 1);
4224 assert(!descs.at(0)->IsRange());
4228 if (
auto spkm_res =
data->watchonly_wallet->AddWalletDescriptor(w_desc,
keys,
"",
false); !spkm_res) {
4236 if (
data->solvable_descs.size() > 0) {
4237 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the unwatched solvable scripts\n");
4240 std::vector<bilingual_str> warnings;
4242 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4244 error =
strprintf(
_(
"Wallet file creation failed: %s"), error);
4249 if (!
data->solvable_wallet) {
4250 error =
_(
"Error: Failed to create new watchonly wallet");
4254 LOCK(
data->solvable_wallet->cs_wallet);
4257 for (
const auto& [desc_str, creation_time] :
data->solvable_descs) {
4260 std::string parse_err;
4261 std::vector<std::unique_ptr<Descriptor>> descs =
Parse(desc_str,
keys, parse_err,
true);
4263 assert(descs.size() == 1);
4264 assert(!descs.at(0)->IsRange());
4268 if (
auto spkm_res =
data->solvable_wallet->AddWalletDescriptor(w_desc,
keys,
"",
false); !spkm_res) {
4280 if (auto res_migration = wallet.ApplyMigrationData(batch, *data); !res_migration) {
4281 error = util::ErrorString(res_migration);
4284 wallet.WalletLogPrintf(
"Wallet migration complete.\n");
4291 std::vector<bilingual_str> warnings;
4297 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4308 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4320 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4326 std::shared_ptr<CWallet> local_wallet = CWallet::LoadExisting(empty_context, wallet_name, std::move(database), error, warnings);
4327 if (!local_wallet) {
4338 std::vector<bilingual_str> warnings;
4344 const std::string wallet_name = local_wallet->GetName();
4348 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4357 const std::string backup_prefix = wallet_name.empty() ?
MigrationPrefixName(*local_wallet) : [&] {
4366 return util::Error{
_(
"Error: Unable to make a backup of your wallet")};
4370 bool success =
false;
4373 if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
4374 if (passphrase.find(
'\0') == std::string::npos) {
4375 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
4377 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase entered was incorrect. "
4378 "The passphrase contains a null character (ie - a zero byte). "
4379 "If this passphrase was set with a version of this software prior to 25.0, "
4380 "please try again with only the characters up to — but not including — "
4381 "the first null character.")};
4391 bool empty_local_wallet =
false;
4394 LOCK(local_wallet->cs_wallet);
4396 if (!local_wallet->MigrateToSQLite(error))
return util::Error{error};
4400 success =
DoMigration(*local_wallet, context, error, res, load_wallet);
4402 empty_local_wallet = local_wallet->GetAllScriptPubKeyMans().empty();
4414 std::set<fs::path> wallet_files_to_remove;
4415 std::set<fs::path> wallet_empty_dirs_to_remove;
4420 const auto files =
wallet.GetDatabase().Files();
4421 wallet_files_to_remove.insert(files.begin(), files.end());
4422 if (
wallet.GetName() != wallet_name) {
4435 if (empty_local_wallet) {
4437 std::vector<fs::path> paths_to_remove = local_wallet->GetDatabase().Files();
4438 local_wallet.reset();
4439 for (
const auto& path_to_remove : paths_to_remove) fs::remove(path_to_remove);
4443 LogInfo(
"Loading new wallets after migration...\n");
4450 bool main_wallet_set{
false};
4452 if (success && *wallet_ptr) {
4453 std::shared_ptr<CWallet>&
wallet = *wallet_ptr;
4455 track_for_cleanup(*
wallet);
4457 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);
4470 if (!main_wallet_set) {
4473 main_wallet_set =
true;
4485 std::vector<std::shared_ptr<CWallet>> created_wallets;
4486 if (local_wallet) created_wallets.push_back(std::move(local_wallet));
4491 for (std::shared_ptr<CWallet>&
wallet : created_wallets) {
4492 track_for_cleanup(*
wallet);
4496 for (std::shared_ptr<CWallet>& w : created_wallets) {
4497 if (w->HaveChain()) {
4500 error +=
_(
"\nUnable to cleanup failed migration");
4506 assert(w.use_count() == 1);
4512 for (
const fs::path& file : wallet_files_to_remove) {
4517 for (
const fs::path& dir : wallet_empty_dirs_to_remove) {
4518 Assume(fs::is_empty(dir));
4525 const auto& ptr_wallet =
RestoreWallet(context, backup_path, wallet_name, std::nullopt, status, restore_error, warnings,
false,
true);
4526 if (!restore_error.
empty()) {
4527 error += restore_error +
_(
"\nUnable to restore backup of wallet.");
4540 for (
const auto&
script : spks) {
4541 m_cached_spks[
script].push_back(spkm);
4548 CacheNewScriptPubKeys(spks, spkm);
4558 for (
const auto& spkm : filter == HDKeyFilter::Active ? GetActiveScriptPubKeyMans() : GetAllScriptPubKeyMans()) {
4560 LOCK(desc_spkm->cs_desc_man);
4562 if (filter == HDKeyFilter::UnusedKey && w_desc.
descriptor->HasScripts())
continue;
4564 std::set<CPubKey> desc_pubkeys;
4565 std::set<CExtPubKey> desc_xpubs;
4566 w_desc.
descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
4568 xpubs[xpub].insert(desc_spkm);
4574std::optional<CKey> CWallet::GetKey(
const CKeyID& keyid)
const
4578 for (
const auto& spkm : GetAllScriptPubKeyMans()) {
4582 if (std::optional<CKey> key = desc_spkm->
GetKey(keyid)) {
4586 return std::nullopt;
4589std::optional<CExtKey> CWallet::GetExtKey(
const CExtPubKey& xpub)
const
4591 if (std::optional<CKey> key = GetKey(xpub.
pubkey.
GetID())) {
4594 return std::nullopt;
4597void CWallet::WriteBestBlock()
const
4601 if (!m_last_block_processed.IsNull()) {
4603 chain().findBlock(m_last_block_processed,
FoundBlock().locator(loc));
4615 for (uint32_t i = 0; i < wtx.
GetTx()->vout.size(); ++i) {
4617 if (!IsMine(txout))
continue;
4619 if (m_txos.contains(outpoint)) {
4621 m_txos.emplace(outpoint,
WalletTXO{wtx, txout});
4626void CWallet::RefreshAllTXOs()
4629 for (
const auto& [
_, wtx] : mapWallet) {
4630 RefreshTXOsFromTx(wtx);
4634std::optional<WalletTXO> CWallet::GetTXO(
const COutPoint& outpoint)
const
4637 const auto& it = m_txos.find(outpoint);
4638 if (it == m_txos.end()) {
4639 return std::nullopt;
4644void CWallet::DisconnectChainNotifications()
4646 if (m_chain_notifications_handler) {
4647 m_chain_notifications_handler->disconnect();
4648 chain().waitForNotifications();
4649 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)
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.
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Serialized script, used inside transaction inputs and outputs.
The basic transaction that is broadcasted on the network and contained in blocks.
const std::vector< CTxOut > vout
const Txid & GetHash() const LIFETIMEBOUND
const std::vector< CTxIn > vin
An input of a transaction.
An output of a transaction.
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 LegacyDataSPKM used for all legacy output types and both internal and external chains.
std::optional< common::PSBTError > FillPSBT(PartiallySignedTransaction &psbtx, const common::PSBTFillOptions &options, bool &complete, size_t *n_signed=nullptr) const
Fills out a PSBT with information from the wallet.
void SetupWalletGeneration() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Setup new descriptors or seed for new address generation.
std::vector< CTxDestination > ListAddrBookAddresses(const std::optional< AddrBookFilter > &filter) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Filter and retrieve destinations stored in the addressbook.
DescriptorScriptPubKeyMan * GetDescriptorScriptPubKeyMan(const WalletDescriptor &desc) const
Return the DescriptorScriptPubKeyMan for a WalletDescriptor if it is already in the wallet.
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
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.
std::map< CExtPubKey, std::set< DescriptorScriptPubKeyMan * > > HDPubKeyMap
bool SetAddressPreviouslySpent(WalletBatch &batch, const CTxDestination &dest, bool used) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor &desc, const KeyMap &keys, const CryptedKeyMap &ckeys)
Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it.
util::Result< void > RemoveTxs(std::vector< Txid > &txs_to_remove) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Erases the provided transactions from the wallet.
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.
void CommitTransaction(CTransactionRef tx, std::optional< Txid > replaces_txid=std::nullopt, std::optional< std::string > comment=std::nullopt, std::optional< std::string > comment_to=std::nullopt, const std::vector< std::string > &messages={}, const std::vector< std::string > &payment_requests={})
Submit the transaction to the node's mempool and then relay to peers.
util::Result< CTxDestination > GetNewChangeDestination(OutputType type)
std::optional< bool > IsInternalScriptPubKeyMan(ScriptPubKeyMan *spk_man) const
Returns whether the provided ScriptPubKeyMan is internal.
void LoadLockedCoin(const COutPoint &coin, bool persistent) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void SetupLegacyDataSPKM()
Create a LegacyDataSPKM and set it for all legacy output types and both internal and external chains.
static std::shared_ptr< CWallet > CreateNew(WalletContext &context, const std::string &name, std::unique_ptr< WalletDatabase > database, uint64_t wallet_creation_flags, bool born_encrypted, bilingual_str &error, std::vector< bilingual_str > &warnings)
SigningResult SignMessage(const std::string &message, const PKHash &pkhash, std::string &str_sig) const
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 from MigrationData to this wallet, removes the LegacyDataSPKM,...
NodeClock::time_point m_next_resend
The next scheduled rebroadcast of wallet transactions.
HDKeyFilter
Which descriptors GetHDPubKeys() should consider.
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)
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.
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.
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
std::vector< std::string > m_messages
const Txid & GetHash() const LIFETIMEBOUND
bool IsEquivalentTo(const CWalletTx &tx) const
True if only scriptSigs are different.
std::set< Txid > mempool_conflicts
std::optional< Txid > m_replaces_txid
void updateState(interfaces::Chain &chain)
Update transaction state when attaching to a chain, filling in heights of conflicted and confirmed bl...
std::optional< std::string > m_comment_to
std::optional< std::string > m_message
int64_t nOrderPos
position in ordered transaction list
bool isUnconfirmed() const
std::optional< std::string > m_comment
unsigned int nTimeReceived
time received by this node
std::optional< std::string > m_from
std::optional< Txid > m_replaced_by_txid
bool Update(CTransactionRef tx, const TxState &new_state)
std::optional< Txid > truc_child_in_mempool
std::vector< std::string > m_payment_requests
int64_t GetTxTime() const
CTransactionRef GetTx() 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()
std::optional< CKey > GetKey(const CKeyID &keyid) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man)
Retrieve the particular key if it is available. Returns nullopt if the key is not in the wallet,...
static std::unique_ptr< DescriptorScriptPubKeyMan > CreateFromImport(WalletStorage &storage, WalletDescriptor &descriptor, int64_t keypool_size, const FlatSigningProvider &provider)
static std::unique_ptr< DescriptorScriptPubKeyMan > LoadFromStorage(WalletStorage &storage, WalletDescriptor &descriptor, int64_t keypool_size, const KeyMap &keys, const CryptedKeyMap &ckeys)
bool HasWalletDescriptor(const WalletDescriptor &desc) const
RecursiveMutex cs_desc_man
static std::unique_ptr< DescriptorScriptPubKeyMan > GenerateNewSingleSig(WalletStorage &storage, WalletBatch &batch, int64_t keypool_size, const CExtKey &master_key, OutputType addr_type, bool internal)
static std::unique_ptr< ExternalSignerScriptPubKeyMan > LoadFromStorage(WalletStorage &storage, WalletDescriptor &descriptor, int64_t keypool_size, const KeyMap &keys, const CryptedKeyMap &ckeys)
static std::unique_ptr< ExternalSignerScriptPubKeyMan > CreateNew(WalletStorage &storage, WalletBatch &batch, int64_t keypool_size, std::unique_ptr< Descriptor > desc)
static util::Result< ExternalSigner > GetExternalSigner()
bool DeleteRecordsWithDB(WalletBatch &batch)
Delete the legacy wallet records from disk.
std::optional< MigrationData > MigrateToDescriptor()
Get the DescriptorScriptPubKeyMans (with private keys) that have the same scriptPubKeys as this Legac...
uint256 GetID() const override
std::unordered_set< CScript, SaltedSipHasher > GetNotMineScriptPubKeys() const
Retrieves scripts that were imported by bugs into the legacy spkm and are simply invalid,...
A wrapper to reserve an address from a wallet.
const CWallet *const pwallet
The wallet to reserve from.
void KeepDestination()
Keep the address. Do not return its key to the keypool when this object goes out of scope.
CTxDestination address
The destination.
bool fInternal
Whether this is from the internal (change output) keypool.
void ReturnDestination()
Return reserved address.
ScriptPubKeyMan * m_spk_man
The ScriptPubKeyMan to reserve from. Based on type when GetReservedDestination is called.
int64_t nIndex
The index of the address's key in the keypool.
util::Result< CTxDestination > GetReservedDestination(bool internal)
Reserve an address.
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 WriteDescriptorCacheItems(const uint256 &desc_id, const DescriptorCache &cache)
bool WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
bool WriteWalletFlags(uint64_t flags)
bool TxnBegin()
Begin a new transaction.
bool WriteAddressPreviouslySpent(const CTxDestination &dest, bool previously_spent)
bool EraseAddressReceiveRequest(const CTxDestination &dest, const std::string &id)
bool TxnCommit()
Commit current transaction.
bool WriteName(const std::string &strAddress, const std::string &strName)
bool WritePurpose(const std::string &strAddress, const std::string &purpose)
bool EraseAddressData(const CTxDestination &dest)
bool WriteOrderPosNext(int64_t nOrderPosNext)
bool 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 to m_batch, indicating the last version of client software to load thi...
bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal)
bool WriteAddressReceiveRequest(const CTxDestination &dest, const std::string &id, const std::string &receive_request)
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.
constexpr int CLIENT_VERSION
static const PrecomputedData data
Precomputed COutPoint and CCoins values.
std::string ShellEscape(const std::string &arg)
constexpr int COINBASE_MATURITY
Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
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)
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver)
Scan active chain for relevant transactions after importing keys.
void SetWalletFlagWithDB(WalletBatch &batch, uint64_t flags)
Store wallet flags.
static bool EncryptMasterKey(const SecureString &wallet_passphrase, const CKeyingMaterial &plain_master_key, CMasterKey &master_key)
uint64_t GetWalletFlags() const
Retrieve all of the wallet's flags.
void updatedBlockTip() override
bool TransactionCanBeAbandoned(const Txid &hashTx) const
Return whether transaction can be abandoned.
void BlockUntilSyncedToCurrentChain() const LOCKS_EXCLUDED(void SetWalletFlag(uint64_t flags)
Blocks until the wallet state is up-to-date to /at least/ the current chain at the time this function...
bool AddToWalletIfInvolvingMe(const CTransactionRef &tx, const SyncTxState &state, bool rescanning_old_block) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Add a transaction to the wallet, or update it.
ScanResult ScanForWalletTransactions(const uint256 &start_block, int start_height, std::optional< int > max_height, const WalletRescanReserver &reserver, bool save_progress)
Scan the block chain (starting in start_block) for transactions from or to us.
void MaybeUpdateBirthTime(int64_t time)
Updates wallet birth time if 'time' is below it.
void blockDisconnected(const interfaces::BlockInfo &block) override
std::set< Txid > GetConflicts(const Txid &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get wallet transactions that conflict with given transaction (spend same outputs)
bool IsWalletFlagSet(uint64_t flag) const override
check if a certain wallet flag is set
SpendType HowSpent(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
static bool DecryptMasterKey(const SecureString &wallet_passphrase, const CMasterKey &master_key, CKeyingMaterial &plain_master_key)
void AddToSpends(const COutPoint &outpoint, const Txid &txid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void SetLastBlockProcessedInMem(int block_height, uint256 block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UnsetWalletFlagWithDB(WalletBatch &batch, uint64_t flag)
Unsets a wallet flag and saves it to disk.
bool IsSpent(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Outpoint is spent if any non-conflicted transaction spends it:
void ResubmitWalletTransactions(node::TxBroadcast broadcast_method, bool force)
std::set< Txid > GetTxConflicts(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UnsetBlankWalletFlag(WalletBatch &batch) override
Unset the blank wallet flag and saves it to disk.
CWalletTx * AddToWallet(CTransactionRef tx, const TxState &state, const UpdateWalletTxFn &update_wtx=nullptr, bool rescanning_old_block=false)
Add the transaction to the wallet, wrapping it up inside a CWalletTx.
bool MarkReplaced(const Txid &originalHash, const Txid &newHash)
Mark a transaction as replaced by another transaction.
bool CanGetAddresses(bool internal=false) const
bool LoadToWallet(CWalletTx &&wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UpdateTrucSiblingConflicts(const CWalletTx &parent_wtx, const Txid &child_txid, bool add_conflict) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Update mempool conflicts for TRUC sibling transactions.
bool LoadWalletFlags(uint64_t flags)
Loads the flags into the wallet.
bool SubmitTxMemoryPoolAndRelay(CWalletTx &wtx, std::string &err_string, node::TxBroadcast broadcast_method) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Pass this transaction to node for optional mempool insertion and relay to peers.
void blockConnected(const kernel::ChainstateRole &role, const interfaces::BlockInfo &block) override
void transactionRemovedFromMempool(const CTransactionRef &tx, MemPoolRemovalReason reason) override
static NodeClock::time_point GetDefaultNextResend()
bool ShouldResend() const
Return true if all conditions for periodically resending transactions are met.
bool SyncTransaction(const CTransactionRef &tx, const SyncTxState &state, bool rescanning_old_block=false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
const CWalletTx * GetWalletTx(const Txid &hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void InitWalletFlags(uint64_t flags)
overwrite all flags by the given uint64_t flags must be uninitialised (or 0) only known flags may be ...
void UnsetWalletFlag(uint64_t flag)
Unsets a single wallet flag.
bool EncryptWallet(const SecureString &strWalletPassphrase)
void SetLastBlockProcessed(int block_height, uint256 block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Set last block processed height, and write to database.
bool IsFromMe(const CTransaction &tx) const
should probably be renamed to IsRelevantToMe
DBErrors ReorderTransactions()
bool IsMine(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UpgradeDescriptorCache() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Upgrade DescriptorCaches.
void SetSpentKeyState(WalletBatch &batch, const Txid &hash, unsigned int n, bool used, std::set< CTxDestination > &tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
CAmount GetDebit(const CTxIn &txin) const
Returns amount of debit, i.e.
void MarkConflicted(const uint256 &hashBlock, int conflicting_height, const Txid &hashTx)
Mark a transaction (and its in-wallet descendants) as conflicting with a particular block.
void transactionAddedToMempool(const CTransactionRef &tx) override
void Close()
Close wallet database.
@ 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)
std::thread thread
Thread variable should be after other struct members so the thread does not start until the other mem...
#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 bool DEFAULT_WALLET_RBF
-walletrbf default
constexpr bool DEFAULT_WALLETCROSSCHAIN
constexpr CAmount HIGH_APS_FEE
discourage APS fee higher than this amount
void ReadDatabaseArgs(const ArgsManager &args, DatabaseOptions &options)
std::shared_ptr< CWallet > LoadWallet(WalletContext &context, const std::string &name, std::optional< bool > load_on_start, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
static std::set< std::string > g_loading_wallet_set GUARDED_BY(g_loading_wallet_mutex)
constexpr unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
std::unique_ptr< WalletDatabase > MakeDatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
void MaybeResendWalletTxs(WalletContext &context)
Called periodically by the schedule thread.
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.
util::Result< MigrationResult > MigrateLegacyToDescriptor(std::shared_ptr< CWallet > local_wallet, const SecureString &passphrase, WalletContext &context, bool load_wallet)
Requirement: The wallet provided to this function must be isolated, with no attachment to the node's ...
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
std::map< CKeyID, std::pair< CPubKey, std::vector< unsigned char > > > CryptedKeyMap
DBErrors
Overview of wallet database classes:
@ UNEXPECTED_LEGACY_ENTRY
@ EXTERNAL_SIGNER_SUPPORT_REQUIRED
bool AddWalletSetting(interfaces::Chain &chain, const std::string &wallet_name)
Add wallet name to persistent configuration so it will be loaded on startup.
static GlobalMutex g_wallet_release_mutex
bool RemoveWalletSetting(interfaces::Chain &chain, const std::string &wallet_name)
Remove wallet name from persistent configuration so it will not be loaded on startup.
static void RefreshMempoolStatus(CWalletTx &tx, interfaces::Chain &chain)
Refresh mempool status so the wallet is in an internally consistent state and immediately knows the t...
std::unique_ptr< interfaces::Handler > HandleLoadWallet(WalletContext &context, LoadWalletFn load_wallet)
bool 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.
const std::unordered_set< OutputType > LEGACY_OUTPUT_TYPES
Output types associated with LegacyDataSPKM.
constexpr CAmount HIGH_TX_FEE_PER_KB
Discourage users to set fees higher than this amount (in satoshis) per kB.
static std::condition_variable g_wallet_release_cv
std::unique_ptr< WalletDatabase > MakeWalletDatabase(const std::string &name, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error_string)
bool IsBDBFile(const fs::path &path)
void NotifyWalletLoaded(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
fs::path BDBDataFile(const fs::path &wallet_path)
constexpr CAmount HIGH_MAX_TX_FEE
-maxtxfee will warn if called with a higher fee than this amount (in satoshis)
std::shared_ptr< CWallet > RestoreWallet(WalletContext &context, const fs::path &backup_file, const std::string &wallet_name, std::optional< bool > load_on_start, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings, bool load_after_restore, bool allow_unnamed)
std::string PurposeToString(AddressPurpose p)
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
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
bool DoMigration(CWallet &wallet, WalletContext &context, bilingual_str &error, MigrationResult &res, const bool load_on_startup=true) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
std::shared_ptr< CWallet > CreateWallet(WalletContext &context, const std::string &name, std::optional< bool > load_on_start, DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
static void FlushAndDeleteWallet(CWallet *wallet)
@ WALLET_FLAG_EXTERNAL_SIGNER
Indicates that the wallet needs an external signer.
@ WALLET_FLAG_LAST_HARDENED_XPUB_CACHED
@ WALLET_FLAG_KEY_ORIGIN_METADATA
@ WALLET_FLAG_AVOID_REUSE
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
@ WALLET_FLAG_BLANK_WALLET
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::map< CKeyID, CKey > KeyMap
std::shared_ptr< CWallet > GetWallet(WalletContext &context, const std::string &name)
util::Result< fs::path > GetWalletPath(const std::string &name)
Determine the path that the wallet is stored in.
constexpr unsigned int WALLET_CRYPTO_KEY_SIZE
constexpr bool DEFAULT_WALLETBROADCAST
constexpr unsigned int WALLET_CRYPTO_SALT_SIZE
@ FAILED_INVALID_BACKUP_FILE
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
std::shared_ptr< CWallet > GetDefaultWallet(WalletContext &context, size_t &count)
constexpr bool DEFAULT_SPEND_ZEROCONF_CHANGE
Default for -spendzeroconfchange.
constexpr unsigned int DEFAULT_TX_CONFIRM_TARGET
-txconfirmtarget default
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)
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
constexpr deserialize_type deserialize
@ PRIVATE_KEY_NOT_AVAILABLE
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
std::vector< uint256 > vHave
void SetSeed(std::span< const std::byte > seed)
A mutable version of CTransaction.
static time_point now() noexcept
Return current system time or mocked time, if set.
std::chrono::time_point< NodeClock > time_point
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
enum wallet::CWallet::ScanResult::@19 status
uint256 last_scanned_block
Hash and height of most recent block that was successfully scanned.
uint256 last_failed_block
Height of the most recent block that could not be scanned due to read errors or pruning.
SecureString create_passphrase
std::optional< DatabaseFormat > require_format
struct containing information needed for migrating legacy wallets to descriptor wallets
std::optional< std::string > solvables_wallet_name
std::optional< std::string > watchonly_wallet_name
std::shared_ptr< CWallet > watchonly_wallet
std::shared_ptr< CWallet > solvables_wallet
std::shared_ptr< CWallet > wallet
State of rejected transaction that conflicts with a confirmed block.
int conflicting_block_height
State of transaction confirmed in a block.
int confirmed_block_height
State of transaction added to mempool.
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.
std::vector< uint16_t > keys
#define EXCLUSIVE_LOCKS_REQUIRED(...)
consteval auto _(util::TranslatedLiteral str)
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
constexpr decltype(CTransaction::version) TRUC_VERSION
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
std::chrono::duration< double, std::chrono::milliseconds::period > MillisecondsDouble
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.