9#include <chainparams.h>
46 "You need to rescan the blockchain in order to correctly mark used "
47 "destinations in the past. Until this is done, some destinations may "
48 "be considered unused, even if the opposite is the case."},
56 const std::string &wallet_name) {
62 if (value.isStr() && value.get_str() == wallet_name) {
71 const std::string &wallet_name) {
78 if (!value.isStr() || value.get_str() != wallet_name) {
82 if (new_value.
size() == setting_value.
size()) {
89 const std::string &wallet_name,
90 std::optional<bool> load_on_startup,
91 std::vector<bilingual_str> &warnings) {
92 if (!load_on_startup) {
96 warnings.emplace_back(
97 Untranslated(
"Wallet load on startup setting could not be updated, "
98 "so wallet may not be loaded next node startup."));
99 }
else if (!load_on_startup.value() &&
101 warnings.emplace_back(
102 Untranslated(
"Wallet load on startup setting could not be updated, "
103 "so wallet may still be loaded next node startup."));
110 std::vector<std::shared_ptr<CWallet>>::const_iterator i =
111 std::find(vpwallets.begin(), vpwallets.end(),
wallet);
112 if (i != vpwallets.end()) {
115 vpwallets.push_back(
wallet);
116 wallet->ConnectScriptPubKeyManNotifiers();
117 wallet->NotifyCanGetAddressesChanged();
122 std::optional<bool> load_on_start,
123 std::vector<bilingual_str> &warnings) {
130 wallet->m_chain_notifications_handler.reset();
132 std::vector<std::shared_ptr<CWallet>>::iterator i =
133 std::find(vpwallets.begin(), vpwallets.end(),
wallet);
134 if (i == vpwallets.end()) {
146 std::optional<bool> load_on_start) {
147 std::vector<bilingual_str> warnings;
158 for (
const std::shared_ptr<CWallet> &
wallet : vpwallets) {
166std::unique_ptr<interfaces::Handler>
169 auto it = g_load_wallet_fns.emplace(g_load_wallet_fns.end(),
170 std::move(load_wallet));
173 g_load_wallet_fns.erase(it);
180static std::set<std::string>
182static std::set<std::string>
188 wallet->WalletLogPrintf(
"Releasing wallet\n");
194 if (g_unloading_wallet_set.erase(
name) == 0) {
207 auto it = g_unloading_wallet_set.insert(
name);
219 while (g_unloading_wallet_set.count(
name) == 1) {
226std::shared_ptr<CWallet>
228 std::optional<bool> load_on_start,
232 std::unique_ptr<WalletDatabase> database =
240 std::shared_ptr<CWallet>
wallet =
250 wallet->postInitProcess();
256 }
catch (
const std::runtime_error &e) {
264std::shared_ptr<CWallet>
268 std::vector<bilingual_str> &warnings) {
270 return g_loading_wallet_set.insert(
name));
271 if (!result.second) {
276 auto wallet = LoadWalletInternal(chain,
name, load_on_start, options,
277 status,
error, warnings);
282std::shared_ptr<CWallet>
286 std::vector<bilingual_str> &warnings) {
295 if (!passphrase.empty()) {
301 std::unique_ptr<WalletDatabase> database =
311 if (!passphrase.empty() &&
314 "Passphrase provided but private keys are disabled. A passphrase "
315 "is only used to encrypt private keys, so cannot be used for "
316 "wallets with private keys disabled.");
322 std::shared_ptr<CWallet>
wallet =
333 if (!passphrase.empty() &&
335 if (!
wallet->EncryptWallet(passphrase)) {
337 Untranslated(
"Error: Wallet created but failed to encrypt.");
343 if (!
wallet->Unlock(passphrase)) {
345 "Error: Wallet was encrypted but could not be unlocked");
354 wallet->SetupDescriptorScriptPubKeyMans();
356 for (
auto spk_man :
wallet->GetActiveScriptPubKeyMans()) {
357 if (!spk_man->SetupGeneration()) {
372 wallet->postInitProcess();
394 std::map<TxId, CWalletTx>::const_iterator it = mapWallet.find(txid);
395 if (it == mapWallet.end()) {
399 return &(it->second);
412 spk_man->UpgradeKeyMetadata();
417 bool accept_no_keys) {
423 for (
const MasterKeyMap::value_type &pMasterKey :
mapMasterKeys) {
425 strWalletPassphrase, pMasterKey.second.vchSalt,
426 pMasterKey.second.nDeriveIterations,
427 pMasterKey.second.nDerivationMethod)) {
430 if (!crypter.
Decrypt(pMasterKey.second.vchCryptedKey,
435 if (
Unlock(_vMasterKey, accept_no_keys)) {
458 strOldWalletPassphrase, pMasterKey.second.vchSalt,
459 pMasterKey.second.nDeriveIterations,
460 pMasterKey.second.nDerivationMethod)) {
464 if (!crypter.
Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey)) {
468 if (
Unlock(_vMasterKey)) {
471 pMasterKey.second.vchSalt,
472 pMasterKey.second.nDeriveIterations,
473 pMasterKey.second.nDerivationMethod);
474 pMasterKey.second.nDeriveIterations =
static_cast<unsigned int>(
475 pMasterKey.second.nDeriveIterations *
480 pMasterKey.second.vchSalt,
481 pMasterKey.second.nDeriveIterations,
482 pMasterKey.second.nDerivationMethod);
483 pMasterKey.second.nDeriveIterations =
484 (pMasterKey.second.nDeriveIterations +
485 static_cast<unsigned int>(
486 pMasterKey.second.nDeriveIterations * 100 /
490 if (pMasterKey.second.nDeriveIterations < 25000) {
491 pMasterKey.second.nDeriveIterations = 25000;
495 "Wallet passphrase changed to an nDeriveIterations of %i\n",
496 pMasterKey.second.nDeriveIterations);
499 strNewWalletPassphrase, pMasterKey.second.vchSalt,
500 pMasterKey.second.nDeriveIterations,
501 pMasterKey.second.nDerivationMethod)) {
505 if (!crypter.
Encrypt(_vMasterKey,
506 pMasterKey.second.vchCryptedKey)) {
531 if (nWalletVersion >= nVersion) {
537 if (fExplicit && nVersion > nWalletMaxVersion) {
541 nWalletVersion = nVersion;
543 if (nVersion > nWalletMaxVersion) {
544 nWalletMaxVersion = nVersion;
548 if (nWalletVersion > 40000) {
560 if (nWalletVersion > nVersion) {
564 nWalletMaxVersion = nVersion;
570 std::set<TxId> result;
573 std::map<TxId, CWalletTx>::const_iterator it = mapWallet.find(txid);
574 if (it == mapWallet.end()) {
580 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
582 for (
const CTxIn &txin : wtx.
tx->vin) {
583 if (mapTxSpends.count(txin.prevout) <= 1) {
588 range = mapTxSpends.equal_range(txin.prevout);
589 for (TxSpends::const_iterator _it = range.first; _it != range.second;
591 result.insert(_it->second);
600 auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0));
601 return (iter != mapTxSpends.end() && iter->first.GetTxId() == txid);
613 std::pair<TxSpends::iterator, TxSpends::iterator> range) {
618 int nMinOrderPos = std::numeric_limits<int>::max();
620 for (TxSpends::iterator it = range.first; it != range.second; ++it) {
621 const CWalletTx *wtx = &mapWallet.at(it->second);
633 for (TxSpends::iterator it = range.first; it != range.second; ++it) {
634 const TxId &txid = it->second;
636 if (copyFrom == copyTo) {
642 "Oldest wallet transaction in range assumed to have been found.");
664 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range =
665 mapTxSpends.equal_range(outpoint);
667 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
668 const TxId &wtxid = it->second;
669 std::map<TxId, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
670 if (mit != mapWallet.end()) {
672 if (depth > 0 || (depth == 0 && !mit->second.isAbandoned())) {
683 mapTxSpends.insert(std::make_pair(outpoint, wtxid));
685 setLockedCoins.erase(outpoint);
687 std::pair<TxSpends::iterator, TxSpends::iterator> range;
688 range = mapTxSpends.equal_range(outpoint);
693 auto it = mapWallet.find(wtxid);
694 assert(it != mapWallet.end());
701 for (
const CTxIn &txin : thisTx.
tx->vin) {
760 delete encrypted_batch;
761 encrypted_batch =
nullptr;
767 auto spk_man = spk_man_pair.second.get();
768 if (!spk_man->Encrypt(_vMasterKey, encrypted_batch)) {
770 delete encrypted_batch;
771 encrypted_batch =
nullptr;
783 delete encrypted_batch;
784 encrypted_batch =
nullptr;
791 delete encrypted_batch;
792 encrypted_batch =
nullptr;
795 Unlock(strWalletPassphrase);
803 if (spk_man->IsHDEnabled()) {
804 if (!spk_man->SetupGeneration(
true)) {
837 for (
auto &entry : mapWallet) {
843 std::vector<int64_t> nOrderPosOffsets;
844 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it) {
848 if (nOrderPos == -1) {
849 nOrderPos = nOrderPosNext++;
850 nOrderPosOffsets.push_back(nOrderPos);
856 int64_t nOrderPosOff = 0;
857 for (
const int64_t &nOffsetStart : nOrderPosOffsets) {
858 if (nOrderPos >= nOffsetStart) {
863 nOrderPos += nOrderPosOff;
864 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
884 int64_t nRet = nOrderPosNext++;
896 for (std::pair<const TxId, CWalletTx> &item : mapWallet) {
897 item.second.MarkDirty();
902 unsigned int n,
bool used,
903 std::set<CTxDestination> &tx_destinations) {
916 tx_destinations.insert(dst);
918 }
else if (!used &&
GetDestData(dst,
"used",
nullptr)) {
939 assert(spk_man !=
nullptr);
940 for (
const auto &keyid :
955 bool fFlushOnClose) {
960 const TxId &txid = tx->GetId();
964 std::set<CTxDestination> tx_destinations;
966 for (
const CTxIn &txin : tx->vin) {
967 const COutPoint &op = txin.prevout;
977 mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(txid),
978 std::forward_as_tuple(tx));
980 bool fInsertedNew = ret.second;
981 bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
1008 (fInsertedNew ?
"new" :
""), (fUpdated ?
"update" :
""));
1011 if ((fInsertedNew || fUpdated) && !batch.
WriteTx(wtx)) {
1021#if defined(HAVE_SYSTEM)
1024 std::string strCmd =
gArgs.
GetArg(
"-walletnotify",
"");
1026 if (!strCmd.empty()) {
1037 std::thread t(runCommand, strCmd);
1048 mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(txid),
1049 std::forward_as_tuple(
nullptr));
1051 if (!fill_wtx(wtx, ins.second)) {
1059 if (
chain().findBlock(
1061 FoundBlock().inActiveChain(active).height(height)) &&
1084 for (
const CTxIn &txin : wtx.
tx->vin) {
1085 auto it = mapWallet.find(txin.prevout.GetTxId());
1086 if (it != mapWallet.end()) {
1102 const TxId &txid = ptx->GetId();
1105 for (
const CTxIn &txin : ptx->vin) {
1106 std::pair<TxSpends::const_iterator, TxSpends::const_iterator>
1107 range = mapTxSpends.equal_range(txin.prevout);
1108 while (range.first != range.second) {
1109 if (range.first->second != txid) {
1111 "Transaction %s (in block %s) conflicts with wallet "
1112 "transaction %s (both spend %s:%i)\n",
1114 range.first->second.ToString(),
1115 range.first->first.GetTxId().ToString(),
1116 range.first->first.GetN());
1118 range.first->second);
1125 bool fExisted = mapWallet.count(txid) != 0;
1126 if (fExisted && !fUpdate) {
1139 for (
const CTxOut &txout : ptx->vout) {
1141 spk_man_pair.second->MarkUnusedAddresses(txout.
scriptPubKey);
1162 for (
const CTxIn &txin : tx->vin) {
1163 auto it = mapWallet.find(txin.prevout.GetTxId());
1164 if (it != mapWallet.end()) {
1165 it->second.MarkDirty();
1175 std::set<TxId> todo;
1176 std::set<TxId> done;
1179 auto it = mapWallet.find(txid);
1180 assert(it != mapWallet.end());
1188 while (!todo.empty()) {
1192 it = mapWallet.find(now);
1193 assert(it != mapWallet.end());
1197 assert(currentconfirm <= 0);
1210 TxSpends::const_iterator iter =
1211 mapTxSpends.lower_bound(COutPoint(now, 0));
1212 while (iter != mapTxSpends.end() && iter->first.GetTxId() == now) {
1213 if (!done.count(iter->second)) {
1214 todo.insert(iter->second);
1233 int conflictconfirms =
1234 (m_last_block_processed_height - conflicting_height + 1) * -1;
1239 if (conflictconfirms >= 0) {
1246 std::set<TxId> todo;
1247 std::set<TxId> done;
1251 while (!todo.empty()) {
1255 auto it = mapWallet.find(now);
1256 assert(it != mapWallet.end());
1259 if (conflictconfirms < currentconfirm) {
1270 TxSpends::const_iterator iter =
1271 mapTxSpends.lower_bound(COutPoint(now, 0));
1272 while (iter != mapTxSpends.end() && iter->first.GetTxId() == now) {
1273 if (!done.count(iter->second)) {
1274 todo.insert(iter->second);
1300 uint64_t mempool_sequence) {
1306 auto it = mapWallet.find(tx->GetId());
1307 if (it != mapWallet.end()) {
1308 it->second.fInMempool =
true;
1314 uint64_t mempool_sequence) {
1316 auto it = mapWallet.find(tx->GetId());
1317 if (it != mapWallet.end()) {
1318 it->second.fInMempool =
false;
1349 {CWalletTx::Status::UNCONFIRMED, 0,
1358 m_last_block_processed_height = height;
1359 m_last_block_processed = block_hash;
1360 for (
size_t index = 0; index < block.
vtx.size(); index++) {
1362 block_hash, int(index)});
1377 m_last_block_processed_height = height - 1;
1381 {CWalletTx::Status::UNCONFIRMED, 0,
1390void CWallet::BlockUntilSyncedToCurrentChain()
const {
1405 std::map<TxId, CWalletTx>::const_iterator mi =
1406 mapWallet.find(txin.prevout.GetTxId());
1407 if (mi != mapWallet.end()) {
1409 if (txin.prevout.GetN() < prev.
tx->vout.size()) {
1410 if (
IsMine(prev.
tx->vout[txin.prevout.GetN()]) & filter) {
1411 return prev.
tx->vout[txin.prevout.GetN()].nValue;
1433 result = std::max(result, spk_man_pair.second->IsMine(script));
1440 for (
const CTxOut &txout : tx.vout) {
1456 for (
const CTxIn &txin : tx.vin) {
1459 throw std::runtime_error(std::string(__func__) +
1460 ": value out of range");
1471 result &= spk_man->IsHDEnabled();
1483 if (spk_man && spk_man->CanGetAddresses(internal)) {
1494 throw std::runtime_error(std::string(__func__) +
1495 ": writing wallet flags failed");
1508 throw std::runtime_error(std::string(__func__) +
1509 ": writing wallet flags failed");
1537 throw std::runtime_error(std::string(__func__) +
1538 ": writing wallet flags failed");
1547 bool use_max_sig)
const {
1552 std::unique_ptr<SigningProvider> provider =
1562 scriptPubKey, sigdata)) {
1573 const std::vector<CTxOut> &txouts,
1574 bool use_max_sig)
const {
1577 for (
const auto &txout : txouts) {
1588 int64_t timestamp) {
1593 LOCK(spk_man->cs_KeyStore);
1594 return spk_man->ImportScripts(scripts, timestamp);
1598 const int64_t timestamp) {
1603 LOCK(spk_man->cs_KeyStore);
1604 return spk_man->ImportPrivKeys(privkey_map, timestamp);
1608 const std::vector<CKeyID> &ordered_pubkeys,
1609 const std::map<CKeyID, CPubKey> &pubkey_map,
1610 const std::map<
CKeyID, std::pair<CPubKey, KeyOriginInfo>> &key_origins,
1611 const bool add_keypool,
const bool internal,
const int64_t timestamp) {
1616 LOCK(spk_man->cs_KeyStore);
1617 return spk_man->ImportPubKeys(ordered_pubkeys, pubkey_map, key_origins,
1618 add_keypool, internal, timestamp);
1622 const std::set<CScript> &script_pub_keys,
1623 const bool have_solving_data,
1624 const bool apply_label,
1625 const int64_t timestamp) {
1630 LOCK(spk_man->cs_KeyStore);
1631 if (!spk_man->ImportScriptPubKeys(script_pub_keys, have_solving_data,
1637 for (
const CScript &script : script_pub_keys) {
1662 int start_height = 0;
1666 FoundBlock().hash(start_block).height(start_height));
1675 start_block, start_height, {} , reserver, update);
1708 const BlockHash &start_block,
int start_height,
1735 double progress_current = progress_begin;
1736 int block_height = start_height;
1738 if (progress_end - progress_begin > 0.0) {
1740 (progress_end - progress_begin);
1746 if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
1748 strprintf(
"%s " +
_(
"Rescanning...").translated,
1755 block_height, progress_current);
1764 bool block_still_active =
false;
1765 bool next_block =
false;
1769 .inActiveChain(block_still_active)
1771 .inActiveChain(next_block)
1772 .hash(next_block_hash)));
1776 if (!block_still_active) {
1783 for (
size_t posInBlock = 0; posInBlock < block.
vtx.size();
1786 block_height, block_hash,
1789 {CWalletTx::Status::CONFIRMED, block_height,
1790 block_hash, int(posInBlock)},
1803 if (max_height && block_height >= *max_height) {
1814 block_hash = next_block_hash;
1819 const BlockHash prev_tip_hash = tip_hash;
1821 if (!max_height && prev_tip_hash != tip_hash) {
1834 block_height, progress_current);
1836 }
else if (block_height &&
chain().shutdownRequested()) {
1838 "Rescan interrupted by shutdown request at block %d. Progress=%f\n",
1839 block_height, progress_current);
1857 std::map<int64_t, CWalletTx *> mapSorted;
1861 for (std::pair<const TxId, CWalletTx> &item : mapWallet) {
1862 const TxId &wtxid = item.first;
1869 mapSorted.insert(std::make_pair(wtx.
nOrderPos, &wtx));
1874 for (
const std::pair<const int64_t, CWalletTx *> &item : mapSorted) {
1876 std::string unused_err_string;
1882 std::string &err_string,
1925 std::set<TxId> result;
1945 if (!
chain().isReadyToBroadcast()) {
1962 int submitted_tx_count = 0;
1968 for (std::pair<const TxId, CWalletTx> &item : mapWallet) {
1976 std::string unused_err_string;
1978 ++submitted_tx_count;
1983 if (submitted_tx_count > 0) {
1984 WalletLogPrintf(
"%s: resubmit %u unconfirmed transactions\n", __func__,
1985 submitted_tx_count);
1992 for (
const std::shared_ptr<CWallet> &pwallet :
GetWallets()) {
1993 pwallet->ResendWalletTransactions();
2007 std::map<COutPoint, Coin> coins;
2008 for (
auto &input : tx.
vin) {
2009 auto mi = mapWallet.find(input.prevout.GetTxId());
2010 if (mi == mapWallet.end() ||
2011 input.prevout.GetN() >= mi->second.tx->vout.size()) {
2015 coins[input.prevout] =
2019 std::map<int, std::string> input_errors;
2024 const std::map<COutPoint, Coin> &coins,
2026 std::map<int, std::string> &input_errors)
const {
2031 if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) {
2042 if (legacy_spk_man &&
2043 legacy_spk_man->SignTransaction(tx, coins, sighash, input_errors)) {
2052 bool sign,
bool bip32derivs)
const {
2055 for (
size_t i = 0; i < psbtx.
tx->vin.size(); ++i) {
2056 const CTxIn &txin = psbtx.
tx->vin[i];
2065 const TxId &txid = txin.prevout.GetTxId();
2066 const auto it = mapWallet.find(txid);
2067 if (it != mapWallet.end()) {
2069 CTxOut utxo = wtx.
tx->vout[txin.prevout.GetN()];
2079 spk_man->FillPSBT(psbtx, sighash_type, sign, bip32derivs);
2087 for (
const auto &input : psbtx.
inputs) {
2096 std::string &str_sig)
const {
2100 if (spk_man_pair.second->CanProvide(script_pub_key, sigdata)) {
2101 return spk_man_pair.second->SignMessage(message, pkhash, str_sig);
2109 const std::vector<CRecipient> &vecSend)
const {
2112 return *change_type;
2126 std::vector<std::pair<std::string, std::string>> orderForm,
2137 wtx.
mapValue = std::move(mapValue);
2145 for (
const CTxIn &txin : tx->vin) {
2146 CWalletTx &coin = mapWallet.at(txin.prevout.GetTxId());
2153 CWalletTx &wtx = mapWallet.at(tx->GetId());
2161 std::string err_string;
2163 WalletLogPrintf(
"CommitTransaction(): Transaction cannot be broadcast "
2164 "immediately, %s\n",
2174 fFirstRunRet =
false;
2177 if (
database->Rewrite(
"\x04pool")) {
2179 spk_man_pair.second->RewriteDB();
2195 return nLoadWalletRet;
2202 std::vector<TxId> &txIdsOut) {
2206 for (
const TxId &txid : txIdsOut) {
2207 const auto &it = mapWallet.find(txid);
2208 wtxOrdered.erase(it->second.m_it_wtxOrdered);
2209 for (
const auto &txin : it->second.tx->vin) {
2210 mapTxSpends.erase(txin.prevout);
2212 mapWallet.erase(it);
2217 if (
database->Rewrite(
"\x04pool")) {
2219 spk_man_pair.second->RewriteDB();
2225 return nZapSelectTxRet;
2235 const std::string &strName,
2236 const std::string &strPurpose) {
2237 bool fUpdated =
false;
2241 std::map<CTxDestination, CAddressBookData>::iterator mi =
2242 m_address_book.find(address);
2243 fUpdated = (mi != m_address_book.end() && !mi->second.IsChange());
2244 m_address_book[address].SetLabel(strName);
2246 if (!strPurpose.empty()) {
2247 m_address_book[address].purpose = strPurpose;
2254 if (!strPurpose.empty() && !batch.
WritePurpose(address, strPurpose)) {
2257 return batch.
WriteName(address, strName);
2261 const std::string &strName,
2262 const std::string &strPurpose) {
2281 "%s called with IsMine address, NOT SUPPORTED. Please "
2282 "report this bug! %s\n",
2283 __func__, PACKAGE_BUGREPORT);
2287 for (
const std::pair<const std::string, std::string> &item :
2288 m_address_book[address].destdata) {
2291 m_address_book.erase(address);
2304 unsigned int count = 0;
2306 count += spk_man->KeypoolCountExternalKeys();
2315 unsigned int count = 0;
2317 count += spk_man->GetKeyPoolSize();
2326 res &= spk_man->TopUp(kpSize);
2335 bool result =
false;
2339 result = spk_man->GetNewDestination(type, dest,
error);
2353 std::string &
error) {
2359 error =
_(
"Error: Keypool ran out, please call keypoolrefill first")
2370 int64_t oldestKey = std::numeric_limits<int64_t>::max();
2373 std::min(oldestKey, spk_man_pair.second->GetOldestKeyPoolTime());
2379 const std::set<CTxDestination> &destinations) {
2380 for (
auto &entry : mapWallet) {
2386 for (
size_t i = 0; i < wtx.
tx->vout.size(); i++) {
2390 destinations.count(dst)) {
2398std::set<CTxDestination>
2401 std::set<CTxDestination> result;
2402 for (
const std::pair<const CTxDestination, CAddressBookData> &item :
2404 if (item.second.IsChange()) {
2408 const std::string &strName = item.second.GetLabel();
2409 if (strName == label) {
2410 result.insert(address);
2457 setLockedCoins.insert(output);
2462 setLockedCoins.erase(output);
2467 setLockedCoins.clear();
2473 return setLockedCoins.count(outpoint) > 0;
2478 for (COutPoint outpoint : setLockedCoins) {
2479 vOutpts.push_back(outpoint);
2487 mapKeyBirth.clear();
2490 std::map<CKeyID, const CWalletTx::Confirmation *> mapKeyFirstBlock;
2501 assert(spk_man !=
nullptr);
2505 for (
const auto &entry : spk_man->mapKeyMetadata) {
2506 if (entry.second.nCreateTime) {
2507 mapKeyBirth[entry.first] = entry.second.nCreateTime;
2513 if (mapKeyBirth.count(keyid) == 0) {
2514 mapKeyFirstBlock[keyid] = &max_confirm;
2519 if (mapKeyFirstBlock.empty()) {
2524 for (
const auto &entry : mapWallet) {
2529 for (
const CTxOut &txout : wtx.
tx->vout) {
2531 for (
const auto &keyid :
2534 auto rit = mapKeyFirstBlock.find(keyid);
2535 if (rit != mapKeyFirstBlock.end() &&
2537 rit->second->block_height) {
2547 for (
const auto &entry : mapKeyFirstBlock) {
2584 int64_t latestEntry = 0;
2588 int64_t latestTolerated = latestNow + 300;
2590 for (
auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
2600 if (nSmartTime <= latestTolerated) {
2601 latestEntry = nSmartTime;
2602 if (nSmartTime > latestNow) {
2603 latestNow = nSmartTime;
2609 nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
2620 const std::string &key,
const std::string &value) {
2621 if (std::get_if<CNoDestination>(&dest)) {
2625 m_address_book[dest].destdata.insert(std::make_pair(key, value));
2630 const std::string &key) {
2631 if (!m_address_book[dest].destdata.erase(key)) {
2639 const std::string &value) {
2640 m_address_book[dest].destdata.insert(std::make_pair(key, value));
2644 std::string *value)
const {
2645 std::map<CTxDestination, CAddressBookData>::const_iterator i =
2646 m_address_book.find(dest);
2647 if (i != m_address_book.end()) {
2648 CAddressBookData::StringMap::const_iterator j =
2649 i->second.destdata.find(key);
2650 if (j != i->second.destdata.end()) {
2661std::vector<std::string>
2663 std::vector<std::string> values;
2664 for (
const auto &address : m_address_book) {
2665 for (
const auto &data : address.second.destdata) {
2667 values.emplace_back(data.second);
2674std::unique_ptr<WalletDatabase>
2685 fs::file_type path_type = fs::symlink_status(wallet_path).type();
2686 if (!(path_type == fs::file_type::not_found ||
2687 path_type == fs::file_type::directory ||
2688 (path_type == fs::file_type::symlink &&
2689 fs::is_directory(wallet_path)) ||
2690 (path_type == fs::file_type::regular &&
2693 strprintf(
"Invalid -wallet path '%s'. -wallet path should point to "
2694 "a directory where wallet.dat and "
2695 "database/log.?????????? files can be stored, a location "
2696 "where such a directory could be created, "
2697 "or (for backwards compatibility) the name of an "
2698 "existing data file in -walletdir (%s)",
2703 return MakeDatabase(wallet_path, options, status, error_string);
2706std::shared_ptr<CWallet>
2708 std::unique_ptr<WalletDatabase> database,
2710 std::vector<bilingual_str> &warnings) {
2711 const std::string &walletFile =
database->Filename();
2716 bool fFirstRun =
true;
2719 std::shared_ptr<CWallet> walletInstance(
2721 DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
2725 strprintf(
_(
"Error loading %s: Wallet corrupted"), walletFile);
2731 strprintf(
_(
"Error reading %s! All keys read correctly, but "
2732 "transaction data or address book entries might be "
2733 "missing or incorrect."),
2737 _(
"Error loading %s: Wallet requires newer version of %s"),
2738 walletFile, PACKAGE_NAME);
2742 _(
"Wallet needed to be rewritten: restart %s to complete"),
2756 walletInstance->AddWalletFlags(wallet_creation_flags);
2760 walletInstance->SetupLegacyScriptPubKeyMan();
2763 if (!(wallet_creation_flags &
2765 LOCK(walletInstance->cs_wallet);
2767 walletInstance->SetupDescriptorScriptPubKeyMans();
2773 walletInstance->GetActiveScriptPubKeyMans()) {
2774 if (!spk_man->SetupGeneration()) {
2775 error =
_(
"Unable to generate initial keys");
2786 "disabled during creation"),
2789 }
else if (walletInstance->IsWalletFlagSet(
2791 for (
auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
2792 if (spk_man->HavePrivateKeys()) {
2794 strprintf(
_(
"Warning: Private keys detected in wallet {%s} "
2795 "with disabled private keys"),
2810 _(
"This is the minimum transaction fee you pay "
2811 "on every transaction."));
2813 walletInstance->m_min_fee =
CFeeRate(n);
2817 const std::string max_aps_fee{
gArgs.
GetArg(
"-maxapsfee",
"")};
2819 if (max_aps_fee ==
"-1") {
2828 _(
"This is the maximum transaction fee you pay (in addition to"
2829 " the normal fee) to prioritize partial spend avoidance over"
2830 " regular coin selection."));
2832 walletInstance->m_max_aps_fee = n;
2839 strprintf(
_(
"Invalid amount for -fallbackfee=<amount>: '%s'"),
2846 _(
"This is the transaction fee you may pay when "
2847 "fee estimates are not available."));
2849 walletInstance->m_fallback_fee =
CFeeRate(nFeePerK);
2852 walletInstance->m_allow_fallback_fee =
2853 walletInstance->m_fallback_fee.GetFeePerK() !=
Amount::zero();
2863 _(
"This is the transaction fee you will pay if "
2864 "you send a transaction."));
2866 walletInstance->m_pay_tx_fee =
CFeeRate(nFeePerK, 1000);
2869 "(must be at least %s)"),
2883 warnings.push_back(
_(
"-maxtxfee is set very high! Fees this large "
2884 "could be paid on a single transaction."));
2888 _(
"Invalid amount for -maxtxfee=<amount>: '%s' (must be at "
2889 "least the minrelay fee of %s to prevent stuck "
2894 walletInstance->m_default_max_tx_fee = nMaxFee;
2900 _(
"The wallet will avoid paying less than the minimum relay fee."));
2903 walletInstance->m_spend_zero_conf_change =
2908 walletInstance->WalletLogPrintf(
"Wallet completed loading in %15dms\n",
2912 walletInstance->TopUpKeyPool();
2914 LOCK(walletInstance->cs_wallet);
2924 walletInstance->m_chain_notifications_handler =
2925 walletInstance->chain().handleNotifications(walletInstance);
2927 int rescan_height = 0;
2932 if (
const std::optional<int> fork_height =
2934 rescan_height = *fork_height;
2941 walletInstance->m_last_block_processed =
2943 walletInstance->m_last_block_processed_height = *tip_height;
2945 walletInstance->m_last_block_processed.
SetNull();
2946 walletInstance->m_last_block_processed_height = -1;
2949 if (tip_height && *tip_height != rescan_height) {
2958 int block_height = *tip_height;
2959 while (block_height > 0 &&
2961 rescan_height != block_height) {
2965 if (rescan_height != block_height) {
2966 error =
_(
"Prune: last wallet synchronisation goes beyond "
2967 "pruned data. You need to -reindex (download the "
2968 "whole blockchain again in case of pruned node)");
2974 walletInstance->WalletLogPrintf(
2975 "Rescanning last %i blocks (from block %i)...\n",
2976 *tip_height - rescan_height, rescan_height);
2980 std::optional<int64_t> time_first_key;
2981 for (
auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
2982 int64_t time = spk_man->GetTimeFirstKey();
2983 if (!time_first_key || time < *time_first_key) {
2984 time_first_key = time;
2987 if (time_first_key) {
2998 ->ScanForWalletTransactions(
3000 {} , reserver,
true )
3002 error =
_(
"Failed to rescan the wallet during initialization");
3007 walletInstance->database->IncrementUpdateCounter();
3012 for (
auto &load_wallet : g_load_wallet_fns) {
3017 walletInstance->SetBroadcastTransactions(
3020 walletInstance->WalletLogPrintf(
"setKeyPool.size() = %u\n",
3021 walletInstance->GetKeyPoolSize());
3022 walletInstance->WalletLogPrintf(
"mapWallet.size() = %u\n",
3023 walletInstance->mapWallet.size());
3024 walletInstance->WalletLogPrintf(
"m_address_book.size() = %u\n",
3025 walletInstance->m_address_book.size());
3027 return walletInstance;
3032 bool allow_change)
const {
3033 const auto &address_book_it = m_address_book.find(dest);
3034 if (address_book_it == m_address_book.end()) {
3037 if ((!allow_change) && address_book_it->second.IsChange()) {
3040 return &address_book_it->second;
3045 int nMaxVersion = version;
3047 if (nMaxVersion == 0) {
3057 error =
_(
"Cannot downgrade wallet");
3071 error =
_(
"Cannot upgrade a non HD split wallet without upgrading to "
3072 "support pre split keypool. Please use version 200300 or no "
3073 "version specified.");
3078 if (!spk_man->Upgrade(prev_version,
error)) {
3132 assert(chain_depth >= 0);
3152 return vMasterKey.empty();
3162 if (!vMasterKey.empty()) {
3165 sizeof(
decltype(vMasterKey)::value_type));
3178 if (!spk_man_pair.second->CheckDecryptionKey(vMasterKeyIn,
3183 vMasterKey = vMasterKeyIn;
3190 std::set<ScriptPubKeyMan *> spk_mans;
3191 for (
bool internal : {
false,
true}) {
3195 spk_mans.insert(spk_man);
3203 std::set<ScriptPubKeyMan *> spk_mans;
3205 spk_mans.insert(spk_man_pair.second.get());
3211 bool internal)
const {
3212 const std::map<OutputType, ScriptPubKeyMan *> &spk_managers =
3214 std::map<OutputType, ScriptPubKeyMan *>::const_iterator it =
3215 spk_managers.find(type);
3216 if (it == spk_managers.end()) {
3218 "%s scriptPubKey Manager for output type %d does not exist\n",
3219 internal ?
"Internal" :
"External",
static_cast<int>(type));
3225std::set<ScriptPubKeyMan *>
3228 std::set<ScriptPubKeyMan *> spk_mans;
3230 if (spk_man_pair.second->CanProvide(script, sigdata)) {
3231 spk_mans.insert(spk_man_pair.second.get());
3240 if (spk_man_pair.second->CanProvide(script, sigdata)) {
3241 return spk_man_pair.second.get();
3254std::unique_ptr<SigningProvider>
3260std::unique_ptr<SigningProvider>
3264 if (spk_man_pair.second->CanProvide(script, sigdata)) {
3265 return spk_man_pair.second->GetSolvingProvider(script);
3308 return cb(vMasterKey);
3318 spk_man->NotifyCanGetAddressesChanged.connect(
3325 auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(
3343 for (
bool internal : {
false,
true}) {
3346 std::make_unique<DescriptorScriptPubKeyMan>(*
this, internal);
3349 throw std::runtime_error(
3350 std::string(__func__) +
3351 ": Wallet is locked, cannot setup new descriptors");
3353 if (!spk_manager->CheckDecryptionKey(vMasterKey) &&
3354 !spk_manager->Encrypt(vMasterKey,
nullptr)) {
3355 throw std::runtime_error(
3356 std::string(__func__) +
3357 ": Could not encrypt new descriptors");
3360 spk_manager->SetupDescriptorGeneration(master_key, t);
3361 uint256 id = spk_manager->GetID();
3373 throw std::runtime_error(std::string(__func__) +
3374 ": writing active ScriptPubKeyMan id failed");
3388 "Setting spkMan to active: id = %s, type = %d, internal = %d\n",
3389 id.
ToString(),
static_cast<int>(type),
static_cast<int>(internal));
3392 auto &spk_mans_other =
3395 spk_man->SetInternal(internal);
3396 spk_mans[type] = spk_man;
3398 const auto it = spk_mans_other.find(type);
3399 if (it != spk_mans_other.end() && it->second == spk_man) {
3400 spk_mans_other.erase(type);
3409 if (spk_man !=
nullptr && spk_man->GetID() ==
id) {
3411 "Deactivate spkMan: id = %s, type = %d, internal = %d\n",
3412 id.
ToString(),
static_cast<int>(type),
static_cast<int>(internal));
3416 throw std::runtime_error(
3417 std::string(__func__) +
3418 ": erasing active ScriptPubKeyMan id failed");
3423 spk_mans.erase(type);
3435 return spk_man !=
nullptr;
3445 spk_man_pair.second.get());
3457 const std::string &label,
bool internal) {
3462 "Cannot add WalletDescriptor to a non-descriptor wallet\n");
3470 spk_man->UpdateWalletDescriptor(desc);
3473 std::make_unique<DescriptorScriptPubKeyMan>(*
this, desc);
3474 spk_man = new_spk_man.get();
3481 for (
const auto &entry : signing_provider.
keys) {
3482 const CKey &key = entry.second;
3483 spk_man->AddDescriptorKey(key, key.
GetPubKey());
3487 if (!spk_man->TopUp()) {
3495 auto script_pub_keys = spk_man->GetScriptPubKeys();
3496 if (script_pub_keys.empty()) {
3498 "Could not generate scriptPubKeys (cache is empty)\n");
3509 spk_man->WriteDescriptor();
bool MoneyRange(const Amount nValue)
static constexpr Amount SATOSHI
static constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
const CChainParams & Params()
Return the currently selected parameters.
#define CHECK_NONFATAL(condition)
Identity function.
#define Assert(val)
Identity function.
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
std::vector< CTransactionRef > vtx
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Encryption/decryption context with key information.
bool Encrypt(const CKeyingMaterial &vchPlaintext, std::vector< uint8_t > &vchCiphertext) const
bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector< uint8_t > &chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
bool Decrypt(const std::vector< uint8_t > &vchCiphertext, CKeyingMaterial &vchPlaintext) const
Fee rate in satoshis per kilobyte: Amount / kB.
std::string ToString() const
Amount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
An encapsulated secp256k1 private key.
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
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.
A key from a CWallet's keypool.
bool fInternal
Whether this keypool entry is in the internal keypool (for change outputs)
CPubKey vchPubKey
The public key.
int64_t nTime
The time at which the key was generated. Set in AddKeypoolPubKeyWithDB.
bool m_pre_split
Whether this key was generated for a keypool before the wallet was upgraded to HD-split.
Private key encryption is done based on a CMasterKey, which holds a salt and random encryption key.
std::vector< uint8_t > vchSalt
unsigned int nDerivationMethod
0 = EVP_sha512() 1 = scrypt()
unsigned int nDeriveIterations
std::vector< uint8_t > vchCryptedKey
A mutable version of CTransaction.
An encapsulated public key.
An output of a transaction.
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
std::unique_ptr< SigningProvider > GetSolvingProvider(const CScript &script) const
Get the SigningProvider for a script.
std::atomic< int64_t > m_best_block_time
BlockHash GetLastBlockHash() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::set< ScriptPubKeyMan * > GetScriptPubKeyMans(const CScript &script, SignatureData &sigdata) const
Get all of the ScriptPubKeyMans for a script given additional information in sigdata (populated by e....
bool HaveChain() const
Interface to assert chain access.
int GetTxBlocksToMaturity(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool DummySignTx(CMutableTransaction &txNew, const std::set< CTxOut > &txouts, bool use_max_sig=false) const
void ConnectScriptPubKeyManNotifiers()
Connect the signals from ScriptPubKeyMans to the signals in CWallet.
void AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
Adds the active ScriptPubKeyMan for the specified type and internal.
void SetupLegacyScriptPubKeyMan()
Make a LegacyScriptPubKeyMan and set it for all types, internal, and external.
bool AddDestData(WalletBatch &batch, const CTxDestination &dest, const std::string &key, const std::string &value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Adds a destination data tuple to the store, and saves it to disk When adding new fields,...
boost::signals2::signal< void()> NotifyCanGetAddressesChanged
Keypool has new keys.
const std::string GetDisplayName() const override
Returns a bracketed wallet name for displaying in logs, will return [default wallet] if the wallet ha...
MasterKeyMap mapMasterKeys
int GetTxDepthInMainChain(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Return depth of transaction in blockchain: <0 : conflicts with a transaction this deep in the blockch...
bool IsTxImmatureCoinBase(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
boost::signals2::signal< void(const std::string &title, int nProgress)> ShowProgress
Show progress e.g.
bool Unlock(const CKeyingMaterial &vMasterKeyIn, bool accept_no_keys=false)
bool GetBroadcastTransactions() const
Inquire whether this wallet broadcasts transactions.
void WalletLogPrintf(std::string fmt, Params... parameters) const
Prepends the wallet name in logging output to ease debugging in multi-wallet use cases.
interfaces::Chain & chain() const
Interface for accessing chain state.
void SetupDescriptorScriptPubKeyMans() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Create new DescriptorScriptPubKeyMans and add them to the wallet.
WalletDatabase & GetDatabase() override
interfaces::Chain * m_chain
Interface for accessing chain state.
bool WithEncryptionKey(const std::function< bool(const CKeyingMaterial &)> &cb) const override
Pass the encryption key to cb().
LegacyScriptPubKeyMan * GetOrCreateLegacyScriptPubKeyMan()
std::map< OutputType, ScriptPubKeyMan * > m_external_spk_managers
void DeactivateScriptPubKeyMan(const uint256 &id, OutputType type, bool internal)
Remove specified ScriptPubKeyMan from set of active SPK managers.
bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Look up a destination data tuple in the store, return true if found false otherwise.
bool IsLegacy() const
Determine if we are a legacy wallet.
std::atomic< bool > fAbortRescan
std::map< uint256, std::unique_ptr< ScriptPubKeyMan > > m_spk_managers
void LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
Loads an active ScriptPubKeyMan for the specified type and internal.
static std::shared_ptr< CWallet > Create(interfaces::Chain &chain, const std::string &name, std::unique_ptr< WalletDatabase > database, uint64_t wallet_creation_flags, bilingual_str &error, std::vector< bilingual_str > &warnings)
Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error.
boost::signals2::signal< void(CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, const std::string &purpose, ChangeType status)> NotifyAddressBookChanged
Address book entry changed.
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get last block processed height.
boost::signals2::signal< void(CWallet *wallet)> NotifyStatusChanged
Wallet status (encrypted, locked) changed.
OutputType m_default_address_type
DescriptorScriptPubKeyMan * GetDescriptorScriptPubKeyMan(const WalletDescriptor &desc) const
Return the DescriptorScriptPubKeyMan for a WalletDescriptor if it is already in the wallet.
void LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor &desc)
Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it.
LegacyScriptPubKeyMan * GetLegacyScriptPubKeyMan() const
Get the LegacyScriptPubKeyMan which is used for all types, internal, and external.
std::atomic< uint64_t > m_wallet_flags
const std::string & GetName() const
Get a name for this wallet for logging/debugging purposes.
bool CanSupportFeature(enum WalletFeature wf) const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
check whether we are allowed to upgrade (or already support) to the named feature
bool BackupWallet(const std::string &strDest) const
unsigned int ComputeTimeSmart(const CWalletTx &wtx) const
Compute smart timestamp for a transaction being added to the wallet.
void WalletLogPrintfToBeContinued(std::string fmt, Params... parameters) const
std::unique_ptr< WalletDatabase > database
Internal database handle.
ScriptPubKeyMan * AddWalletDescriptor(WalletDescriptor &desc, const FlatSigningProvider &signing_provider, const std::string &label, bool internal) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Add a descriptor to the wallet, return a ScriptPubKeyMan & associated output type.
std::set< ScriptPubKeyMan * > GetActiveScriptPubKeyMans() const
Returns all unique ScriptPubKeyMans in m_internal_spk_managers and m_external_spk_managers.
std::vector< std::string > GetDestValues(const std::string &prefix) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get all destination values matching a prefix.
boost::signals2::signal< void(bool fHaveWatchOnly)> NotifyWatchonlyChanged
Watch-only address added.
bool IsLocked() const override
std::map< OutputType, ScriptPubKeyMan * > m_internal_spk_managers
std::atomic< double > m_scanning_progress
int GetVersion() const
get the current wallet format (the oldest client version guaranteed to understand this wallet)
void GetKeyBirthTimes(std::map< CKeyID, int64_t > &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool EraseDestData(WalletBatch &batch, const CTxDestination &dest, const std::string &key) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Erases a destination data tuple in the store and on disk.
boost::signals2::signal< void(CWallet *wallet, const TxId &txid, ChangeType status)> NotifyTransactionChanged
Wallet transaction added, removed or updated.
bool HasEncryptionKeys() const override
CWallet(interfaces::Chain *chain, const std::string &name, std::unique_ptr< WalletDatabase > _database)
Construct wallet with specified name and database implementation.
Amount m_default_max_tx_fee
Absolute maximum transaction fee (in satoshis) used by default for the wallet.
bool UpgradeWallet(int version, bilingual_str &error)
Upgrade the wallet.
bool fBroadcastTransactions
ScriptPubKeyMan * GetScriptPubKeyMan(const OutputType &type, bool internal) const
Get the ScriptPubKeyMan for the given OutputType and internal/external chain.
std::set< ScriptPubKeyMan * > GetAllScriptPubKeyMans() const
Returns all unique ScriptPubKeyMans.
std::multimap< int64_t, CWalletTx * > TxItems
void LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Adds a destination data tuple to the store, without saving it to disk.
unsigned int nMasterKeyMaxID
std::function< bool(CWalletTx &wtx, bool new_tx)> UpdateWalletTxFn
Callback for updating transaction metadata in mapWallet.
void postInitProcess()
Wallet post-init setup Gives the wallet a chance to register repetitive tasks and complete post-init ...
const CAddressBookData * FindAddressBookEntry(const CTxDestination &, bool allow_change=false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
A transaction with a bunch of additional info that only the owner cares about.
mapValue_t mapValue
Key/value map with information about the transaction.
bool isUnconfirmed() const
unsigned int nTimeSmart
Stable timestamp that never changes, and reflects the order a transaction was added to the wallet.
bool IsEquivalentTo(const CWalletTx &tx) const
bool isConflicted() const
std::vector< std::pair< std::string, std::string > > vOrderForm
bool fFromMe
From me flag is set to 1 for transactions that were created by the wallet on this bitcoin node,...
unsigned int fTimeReceivedIsTxTime
void MarkDirty()
make sure balances are recalculated
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 nTimeReceived
time received by this node
int64_t nOrderPos
position in ordered transaction list
bool HasWalletDescriptor(const WalletDescriptor &desc) const
RecursiveMutex cs_KeyStore
Different type to mark Mutex at global scope.
std::set< CKeyID > GetKeys() const override
A wrapper to reserve an address from a wallet.
bool fInternal
Whether this is from the internal (change output) keypool.
ScriptPubKeyMan * m_spk_man
The ScriptPubKeyMan to reserve from.
int64_t nIndex
The index of the address's key in the keypool.
CTxDestination address
The destination.
const CWallet *const pwallet
The wallet to reserve from.
A class implementing ScriptPubKeyMan manages some (or all) scriptPubKeys used in a wallet.
virtual bool TopUp(unsigned int size=0)
Fills internal address pool.
virtual bool GetReservedDestination(const OutputType type, bool internal, CTxDestination &address, int64_t &index, CKeyPool &keypool)
virtual void KeepDestination(int64_t index, const OutputType &type)
virtual void ReturnDestination(int64_t index, bool internal, const CTxDestination &addr)
Signature hash type wrapper class.
void push_back(UniValue val)
const std::vector< UniValue > & getValues() const
Access to the wallet database.
bool TxnCommit()
Commit current transaction.
bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256 &id, bool internal)
bool WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
bool WriteName(const CTxDestination &address, const std::string &strName)
bool WritePurpose(const CTxDestination &address, const std::string &purpose)
bool WriteMinVersion(int nVersion)
bool ErasePurpose(const CTxDestination &address)
bool EraseDestData(const CTxDestination &address, const std::string &key)
Erase destination data tuple from wallet database.
bool WriteWalletFlags(const uint64_t flags)
bool ReadBestBlock(CBlockLocator &locator)
bool WriteOrderPosNext(int64_t nOrderPosNext)
bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal)
bool WriteTx(const CWalletTx &wtx)
bool TxnBegin()
Begin a new transaction.
bool TxnAbort()
Abort current transaction.
bool EraseName(const CTxDestination &address)
bool WriteBestBlock(const CBlockLocator &locator)
DBErrors ZapSelectTx(std::vector< TxId > &txIdsIn, std::vector< TxId > &txIdsOut)
DBErrors LoadWallet(CWallet *pwallet)
bool WriteDestData(const CTxDestination &address, const std::string &key, const std::string &value)
Write destination data key,value tuple to database.
Descriptor with some wallet metadata.
std::shared_ptr< Descriptor > descriptor
RAII object to check and reserve a wallet rescan.
std::string ToString() const
std::string GetHex() const
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
virtual CBlockLocator getTipLocator()=0
Get locator for the current chain tip.
virtual std::optional< int > getHeight()=0
Get current chain height, not including genesis block (returns 0 if chain only contains genesis block...
virtual BlockHash getBlockHash(int height)=0
Get block hash. Height must be valid or this function will abort.
virtual bool findBlock(const BlockHash &hash, const FoundBlock &block={})=0
Return whether node has the block and optionally return block metadata or contents.
virtual bool updateRwSetting(const std::string &name, const util::SettingsValue &value, bool write=true)=0
Write a setting to <datadir>/settings.json.
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 broadcastTransaction(const Config &config, const CTransactionRef &tx, const Amount &max_tx_fee, bool relay, std::string &err_string)=0
Transaction is added to memory pool, if the transaction fee is below the amount specified by max_tx_f...
virtual util::SettingsValue getRwSetting(const std::string &name)=0
Return <datadir>/settings.json setting value.
virtual double guessVerificationProgress(const BlockHash &block_hash)=0
Estimate fraction of total transactions verified if blocks up to the specified block hash are verifie...
virtual const CChainParams & params() const =0
This Chain's parameters.
virtual bool havePruned()=0
Check if any block has been pruned.
virtual bool findAncestorByHeight(const BlockHash &block_hash, int ancestor_height, const FoundBlock &ancestor_out={})=0
Find ancestor of block at specified height and optionally return ancestor information.
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 void requestMempoolTransactions(Notifications ¬ifications)=0
Synchronously send transactionAddedToMempool notifications about all current mempool transactions to ...
virtual void waitForNotificationsIfTipChanged(const BlockHash &old_tip)=0
Wait for pending notifications to be processed unless block hash points to the current chain tip.
virtual CFeeRate relayMinFee()=0
Relay current minimum fee (from -minrelaytxfee settings).
Helper for findBlock to selectively return pieces of block data.
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
const Config & GetConfig()
static const int COINBASE_MATURITY
Coinbase transaction outputs can only be spent after this number of new blocks (network rule).
const unsigned int WALLET_CRYPTO_SALT_SIZE
std::vector< uint8_t, secure_allocator< uint8_t > > CKeyingMaterial
const unsigned int WALLET_CRYPTO_KEY_SIZE
bilingual_str AmountHighWarn(const std::string &optname)
bilingual_str AmountErrMsg(const std::string &optname, const std::string &strValue)
void LockCoin(const COutPoint &output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
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 ...
size_t KeypoolCountExternalKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void KeepDestination()
Keep the address.
void ListLockedCoins(std::vector< COutPoint > &vOutpts) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
unsigned int GetKeyPoolSize() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::set< CTxDestination > GetLabelAddresses(const std::string &label) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool IsLockedCoin(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
SigningResult SignMessage(const std::string &message, const PKHash &pkhash, std::string &str_sig) const
void UnlockCoin(const COutPoint &output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
DBErrors LoadWallet(bool &fFirstRunRet)
OutputType TransactionChangeType(const std::optional< OutputType > &change_type, const std::vector< CRecipient > &vecSend) const
bool SignTransaction(CMutableTransaction &tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void ReturnDestination()
Return reserved address.
bool GetNewChangeDestination(const OutputType type, CTxDestination &dest, std::string &error)
void UnlockAllCoins() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool TopUpKeyPool(unsigned int kpSize=0)
bool SetAddressBookWithDB(WalletBatch &batch, const CTxDestination &address, const std::string &strName, const std::string &strPurpose)
TransactionError FillPSBT(PartiallySignedTransaction &psbtx, bool &complete, SigHashType sighash_type=SigHashType().withForkId(), bool sign=true, bool bip32derivs=true) const
Fills out a PSBT with information from the wallet.
bool GetReservedDestination(CTxDestination &pubkey, bool internal)
Reserve an address.
int64_t GetOldestKeyPoolTime() const
bool DelAddressBook(const CTxDestination &address)
bool GetNewDestination(const OutputType type, const std::string label, CTxDestination &dest, std::string &error)
DBErrors ZapSelectTx(std::vector< TxId > &txIdsIn, std::vector< TxId > &txIdsOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector< std::pair< std::string, std::string > > orderForm, bool broadcast=true)
Add the transaction to the wallet and maybe attempt to broadcast it.
bool AddWalletFlags(uint64_t flags)
Overwrite all flags by the given uint64_t.
bool ImportPubKeys(const std::vector< CKeyID > &ordered_pubkeys, const std::map< CKeyID, CPubKey > &pubkey_map, const std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > &key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void blockConnected(const CBlock &block, int height) override
bool LoadToWallet(const TxId &txid, const UpdateWalletTxFn &fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void MarkConflicted(const BlockHash &hashBlock, int conflicting_height, const TxId &txid)
Mark a transaction (and its in-wallet descendants) as conflicting with a particular block.
void Flush()
Flush wallet (bitdb flush)
void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo.
bool SetMaxVersion(int nVersion)
change which version we're allowed to upgrade to (note that this does not immediately imply upgrading...
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 SubmitTxMemoryPoolAndRelay(const CWalletTx &wtx, std::string &err_string, bool relay) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Pass this transaction to node for mempool insertion and relay to peers if flag set to true.
void AddToSpends(const COutPoint &outpoint, const TxId &wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void SyncTransaction(const CTransactionRef &tx, CWalletTx::Confirmation confirm, bool update_tx=true) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Used by TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions.
bool ImportScripts(const std::set< CScript > scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
CWalletTx * AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation &confirm, const UpdateWalletTxFn &update_wtx=nullptr, bool fFlushOnClose=true)
bool HasWalletSpend(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Check if a given transaction has any of its outputs spent by another transaction in the wallet.
bool ChangeWalletPassphrase(const SecureString &strOldWalletPassphrase, const SecureString &strNewWalletPassphrase)
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 IsFromMe(const CTransaction &tx) const
should probably be renamed to IsRelevantToMe
bool ImportPrivKeys(const std::map< CKeyID, CKey > &privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
isminetype IsMine(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool LoadWalletFlags(uint64_t flags)
Loads the flags into the wallet.
bool ImportScriptPubKeys(const std::string &label, const std::set< CScript > &script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool CanGetAddresses(bool internal=false) const
Returns true if the wallet can give out new addresses.
ScanResult ScanForWalletTransactions(const BlockHash &start_block, int start_height, std::optional< int > max_height, const WalletRescanReserver &reserver, bool fUpdate)
Scan the block chain (starting in start_block) for transactions from or to us.
bool IsSpentKey(const TxId &txid, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool TransactionCanBeAbandoned(const TxId &txid) const
Return whether transaction can be abandoned.
const CChainParams & GetChainParams() const override
Amount GetDebit(const CTxIn &txin, const isminefilter &filter) const
Returns amount of debit if the input matches the filter, otherwise returns 0.
void MarkInputsDirty(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed.
bool AddToWalletIfInvolvingMe(const CTransactionRef &tx, CWalletTx::Confirmation confirm, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Add a transaction to the wallet, or update it.
bool IsSpent(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Outpoint is spent if any non-conflicted transaction, spends it:
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UnsetWalletFlagWithDB(WalletBatch &batch, uint64_t flag)
Unsets a wallet flag and saves it to disk.
void SyncMetaData(std::pair< TxSpends::iterator, TxSpends::iterator >) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool EncryptWallet(const SecureString &strWalletPassphrase)
void updatedBlockTip() override
void UnsetWalletFlag(uint64_t flag)
Unsets a single wallet flag.
void transactionRemovedFromMempool(const CTransactionRef &tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override
bool IsWalletFlagSet(uint64_t flag) const override
Check if a certain wallet flag is set.
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver, bool update)
Scan active chain for relevant transactions after importing keys.
bool AbandonTransaction(const TxId &txid)
Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent.
void UnsetBlankWalletFlag(WalletBatch &batch) override
Unset the blank wallet flag and saves it to disk.
void SetSpentKeyState(WalletBatch &batch, const TxId &txid, unsigned int n, bool used, std::set< CTxDestination > &tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void transactionAddedToMempool(const CTransactionRef &tx, uint64_t mempool_sequence) override
DBErrors ReorderTransactions()
void blockDisconnected(const CBlock &block, int height) override
void Close()
Close wallet database.
int64_t IncOrderPosNext(WalletBatch *batch=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Increment the next transaction order id.
const CWalletTx * GetWalletTx(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void ResendWalletTransactions()
void SetMinVersion(enum WalletFeature, WalletBatch *batch_in=nullptr, bool fExplicit=false) override
signify that a particular wallet feature is now used.
std::set< TxId > GetTxConflicts(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool DummySignInput(CTxIn &tx_in, const CTxOut &txout, bool use_max_sig=false) const
void chainStateFlushed(const CBlockLocator &loc) override
isminetype
IsMine() return codes.
bool error(const char *fmt, const Args &...args)
@ PRIVATE_KEY_NOT_AVAILABLE
bool ParseMoney(const std::string &money_string, Amount &nRet)
Parse an amount denoted in full coins.
static auto quoted(const std::string &s)
static std::string PathToString(const path &path)
Convert path object to byte string.
static path PathFromString(const std::string &string)
Convert byte string to path object.
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
std::unique_ptr< Wallet > MakeWallet(const std::shared_ptr< CWallet > &wallet)
Return implementation of Wallet interface.
std::unique_ptr< Handler > MakeHandler(boost::signals2::connection connection)
Return handler wrapping a boost signal connection.
const std::string & FormatOutputType(OutputType type)
const std::array< OutputType, 1 > OUTPUT_TYPES
std::shared_ptr< const CTransaction > CTransactionRef
bool PSBTInputSigned(const PSBTInput &input)
Checks whether a PSBTInput is already signed.
void GetStrongRandBytes(Span< uint8_t > bytes) noexcept
Gather entropy from various sources, feed it into the internal PRNG, and generate random data using i...
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
std::vector< CKeyID > GetAffectedKeys(const CScript &spk, const SigningProvider &provider)
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
bool ProduceSignature(const SigningProvider &provider, const BaseSignatureCreator &creator, const CScript &fromPubKey, SignatureData &sigdata)
Produce a script signature using a generic signature creator.
void UpdateInput(CTxIn &input, const SignatureData &data)
const BaseSignatureCreator & DUMMY_MAXIMUM_SIGNATURE_CREATOR
A signature creator that just produces 72-byte empty signatures.
const BaseSignatureCreator & DUMMY_SIGNATURE_CREATOR
A signature creator that just produces 71-byte empty signatures.
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
std::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
void ReplaceAll(std::string &in_out, const std::string &search, const std::string &substitute)
std::string ToString(const T &t)
Locale-independent version of std::to_string.
static constexpr Amount zero() noexcept
A BlockHash is a unqiue identifier for a block.
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
void SetSeed(Span< const std::byte > seed)
std::optional< int > last_scanned_height
BlockHash last_scanned_block
Hash and height of most recent block that was successfully scanned.
enum CWallet::ScanResult::@20 status
BlockHash last_failed_block
Hash of the most recent block that could not be scanned due to read errors or pruning.
Confirmation includes tx status and a triplet of {block height/block hash/tx index in block} at which...
SecureString create_passphrase
std::map< CKeyID, CKey > keys
A version of CTransaction with the PSBT format.
std::vector< PSBTInput > inputs
std::optional< CMutableTransaction > tx
A TxId is the identifier of a transaction.
#define WAIT_LOCK(cs, name)
#define AssertLockNotHeld(cs)
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
std::string ShellEscape(const std::string &arg)
int64_t GetTimeMillis()
Returns the system time (not mockable)
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
bilingual_str _(const char *psz)
Translation function.
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
MemPoolRemovalReason
Reason why a transaction was removed from the mempool, this is passed to the notification signal.
@ BLOCK
Removed for block.
@ CONFLICT
Removed for conflict with in-block transaction.
std::unique_ptr< WalletDatabase > MakeDatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
std::map< std::string, std::string > mapValue_t
constexpr Amount HIGH_TX_FEE_PER_KB
Discourage users to set fees higher than this amount (in satoshis) per kB.
std::function< void(std::unique_ptr< interfaces::Wallet > wallet)> LoadWalletFn
constexpr OutputType DEFAULT_ADDRESS_TYPE
Default for -addresstype.
constexpr Amount HIGH_MAX_TX_FEE
-maxtxfee will warn if called with a higher fee than this amount (in satoshis)
static const bool DEFAULT_SPEND_ZEROCONF_CHANGE
Default for -spendzeroconfchange.
static constexpr uint64_t KNOWN_WALLET_FLAGS
static const bool DEFAULT_WALLETBROADCAST
constexpr Amount HIGH_APS_FEE
discourage APS fee higher than this amount
std::unique_ptr< interfaces::Handler > HandleLoadWallet(LoadWalletFn load_wallet)
bool RemoveWallet(const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
static void ReleaseWallet(CWallet *wallet)
std::unique_ptr< WalletDatabase > MakeWalletDatabase(const std::string &name, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error_string)
const std::map< uint64_t, std::string > WALLET_FLAG_CAVEATS
void MaybeResendWalletTxs()
Called periodically by the schedule thread.
static std::vector< std::shared_ptr< CWallet > > vpwallets GUARDED_BY(cs_wallets)
void UnloadWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly unload and delete the wallet.
static std::condition_variable g_wallet_release_cv
static GlobalMutex g_loading_wallet_mutex
RecursiveMutex cs_wallets
bool AddWalletSetting(interfaces::Chain &chain, const std::string &wallet_name)
Add wallet name to persistent configuration so it will be loaded on startup.
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 UpdateWalletSetting(interfaces::Chain &chain, const std::string &wallet_name, std::optional< bool > load_on_startup, std::vector< bilingual_str > &warnings)
static GlobalMutex g_wallet_release_mutex
std::shared_ptr< CWallet > GetWallet(const std::string &name)
std::vector< std::shared_ptr< CWallet > > GetWallets()
bool AddWallet(const std::shared_ptr< CWallet > &wallet)
std::shared_ptr< CWallet > LoadWallet(interfaces::Chain &chain, const std::string &name, std::optional< bool > load_on_start, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
std::shared_ptr< CWallet > CreateWallet(interfaces::Chain &chain, const std::string &name, std::optional< bool > load_on_start, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
DBErrors
Error statuses for the wallet database.
fs::path GetWalletDir()
Get the path of the wallet directory.
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
@ WALLET_FLAG_AVOID_REUSE
@ WALLET_FLAG_KEY_ORIGIN_METADATA
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
@ WALLET_FLAG_BLANK_WALLET
Flag set when a wallet contains no HD seed and no private keys, scripts, addresses,...
WalletFeature
(client) version numbers for particular wallet features
@ FEATURE_PRE_SPLIT_KEYPOOL