8#include <bitcoin-build-config.h>
11#include <blockfilter.h>
79#include <condition_variable>
104 if (!setting_value.isArray()) setting_value.setArray();
105 for (
const auto& value : setting_value.getValues()) {
108 setting_value.push_back(wallet_name);
117 if (!setting_value.isArray()) {
118 if (wallet_name.empty() && setting_value.isNull()) {
120 setting_value.setArray();
126 for (
const auto& value : setting_value.getValues()) {
127 if (!value.isStr() || value.get_str() != wallet_name) new_value.
push_back(value);
130 setting_value = std::move(new_value);
137 const std::string& wallet_name,
138 std::optional<bool> load_on_startup,
139 std::vector<bilingual_str>& warnings)
141 if (!load_on_startup)
return;
143 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
145 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));
167 std::vector<std::shared_ptr<CWallet>>::const_iterator i = std::find(
context.wallets.begin(),
context.wallets.end(),
wallet);
168 if (i !=
context.wallets.end())
return false;
170 wallet->ConnectScriptPubKeyManNotifiers();
171 wallet->NotifyCanGetAddressesChanged();
184 wallet->DisconnectChainNotifications();
187 std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(
context.wallets.begin(),
context.wallets.end(),
wallet);
188 if (i ==
context.wallets.end())
return false;
202 std::vector<bilingual_str> warnings;
222 for (
const std::shared_ptr<CWallet>&
wallet :
context.wallets) {
231 auto it =
context.wallet_load_fns.emplace(
context.wallet_load_fns.end(), std::move(load_wallet));
238 for (
auto& load_wallet :
context.wallet_load_fns) {
253 wallet->WalletLogPrintf(
"Releasing wallet %s..\n",
name);
258 if (g_unloading_wallet_set.erase(
name) == 0) {
272 g_unloading_wallet_set.insert(
name);
281 while (g_unloading_wallet_set.contains(
name)) {
288std::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)
307 wallet->postInitProcess();
313 }
catch (
const std::runtime_error& e) {
324 if (!result.second) {
329 auto wallet = LoadWalletInternal(
context,
name, load_on_start, options, status, error, warnings);
345 bool born_encrypted = !passphrase.empty();
354 error =
Untranslated(
"Private keys must be disabled when using an external signer");
361 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.");
384 if (born_encrypted) {
385 if (!
wallet->EncryptWallet(passphrase)) {
386 error =
Untranslated(
"Error: Wallet created but failed to encrypt.");
395 wallet->postInitProcess();
410 if (!allow_unnamed && wallet_name.empty()) {
421 auto wallet_file = wallet_path /
"wallet.dat";
422 std::shared_ptr<CWallet>
wallet;
423 bool wallet_file_copied =
false;
424 bool created_parent_dir =
false;
437 if (!fs::is_directory(wallet_path)) {
456 created_parent_dir =
true;
459 fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
460 wallet_file_copied =
true;
462 if (load_after_restore) {
465 }
catch (
const std::exception& e) {
472 if (load_after_restore && !
wallet) {
473 if (wallet_file_copied) fs::remove(wallet_file);
476 if (created_parent_dir) {
477 Assume(fs::is_empty(wallet_path));
478 fs::remove(wallet_path);
488 m_database(
std::move(database)),
510 const auto it = mapWallet.find(hash);
511 if (it == mapWallet.end())
513 return &(it->second);
538 for (
int i = 0; i < 2; i++){
540 const bool key_set{crypter.
SetKeyFromPassphrase(wallet_passphrase, updated_master_key.vchSalt, updated_master_key.nDeriveIterations, updated_master_key.nDerivationMethod)};
546 if (elapsed_time <= 0
s) {
553 const double target_iterations{updated_master_key.nDeriveIterations * target_time / elapsed_time};
554 if (target_iterations < 1 || target_iterations > std::numeric_limits<unsigned int>::max()) {
559 updated_master_key.nDeriveIterations = (uint64_t{updated_master_key.nDeriveIterations} * i +
static_cast<unsigned int>(target_iterations)) / (i + 1);
566 if (!crypter.
SetKeyFromPassphrase(wallet_passphrase, updated_master_key.vchSalt, updated_master_key.nDeriveIterations, updated_master_key.nDerivationMethod)) {
569 if (!crypter.
Encrypt(plain_master_key, updated_master_key.vchCryptedKey)) {
573 master_key = std::move(updated_master_key);
593 if (passphrase.find(
'\0') != std::string::npos) {
595 message =
_(
"Error: The wallet passphrase entered is incorrect. "
596 "It contains a null character (ie - a zero byte). "
597 "If the passphrase was set with a version of this software prior to 25.0, "
598 "please try again with only the characters up to — but not including — "
599 "the first null character. If this is successful, please set a new "
600 "passphrase to avoid this issue in the future.");
601 }
else if (passphrase.empty()) {
602 message =
_(
"Error: The wallet passphrase was not provided");
604 message =
_(
"Error: The wallet passphrase entered was incorrect.");
620 if (
Unlock(plain_master_key)) {
652 if (!
DecryptMasterKey(strOldWalletPassphrase, master_key, plain_master_key)) {
655 if (
Unlock(plain_master_key))
657 if (fWasLocked)
Lock();
659 if (!
EncryptMasterKey(strNewWalletPassphrase, plain_master_key, new_master_key)) {
665 WalletLogPrintf(
"Wallet passphrase changed to an nDeriveIterations of %i\n", new_master_key.nDeriveIterations);
666 master_key = std::move(new_master_key);
679 m_last_block_processed = block_hash;
680 m_last_block_processed_height = block_height;
693 std::set<Txid> result;
696 const auto it = mapWallet.find(txid);
697 if (it == mapWallet.end())
701 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
705 if (mapTxSpends.count(txin.prevout) <= 1)
707 range = mapTxSpends.equal_range(txin.prevout);
708 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
709 result.insert(_it->second);
717 const Txid& txid = tx->GetHash();
718 for (
unsigned int i = 0; i < tx->vout.size(); ++i) {
734 std::set<CWalletTx*, WalletTxOrderComparator> txs;
740 if (std::ranges::none_of(wtx.
GetTx()->vin, [](
const CTxIn& in) { return in.scriptWitness.IsNull(); })) {
745 bool found_self =
false;
746 const auto [begin, end] = mapTxSpends.equal_range(wtx.
GetTx()->vin.front().prevout);
747 for (
auto it = begin; it != end; ++it) {
748 auto entry = mapWallet.find(it->second);
749 if (!
Assume(entry != mapWallet.end()))
continue;
750 const bool is_self = &entry->second == &wtx;
751 found_self |= is_self;
753 Assume(txs.insert(&entry->second).second);
764 if (txs.size() <= 1)
return;
767 const CWalletTx* copyFrom = *txs.begin();
771 const auto metadata = [](
auto& tx) {
772 return std::tie(tx.m_from, tx.m_message, tx.m_comment, tx.m_comment_to,
773 tx.m_replaces_txid, tx.m_replaced_by_txid,
774 tx.m_messages, tx.m_payment_requests, tx.nTimeSmart);
779 if (copyTo == copyFrom)
continue;
780 metadata(*copyTo) = metadata(*copyFrom);
791 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
792 range = mapTxSpends.equal_range(outpoint);
794 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
795 const Txid& txid = it->second;
796 const auto mit = mapWallet.find(txid);
797 if (mit != mapWallet.end()) {
798 const auto& wtx = mit->second;
799 if (!wtx.isAbandoned() && !wtx.isBlockConflicted() && !wtx.isMempoolConflicted())
810 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
811 range = mapTxSpends.equal_range(outpoint);
813 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
814 const Txid& txid = it->second;
815 const auto mit = mapWallet.find(txid);
816 if (mit != mapWallet.end()) {
817 const auto& wtx = mit->second;
819 if (wtx.InMempool()) {
821 }
else if (!wtx.isAbandoned() && !wtx.isBlockConflicted() && !wtx.isMempoolConflicted()) {
831 mapTxSpends.insert(std::make_pair(outpoint, txid));
877 if (!spk_man_pair.second->Encrypt(plain_master_key, &batch)) {
890 if (!
Unlock(strWalletPassphrase)) {
916 typedef std::multimap<int64_t, CWalletTx*>
TxItems;
919 for (
auto& entry : mapWallet)
926 std::vector<int64_t> nOrderPosOffsets;
927 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
934 nOrderPos = nOrderPosNext++;
935 nOrderPosOffsets.push_back(nOrderPos);
942 int64_t nOrderPosOff = 0;
943 for (
const int64_t& nOffsetStart : nOrderPosOffsets)
945 if (nOrderPos >= nOffsetStart)
948 nOrderPos += nOrderPosOff;
949 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
967 int64_t nRet = nOrderPosNext++;
980 for (
auto& [
_, wtx] : mapWallet)
989 auto mi = mapWallet.find(originalHash);
992 assert(mi != mapWallet.end());
1006 bool success =
true;
1015 if (variant == &wtx)
continue;
1016 variant->m_replaced_by_txid = newHash;
1018 WalletLogPrintf(
"%s: Updating variant tx %s failed\n", __func__, variant->GetHash().ToString());
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);
1104 fUpdated |= wtx.
Update(tx, state, batch, fUpdated);
1105 }
catch (
const std::ios_base::failure& e) {
1113 std::vector<CWalletTx*> txs{&wtx};
1117 while (!txs.empty()) {
1120 desc_tx->
m_state = inactive_state;
1125 for (
unsigned int i = 0; i < desc_tx->
GetTx()->vout.size(); ++i) {
1127 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(outpoint);
1128 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
1129 const auto wit = mapWallet.find(it->second);
1130 if (wit != mapWallet.end()) {
1131 txs.push_back(&wit->second);
1139 std::string status{
"no-change"};
1140 if (fInsertedNew || fUpdated) {
1141 status = fInsertedNew ? (fUpdated ?
"new, update" :
"new") :
"update";
1158 if (!strCmd.empty())
1163 ReplaceAll(strCmd,
"%b", conf->confirmed_block_hash.GetHex());
1187 const auto& ins = mapWallet.emplace(wtx_in.GetHash(), std::move(wtx_in));
1200 auto it = mapWallet.find(txin.prevout.hash);
1201 if (it != mapWallet.end()) {
1223 if (
auto* conf = std::get_if<TxStateConfirmed>(&state)) {
1225 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.
prevout);
1226 while (range.first != range.second) {
1227 if (range.first->second != tx.
GetHash()) {
1228 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);
1229 MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
1236 bool fExisted = mapWallet.contains(tx.
GetHash());
1248 for (
auto &dest : spk_man->MarkUnusedAddresses(txout.
scriptPubKey)) {
1250 if (!dest.internal.has_value()) {
1255 if (!dest.internal.has_value())
continue;
1269 TxState tx_state = std::visit([](
auto&&
s) ->
TxState {
return s; }, state);
1274 throw std::runtime_error(
"DB error adding transaction to wallet, write failed");
1293 for (
long unsigned int i = 0; i < parent_wtx.GetTx()->vout.size(); i++) {
1294 for (
auto range = mapTxSpends.equal_range(
COutPoint(parent_wtx.GetTx()->GetHash(), i)); range.first != range.second; range.first++) {
1295 const Txid& sibling_txid = range.first->second;
1297 if (sibling_txid == child_txid)
continue;
1299 return add_conflict ? (wtx.
mempool_conflicts.insert(child_txid).second ? TxUpdate::CHANGED : TxUpdate::UNCHANGED)
1300 : (wtx.
mempool_conflicts.erase(child_txid) ? TxUpdate::CHANGED : TxUpdate::UNCHANGED);
1308 for (
const CTxIn& txin : tx->vin) {
1310 if (it != mapWallet.end()) {
1311 it->second.MarkDirty();
1319 auto it = mapWallet.find(hashTx);
1320 assert(it != mapWallet.end());
1333 assert(!wtx.isConfirmed());
1334 assert(!wtx.InMempool());
1336 if (!wtx.isBlockConflicted() && !wtx.isAbandoned()) {
1362 if (m_last_block_processed_height < 0 || conflicting_height < 0) {
1365 int conflictconfirms = (m_last_block_processed_height - conflicting_height + 1) * -1;
1366 if (conflictconfirms >= 0)
1390 std::set<Txid> todo;
1391 std::set<Txid> done;
1393 todo.insert(tx_hash);
1395 while (!todo.empty()) {
1399 auto it = mapWallet.find(now);
1400 assert(it != mapWallet.end());
1403 TxUpdate update_state = try_updating_state(wtx);
1408 for (
unsigned int i = 0; i < wtx.
GetTx()->vout.size(); ++i) {
1409 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(
COutPoint(now, i));
1410 for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
1411 if (!done.contains(iter->second)) {
1412 todo.insert(iter->second);
1444 auto it = mapWallet.find(tx->GetHash());
1445 if (it != mapWallet.end()) {
1449 const Txid& txid = tx->GetHash();
1451 for (
const CTxIn& tx_in : tx->vin) {
1453 for (
auto range = mapTxSpends.equal_range(tx_in.
prevout); range.first != range.second; range.first++) {
1454 const Txid& spent_id = range.first->second;
1456 if (spent_id == txid)
continue;
1468 for (
const CTxIn& tx_in : tx->vin) {
1469 auto parent_it = mapWallet.find(tx_in.
prevout.
hash);
1470 if (parent_it != mapWallet.end()) {
1471 CWalletTx& parent_wtx = parent_it->second;
1485 auto it = mapWallet.find(tx->GetHash());
1486 if (it != mapWallet.end()) {
1519 const Txid& txid = tx->GetHash();
1521 for (
const CTxIn& tx_in : tx->vin) {
1525 for (
auto range = mapTxSpends.equal_range(tx_in.
prevout); range.first != range.second; range.first++) {
1526 const Txid& spent_id = range.first->second;
1539 for (
const CTxIn& tx_in : tx->vin) {
1540 auto parent_it = mapWallet.find(tx_in.
prevout.
hash);
1541 if (parent_it != mapWallet.end()) {
1542 CWalletTx& parent_wtx = parent_it->second;
1569 bool wallet_updated =
false;
1570 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1576 if (wallet_updated || block.
height % 144 == 0) {
1590 int disconnect_height = block.
height;
1592 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1598 for (
const CTxIn& tx_in : ptx->vin) {
1600 if (!mapTxSpends.contains(tx_in.
prevout))
continue;
1602 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(tx_in.
prevout);
1605 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) {
1606 CWalletTx& wtx = mapWallet.find(_it->second)->second;
1610 auto try_updating_state = [&](
CWalletTx& tx) {
1633void CWallet::BlockUntilSyncedToCurrentChain()
const {
1650 return txo->GetTxOut().nValue;
1675 for (
const auto& spkm : it->second) {
1676 res = res || spkm->IsMine(
script);
1701 if (outpoint.
n >= wtx->GetTx()->vout.size()) {
1704 return IsMine(wtx->GetTx()->vout[outpoint.
n]);
1723 throw std::runtime_error(std::string(__func__) +
": value out of range");
1731 bool result =
false;
1733 if (!spk_man->IsHDEnabled())
return false;
1745 if (spk_man && spk_man->CanGetAddresses(internal)) {
1763 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1777 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1812 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1826 if (time < birthtime) {
1832 std::string& err_string,
1847 const char* what{
""};
1848 switch (broadcast_method) {
1850 what =
"to mempool and for broadcast to peers";
1853 what =
"to mempool without broadcast";
1856 what =
"for private broadcast without adding to the mempool";
1880 result.erase(myHash);
1892 if (!
chain().isReadyToBroadcast())
return false;
1934 int submitted_tx_count = 0;
1941 std::set<CWalletTx*, WalletTxOrderComparator> to_submit;
1942 for (
auto& [txid, wtx] : mapWallet) {
1944 if (!wtx.isUnconfirmed())
continue;
1949 to_submit.insert(&wtx);
1952 for (
auto wtx : to_submit) {
1953 std::string unused_err_string;
1958 if (submitted_tx_count > 0) {
1959 WalletLogPrintf(
"%s: resubmit %u unconfirmed transactions\n", __func__, submitted_tx_count);
1968 if (!pwallet->ShouldResend())
continue;
1970 pwallet->SetNextResend();
1980 std::map<COutPoint, Coin> coins;
1981 for (
auto& input : tx.
vin) {
1982 const auto mi = mapWallet.find(input.prevout.hash);
1983 if(mi == mapWallet.end() || input.prevout.n >= mi->second.GetTx()->vout.size()) {
1988 coins[input.prevout] =
Coin(wtx.
GetTx()->vout[input.prevout.n], prev_height, wtx.
IsCoinBase());
1990 std::map<int, bilingual_str> input_errors;
2000 if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) {
2024 const auto it = mapWallet.find(txhash);
2025 if (it != mapWallet.end()) {
2036 return PSBTError::INVALID_TX;
2042 int n_signed_this_spkm = 0;
2043 const auto error{spk_man->FillPSBT(psbtx, txdata, options, &n_signed_this_spkm)};
2049 (*n_signed) += n_signed_this_spkm;
2057 for (
size_t i = 0; i < psbtx.
inputs.size(); ++i) {
2069 if (spk_man_pair.second->CanProvide(script_pub_key, sigdata)) {
2071 return spk_man_pair.second->SignMessage(message, pkhash, str_sig);
2081 return *change_type;
2090 bool any_wpkh{
false};
2092 bool any_pkh{
false};
2094 for (
const auto& recipient : vecSend) {
2095 if (std::get_if<WitnessV1Taproot>(&recipient.dest)) {
2097 }
else if (std::get_if<WitnessV0KeyHash>(&recipient.dest)) {
2099 }
else if (std::get_if<ScriptHash>(&recipient.dest)) {
2101 }
else if (std::get_if<PKHash>(&recipient.dest)) {
2107 if (has_bech32m_spkman && any_tr) {
2112 if (has_bech32_spkman && any_wpkh) {
2117 if (has_p2sh_segwit_spkman && any_sh) {
2123 if (has_legacy_spkman && any_pkh) {
2128 if (has_bech32m_spkman) {
2131 if (has_bech32_spkman) {
2140 std::optional<Txid> replaces_txid,
2141 std::optional<std::string> comment,
2142 std::optional<std::string> comment_to,
2143 const std::vector<std::string>&
messages,
2144 const std::vector<std::string>& payment_requests
2163 throw std::runtime_error(std::string(__func__) +
": Wallet db error, transaction commit failed");
2167 for (
const CTxIn& txin : tx->vin) {
2178 std::string err_string;
2180 WalletLogPrintf(
"CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
2198 const auto wallet_file =
m_database->Filename();
2199 switch (nLoadWalletRet) {
2203 warnings.push_back(
strprintf(
_(
"Error reading %s! All keys read correctly, but transaction data"
2204 " or address metadata may be missing or incorrect."),
2208 warnings.push_back(
strprintf(
_(
"Error reading %s! Transaction data may be missing or incorrect."
2209 " Rescanning wallet."), wallet_file));
2212 error =
strprintf(
_(
"Error loading %s: Wallet corrupted"), wallet_file);
2215 error =
strprintf(
_(
"Error loading %s: Wallet requires newer version of %s"), wallet_file, CLIENT_NAME);
2218 error =
strprintf(
_(
"Error loading %s: External signer wallet being loaded without external signer support compiled"), wallet_file);
2221 error =
strprintf(
_(
"Unrecognized descriptor found. Loading wallet %s\n\n"
2222 "The wallet might have been created on a newer version.\n"
2223 "Please try running the latest software version.\n"), wallet_file);
2226 error =
strprintf(
_(
"Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
2227 "The wallet might have been tampered with or created with malicious intent.\n"), wallet_file);
2230 error =
strprintf(
_(
"Error loading %s: Wallet is a legacy wallet. Please migrate to a descriptor wallet using the migration tool (migratewallet RPC)."), wallet_file);
2233 error =
strprintf(
_(
"Error loading %s"), wallet_file);
2236 return nLoadWalletRet;
2246 return result.has_value();
2249 if (!was_txn_committed)
return util::Error{
_(
"Error starting/committing db txn for wallet transactions removal process")};
2259 std::vector<
decltype(mapWallet)::const_iterator> erased_txs;
2261 for (
const Txid& hash : txs_to_remove) {
2262 auto it_wtx = mapWallet.find(hash);
2263 if (it_wtx == mapWallet.end()) {
2269 erased_txs.emplace_back(it_wtx);
2275 for (
const auto& it : erased_txs) {
2276 const Txid hash{it->first};
2277 wtxOrdered.erase(it->second.m_it_wtxOrdered);
2278 for (
const auto& txin : it->second.GetTx()->vin) {
2279 auto range = mapTxSpends.equal_range(txin.prevout);
2280 for (
auto iter = range.first; iter != range.second; ++iter) {
2281 if (iter->second == hash) {
2282 mapTxSpends.erase(iter);
2287 for (
unsigned int i = 0; i < it->second.GetTx()->vout.size(); ++i) {
2290 mapWallet.erase(it);
2302 bool fUpdated =
false;
2304 std::optional<AddressPurpose> purpose;
2307 std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
2308 fUpdated = mi != m_address_book.end() && !mi->second.IsChange();
2310 CAddressBookData& record = mi != m_address_book.end() ? mi->second : m_address_book[address];
2312 is_mine =
IsMine(address);
2321 WalletLogPrintf(
"Error: fail to write address book 'purpose' entry\n");
2324 if (!batch.
WriteName(encoded_dest, strName)) {
2358 WalletLogPrintf(
"%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, CLIENT_BUGREPORT);
2380 m_address_book.erase(address);
2392 unsigned int count = 0;
2394 count += spk_man.second->GetKeyPoolSize();
2404 unsigned int count = 0;
2406 count += spk_man->GetKeyPoolSize();
2416 res &= spk_man->TopUp(kpSize);
2429 auto op_dest = spk_man->GetNewDestination(type);
2449 for (
auto& entry : mapWallet) {
2452 for (
unsigned int i = 0; i < wtx.
GetTx()->vout.size(); i++) {
2465 for (
const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book) {
2466 const auto& entry = item.second;
2467 func(item.first, entry.GetLabel(), entry.IsChange(), entry.purpose);
2474 std::vector<CTxDestination> result;
2482 result.emplace_back(dest);
2490 std::set<std::string> label_set;
2492 bool _is_change,
const std::optional<AddressPurpose>& _purpose) {
2493 if (_is_change)
return;
2494 if (!purpose || purpose == _purpose) {
2495 label_set.insert(_label);
2511 if (!op_address)
return op_address;
2541 if (signer_spk_man ==
nullptr) {
2546 return signer_spk_man->DisplayAddress(dest, *
signer);
2548 return util::Error{
_(
"There is no ScriptPubKeyManager for this address")};
2554 m_locked_coins.emplace(coin, persistent);
2571 auto locked_coin_it = m_locked_coins.find(output);
2572 if (locked_coin_it != m_locked_coins.end()) {
2573 bool persisted = locked_coin_it->second;
2574 m_locked_coins.erase(locked_coin_it);
2586 bool success =
true;
2588 for (
const auto& [coin, persistent] : m_locked_coins) {
2591 m_locked_coins.clear();
2598 return m_locked_coins.contains(output);
2604 for (
const auto& [coin,
_] : m_locked_coins) {
2605 vOutpts.push_back(coin);
2634 std::optional<uint256> block_hash;
2636 block_hash = conf->confirmed_block_hash;
2638 block_hash = conf->conflicting_block_hash;
2644 int64_t block_max_time;
2645 if (
chain().findBlock(*block_hash,
FoundBlock().time(blocktime).maxTime(block_max_time))) {
2646 if (rescanning_old_block) {
2647 nTimeSmart = block_max_time;
2650 int64_t latestEntry = 0;
2653 int64_t latestTolerated = latestNow + 300;
2655 for (
auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
2665 if (nSmartTime <= latestTolerated) {
2666 latestEntry = nSmartTime;
2667 if (nSmartTime > latestNow) {
2668 latestNow = nSmartTime;
2674 nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
2685 if (std::get_if<CNoDestination>(&dest))
2699 m_address_book[dest].previously_spent =
true;
2704 m_address_book[dest].receive_requests[id] = request;
2715 std::vector<std::string>
values;
2716 for (
const auto& [dest, entry] : m_address_book) {
2717 for (
const auto& [
id, request] : entry.receive_requests) {
2718 values.emplace_back(request);
2727 m_address_book[dest].receive_requests[id] = value;
2734 m_address_book[dest].receive_requests.erase(
id);
2743 if (name_path != name_path.lexically_normal()) {
2749 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.")};
2753 if (name_path.has_root_path() && name_path.root_path() == name_path) {
2764 fs::file_type path_type = fs::symlink_status(wallet_path).type();
2765 if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory ||
2766 (path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) ||
2767 (path_type == fs::file_type::regular && name_path.filename() == name_path))) {
2769 "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
2770 "database/log.?????????? files can be stored, a location where such a directory could be created, "
2771 "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
2785 return MakeDatabase(*wallet_path, options, status, error_string);
2793 if (!
args.
GetArg(
"-addresstype",
"").empty()) {
2799 wallet->m_default_address_type = parsed.value();
2802 if (!
args.
GetArg(
"-changetype",
"").empty()) {
2808 wallet->m_default_change_type = parsed.value();
2811 if (
const auto arg{
args.
GetArg(
"-mintxfee")}) {
2812 std::optional<CAmount> min_tx_fee =
ParseMoney(*arg);
2818 _(
"This is the minimum transaction fee you pay on every transaction."));
2824 if (
const auto arg{
args.
GetArg(
"-maxapsfee")}) {
2825 const std::string& max_aps_fee_str{*arg};
2826 if (max_aps_fee_str ==
"-1") {
2827 wallet->m_max_aps_fee = -1;
2828 }
else if (std::optional<CAmount> max_aps_fee =
ParseMoney(max_aps_fee_str)) {
2831 _(
"This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
2833 wallet->m_max_aps_fee = max_aps_fee.value();
2840 if (
const auto arg{
args.
GetArg(
"-fallbackfee")}) {
2841 std::optional<CAmount> fallback_fee =
ParseMoney(*arg);
2842 if (!fallback_fee) {
2843 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s'"),
"-fallbackfee", *arg);
2847 _(
"This is the transaction fee you may pay when fee estimates are not available."));
2853 wallet->m_allow_fallback_fee =
wallet->m_fallback_fee.GetFeePerK() != 0;
2855 if (
const auto arg{
args.
GetArg(
"-discardfee")}) {
2856 std::optional<CAmount> discard_fee =
ParseMoney(*arg);
2858 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s'"),
"-discardfee", *arg);
2862 _(
"This is the transaction fee you may discard if change is smaller than dust at this level"));
2867 if (
const auto arg{
args.
GetArg(
"-maxtxfee")}) {
2868 std::optional<CAmount> max_tx_fee =
ParseMoney(*arg);
2873 warnings.push_back(
strprintf(
_(
"%s is set very high! Fees this large could be paid on a single transaction."),
"-maxtxfee"));
2875 const CFeeRate max_txfee{max_tx_fee.value(), 1000};
2876 if (
chain && max_txfee < chain->relayMinFee()) {
2882 warnings.push_back(
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' conflicts with the minimum relay transaction feerate %s. Please set a higher %s or lower %s"),
2886 wallet->m_max_tx_fee = max_tx_fee.value();
2889 if (
const auto arg{
args.
GetArg(
"-maxfeerate")}) {
2890 std::optional<CAmount> max_tx_fee_rate =
ParseMoney(*arg);
2891 if (!max_tx_fee_rate) {
2896 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
2901 warnings.push_back(
strprintf(
_(
"%s is set very high! Fee rate this large could be paid on a single transaction."),
"-maxfeerate"));
2907 if (
const auto arg{
args.
GetArg(
"-consolidatefeerate")}) {
2908 if (std::optional<CAmount> consolidate_feerate =
ParseMoney(*arg)) {
2918 _(
"The wallet will avoid paying less than the minimum relay fee."));
2925 warnings.push_back(
_(
"-walletrbf is deprecated and will be fully removed in the next release."));
2926 wallet->m_signal_rbf = *value;
2939 const std::string& walletFile = database->Filename();
2941 const auto start{SteadyClock::now()};
2954 error =
strprintf(
_(
"Error creating %s: Could not write version metadata."), walletFile);
2958 error =
strprintf(
_(
"Error creating %s: Could not write features metadata."), walletFile);
2963 LOCK(walletInstance->cs_wallet);
2973 if (!born_encrypted) {
2974 walletInstance->SetupWalletGeneration();
2980 walletInstance->SetLastBlockProcessed(*tip_height,
chain->
getBlockHash(*tip_height));
2985 walletInstance->WalletLogPrintf(
"Wallet completed creation in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
2988 walletInstance->TopUpKeyPool();
2991 walletInstance->DisconnectChainNotifications();
2995 return walletInstance;
3001 const std::string& walletFile = database->Filename();
3003 const auto start{SteadyClock::now()};
3011 auto nLoadWalletRet = walletInstance->PopulateWalletFromDB(error, warnings);
3018 for (
auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
3019 if (spk_man->HavePrivateKeys()) {
3020 warnings.push_back(
strprintf(
_(
"Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
3026 walletInstance->WalletLogPrintf(
"Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
3029 walletInstance->TopUpKeyPool();
3032 walletInstance->DisconnectChainNotifications();
3036 WITH_LOCK(walletInstance->cs_wallet, walletInstance->LogStats());
3038 return walletInstance;
3044 LOCK(walletInstance->cs_wallet);
3046 assert(!walletInstance->m_chain || walletInstance->m_chain == &
chain);
3047 walletInstance->m_chain = &
chain;
3057 error =
Untranslated(
"Wallet files should not be reused across chains. Restart bitcoind with -walletcrosschain to override.");
3069 walletInstance->m_chain_notifications_handler = walletInstance->chain().handleNotifications(walletInstance);
3072 int rescan_height = 0;
3073 if (!rescan_required)
3079 rescan_height = *fork_height;
3086 walletInstance->SetLastBlockProcessedInMem(*tip_height,
chain.
getBlockHash(*tip_height));
3088 walletInstance->SetLastBlockProcessedInMem(-1,
uint256());
3091 if (tip_height && *tip_height != rescan_height)
3095 std::optional<int64_t> time_first_key = walletInstance->m_birth_time.load();
3096 if (time_first_key) {
3103 rescan_height = *tip_height;
3111 int block_height = *tip_height;
3112 while (block_height > 0 &&
chain.
haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
3116 if (rescan_height != block_height) {
3127 _(
"Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of a pruned node)") :
3129 "Error loading wallet. Wallet requires blocks to be downloaded, "
3130 "and software does not currently support loading wallets while "
3131 "blocks are being downloaded out of order when using assumeutxo "
3132 "snapshots. Wallet should be able to load successfully after "
3133 "node sync reaches height %s"), block_height);
3139 walletInstance->WalletLogPrintf(
"Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
3144 error =
_(
"Failed to acquire rescan reserver during wallet initialization");
3149 error =
_(
"Failed to rescan the wallet during initialization");
3164 const auto& address_book_it = m_address_book.find(dest);
3165 if (address_book_it == m_address_book.end())
return nullptr;
3166 if ((!allow_change) && address_book_it->second.IsChange()) {
3169 return &address_book_it->second;
3192 assert(conf->confirmed_block_height >= 0);
3195 assert(conf->conflicting_block_height >= 0);
3210 assert(chain_depth >= 0);
3228 return vMasterKey.empty();
3238 if (!vMasterKey.empty()) {
3239 memory_cleanse(vMasterKey.data(), vMasterKey.size() *
sizeof(
decltype(vMasterKey)::value_type));
3253 if (!spk_man_pair.second->CheckDecryptionKey(vMasterKeyIn)) {
3257 vMasterKey = vMasterKeyIn;
3265 std::set<ScriptPubKeyMan*> spk_mans;
3266 for (
bool internal : {
false,
true}) {
3270 spk_mans.insert(spk_man);
3280 if (ext_spkm == &spkm)
return true;
3283 if (int_spkm == &spkm)
return true;
3290 std::set<ScriptPubKeyMan*> spk_mans;
3292 spk_mans.insert(spk_man_pair.second.get());
3300 std::map<OutputType, ScriptPubKeyMan*>::const_iterator it = spk_managers.find(type);
3301 if (it == spk_managers.end()) {
3309 std::set<ScriptPubKeyMan*> spk_mans;
3314 spk_mans.insert(it->second.begin(), it->second.end());
3317 Assume(std::all_of(spk_mans.begin(), spk_mans.end(), [&
script, &sigdata](
ScriptPubKeyMan* spkm) { return spkm->CanProvide(script, sigdata); }));
3343 return it->second.at(0)->GetSolvingProvider(
script);
3351 std::vector<WalletDescriptor> descs;
3354 LOCK(desc_spk_man->cs_desc_man);
3355 descs.push_back(desc_spk_man->GetWalletDescriptor());
3394 std::unique_ptr<ScriptPubKeyMan> spk_manager = std::make_unique<LegacyDataSPKM>(*
this);
3400 uint256 id = spk_manager->GetID();
3407 return cb(vMasterKey);
3418 if (spkm->HaveCryptedKeys())
return true;
3426 spk_man->NotifyCanGetAddressesChanged.connect([
this] {
3429 spk_man->NotifyFirstKeyTimeChanged.connect([
this](
const ScriptPubKeyMan*, int64_t time) {
3437 std::unique_ptr<DescriptorScriptPubKeyMan> spk_manager;
3450 throw std::runtime_error(std::string(__func__) +
": Wallet is locked, cannot setup new descriptors");
3454 uint256 id = spk_manager->GetID();
3463 for (
bool internal : {
false,
true}) {
3494 }))
throw std::runtime_error(
"Error: cannot process db transaction for descriptors setup");
3503 if (!signer_res.
isObject())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3506 if (!batch.
TxnBegin())
throw std::runtime_error(
"Error: cannot create db transaction for descriptors import");
3508 for (
bool internal : {
false,
true}) {
3509 const UniValue& descriptor_vals = signer_res.
find_value(internal ?
"internal" :
"receive");
3510 if (!descriptor_vals.
isArray())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3512 const std::string& desc_str = desc_val.getValStr();
3514 std::string desc_error;
3515 auto descs =
Parse(desc_str,
keys, desc_error,
false);
3516 if (descs.empty()) {
3517 throw std::runtime_error(std::string(__func__) +
": Invalid descriptor \"" + desc_str +
"\" (" + desc_error +
")");
3519 auto& desc = descs.at(0);
3520 if (!desc->GetOutputType()) {
3525 uint256 id = spk_manager->GetID();
3532 if (!batch.
TxnCommit())
throw std::runtime_error(
"Error: cannot commit db transaction for descriptors import");
3557 throw std::runtime_error(std::string(__func__) +
": writing active ScriptPubKeyMan id failed");
3572 spk_mans[type] = spk_man;
3574 const auto it = spk_mans_other.find(type);
3575 if (it != spk_mans_other.end() && it->second == spk_man) {
3576 spk_mans_other.erase(type);
3585 if (spk_man !=
nullptr && spk_man->GetID() ==
id) {
3589 throw std::runtime_error(std::string(__func__) +
": erasing active ScriptPubKeyMan id failed");
3593 spk_mans.erase(type);
3602 DescriptorScriptPubKeyMan* spk_manager = dynamic_cast<DescriptorScriptPubKeyMan*>(item.second.get());
3603 return spk_manager != nullptr && spk_manager->HasWalletDescriptor(desc);
3617 return std::nullopt;
3621 if (!desc_spk_man) {
3622 throw std::runtime_error(std::string(__func__) +
": unexpected ScriptPubKeyMan type.");
3625 LOCK(desc_spk_man->cs_desc_man);
3626 const auto& type = desc_spk_man->GetWalletDescriptor().descriptor->GetOutputType();
3627 assert(type.has_value());
3641 if (
auto spkm_res = spk_man->UpdateWalletDescriptor(desc, signing_provider); !spkm_res) {
3646 spk_man = new_spk_man.get();
3649 uint256 id = new_spk_man->GetID();
3655 return util::Error{
_(
"Unable to write descriptor cache")};
3662 auto script_pub_keys = spk_man->GetScriptPubKeys();
3663 if (script_pub_keys.empty()) {
3664 return util::Error{
_(
"Could not generate scriptPubKeys (cache is empty)")};
3668 for (
const auto&
script : script_pub_keys) {
3678 spk_man->WriteDescriptor();
3683 return std::reference_wrapper(*spk_man);
3690 if (key && !key->key.IsValid()) {
3693 _(
"Invalid HD key"),
3700 _(
"addhdkey is not available for wallets without private keys")
3707 _(
"Wallet needs to be unlocked to perform this operation.")
3719 std::string desc_str =
"unused(" +
EncodeExtKey(hdkey) +
")";
3721 std::string parse_error;
3722 std::vector<std::unique_ptr<Descriptor>> descs =
Parse(desc_str,
keys, parse_error,
false);
3723 if (descs.empty()) {
3734 _(
"HD key already exists")
3748 std::set<CPubKey> pubkeys;
3749 std::set<CExtPubKey> extpubs;
3752 Assume(extpubs.size() == 1);
3754 return *extpubs.begin();
3761 WalletLogPrintf(
"Migrating wallet storage database from BerkeleyDB to SQLite.\n");
3764 error =
_(
"Error: This wallet already uses SQLite");
3769 std::unique_ptr<DatabaseBatch> batch =
m_database->MakeBatch();
3770 std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor();
3771 std::vector<std::pair<SerializeData, SerializeData>> records;
3773 error =
_(
"Error: Unable to begin reading all records in the database");
3780 status = cursor->Next(ss_key, ss_value);
3786 records.emplace_back(key, value);
3791 error =
_(
"Error: Unable to read all records in the database");
3798 fs::remove(db_path);
3809 std::unique_ptr<WalletDatabase> new_db =
MakeDatabase(wallet_path, opts, db_status, error);
3816 bool began = batch->TxnBegin();
3818 for (
const auto& [key, value] : records) {
3819 if (!batch->Write(std::span{key}, std::span{value})) {
3826 bool committed = batch->TxnCommit();
3836 if (!
Assume(legacy_spkm)) {
3839 return std::nullopt;
3843 if (res == std::nullopt) {
3844 error =
_(
"Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
3845 return std::nullopt;
3855 if (!
Assume(legacy_spkm)) {
3861 bool has_spendable_material = !
data.desc_spkms.empty() ||
data.master_key.key.IsValid();
3864 std::set<CTxDestination> not_migrated_dests;
3873 if (!
data.watch_descs.empty())
Assume(!
data.watchonly_wallet->m_cached_spks.empty());
3874 if (!
data.solvable_descs.empty())
Assume(!
data.solvable_wallet->m_cached_spks.empty());
3876 for (
auto& desc_spkm :
data.desc_spkms) {
3878 return util::Error{
_(
"Error: Duplicate descriptors created during migration. Your wallet may be corrupted.")};
3880 uint256 id = desc_spkm->GetID();
3886 return util::Error{
_(
"Error: cannot remove legacy wallet records")};
3898 if (
data.master_key.key.IsValid()) {
3908 return util::Error{
_(
"Error: Unable to write last opened version")};
3911 return util::Error{
_(
"Error: Unable to write last opened features")};
3915 return util::Error{
_(
"Error: Unable to write last decrypted features")};
3930 std::vector<Txid> txids_to_delete;
3931 std::unique_ptr<WalletBatch> watchonly_batch;
3932 if (
data.watchonly_wallet) {
3933 watchonly_batch = std::make_unique<WalletBatch>(
data.watchonly_wallet->GetDatabase());
3934 if (!watchonly_batch->TxnBegin())
return util::Error{
strprintf(
_(
"Error: database transaction cannot be executed for wallet %s"),
data.watchonly_wallet->GetName())};
3936 LOCK(
data.watchonly_wallet->cs_wallet);
3937 data.watchonly_wallet->nOrderPosNext = nOrderPosNext;
3938 watchonly_batch->WriteOrderPosNext(
data.watchonly_wallet->nOrderPosNext);
3940 if (!watchonly_batch->WriteBestBlock(best_block_locator)) {
3941 return util::Error{
_(
"Error: Unable to write watchonly wallet best block locator record")};
3944 std::unique_ptr<WalletBatch> solvables_batch;
3945 if (
data.solvable_wallet) {
3946 solvables_batch = std::make_unique<WalletBatch>(
data.solvable_wallet->GetDatabase());
3947 if (!solvables_batch->TxnBegin())
return util::Error{
strprintf(
_(
"Error: database transaction cannot be executed for wallet %s"),
data.solvable_wallet->GetName())};
3949 if (!solvables_batch->WriteBestBlock(best_block_locator)) {
3950 return util::Error{
_(
"Error: Unable to write solvable wallet best block locator record")};
3957 if (
data.watchonly_wallet) {
3958 LOCK(
data.watchonly_wallet->cs_wallet);
3959 if (
data.watchonly_wallet->IsMine(*wtx->GetTx()) ||
data.watchonly_wallet->IsFromMe(*wtx->GetTx())) {
3961 const Txid& hash = wtx->GetHash();
3965 if (!
data.watchonly_wallet->LoadToWallet(std::move(copy_wtx))) {
3966 return util::Error{
strprintf(
_(
"Error: Could not add watchonly tx %s to watchonly wallet"), wtx->GetHash().GetHex())};
3968 watchonly_batch->WriteFullTx(
data.watchonly_wallet->mapWallet.at(hash));
3971 txids_to_delete.push_back(hash);
3978 return util::Error{
strprintf(
_(
"Error: Transaction %s in wallet cannot be identified to belong to migrated wallets"), wtx->GetHash().GetHex())};
3985 if (txids_to_delete.size() > 0) {
3986 if (
auto res =
RemoveTxs(local_wallet_batch, txids_to_delete); !res) {
3992 std::vector<std::pair<std::shared_ptr<CWallet>, std::unique_ptr<WalletBatch>>> wallets_vec;
3993 if (
data.watchonly_wallet) wallets_vec.emplace_back(
data.watchonly_wallet, std::move(watchonly_batch));
3994 if (
data.solvable_wallet) wallets_vec.emplace_back(
data.solvable_wallet, std::move(solvables_batch));
4000 if (entry.label) batch.
WriteName(address, *entry.label);
4001 for (
const auto& [
id, request] : entry.receive_requests) {
4008 std::vector<CTxDestination> dests_to_delete;
4009 for (
const auto& [dest, record] : m_address_book) {
4013 bool copied =
false;
4014 for (
auto& [
wallet, batch] : wallets_vec) {
4016 if (require_transfer && !
wallet->IsMine(dest))
continue;
4019 wallet->m_address_book[dest] = record;
4020 func_store_addr(*batch, dest, record);
4024 if (require_transfer) {
4025 dests_to_delete.push_back(dest);
4033 if (require_transfer && !copied) {
4036 if (not_migrated_dests.contains(dest)) {
4037 dests_to_delete.push_back(dest);
4041 return util::Error{
_(
"Error: Address book data in wallet cannot be identified to belong to migrated wallets")};
4046 for (
auto& [
wallet, batch] : wallets_vec) {
4053 if (dests_to_delete.size() > 0) {
4054 for (
const auto& dest : dests_to_delete) {
4056 return util::Error{
_(
"Error: Unable to remove watchonly address book data")};
4064 if (!has_spendable_material) {
4065 if (!m_address_book.empty())
return util::Error{
_(
"Error: Not all address book records were migrated")};
4066 if (!mapWallet.empty())
return util::Error{
_(
"Error: Not all transaction records were migrated")};
4083 return name.empty() ?
"default_wallet" :
name;
4091 std::optional<MigrationData>
data =
wallet.GetDescriptorsForLegacy(error);
4092 if (
data == std::nullopt)
return false;
4095 if (
data->watch_descs.size() > 0 ||
data->solvable_descs.size() > 0) {
4112 if (
data->watch_descs.size() > 0) {
4113 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the watched scripts\n");
4116 std::vector<bilingual_str> warnings;
4118 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4120 error =
strprintf(
_(
"Wallet file creation failed: %s"), error);
4125 if (!
data->watchonly_wallet) {
4126 error =
_(
"Error: Failed to create new watchonly wallet");
4130 LOCK(
data->watchonly_wallet->cs_wallet);
4133 for (
const auto& [desc_str, creation_time] :
data->watch_descs) {
4136 std::string parse_err;
4137 std::vector<std::unique_ptr<Descriptor>> descs =
Parse(desc_str,
keys, parse_err,
true);
4139 assert(descs.size() == 1);
4140 assert(!descs.at(0)->IsRange());
4144 if (
auto spkm_res =
data->watchonly_wallet->AddWalletDescriptor(w_desc,
keys,
"",
false); !spkm_res) {
4152 if (
data->solvable_descs.size() > 0) {
4153 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the unwatched solvable scripts\n");
4156 std::vector<bilingual_str> warnings;
4158 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4160 error =
strprintf(
_(
"Wallet file creation failed: %s"), error);
4165 if (!
data->solvable_wallet) {
4166 error =
_(
"Error: Failed to create new watchonly wallet");
4170 LOCK(
data->solvable_wallet->cs_wallet);
4173 for (
const auto& [desc_str, creation_time] :
data->solvable_descs) {
4176 std::string parse_err;
4177 std::vector<std::unique_ptr<Descriptor>> descs =
Parse(desc_str,
keys, parse_err,
true);
4179 assert(descs.size() == 1);
4180 assert(!descs.at(0)->IsRange());
4184 if (
auto spkm_res =
data->solvable_wallet->AddWalletDescriptor(w_desc,
keys,
"",
false); !spkm_res) {
4196 if (auto res_migration = wallet.ApplyMigrationData(batch, *data); !res_migration) {
4197 error = util::ErrorString(res_migration);
4200 wallet.WalletLogPrintf(
"Wallet migration complete.\n");
4207 std::vector<bilingual_str> warnings;
4213 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4224 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4236 std::unique_ptr<WalletDatabase> database =
MakeWalletDatabase(wallet_name, options, status, error);
4242 std::shared_ptr<CWallet> local_wallet = CWallet::LoadExisting(empty_context, wallet_name, std::move(database), error, warnings);
4243 if (!local_wallet) {
4254 std::vector<bilingual_str> warnings;
4260 const std::string wallet_name = local_wallet->GetName();
4264 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4273 const std::string backup_prefix = wallet_name.empty() ?
MigrationPrefixName(*local_wallet) : [&] {
4282 return util::Error{
_(
"Error: Unable to make a backup of your wallet")};
4286 bool success =
false;
4289 if (local_wallet->IsLocked()) {
4290 if (
auto unlocked{local_wallet->Unlock(passphrase)}; !unlocked)
return util::Error{unlocked.error().
message};
4299 bool empty_local_wallet =
false;
4302 LOCK(local_wallet->cs_wallet);
4304 if (!local_wallet->MigrateToSQLite(error))
return util::Error{error};
4310 empty_local_wallet = local_wallet->GetAllScriptPubKeyMans().empty();
4322 std::set<fs::path> wallet_files_to_remove;
4323 std::set<fs::path> wallet_empty_dirs_to_remove;
4328 const auto files =
wallet.GetDatabase().Files();
4329 wallet_files_to_remove.insert(files.begin(), files.end());
4330 if (
wallet.GetName() != wallet_name) {
4343 if (empty_local_wallet) {
4345 std::vector<fs::path> paths_to_remove = local_wallet->GetDatabase().Files();
4346 local_wallet.reset();
4347 for (
const auto& path_to_remove : paths_to_remove) fs::remove(path_to_remove);
4351 LogInfo(
"Loading new wallets after migration...\n");
4358 bool main_wallet_set{
false};
4360 if (success && *wallet_ptr) {
4361 std::shared_ptr<CWallet>&
wallet = *wallet_ptr;
4363 track_for_cleanup(*
wallet);
4365 std::string wallet_name =
wallet->GetName();
4370 LogError(
"Failed to load wallet '%s' after migration. Rolling back migration to preserve consistency. "
4371 "Error cause: %s\n", wallet_name, error.
original);
4378 if (!main_wallet_set) {
4381 main_wallet_set =
true;
4393 std::vector<std::shared_ptr<CWallet>> created_wallets;
4394 if (local_wallet) created_wallets.push_back(std::move(local_wallet));
4399 for (std::shared_ptr<CWallet>&
wallet : created_wallets) {
4400 track_for_cleanup(*
wallet);
4404 for (std::shared_ptr<CWallet>& w : created_wallets) {
4405 if (w->HaveChain()) {
4408 error +=
_(
"\nUnable to cleanup failed migration");
4414 assert(w.use_count() == 1);
4420 for (
const fs::path& file : wallet_files_to_remove) {
4425 for (
const fs::path& dir : wallet_empty_dirs_to_remove) {
4426 Assume(fs::is_empty(dir));
4433 const auto& ptr_wallet =
RestoreWallet(
context, backup_path, wallet_name, std::nullopt, status, restore_error, warnings,
false,
true);
4434 if (!restore_error.
empty()) {
4435 error += restore_error +
_(
"\nUnable to restore backup of wallet.");
4448 for (
const auto&
script : spks) {
4449 m_cached_spks[
script].push_back(spkm);
4456 CacheNewScriptPubKeys(spks, spkm);
4466 for (
const auto& spkm : filter == HDKeyFilter::Active ? GetActiveScriptPubKeyMans() : GetAllScriptPubKeyMans()) {
4468 LOCK(desc_spkm->cs_desc_man);
4470 if (filter == HDKeyFilter::UnusedKey && w_desc.
descriptor->HasScripts())
continue;
4472 std::set<CPubKey> desc_pubkeys;
4473 std::set<CExtPubKey> desc_xpubs;
4474 w_desc.
descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
4476 xpubs[xpub].insert(desc_spkm);
4482std::optional<CKey> CWallet::GetKey(
const CKeyID& keyid)
const
4486 for (
const auto& spkm : GetAllScriptPubKeyMans()) {
4490 if (std::optional<CKey> key = desc_spkm->
GetKey(keyid)) {
4494 return std::nullopt;
4497std::optional<CExtKey> CWallet::GetExtKey(
const CExtPubKey& xpub)
const
4499 if (std::optional<CKey> key = GetKey(xpub.
pubkey.
GetID())) {
4502 return std::nullopt;
4505void CWallet::WriteBestBlock()
const
4509 if (!m_last_block_processed.IsNull()) {
4511 chain().findBlock(m_last_block_processed,
FoundBlock().locator(loc));
4523 for (uint32_t i = 0; i < wtx.
GetTx()->vout.size(); ++i) {
4525 if (!IsMine(txout))
continue;
4527 if (m_txos.contains(outpoint)) {
4529 m_txos.emplace(outpoint,
WalletTXO{wtx, txout});
4534void CWallet::RefreshAllTXOs()
4537 for (
const auto& [
_, wtx] : mapWallet) {
4538 RefreshTXOsFromTx(wtx);
4542std::optional<WalletTXO> CWallet::GetTXO(
const COutPoint& outpoint)
const
4545 const auto& it = m_txos.find(outpoint);
4546 if (it == m_txos.end()) {
4547 return std::nullopt;
4552void CWallet::DisconnectChainNotifications()
4554 if (m_chain_notifications_handler) {
4555 m_chain_notifications_handler->disconnect();
4556 chain().waitForNotifications();
4557 m_chain_notifications_handler.reset();
4561void CWallet::SetLastDecryptedFeatures(uint64_t features)
4564 m_last_decrypted_features = features;
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 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.
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
bool empty() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
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 bool broadcastTransaction(const CTransactionRef &tx, const CAmount &max_tx_fee, const CFeeRate &max_tx_fee_rate, 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 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 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 CFeeRate relayMinFee()=0
Relay current minimum fee (from -minrelaytxfee and -incrementalrelayfee settings).
Helper for findBlock to selectively return pieces of block data.
FoundBlock & height(int &height)
std::string ToString() const
constexpr const std::byte * begin() const
std::string GetHex() const
The util::Expected class provides a standard way for low-level functions to return either error value...
The util::Unexpected class represents an unexpected value stored in util::Expected.
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)
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.
btcsignals::signal< void()> NotifyUnload
Wallet is about to be unloaded.
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.
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.
std::unique_ptr< ChainScanner > m_scanner
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...
CAmount m_max_tx_fee
Absolute maximum transaction fee (in satoshis) used by the wallet.
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
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,...
util::Expected< CExtPubKey, WalletError > AddHDKey(const std::optional< CExtKey > &key)
Add an HD key to the wallet and return its master xpub.
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)
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().
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)
CFeeRate m_max_tx_fee_rate
Maximum transaction fee rate used for the wallet.
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.
void SetLastDecryptedFeatures(uint64_t features) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Set the features of the last client to decrypt this wallet.
A transaction with a bunch of additional info that only the owner cares about.
bool Update(CTransactionRef tx, const TxState &new_state, WalletBatch &batch, bool metadata_changed)
bool isBlockConflicted() const
std::vector< std::string > m_messages
const Txid & GetHash() const LIFETIMEBOUND
std::set< Txid > mempool_conflicts
std::optional< Txid > m_replaces_txid
void updateState(interfaces::Chain &chain)
Update transaction state when attaching to a chain, filling in heights of conflicted and confirmed bl...
std::optional< std::string > m_comment_to
int64_t nOrderPos
position in ordered transaction list
bool isUnconfirmed() const
std::optional< std::string > m_comment
unsigned int nTimeReceived
time received by this node
std::optional< Txid > m_replaced_by_txid
std::optional< Txid > truc_child_in_mempool
std::vector< std::string > m_payment_requests
int64_t GetTxTime() const
CTransactionRef GetTx() const
bool IsMalleation(const CWalletTx &tx) const
True if tx is a malleation of this, i.e.
bool m_is_cache_empty
This flag is true if all m_amounts caches are empty.
std::multimap< int64_t, CWalletTx * >::const_iterator m_it_wtxOrdered
unsigned int nTimeSmart
Stable timestamp that never changes, and reflects the order a transaction was added to the wallet.
void MarkDirty()
make sure balances are recalculated
void UpgradeDescriptorCache()
WalletDescriptor GetWalletDescriptor() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man)
std::optional< CKey > GetKey(const CKeyID &keyid) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man)
Retrieve the particular key if it is available. Returns nullopt if the key is not in the wallet,...
static std::unique_ptr< DescriptorScriptPubKeyMan > LoadFromStorage(WalletStorage &storage, const uint256 &id, WalletDescriptor &descriptor, int64_t keypool_size, const KeyMap &keys, const CryptedKeyMap &ckeys)
static std::unique_ptr< DescriptorScriptPubKeyMan > CreateFromImport(WalletStorage &storage, WalletDescriptor &descriptor, int64_t keypool_size, const FlatSigningProvider &provider)
RecursiveMutex cs_desc_man
static std::unique_ptr< DescriptorScriptPubKeyMan > GenerateNewSingleSig(WalletStorage &storage, WalletBatch &batch, int64_t keypool_size, const CExtKey &master_key, OutputType addr_type, bool internal)
static std::unique_ptr< ExternalSignerScriptPubKeyMan > CreateNew(WalletStorage &storage, WalletBatch &batch, int64_t keypool_size, std::unique_ptr< Descriptor > desc)
static std::unique_ptr< ExternalSignerScriptPubKeyMan > LoadFromStorage(WalletStorage &storage, const uint256 &id, WalletDescriptor &descriptor, int64_t keypool_size, const KeyMap &keys, const CryptedKeyMap &ckeys)
static util::Result< ExternalSigner > GetExternalSigner()
bool DeleteRecordsWithDB(WalletBatch &batch)
Delete the legacy wallet records from disk.
std::optional< MigrationData > MigrateToDescriptor()
Get the DescriptorScriptPubKeyMans (with private keys) that have the same scriptPubKeys as this Legac...
uint256 GetID() const override
std::unordered_set< CScript, SaltedSipHasher > GetNotMineScriptPubKeys() const
Retrieves scripts that were imported by bugs into the legacy spkm and are simply invalid,...
A wrapper to reserve an address from a wallet.
const CWallet *const pwallet
The wallet to reserve from.
void KeepDestination()
Keep the address. Do not return its key to the keypool when this object goes out of scope.
CTxDestination address
The destination.
bool fInternal
Whether this is from the internal (change output) keypool.
void ReturnDestination()
Return reserved address.
ScriptPubKeyMan * m_spk_man
The ScriptPubKeyMan to reserve from. Based on type when GetReservedDestination is called.
int64_t nIndex
The index of the address's key in the keypool.
util::Result< CTxDestination > GetReservedDestination(bool internal)
Reserve an address.
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 EraseName(const std::string &strAddress)
DBErrors LoadWallet(CWallet *pwallet)
bool WriteBestBlock(const CBlockLocator &locator)
bool ReadBestBlock(CBlockLocator &locator)
bool WriteLastOpenedVersion()
Write the current client version in the VERSION record.
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 WriteLastOpenedFeatures()
Write the current client features in the LAST_OPENED_FEATURES record.
bool EraseAddressData(const CTxDestination &dest)
bool WriteOrderPosNext(int64_t nOrderPosNext)
bool WriteFullTx(const CWalletTx &wtx)
bool ErasePurpose(const std::string &strAddress)
bool EraseLockedUTXO(const COutPoint &output)
bool WriteLastDecryptedFeatures()
Write the current wallet client features to the LAST_DECRYPTED_FEATURES record.
bool WriteTxMetadata(const CWalletTx &wtx)
void RegisterTxnListener(DbTxnListener l)
Registers db txn callback functions.
bool WriteLockedUTXO(const COutPoint &output)
bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256 &id, bool internal)
bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal)
bool WriteAddressReceiveRequest(const CTxDestination &dest, const std::string &id, const std::string &receive_request)
virtual void Close()=0
Flush to the database file and close the database.
virtual bool Backup(const std::string &strDest) const =0
Back up the entire database to a file.
virtual bool Rewrite()=0
Rewrite the entire database on disk.
Descriptor with some wallet metadata.
const std::shared_ptr< const Descriptor > descriptor
RAII object to check and reserve a wallet rescan.
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.
for(const auto &cache :caches)
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 AbandonTransaction(const Txid &hashTx)
void SetWalletFlagWithDB(WalletBatch &batch, uint64_t flags)
Store wallet flags.
static bool EncryptMasterKey(const SecureString &wallet_passphrase, const CKeyingMaterial &plain_master_key, CMasterKey &master_key)
uint64_t GetWalletFlags() const
Retrieve all of the wallet's flags.
void updatedBlockTip() override
bool TransactionCanBeAbandoned(const Txid &hashTx) const
Return whether transaction can be abandoned.
void SyncMalleatedTxMetadata(WalletBatch &batch, const CWalletTx &wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void BlockUntilSyncedToCurrentChain() const LOCKS_EXCLUDED(void SetWalletFlag(uint64_t flags)
Blocks until the wallet state is up-to-date to /at least/ the current chain at the time this function...
bool AddToWalletIfInvolvingMe(const CTransactionRef &tx, const SyncTxState &state, bool rescanning_old_block) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Add a transaction to the wallet, or update it.
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)
util::Expected< void, WalletError > ChangeWalletPassphrase(const SecureString &strOldWalletPassphrase, const SecureString &strNewWalletPassphrase)
static bool DecryptMasterKey(const SecureString &wallet_passphrase, const CMasterKey &master_key, CKeyingMaterial &plain_master_key)
void AddToSpends(const COutPoint &outpoint, const Txid &txid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void SetLastBlockProcessedInMem(int block_height, uint256 block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UnsetWalletFlagWithDB(WalletBatch &batch, uint64_t flag)
Unsets a wallet flag and saves it to disk.
bool IsSpent(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Outpoint is spent if any non-conflicted transaction spends it:
void ResubmitWalletTransactions(node::TxBroadcast broadcast_method, bool force)
std::set< Txid > GetTxConflicts(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UnsetBlankWalletFlag(WalletBatch &batch) override
Unset the blank wallet flag and saves it to disk.
CWalletTx * AddToWallet(CTransactionRef tx, const TxState &state, const UpdateWalletTxFn &update_wtx=nullptr, bool rescanning_old_block=false)
Add the transaction to the wallet, wrapping it up inside a CWalletTx.
bool MarkReplaced(const Txid &originalHash, const Txid &newHash)
Mark a transaction as replaced by another transaction.
bool CanGetAddresses(bool internal=false) const
bool LoadToWallet(CWalletTx &&wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UpdateTrucSiblingConflicts(const CWalletTx &parent_wtx, const Txid &child_txid, bool add_conflict) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Update mempool conflicts for TRUC sibling transactions.
bool LoadWalletFlags(uint64_t flags)
Loads the flags into the wallet.
bool SubmitTxMemoryPoolAndRelay(CWalletTx &wtx, std::string &err_string, node::TxBroadcast broadcast_method) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Pass this transaction to node for optional mempool insertion and relay to peers.
void blockConnected(const kernel::ChainstateRole &role, const interfaces::BlockInfo &block) override
void transactionRemovedFromMempool(const CTransactionRef &tx, MemPoolRemovalReason reason) override
static NodeClock::time_point GetDefaultNextResend()
bool ShouldResend() const
Return true if all conditions for periodically resending transactions are met.
bool SyncTransaction(const CTransactionRef &tx, const SyncTxState &state, bool rescanning_old_block=false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
const CWalletTx * GetWalletTx(const Txid &hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void InitWalletFlags(uint64_t flags)
overwrite all flags by the given uint64_t flags must be uninitialised (or 0) only known flags may be ...
void UnsetWalletFlag(uint64_t flag)
Unsets a single wallet flag.
std::set< CWalletTx *, WalletTxOrderComparator > GetMalleatedVariants(const CWalletTx &wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Collects all wallet txs that differ from wtx only in their scriptSigs (i.e.
bool EncryptWallet(const SecureString &strWalletPassphrase)
void SetLastBlockProcessed(int block_height, uint256 block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Set last block processed height, and write to database.
bool IsFromMe(const CTransaction &tx) const
should probably be renamed to IsRelevantToMe
DBErrors ReorderTransactions()
bool IsMine(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UpgradeDescriptorCache() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Upgrade DescriptorCaches.
void SetSpentKeyState(WalletBatch &batch, const Txid &hash, unsigned int n, bool used, std::set< CTxDestination > &tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
CAmount GetDebit(const CTxIn &txin) const
Returns amount of debit, i.e.
void MarkConflicted(const uint256 &hashBlock, int conflicting_height, const Txid &hashTx)
Mark a transaction (and its in-wallet descendants) as conflicting with a particular block.
void transactionAddedToMempool(const CTransactionRef &tx) override
void Close()
Close wallet database.
static util::Unexpected< WalletError > UnlockPassphraseError(const SecureString &passphrase)
@ 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 EncodeExtKey(const CExtKey &key)
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...
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 LIFETIMEBOUND, std::string_view suffix)
void ReplaceAll(std::string &in_out, std::string_view search, std::string_view substitute)
Replace every non-overlapping occurrence of search with substitute, treating both literally; the repl...
std::string ToString(const T &t)
Locale-independent version of std::to_string.
constexpr bool DEFAULT_WALLET_RBF
-walletrbf default
constexpr bool DEFAULT_WALLETCROSSCHAIN
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.
@ PassphraseIncorrect
The passphrase does not decrypt the wallet. Callers may ask the user to enter it again.
@ UnlockNeeded
The wallet is locked and the operation requires access to private keys.
@ GenericError
Generic wallet error.
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 CFeeRate HIGH_MAX_TX_FEERATE
A warning will be emitted if -maxfeerate is set higher than this fee rate (in satoshis per kB).
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
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
uint256 last_scanned_block
Hash and height of most recent block that was successfully scanned.
enum wallet::ScanResult::@19 status
std::optional< int > last_scanned_height
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
Wallet-layer error with both programmatic and user-facing information.
#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,...
std::shared_ptr< CWallet > wallet
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.