8 #if defined(HAVE_CONFIG_H)
12 #include <blockfilter.h>
76 #include <condition_variable>
95 if (value.isStr() && value.get_str() == wallet_name)
return true;
104 if (!setting_value.
isArray())
return true;
107 if (!value.isStr() || value.get_str() != wallet_name) new_value.
push_back(value);
109 if (new_value.
size() == setting_value.
size())
return true;
114 const std::string& wallet_name,
115 std::optional<bool> load_on_startup,
116 std::vector<bilingual_str>& warnings)
118 if (!load_on_startup)
return;
120 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
122 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));
144 std::vector<std::shared_ptr<CWallet>>::const_iterator i = std::find(
context.wallets.begin(),
context.wallets.end(),
wallet);
145 if (i !=
context.wallets.end())
return false;
147 wallet->ConnectScriptPubKeyManNotifiers();
148 wallet->NotifyCanGetAddressesChanged();
160 wallet->m_chain_notifications_handler.reset();
162 std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(
context.wallets.begin(),
context.wallets.end(),
wallet);
163 if (i ==
context.wallets.end())
return false;
174 std::vector<bilingual_str> warnings;
194 for (
const std::shared_ptr<CWallet>&
wallet :
context.wallets) {
203 auto it =
context.wallet_load_fns.emplace(
context.wallet_load_fns.end(), std::move(load_wallet));
210 for (
auto& load_wallet :
context.wallet_load_fns) {
225 wallet->WalletLogPrintf(
"Releasing wallet\n");
231 if (g_unloading_wallet_set.erase(
name) == 0) {
245 auto it = g_unloading_wallet_set.insert(
name);
257 while (g_unloading_wallet_set.count(
name) == 1) {
264 std::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)
283 warnings.push_back(
_(
"Wallet loaded successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future. Legacy wallets can be migrated to a descriptor wallet with migratewallet."));
288 wallet->postInitProcess();
294 }
catch (
const std::runtime_error& e) {
301 class FastWalletRescanFilter
310 for (
auto spkm :
m_wallet.GetAllScriptPubKeyMans()) {
311 auto desc_spkm{
dynamic_cast<DescriptorScriptPubKeyMan*
>(spkm)};
312 assert(desc_spkm !=
nullptr);
313 AddScriptPubKeys(desc_spkm);
315 if (desc_spkm->IsHDEnabled()) {
321 void UpdateIfNeeded()
325 auto desc_spkm{
dynamic_cast<DescriptorScriptPubKeyMan*
>(
m_wallet.GetScriptPubKeyMan(desc_spkm_id))};
326 assert(desc_spkm !=
nullptr);
327 int32_t current_range_end{desc_spkm->GetEndRange()};
328 if (current_range_end > last_range_end) {
329 AddScriptPubKeys(desc_spkm, last_range_end);
335 std::optional<bool> MatchesBlock(
const uint256& block_hash)
const
351 void AddScriptPubKeys(
const DescriptorScriptPubKeyMan* desc_spkm, int32_t last_range_end = 0)
353 for (
const auto& script_pub_key : desc_spkm->GetScriptPubKeys(last_range_end)) {
354 m_filter_set.emplace(script_pub_key.begin(), script_pub_key.end());
363 if (!result.second) {
384 if (!passphrase.empty()) {
390 error =
Untranslated(
"Private keys must be disabled when using an external signer");
397 error =
Untranslated(
"Descriptor support must be enabled when using an external signer");
404 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.");
428 if (!
wallet->EncryptWallet(passphrase)) {
435 if (!
wallet->Unlock(passphrase)) {
445 wallet->SetupDescriptorScriptPubKeyMans();
447 for (
auto spk_man :
wallet->GetActiveScriptPubKeyMans()) {
448 if (!spk_man->SetupGeneration()) {
464 wallet->postInitProcess();
471 warnings.push_back(
_(
"Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future."));
485 auto wallet_file = wallet_path /
"wallet.dat";
486 std::shared_ptr<CWallet>
wallet;
501 fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
504 }
catch (
const std::exception& e) {
510 fs::remove_all(wallet_path);
524 const auto it = mapWallet.find(hash);
525 if (it == mapWallet.end())
527 return &(it->second);
541 spk_man->UpgradeKeyMetadata();
565 for (
const MasterKeyMap::value_type& pMasterKey :
mapMasterKeys)
567 if(!crypter.
SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
569 if (!crypter.
Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
571 if (
Unlock(_vMasterKey, accept_no_keys)) {
595 if(!crypter.
SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
597 if (!crypter.
Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
602 auto start{SteadyClock::now()};
603 crypter.
SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
604 pMasterKey.second.nDeriveIterations =
static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start));
606 start = SteadyClock::now();
607 crypter.
SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
608 pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations +
static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
610 if (pMasterKey.second.nDeriveIterations < 25000)
611 pMasterKey.second.nDeriveIterations = 25000;
613 WalletLogPrintf(
"Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
615 if (!crypter.
SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
617 if (!crypter.
Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey))
644 if (nWalletVersion >= nVersion)
647 nWalletVersion = nVersion;
651 if (nWalletVersion > 40000)
660 std::set<uint256> result;
663 const auto it = mapWallet.find(txid);
664 if (it == mapWallet.end())
668 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
670 for (
const CTxIn& txin : wtx.
tx->vin)
672 if (mapTxSpends.count(txin.
prevout) <= 1)
674 range = mapTxSpends.equal_range(txin.
prevout);
675 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
676 result.insert(_it->second);
684 const Txid& txid = tx->GetHash();
685 for (
unsigned int i = 0; i < tx->vout.size(); ++i) {
709 int nMinOrderPos = std::numeric_limits<int>::max();
711 for (TxSpends::iterator it = range.first; it != range.second; ++it) {
712 const CWalletTx* wtx = &mapWallet.at(it->second);
724 for (TxSpends::iterator it = range.first; it != range.second; ++it)
726 const uint256& hash = it->second;
728 if (copyFrom == copyTo)
continue;
729 assert(copyFrom &&
"Oldest wallet transaction in range assumed to have been found.");
748 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
749 range = mapTxSpends.equal_range(outpoint);
751 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
752 const uint256& wtxid = it->second;
753 const auto mit = mapWallet.find(wtxid);
754 if (mit != mapWallet.end()) {
756 if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
765 mapTxSpends.insert(std::make_pair(outpoint, wtxid));
774 std::pair<TxSpends::iterator, TxSpends::iterator> range;
775 range = mapTxSpends.equal_range(outpoint);
785 for (
const CTxIn& txin : wtx.
tx->vin)
806 auto start{SteadyClock::now()};
808 kMasterKey.
nDeriveIterations =
static_cast<unsigned int>(25000 * target / (SteadyClock::now() - start));
810 start = SteadyClock::now();
829 delete encrypted_batch;
830 encrypted_batch =
nullptr;
836 auto spk_man = spk_man_pair.second.get();
837 if (!spk_man->Encrypt(_vMasterKey, encrypted_batch)) {
839 delete encrypted_batch;
840 encrypted_batch =
nullptr;
851 delete encrypted_batch;
852 encrypted_batch =
nullptr;
858 delete encrypted_batch;
859 encrypted_batch =
nullptr;
862 Unlock(strWalletPassphrase);
869 if (spk_man->IsHDEnabled()) {
870 if (!spk_man->SetupGeneration(
true)) {
901 typedef std::multimap<int64_t, CWalletTx*>
TxItems;
904 for (
auto& entry : mapWallet)
911 std::vector<int64_t> nOrderPosOffsets;
912 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
919 nOrderPos = nOrderPosNext++;
920 nOrderPosOffsets.push_back(nOrderPos);
927 int64_t nOrderPosOff = 0;
928 for (
const int64_t& nOffsetStart : nOrderPosOffsets)
930 if (nOrderPos >= nOffsetStart)
933 nOrderPos += nOrderPosOff;
934 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
952 int64_t nRet = nOrderPosNext++;
965 for (std::pair<const uint256, CWalletTx>& item : mapWallet)
966 item.second.MarkDirty();
974 auto mi = mapWallet.find(originalHash);
977 assert(mi != mapWallet.end());
1013 tx_destinations.insert(dst);
1033 assert(spk_man !=
nullptr);
1062 std::set<CTxDestination> tx_destinations;
1064 for (
const CTxIn& txin : tx->vin) {
1073 auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(tx, state));
1075 bool fInsertedNew =
ret.second;
1076 bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
1087 if (state.index() != wtx.
m_state.index()) {
1099 if (tx->HasWitness() && !wtx.
tx->HasWitness()) {
1107 std::vector<CWalletTx*> txs{&wtx};
1111 while (!txs.empty()) {
1114 desc_tx->
m_state = inactive_state;
1119 for (
unsigned int i = 0; i < desc_tx->
tx->vout.size(); ++i) {
1121 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(outpoint);
1122 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
1123 const auto wit = mapWallet.find(it->second);
1124 if (wit != mapWallet.end()) {
1125 txs.push_back(&wit->second);
1136 if (fInsertedNew || fUpdated)
1150 if (!strCmd.empty())
1155 ReplaceAll(strCmd,
"%b", conf->confirmed_block_hash.GetHex());
1169 std::thread
t(runCommand, strCmd);
1179 const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(
nullptr,
TxStateInactive{}));
1181 if (!fill_wtx(wtx, ins.second)) {
1193 for (
const CTxIn& txin : wtx.
tx->vin) {
1195 if (it != mapWallet.end()) {
1211 if (
auto* conf = std::get_if<TxStateConfirmed>(&state)) {
1213 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.
prevout);
1214 while (range.first != range.second) {
1215 if (range.first->second != tx.
GetHash()) {
1216 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);
1217 MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
1224 bool fExisted = mapWallet.count(tx.
GetHash()) != 0;
1225 if (fExisted && !fUpdate)
return false;
1237 for (
auto &dest : spk_man->MarkUnusedAddresses(txout.
scriptPubKey)) {
1239 if (!dest.internal.has_value()) {
1244 if (!dest.internal.has_value())
continue;
1258 TxState tx_state = std::visit([](
auto&& s) ->
TxState {
return s; }, state);
1263 throw std::runtime_error(
"DB error adding transaction to wallet, write failed");
1280 for (
const CTxIn& txin : tx->vin) {
1282 if (it != mapWallet.end()) {
1283 it->second.MarkDirty();
1293 auto it = mapWallet.find(hashTx);
1294 assert(it != mapWallet.end());
1302 assert(!wtx.isConfirmed());
1303 assert(!wtx.InMempool());
1305 if (!wtx.isConflicted() && !wtx.isAbandoned()) {
1331 if (m_last_block_processed_height < 0 || conflicting_height < 0) {
1334 int conflictconfirms = (m_last_block_processed_height - conflicting_height + 1) * -1;
1335 if (conflictconfirms >= 0)
1357 std::set<uint256> todo;
1358 std::set<uint256> done;
1360 todo.insert(tx_hash);
1362 while (!todo.empty()) {
1366 auto it = mapWallet.find(now);
1367 assert(it != mapWallet.end());
1370 TxUpdate update_state = try_updating_state(wtx);
1371 if (update_state != TxUpdate::UNCHANGED) {
1375 for (
unsigned int i = 0; i < wtx.
tx->vout.size(); ++i) {
1376 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(
COutPoint(
Txid::FromUint256(now), i));
1377 for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
1378 if (!done.count(iter->second)) {
1379 todo.insert(iter->second);
1384 if (update_state == TxUpdate::NOTIFY_CHANGED) {
1390 MarkInputsDirty(wtx.
tx);
1410 auto it = mapWallet.find(tx->GetHash());
1411 if (it != mapWallet.end()) {
1418 auto it = mapWallet.find(tx->GetHash());
1419 if (it != mapWallet.end()) {
1461 m_last_block_processed_height = block.
height;
1462 m_last_block_processed = block.
hash;
1469 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1484 m_last_block_processed_height = block.
height - 1;
1487 int disconnect_height = block.
height;
1492 for (
const CTxIn& tx_in : ptx->vin) {
1494 if (mapTxSpends.count(tx_in.
prevout) < 1)
continue;
1496 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(tx_in.
prevout);
1499 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) {
1500 CWalletTx& wtx = mapWallet.find(_it->second)->second;
1504 auto try_updating_state = [&](
CWalletTx& tx) {
1524 void CWallet::BlockUntilSyncedToCurrentChain()
const {
1540 const auto mi = mapWallet.find(txin.
prevout.
hash);
1541 if (mi != mapWallet.end())
1569 result = std::max(result, spk_man_pair.second->IsMine(script));
1590 if (outpoint.
n >= wtx->tx->vout.size()) {
1593 return IsMine(wtx->tx->vout[outpoint.
n]);
1608 throw std::runtime_error(std::string(__func__) +
": value out of range");
1616 bool result =
false;
1618 if (!spk_man->IsHDEnabled())
return false;
1630 if (spk_man && spk_man->CanGetAddresses(
internal)) {
1637 void CWallet::SetWalletFlag(uint64_t
flags)
1642 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1656 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1691 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1703 LOCK(spk_man->cs_KeyStore);
1704 return spk_man->ImportScripts(scripts, timestamp);
1713 LOCK(spk_man->cs_KeyStore);
1714 return spk_man->ImportPrivKeys(privkey_map, timestamp);
1717 bool CWallet::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)
1723 LOCK(spk_man->cs_KeyStore);
1724 return spk_man->ImportPubKeys(ordered_pubkeys, pubkey_map, key_origins, add_keypool,
internal, timestamp);
1727 bool CWallet::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)
1733 LOCK(spk_man->cs_KeyStore);
1734 if (!spk_man->ImportScriptPubKeys(script_pub_keys, have_solving_data, timestamp)) {
1739 for (
const CScript& script : script_pub_keys) {
1753 if (new_birth_time < birthtime) {
1771 int start_height = 0;
1812 constexpr
auto INTERVAL_TIME{60s};
1813 auto current_time{reserver.
now()};
1814 auto start_time{reserver.
now()};
1818 uint256 block_hash = start_block;
1821 std::unique_ptr<FastWalletRescanFilter> fast_rescan_filter;
1825 fast_rescan_filter ?
"fast variant using block filters" :
"slow variant inspecting all blocks");
1834 double progress_current = progress_begin;
1835 int block_height = start_height;
1837 if (progress_end - progress_begin > 0.0) {
1838 m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin);
1842 if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
1846 bool next_interval = reserver.
now() >= current_time + INTERVAL_TIME;
1847 if (next_interval) {
1848 current_time = reserver.
now();
1849 WalletLogPrintf(
"Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
1852 bool fetch_block{
true};
1853 if (fast_rescan_filter) {
1854 fast_rescan_filter->UpdateIfNeeded();
1855 auto matches_block{fast_rescan_filter->MatchesBlock(block_hash)};
1856 if (matches_block.has_value()) {
1857 if (*matches_block) {
1862 fetch_block =
false;
1865 LogPrint(
BCLog::SCAN,
"Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.
ToString());
1871 bool block_still_active =
false;
1872 bool next_block =
false;
1883 if (!block_still_active) {
1890 for (
size_t posInBlock = 0; posInBlock < block.
vtx.size(); ++posInBlock) {
1897 if (save_progress && next_interval) {
1912 if (max_height && block_height >= *max_height) {
1923 block_hash = next_block_hash;
1928 const uint256 prev_tip_hash = tip_hash;
1930 if (!max_height && prev_tip_hash != tip_hash) {
1942 WalletLogPrintf(
"Rescan aborted at block %d. Progress=%f\n", block_height, progress_current);
1944 }
else if (block_height &&
chain().shutdownRequested()) {
1945 WalletLogPrintf(
"Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height, progress_current);
1948 WalletLogPrintf(
"Rescan completed in %15dms\n", Ticks<std::chrono::milliseconds>(reserver.
now() - start_time));
1989 result.erase(myHash);
2001 if (!
chain().isReadyToBroadcast())
return false;
2042 int submitted_tx_count = 0;
2049 std::set<CWalletTx*, WalletTxOrderComparator> to_submit;
2050 for (
auto& [txid, wtx] : mapWallet) {
2052 if (!wtx.isUnconfirmed())
continue;
2057 to_submit.insert(&wtx);
2060 for (
auto wtx : to_submit) {
2061 std::string unused_err_string;
2066 if (submitted_tx_count > 0) {
2067 WalletLogPrintf(
"%s: resubmit %u unconfirmed transactions\n", __func__, submitted_tx_count);
2076 if (!pwallet->ShouldResend())
continue;
2077 pwallet->ResubmitWalletTransactions(
true,
false);
2078 pwallet->SetNextResend();
2093 std::map<COutPoint, Coin> coins;
2094 for (
auto& input : tx.
vin) {
2095 const auto mi = mapWallet.find(input.prevout.hash);
2096 if(mi == mapWallet.end() || input.prevout.n >= mi->second.tx->vout.size()) {
2101 coins[input.prevout] =
Coin(wtx.
tx->vout[input.prevout.n], prev_height, wtx.
IsCoinBase());
2103 std::map<int, bilingual_str> input_errors;
2113 if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) {
2129 for (
unsigned int i = 0; i < psbtx.
tx->vin.size(); ++i) {
2130 const CTxIn& txin = psbtx.
tx->vin[i];
2140 const auto it = mapWallet.find(txhash);
2141 if (it != mapWallet.end()) {
2154 int n_signed_this_spkm = 0;
2155 TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm, finalize);
2161 (*n_signed) += n_signed_this_spkm;
2169 for (
const auto& input : psbtx.
inputs) {
2181 if (spk_man_pair.second->CanProvide(script_pub_key, sigdata)) {
2183 return spk_man_pair.second->SignMessage(message, pkhash, str_sig);
2193 return *change_type;
2202 bool any_wpkh{
false};
2204 bool any_pkh{
false};
2206 for (
const auto& recipient : vecSend) {
2207 if (std::get_if<WitnessV1Taproot>(&recipient.dest)) {
2209 }
else if (std::get_if<WitnessV0KeyHash>(&recipient.dest)) {
2211 }
else if (std::get_if<ScriptHash>(&recipient.dest)) {
2213 }
else if (std::get_if<PKHash>(&recipient.dest)) {
2219 if (has_bech32m_spkman && any_tr) {
2224 if (has_bech32_spkman && any_wpkh) {
2229 if (has_p2sh_segwit_spkman && any_sh) {
2235 if (has_legacy_spkman && any_pkh) {
2240 if (has_bech32m_spkman) {
2243 if (has_bech32_spkman) {
2260 wtx.
mapValue = std::move(mapValue);
2269 throw std::runtime_error(std::string(__func__) +
": Wallet db error, transaction commit failed");
2273 for (
const CTxIn& txin : tx->vin) {
2284 std::string err_string;
2286 WalletLogPrintf(
"CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
2301 spk_man_pair.second->RewriteDB();
2311 return nLoadWalletRet;
2318 for (
const uint256& hash : vHashOut) {
2319 const auto& it = mapWallet.find(hash);
2320 wtxOrdered.erase(it->second.m_it_wtxOrdered);
2321 for (
const auto& txin : it->second.tx->vin)
2322 mapTxSpends.erase(txin.prevout);
2323 mapWallet.erase(it);
2332 spk_man_pair.second->RewriteDB();
2338 return nZapSelectTxRet;
2347 bool fUpdated =
false;
2349 std::optional<AddressPurpose> purpose;
2352 std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
2353 fUpdated = (mi != m_address_book.end() && !mi->second.IsChange());
2354 m_address_book[address].SetLabel(strName);
2357 purpose = m_address_book[address].purpose = new_purpose;
2359 purpose = m_address_book[address].purpose;
2391 m_address_book.erase(address);
2405 if (legacy_spk_man) {
2406 return legacy_spk_man->KeypoolCountExternalKeys();
2409 unsigned int count = 0;
2411 count += spk_man.second->GetKeyPoolSize();
2421 unsigned int count = 0;
2423 count += spk_man->GetKeyPoolSize();
2433 res &= spk_man->TopUp(kpSize);
2446 auto op_dest = spk_man->GetNewDestination(type);
2469 return std::nullopt;
2472 std::optional<int64_t> oldest_key{std::numeric_limits<int64_t>::max()};
2474 oldest_key = std::min(oldest_key, spk_man_pair.second->GetOldestKeyPoolTime());
2480 for (
auto& entry : mapWallet) {
2483 for (
unsigned int i = 0; i < wtx.
tx->vout.size(); i++) {
2496 for (
const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book) {
2497 const auto& entry = item.second;
2498 func(item.first, entry.GetLabel(), entry.IsChange(), entry.purpose);
2505 std::vector<CTxDestination> result;
2513 result.emplace_back(dest);
2521 std::set<std::string> label_set;
2523 bool _is_change,
const std::optional<AddressPurpose>& _purpose) {
2524 if (_is_change)
return;
2525 if (!purpose || purpose == _purpose) {
2526 label_set.insert(_label);
2542 if (!op_address)
return op_address;
2572 if (signer_spk_man ==
nullptr) {
2576 return signer_spk_man->DisplayAddress(scriptPubKey, signer);
2584 setLockedCoins.insert(output);
2594 bool was_locked = setLockedCoins.erase(output);
2595 if (batch && was_locked) {
2604 bool success =
true;
2606 for (
auto it = setLockedCoins.begin(); it != setLockedCoins.end(); ++it) {
2609 setLockedCoins.clear();
2616 return setLockedCoins.count(output) > 0;
2622 for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
2623 it != setLockedCoins.end(); it++) {
2625 vOutpts.push_back(outpt);
2633 mapKeyBirth.clear();
2636 std::map<CKeyID, const TxStateConfirmed*> mapKeyFirstBlock;
2643 assert(spk_man !=
nullptr);
2647 for (
const auto& entry : spk_man->mapKeyMetadata) {
2648 if (entry.second.nCreateTime) {
2649 mapKeyBirth[entry.first] = entry.second.nCreateTime;
2655 if (mapKeyBirth.count(keyid) == 0)
2656 mapKeyFirstBlock[keyid] = &max_confirm;
2660 if (mapKeyFirstBlock.empty())
2664 for (
const auto& entry : mapWallet) {
2669 for (
const CTxOut &txout : wtx.
tx->vout) {
2673 auto rit = mapKeyFirstBlock.find(keyid);
2674 if (rit != mapKeyFirstBlock.end() && conf->confirmed_block_height < rit->second->confirmed_block_height) {
2684 for (
const auto& entry : mapKeyFirstBlock) {
2716 std::optional<uint256> block_hash;
2718 block_hash = conf->confirmed_block_hash;
2720 block_hash = conf->conflicting_block_hash;
2726 int64_t block_max_time;
2727 if (
chain().findBlock(*block_hash,
FoundBlock().time(blocktime).maxTime(block_max_time))) {
2728 if (rescanning_old_block) {
2729 nTimeSmart = block_max_time;
2732 int64_t latestEntry = 0;
2735 int64_t latestTolerated = latestNow + 300;
2737 for (
auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
2747 if (nSmartTime <= latestTolerated) {
2748 latestEntry = nSmartTime;
2749 if (nSmartTime > latestNow) {
2750 latestNow = nSmartTime;
2756 nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
2767 if (std::get_if<CNoDestination>(&dest))
2771 if (
auto* data{
common::FindKey(m_address_book, dest)}) data->previously_spent =
false;
2781 m_address_book[dest].previously_spent =
true;
2786 m_address_book[dest].receive_requests[id] = request;
2791 if (
auto* data{
common::FindKey(m_address_book, dest)})
return data->previously_spent;
2797 std::vector<std::string>
values;
2798 for (
const auto& [dest, entry] : m_address_book) {
2799 for (
const auto& [
id, request] : entry.receive_requests) {
2800 values.emplace_back(request);
2809 m_address_book[dest].receive_requests[id] = value;
2816 m_address_book[dest].receive_requests.erase(
id);
2829 fs::file_type path_type = fs::symlink_status(wallet_path).type();
2830 if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory ||
2831 (path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) ||
2834 "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
2835 "database/log.?????????? files can be stored, a location where such a directory could be created, "
2836 "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
2841 return MakeDatabase(wallet_path, options, status, error_string);
2848 const std::string& walletFile = database->Filename();
2850 const auto start{SteadyClock::now()};
2855 walletInstance->m_notify_tx_changed_script =
args.
GetArg(
"-walletnotify",
"");
2858 bool rescan_required =
false;
2859 DBErrors nLoadWalletRet = walletInstance->LoadWallet();
2862 error =
strprintf(
_(
"Error loading %s: Wallet corrupted"), walletFile);
2867 warnings.push_back(
strprintf(
_(
"Error reading %s! All keys read correctly, but transaction data"
2868 " or address metadata may be missing or incorrect."),
2876 error =
strprintf(
_(
"Error loading %s: External signer wallet being loaded without external signer support compiled"), walletFile);
2884 warnings.push_back(
strprintf(
_(
"Error reading %s! Transaction data may be missing or incorrect."
2885 " Rescanning wallet."), walletFile));
2886 rescan_required =
true;
2888 error =
strprintf(
_(
"Unrecognized descriptor found. Loading wallet %s\n\n"
2889 "The wallet might had been created on a newer version.\n"
2890 "Please try running the latest software version.\n"), walletFile);
2893 error =
strprintf(
_(
"Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
2894 "The wallet might have been tampered with or created with malicious intent.\n"), walletFile);
2903 const bool fFirstRun = walletInstance->m_spk_managers.empty() &&
2911 walletInstance->InitWalletFlags(wallet_creation_flags);
2915 walletInstance->SetupLegacyScriptPubKeyMan();
2919 LOCK(walletInstance->cs_wallet);
2921 walletInstance->SetupDescriptorScriptPubKeyMans();
2925 for (
auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
2926 if (!spk_man->SetupGeneration()) {
2927 error =
_(
"Unable to generate initial keys");
2939 error =
strprintf(
_(
"Error loading %s: Private keys can only be disabled during creation"), walletFile);
2942 for (
auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
2943 if (spk_man->HavePrivateKeys()) {
2944 warnings.push_back(
strprintf(
_(
"Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
2950 if (!
args.
GetArg(
"-addresstype",
"").empty()) {
2956 walletInstance->m_default_address_type = parsed.value();
2959 if (!
args.
GetArg(
"-changetype",
"").empty()) {
2965 walletInstance->m_default_change_type = parsed.value();
2975 _(
"This is the minimum transaction fee you pay on every transaction."));
2978 walletInstance->m_min_fee =
CFeeRate{min_tx_fee.value()};
2982 const std::string max_aps_fee{
args.
GetArg(
"-maxapsfee",
"")};
2983 if (max_aps_fee ==
"-1") {
2984 walletInstance->m_max_aps_fee = -1;
2985 }
else if (std::optional<CAmount> max_fee =
ParseMoney(max_aps_fee)) {
2988 _(
"This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
2990 walletInstance->m_max_aps_fee = max_fee.value();
2999 if (!fallback_fee) {
3004 _(
"This is the transaction fee you may pay when fee estimates are not available."));
3006 walletInstance->m_fallback_fee =
CFeeRate{fallback_fee.value()};
3010 walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.
GetFeePerK() != 0;
3019 _(
"This is the transaction fee you may discard if change is smaller than dust at this level"));
3021 walletInstance->m_discard_rate =
CFeeRate{discard_fee.value()};
3031 _(
"This is the transaction fee you will pay if you send a transaction."));
3034 walletInstance->m_pay_tx_fee =
CFeeRate{pay_tx_fee.value(), 1000};
3037 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' (must be at least %s)"),
3049 warnings.push_back(
strprintf(
_(
"%s is set very high! Fees this large could be paid on a single transaction."),
"-maxtxfee"));
3053 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
3058 walletInstance->m_default_max_tx_fee = max_fee.value();
3062 if (std::optional<CAmount> consolidate_feerate =
ParseMoney(
args.
GetArg(
"-consolidatefeerate",
""))) {
3063 walletInstance->m_consolidate_feerate =
CFeeRate(*consolidate_feerate);
3072 _(
"The wallet will avoid paying less than the minimum relay fee."));
3079 walletInstance->WalletLogPrintf(
"Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
3082 walletInstance->TopUpKeyPool();
3085 std::optional<int64_t> time_first_key;
3086 for (
auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
3087 int64_t time = spk_man->GetTimeFirstKey();
3088 if (!time_first_key || time < *time_first_key) time_first_key = time;
3090 if (time_first_key) walletInstance->m_birth_time = *time_first_key;
3097 LOCK(walletInstance->cs_wallet);
3099 walletInstance->WalletLogPrintf(
"setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
3100 walletInstance->WalletLogPrintf(
"mapWallet.size() = %u\n", walletInstance->mapWallet.size());
3101 walletInstance->WalletLogPrintf(
"m_address_book.size() = %u\n", walletInstance->m_address_book.size());
3104 return walletInstance;
3109 LOCK(walletInstance->cs_wallet);
3111 assert(!walletInstance->m_chain || walletInstance->m_chain == &
chain);
3112 walletInstance->m_chain = &
chain;
3122 error =
Untranslated(
"Wallet files should not be reused across chains. Restart bitcoind with -walletcrosschain to override.");
3138 walletInstance->m_attaching_chain =
true;
3139 walletInstance->m_chain_notifications_handler = walletInstance->chain().handleNotifications(walletInstance);
3142 int rescan_height = 0;
3143 if (!rescan_required)
3149 rescan_height = *fork_height;
3157 walletInstance->m_last_block_processed_height = *tip_height;
3159 walletInstance->m_last_block_processed.
SetNull();
3160 walletInstance->m_last_block_processed_height = -1;
3163 if (tip_height && *tip_height != rescan_height)
3167 std::optional<int64_t> time_first_key = walletInstance->m_birth_time.load();
3168 if (time_first_key) {
3175 rescan_height = *tip_height;
3183 int block_height = *tip_height;
3184 while (block_height > 0 &&
chain.
haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
3188 if (rescan_height != block_height) {
3199 _(
"Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)") :
3201 "Error loading wallet. Wallet requires blocks to be downloaded, "
3202 "and software does not currently support loading wallets while "
3203 "blocks are being downloaded out of order when using assumeutxo "
3204 "snapshots. Wallet should be able to load successfully after "
3205 "node sync reaches height %s"), block_height);
3211 walletInstance->WalletLogPrintf(
"Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
3216 error =
_(
"Failed to rescan the wallet during initialization");
3220 walletInstance->m_attaching_chain =
false;
3222 walletInstance->GetDatabase().IncrementUpdateCounter();
3224 walletInstance->m_attaching_chain =
false;
3231 const auto& address_book_it = m_address_book.find(dest);
3232 if (address_book_it == m_address_book.end())
return nullptr;
3233 if ((!allow_change) && address_book_it->second.IsChange()) {
3236 return &address_book_it->second;
3248 if (version < prev_version) {
3249 error =
strprintf(
_(
"Cannot downgrade wallet from version %i to version %i. Wallet version unchanged."), prev_version, version);
3257 error =
strprintf(
_(
"Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified."), prev_version, version,
FEATURE_PRE_SPLIT_KEYPOOL);
3265 if (!spk_man->Upgrade(prev_version, version,
error)) {
3306 assert(conf->confirmed_block_height >= 0);
3309 assert(conf->conflicting_block_height >= 0);
3324 assert(chain_depth >= 0);
3347 return vMasterKey.empty();
3357 if (!vMasterKey.empty()) {
3358 memory_cleanse(vMasterKey.data(), vMasterKey.size() *
sizeof(decltype(vMasterKey)::value_type));
3372 if (!spk_man_pair.second->CheckDecryptionKey(vMasterKeyIn, accept_no_keys)) {
3376 vMasterKey = vMasterKeyIn;
3384 std::set<ScriptPubKeyMan*> spk_mans;
3385 for (
bool internal : {
false,
true}) {
3389 spk_mans.insert(spk_man);
3398 std::set<ScriptPubKeyMan*> spk_mans;
3400 spk_mans.insert(spk_man_pair.second.get());
3408 std::map<OutputType, ScriptPubKeyMan*>::const_iterator it = spk_managers.find(type);
3409 if (it == spk_managers.end()) {
3417 std::set<ScriptPubKeyMan*> spk_mans;
3420 if (spk_man_pair.second->CanProvide(script, sigdata)) {
3421 spk_mans.insert(spk_man_pair.second.get());
3444 if (spk_man_pair.second->CanProvide(script, sigdata)) {
3445 return spk_man_pair.second->GetSolvingProvider(script);
3453 std::vector<WalletDescriptor> descs;
3456 LOCK(desc_spk_man->cs_desc_man);
3457 descs.push_back(desc_spk_man->GetWalletDescriptor());
3500 uint256 id = spk_manager->GetID();
3519 spk_man->NotifyFirstKeyTimeChanged.connect(std::bind(&
CWallet::FirstKeyTimeChanged,
this, std::placeholders::_1, std::placeholders::_2));
3538 for (
bool internal : {
false,
true}) {
3543 throw std::runtime_error(std::string(__func__) +
": Wallet is locked, cannot setup new descriptors");
3545 if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey,
nullptr)) {
3546 throw std::runtime_error(std::string(__func__) +
": Could not encrypt new descriptors");
3549 spk_manager->SetupDescriptorGeneration(master_key,
t,
internal);
3550 uint256 id = spk_manager->GetID();
3580 if (!signer_res.
isObject())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3581 for (
bool internal : {
false,
true}) {
3582 const UniValue& descriptor_vals = signer_res.
find_value(
internal ?
"internal" :
"receive");
3583 if (!descriptor_vals.
isArray())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3585 const std::string& desc_str = desc_val.getValStr();
3587 std::string desc_error;
3588 std::unique_ptr<Descriptor> desc =
Parse(desc_str, keys, desc_error,
false);
3589 if (desc ==
nullptr) {
3590 throw std::runtime_error(std::string(__func__) +
": Invalid descriptor \"" + desc_str +
"\" (" + desc_error +
")");
3592 if (!desc->GetOutputType()) {
3597 spk_manager->SetupDescriptor(std::move(desc));
3598 uint256 id = spk_manager->GetID();
3610 throw std::runtime_error(std::string(__func__) +
": writing active ScriptPubKeyMan id failed");
3625 spk_mans[type] = spk_man;
3627 const auto it = spk_mans_other.find(type);
3628 if (it != spk_mans_other.end() && it->second == spk_man) {
3629 spk_mans_other.erase(type);
3638 if (spk_man !=
nullptr && spk_man->GetID() ==
id) {
3642 throw std::runtime_error(std::string(__func__) +
": erasing active ScriptPubKeyMan id failed");
3646 spk_mans.erase(type);
3658 return spk_man !=
nullptr;
3678 return std::nullopt;
3683 return std::nullopt;
3687 if (!desc_spk_man) {
3688 throw std::runtime_error(std::string(__func__) +
": unexpected ScriptPubKeyMan type.");
3691 LOCK(desc_spk_man->cs_desc_man);
3692 const auto& type = desc_spk_man->GetWalletDescriptor().descriptor->GetOutputType();
3693 assert(type.has_value());
3703 WalletLogPrintf(
"Cannot add WalletDescriptor to a non-descriptor wallet\n");
3710 spk_man->UpdateWalletDescriptor(desc);
3713 spk_man = new_spk_man.get();
3716 uint256 id = new_spk_man->GetID();
3721 for (
const auto& entry : signing_provider.
keys) {
3722 const CKey& key = entry.second;
3723 spk_man->AddDescriptorKey(key, key.
GetPubKey());
3727 if (!spk_man->TopUp()) {
3735 auto script_pub_keys = spk_man->GetScriptPubKeys();
3736 if (script_pub_keys.empty()) {
3737 WalletLogPrintf(
"Could not generate scriptPubKeys (cache is empty)\n");
3742 for (
const auto& script : script_pub_keys) {
3752 spk_man->WriteDescriptor();
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(
Span{key},
Span{value})) {
3826 bool committed = batch->TxnCommit();
3839 if (res == std::nullopt) {
3840 error =
_(
"Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
3841 return std::nullopt;
3852 error =
_(
"Error: This wallet is already a descriptor wallet");
3857 std::set<CTxDestination> not_migrated_dests;
3865 error =
_(
"Error: Duplicate descriptors created during migration. Your wallet may be corrupted.");
3868 uint256 id = desc_spkm->GetID();
3896 std::vector<uint256> txids_to_delete;
3897 std::unique_ptr<WalletBatch> watchonly_batch;
3899 watchonly_batch = std::make_unique<WalletBatch>(data.
watchonly_wallet->GetDatabase());
3913 const uint256& hash = wtx->GetHash();
3916 if (!new_tx) return false;
3917 ins_wtx.SetTx(to_copy_wtx.tx);
3918 ins_wtx.CopyFrom(to_copy_wtx);
3921 error =
strprintf(
_(
"Error: Could not add watchonly tx %s to watchonly wallet"), wtx->GetHash().GetHex());
3926 txids_to_delete.push_back(hash);
3931 error =
strprintf(
_(
"Error: Transaction %s in wallet cannot be identified to belong to migrated wallets"), wtx->GetHash().GetHex());
3935 watchonly_batch.reset();
3937 if (txids_to_delete.size() > 0) {
3938 std::vector<uint256> deleted_txids;
3940 error =
_(
"Error: Could not delete watchonly transactions");
3943 if (deleted_txids != txids_to_delete) {
3944 error =
_(
"Error: Not all watchonly txs could be deleted");
3948 for (
const uint256& txid : deleted_txids) {
3954 std::vector<CTxDestination> dests_to_delete;
3955 for (
const auto& addr_pair : m_address_book) {
3958 if (!
IsMine(addr_pair.first)) {
3964 std::string label = addr_pair.second.GetLabel();
3965 data.
watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
3966 if (!addr_pair.second.IsChange()) {
3969 dests_to_delete.push_back(addr_pair.first);
3977 std::string label = addr_pair.second.GetLabel();
3978 data.
solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
3979 if (!addr_pair.second.IsChange()) {
3980 data.
solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
3982 dests_to_delete.push_back(addr_pair.first);
3988 if (not_migrated_dests.count(addr_pair.first) > 0) {
3989 dests_to_delete.push_back(addr_pair.first);
3994 error =
_(
"Error: Address book data in wallet cannot be identified to belong to migrated wallets");
4002 std::string label = addr_pair.second.GetLabel();
4003 data.
watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4004 if (!addr_pair.second.IsChange()) {
4011 std::string label = addr_pair.second.GetLabel();
4012 data.
solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4013 if (!addr_pair.second.IsChange()) {
4014 data.
solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
4024 for (
const auto& [destination, addr_book_data] :
wallet.m_address_book) {
4026 std::optional<std::string> label = addr_book_data.IsChange() ? std::nullopt : std::make_optional(addr_book_data.GetLabel());
4028 if (addr_book_data.purpose) batch.WritePurpose(address,
PurposeToString(*addr_book_data.purpose));
4029 if (label) batch.WriteName(address, *label);
4036 if (dests_to_delete.size() > 0) {
4037 for (
const auto& dest : dests_to_delete) {
4039 error =
_(
"Error: Unable to remove watchonly address book data");
4064 std::optional<MigrationData> data =
wallet.GetDescriptorsForLegacy(
error);
4065 if (data == std::nullopt)
return false;
4068 if (data->watch_descs.size() > 0 || data->solvable_descs.size() > 0) {
4085 if (data->watch_descs.size() > 0) {
4086 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the watched scripts\n");
4089 std::vector<bilingual_str> warnings;
4090 std::string wallet_name =
wallet.GetName() +
"_watchonly";
4098 if (!data->watchonly_wallet) {
4099 error =
_(
"Error: Failed to create new watchonly wallet");
4102 res.watchonly_wallet = data->watchonly_wallet;
4103 LOCK(data->watchonly_wallet->cs_wallet);
4106 for (
const auto& [desc_str, creation_time] : data->watch_descs) {
4109 std::string parse_err;
4110 std::unique_ptr<Descriptor> desc =
Parse(desc_str, keys, parse_err,
true);
4112 assert(!desc->IsRange());
4116 data->watchonly_wallet->AddWalletDescriptor(w_desc, keys,
"",
false);
4122 if (data->solvable_descs.size() > 0) {
4123 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the unwatched solvable scripts\n");
4126 std::vector<bilingual_str> warnings;
4127 std::string wallet_name =
wallet.GetName() +
"_solvables";
4135 if (!data->solvable_wallet) {
4136 error =
_(
"Error: Failed to create new watchonly wallet");
4139 res.solvables_wallet = data->solvable_wallet;
4140 LOCK(data->solvable_wallet->cs_wallet);
4143 for (
const auto& [desc_str, creation_time] : data->solvable_descs) {
4146 std::string parse_err;
4147 std::unique_ptr<Descriptor> desc =
Parse(desc_str, keys, parse_err,
true);
4149 assert(!desc->IsRange());
4153 data->solvable_wallet->AddWalletDescriptor(w_desc, keys,
"",
false);
4172 std::vector<bilingual_str> warnings;
4177 return util::Error{
_(
"Unable to unload the wallet before migrating")};
4196 if (!local_wallet) {
4201 if (!local_wallet->GetLegacyScriptPubKeyMan()) {
4202 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4208 fs::path backup_path = this_wallet_dir / backup_filename;
4210 return util::Error{
_(
"Error: Unable to make a backup of your wallet")};
4214 bool success =
false;
4216 LOCK(local_wallet->cs_wallet);
4219 if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
4220 if (passphrase.find(
'\0') == std::string::npos) {
4221 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
4223 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase entered was incorrect. "
4224 "The passphrase contains a null character (ie - a zero byte). "
4225 "If this passphrase was set with a version of this software prior to 25.0, "
4226 "please try again with only the characters up to — but not including — "
4227 "the first null character.")};
4242 std::set<fs::path> wallet_dirs;
4245 const auto& reload_wallet = [&](std::shared_ptr<CWallet>& to_reload) {
4246 assert(to_reload.use_count() == 1);
4247 std::string
name = to_reload->GetName();
4248 wallet_dirs.insert(
fs::PathFromString(to_reload->GetDatabase().Filename()).parent_path());
4251 return to_reload !=
nullptr;
4254 success = reload_wallet(local_wallet);
4255 res.
wallet = local_wallet;
4270 fs::copy_file(backup_path, temp_backup_location, fs::copy_options::none);
4273 std::vector<std::shared_ptr<CWallet>> created_wallets;
4274 if (local_wallet) created_wallets.push_back(std::move(local_wallet));
4279 for (std::shared_ptr<CWallet>& w : created_wallets) {
4284 for (std::shared_ptr<CWallet>& w : created_wallets) {
4285 if (w->HaveChain()) {
4288 error +=
_(
"\nUnable to cleanup failed migration");
4294 assert(w.use_count() == 1);
4300 for (
const fs::path& dir : wallet_dirs) {
4301 fs::remove_all(dir);
4306 std::vector<bilingual_str> warnings;
4308 error +=
_(
"\nUnable to restore backup of wallet.");
4313 fs::copy_file(temp_backup_location, backup_path, fs::copy_options::none);
4314 fs::remove(temp_backup_location);
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a scriptPubKey for the destination.
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination corresponds to one with an address.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
bool MoneyRange(const CAmount &nValue)
int64_t CAmount
Amount in satoshis (Can be negative)
#define PACKAGE_BUGREPORT
static constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
#define CHECK_NONFATAL(condition)
Identity function.
#define Assert(val)
Identity function.
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
std::vector< CTransactionRef > vtx
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
std::string ToString(const FeeEstimateMode &fee_estimate_mode=FeeEstimateMode::BTC_KVB) const
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
An encapsulated private key.
bool IsValid() const
Check whether this private key is valid.
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.
An outpoint - a combination of a transaction hash and an index n into its vout.
An encapsulated public key.
Serialized script, used inside transaction inputs and outputs.
The basic transaction that is broadcasted on the network and contained in blocks.
const Txid & GetHash() const LIFETIMEBOUND
const std::vector< CTxOut > vout
const std::vector< CTxIn > vin
An input of a transaction.
An output of a transaction.
Double ended buffer combining vector and stream-like interfaces.
Enables interaction with an external signing device or service, such as a hardware wallet.
UniValue GetDescriptors(const int account)
Get receive and change Descriptor(s) from device for a given account.
Tp rand_uniform_delay(const Tp &time, typename Tp::duration range)
Return the time point advanced by a uniform random duration.
RecursiveMutex cs_KeyStore
std::unordered_set< Element, ByteVectorHash > ElementSet
Different type to mark Mutex at global scope.
A Span is an object that can refer to a contiguous sequence of objects.
void push_back(UniValue val)
const UniValue & find_value(std::string_view key) const
const std::vector< UniValue > & getValues() const
const UniValue & get_array() const
std::string ToString() const
constexpr unsigned char * begin()
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 CBlockLocator getActiveChainLocator(const uint256 &block_hash)=0
Return a locator that refers to a block in the active chain.
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 common::SettingsValue getRwSetting(const std::string &name)=0
Return <datadir>/settings.json setting value.
virtual std::optional< int > getHeight()=0
Get current chain height, not including genesis block (returns 0 if chain only contains genesis block...
virtual bool hasAssumedValidChain()=0
Return true if an assumed-valid chain is in use.
virtual bool findAncestorByHeight(const uint256 &block_hash, int ancestor_height, const FoundBlock &ancestor_out={})=0
Find ancestor of block at specified height and optionally return ancestor information.
virtual bool findBlock(const uint256 &hash, const FoundBlock &block={})=0
Return whether node has the block and optionally return block metadata or contents.
virtual double guessVerificationProgress(const uint256 &block_hash)=0
Estimate fraction of total transactions verified if blocks up to the specified block hash are verifie...
virtual 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 void waitForNotificationsIfTipChanged(const uint256 &old_tip)=0
Wait for pending notifications to be processed unless block hash points to the current chain tip.
virtual void initMessage(const std::string &message)=0
Send init message.
virtual bool isInMempool(const uint256 &txid)=0
Check if transaction is in mempool.
virtual bool broadcastTransaction(const CTransactionRef &tx, const CAmount &max_tx_fee, bool relay, std::string &err_string)=0
Transaction is added to memory pool, if the transaction fee is below the amount specified by max_tx_f...
virtual bool updateRwSetting(const std::string &name, const common::SettingsValue &value, bool write=true)=0
Write a setting to <datadir>/settings.json.
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
static transaction_identifier FromUint256(const uint256 &id)
Encryption/decryption context with key information.
bool Decrypt(const std::vector< unsigned char > &vchCiphertext, CKeyingMaterial &vchPlaintext) const
bool Encrypt(const CKeyingMaterial &vchPlaintext, std::vector< unsigned char > &vchCiphertext) const
bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector< unsigned char > &chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
A key from a CWallet's keypool.
int64_t nTime
The time at which the key was generated. Set in AddKeypoolPubKeyWithDB.
CPubKey vchPubKey
The public key.
bool fInternal
Whether this keypool entry is in the internal keypool (for change outputs)
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< unsigned char > vchSalt
unsigned int nDerivationMethod
0 = EVP_sha512() 1 = scrypt()
std::vector< unsigned char > vchCryptedKey
unsigned int nDeriveIterations
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
std::atomic< bool > fAbortRescan
const std::string & GetName() const
Get a name for this wallet for logging/debugging purposes.
bool HaveChain() const
Interface to assert chain access.
bool GetBroadcastTransactions() const
Inquire whether this wallet broadcasts transactions.
std::function< bool(CWalletTx &wtx, bool new_tx)> UpdateWalletTxFn
Callback for updating transaction metadata in mapWallet.
CAmount m_default_max_tx_fee
Absolute maximum transaction fee (in satoshis) used by default for the wallet.
OutputType m_default_address_type
LegacyScriptPubKeyMan * GetLegacyScriptPubKeyMan() const
Get the LegacyScriptPubKeyMan which is used for all types, internal, and external.
void AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
Adds the active ScriptPubKeyMan for the specified type and internal.
void LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
Loads an active ScriptPubKeyMan for the specified type and internal.
std::unique_ptr< WalletDatabase > m_database
Internal database handle.
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)
const CKeyingMaterial & GetEncryptionKey() const override
std::set< ScriptPubKeyMan * > GetActiveScriptPubKeyMans() const
Returns all unique ScriptPubKeyMans in m_internal_spk_managers and m_external_spk_managers.
const CAddressBookData * FindAddressBookEntry(const CTxDestination &, bool allow_change=false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void postInitProcess()
Wallet post-init setup Gives the wallet a chance to register repetitive tasks and complete post-init ...
int GetTxDepthInMainChain(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Return depth of transaction in blockchain: <0 : conflicts with a transaction this deep in the blockch...
unsigned int nMasterKeyMaxID
bool SetAddressReceiveRequest(WalletBatch &batch, const CTxDestination &dest, const std::string &id, const std::string &value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get last block processed height.
std::atomic< double > m_scanning_progress
boost::signals2::signal< void(bool fHaveWatchOnly)> NotifyWatchonlyChanged
Watch-only address added.
WalletDatabase & GetDatabase() const override
DescriptorScriptPubKeyMan * GetDescriptorScriptPubKeyMan(const WalletDescriptor &desc) const
Return the DescriptorScriptPubKeyMan for a WalletDescriptor if it is already in the wallet.
std::map< OutputType, ScriptPubKeyMan * > m_external_spk_managers
void LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor &desc)
Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it.
bool IsLegacy() const
Determine if we are a legacy wallet.
std::optional< MigrationData > GetDescriptorsForLegacy(bilingual_str &error) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get all of the descriptors from a legacy wallet.
bool MigrateToSQLite(bilingual_str &error) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Move all records from the BDB database to a new SQLite database for storage.
bool BackupWallet(const std::string &strDest) const
std::map< OutputType, ScriptPubKeyMan * > m_internal_spk_managers
std::string m_name
Wallet name: relative directory name or "" for default wallet.
bool SetAddressPreviouslySpent(WalletBatch &batch, const CTxDestination &dest, bool used) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
RecursiveMutex m_relock_mutex
std::string m_notify_tx_changed_script
Notify external script when a wallet transaction comes in or is updated (handled by -walletnotify)
std::string GetDisplayName() const override
Returns a bracketed wallet name for displaying in logs, will return [default wallet] if the wallet ha...
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.
std::atomic< bool > m_attaching_chain
bool fBroadcastTransactions
Whether this wallet will submit newly created transactions to the node's mempool and prompt rebroadca...
int GetTxBlocksToMaturity(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool HasEncryptionKeys() const override
static std::shared_ptr< CWallet > Create(WalletContext &context, const std::string &name, std::unique_ptr< WalletDatabase > database, uint64_t wallet_creation_flags, bilingual_str &error, std::vector< bilingual_str > &warnings)
int GetVersion() const
get the current wallet format (the oldest client version guaranteed to understand this wallet)
bool CanGrindR() const
Whether the (external) signer performs R-value signature grinding.
std::optional< bool > IsInternalScriptPubKeyMan(ScriptPubKeyMan *spk_man) const
Returns whether the provided ScriptPubKeyMan is internal.
bool CanSupportFeature(enum WalletFeature wf) const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
check whether we support the named feature
MasterKeyMap mapMasterKeys
NodeClock::time_point m_next_resend
The next scheduled rebroadcast of wallet transactions.
void WalletLogPrintf(const char *fmt, Params... parameters) const
Prepends the wallet name in logging output to ease debugging in multi-wallet use cases.
bool EraseAddressReceiveRequest(WalletBatch &batch, const CTxDestination &dest, const std::string &id) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
boost::signals2::signal< void(const std::string &title, int nProgress)> ShowProgress
Show progress e.g.
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.
bool UpgradeWallet(int version, bilingual_str &error)
Upgrade the wallet.
std::atomic< uint64_t > m_wallet_flags
WalletFlags set on this wallet.
interfaces::Chain * m_chain
Interface for accessing chain state.
bool Unlock(const CKeyingMaterial &vMasterKeyIn, bool accept_no_keys=false)
bool IsLocked() const override
boost::signals2::signal< void(const uint256 &hashTx, ChangeType status)> NotifyTransactionChanged
Wallet transaction added, removed or updated.
boost::signals2::signal< void()> NotifyCanGetAddressesChanged
Keypool has new keys.
std::set< ScriptPubKeyMan * > GetAllScriptPubKeyMans() const
Returns all unique ScriptPubKeyMans.
unsigned int ComputeTimeSmart(const CWalletTx &wtx, bool rescanning_old_block) const
Compute smart timestamp for a transaction being added to the wallet.
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.
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)
void GetKeyBirthTimes(std::map< CKeyID, int64_t > &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
uint256 GetLastBlockHash() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
int64_t m_keypool_size
Number of pre-generated keys/scripts by each spkm (part of the look-ahead process,...
RecursiveMutex cs_wallet
Main wallet lock.
void ConnectScriptPubKeyManNotifiers()
Connect the signals from ScriptPubKeyMans to the signals in CWallet.
std::atomic< int64_t > m_best_block_time
void SetupLegacyScriptPubKeyMan()
Make a LegacyScriptPubKeyMan and set it for all types, internal, and external.
static bool AttachChain(const std::shared_ptr< CWallet > &wallet, interfaces::Chain &chain, const bool rescan_required, bilingual_str &error, std::vector< bilingual_str > &warnings)
Catch wallet up to current chain, scanning new blocks, updating the best block locator and m_last_blo...
boost::signals2::signal< void(const CTxDestination &address, const std::string &label, bool isMine, AddressPurpose purpose, ChangeType status)> NotifyAddressBookChanged
Address book entry changed.
LegacyScriptPubKeyMan * GetOrCreateLegacyScriptPubKeyMan()
std::multimap< int64_t, CWalletTx * > TxItems
boost::signals2::signal< void(CWallet *wallet)> NotifyStatusChanged
Wallet status (encrypted, locked) changed.
void SetupDescriptorScriptPubKeyMans() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool ApplyMigrationData(MigrationData &data, bilingual_str &error) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Adds the ScriptPubKeyMans given in MigrationData to this wallet, removes LegacyScriptPubKeyMan,...
std::map< uint256, std::unique_ptr< ScriptPubKeyMan > > m_spk_managers
std::function< TxUpdate(CWalletTx &wtx)> TryUpdatingStateFn
std::atomic< int64_t > m_birth_time
void LoadAddressPreviouslySpent(const CTxDestination &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Marks destination as previously spent.
std::set< ScriptPubKeyMan * > GetScriptPubKeyMans(const CScript &script) const
Get all the ScriptPubKeyMans for a script.
interfaces::Chain & chain() const
Interface for accessing chain state.
A transaction with a bunch of additional info that only the owner cares about.
bool IsEquivalentTo(const CWalletTx &tx) const
True if only scriptSigs are different.
std::vector< std::pair< std::string, std::string > > vOrderForm
const Txid & GetHash() const LIFETIMEBOUND
mapValue_t mapValue
Key/value map with information about the transaction.
void updateState(interfaces::Chain &chain)
Update transaction state when attaching to a chain, filling in heights of conflicted and confirmed bl...
int64_t nOrderPos
position in ordered transaction list
bool fFromMe
From me flag is set to 1 for transactions that were created by the wallet on this bitcoin node,...
unsigned int nTimeReceived
time received by this node
bool isConflicted() const
void SetTx(CTransactionRef arg)
unsigned int fTimeReceivedIsTxTime
std::multimap< int64_t, CWalletTx * >::const_iterator m_it_wtxOrdered
bool m_is_cache_empty
This flag is true if all m_amounts caches are empty.
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()
bool HasWalletDescriptor(const WalletDescriptor &desc) const
static ExternalSigner GetExternalSigner()
bool DeleteRecords()
Delete all the records ofthis LegacyScriptPubKeyMan from disk.
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,...
std::set< CKeyID > GetKeys() const override
std::optional< MigrationData > MigrateToDescriptor()
Get the DescriptorScriptPubKeyMans (with private keys) that have the same scriptPubKeys as this Legac...
A wrapper to reserve an address from a wallet.
const CWallet *const pwallet
The wallet to reserve from.
CTxDestination address
The destination.
bool fInternal
Whether this is from the internal (change output) keypool.
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.
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, CKeyPool &keypool)
Access to the wallet database.
bool TxnAbort()
Abort current transaction.
bool EraseName(const std::string &strAddress)
DBErrors LoadWallet(CWallet *pwallet)
bool WriteBestBlock(const CBlockLocator &locator)
bool ReadBestBlock(CBlockLocator &locator)
bool WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
bool WriteMinVersion(int nVersion)
bool TxnBegin()
Begin a new transaction.
bool WriteAddressPreviouslySpent(const CTxDestination &dest, bool previously_spent)
bool EraseAddressReceiveRequest(const CTxDestination &dest, const std::string &id)
bool TxnCommit()
Commit current transaction.
bool WriteName(const std::string &strAddress, const std::string &strName)
bool WritePurpose(const std::string &strAddress, const std::string &purpose)
bool WriteWalletFlags(const uint64_t flags)
bool EraseAddressData(const CTxDestination &dest)
bool WriteOrderPosNext(int64_t nOrderPosNext)
bool WriteTx(const CWalletTx &wtx)
bool ErasePurpose(const std::string &strAddress)
bool EraseLockedUTXO(const COutPoint &output)
bool WriteLockedUTXO(const COutPoint &output)
bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256 &id, bool internal)
bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal)
bool WriteAddressReceiveRequest(const CTxDestination &dest, const std::string &id, const std::string &receive_request)
DBErrors ZapSelectTx(std::vector< uint256 > &vHashIn, std::vector< uint256 > &vHashOut)
virtual bool Rewrite(const char *pszSkip=nullptr)=0
Rewrite the entire database on disk, with the exception of key pszSkip if non-zero.
virtual void ReloadDbEnv()=0
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 void Flush()=0
Make sure all changes are flushed to database file.
Descriptor with some wallet metadata.
std::shared_ptr< Descriptor > descriptor
RAII object to check and reserve a wallet rescan.
Clock::time_point now() const
bool reserve(bool with_passphrase=false)
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
static UniValue Parse(std::string_view raw)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
std::string ShellEscape(const std::string &arg)
static const int COINBASE_MATURITY
Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
bilingual_str AmountHighWarn(const std::string &optname)
bilingual_str AmountErrMsg(const std::string &optname, const std::string &strValue)
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by create_directories if the requested directory exists.
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 UnlockCoin(const COutPoint &output, WalletBatch *batch=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
unsigned int GetKeyPoolSize() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void KeepDestination()
Keep the address. Do not return its key to the keypool when this object goes out of scope.
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.
std::vector< CTxDestination > ListAddrBookAddresses(const std::optional< AddrBookFilter > &filter) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Filter and retrieve destinations stored in the addressbook.
void ReturnDestination()
Return reserved address.
util::Result< CTxDestination > GetNewDestination(const OutputType type, const std::string label)
size_t KeypoolCountExternalKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool LockCoin(const COutPoint &output, WalletBatch *batch=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::optional< int64_t > GetOldestKeyPoolTime() const
SigningResult SignMessage(const std::string &message, const PKHash &pkhash, std::string &str_sig) const
void CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector< std::pair< std::string, std::string >> orderForm)
Submit the transaction to the node's mempool and then relay to peers.
bool SetAddressBookWithDB(WalletBatch &batch, const CTxDestination &address, const std::string &strName, const std::optional< AddressPurpose > &strPurpose)
bool DisplayAddress(const CTxDestination &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Display address on an external signer.
DBErrors ZapSelectTx(std::vector< uint256 > &vHashIn, std::vector< uint256 > &vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::set< std::string > ListAddrBookLabels(const std::optional< AddressPurpose > purpose) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Retrieve all the known labels in the address book.
OutputType TransactionChangeType(const std::optional< OutputType > &change_type, const std::vector< CRecipient > &vecSend) const
void ListLockedCoins(std::vector< COutPoint > &vOutpts) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool UnlockAllCoins() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
util::Result< CTxDestination > GetNewChangeDestination(const OutputType type)
void ForEachAddrBookEntry(const ListAddrBookFunc &func) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool DelAddressBook(const CTxDestination &address)
util::Result< CTxDestination > GetReservedDestination(bool internal)
Reserve an address.
TransactionError FillPSBT(PartiallySignedTransaction &psbtx, bool &complete, int sighash_type=SIGHASH_DEFAULT, bool sign=true, bool bip32derivs=true, size_t *n_signed=nullptr, bool finalize=true) const
Fills out a PSBT with information from the wallet.
bool IsSpentKey(const CScript &scriptPubKey) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void SyncTransaction(const CTransactionRef &tx, const SyncTxState &state, bool update_tx=true, bool rescanning_old_block=false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool LoadToWallet(const uint256 &hash, const UpdateWalletTxFn &fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
int64_t IncOrderPosNext(WalletBatch *batch=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Increment the next transaction order id.
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.
void SetMinVersion(enum WalletFeature, WalletBatch *batch_in=nullptr) override
signify that a particular wallet feature is now used.
bool ChangeWalletPassphrase(const SecureString &strOldWalletPassphrase, const SecureString &strNewWalletPassphrase)
void SyncMetaData(std::pair< TxSpends::iterator, TxSpends::iterator >) EXCLUSIVE_LOCKS_REQUIRED(cs_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)
void MarkConflicted(const uint256 &hashBlock, int conflicting_height, const uint256 &hashTx)
Mark a transaction (and its in-wallet descendants) as conflicting with a particular block.
void updatedBlockTip() override
bool TransactionCanBeAbandoned(const uint256 &hashTx) const
Return whether transaction can be abandoned.
bool ImportScripts(const std::set< CScript > scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void blockConnected(ChainstateRole role, const interfaces::BlockInfo &block) override
void Flush()
Flush wallet (bitdb flush)
void blockDisconnected(const interfaces::BlockInfo &block) override
bool IsWalletFlagSet(uint64_t flag) const override
check if a certain wallet flag is set
std::set< uint256 > GetConflicts(const uint256 &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get wallet transactions that conflict with given transaction (spend same outputs)
void UnsetWalletFlagWithDB(WalletBatch &batch, uint64_t flag)
Unsets a wallet flag and saves it to disk.
void FirstKeyTimeChanged(const ScriptPubKeyMan *spkm, int64_t new_birth_time)
Updates wallet birth time if 'new_birth_time' is below it.
bool IsSpent(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Outpoint is spent if any non-conflicted transaction spends it:
void UnsetBlankWalletFlag(WalletBatch &batch) override
Unset the blank wallet flag and saves it to disk.
void ResubmitWalletTransactions(bool relay, bool force)
void SetSpentKeyState(WalletBatch &batch, const uint256 &hash, unsigned int n, bool used, std::set< CTxDestination > &tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void RecursiveUpdateTxState(const uint256 &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.
bool CanGetAddresses(bool internal=false) const
ScanResult ScanForWalletTransactions(const uint256 &start_block, int start_height, std::optional< int > max_height, const WalletRescanReserver &reserver, bool fUpdate, const bool save_progress)
Scan the block chain (starting in start_block) for transactions from or to us.
bool LoadWalletFlags(uint64_t flags)
Loads the flags into the wallet.
std::set< uint256 > GetTxConflicts(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo.
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 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.
void InitWalletFlags(uint64_t flags)
overwrite all flags by the given uint64_t flags must be uninitialised (or 0) only known flags may be ...
void UnsetWalletFlag(uint64_t flag)
Unsets a single wallet flag.
bool AbandonTransaction(const uint256 &hashTx)
CAmount GetDebit(const CTxIn &txin, const isminefilter &filter) const
Returns amount of debit if the input matches the filter, otherwise returns 0.
bool EncryptWallet(const SecureString &strWalletPassphrase)
CWalletTx * AddToWallet(CTransactionRef tx, const TxState &state, const UpdateWalletTxFn &update_wtx=nullptr, bool fFlushOnClose=true, bool rescanning_old_block=false)
Add the transaction to the wallet, wrapping it up inside a CWalletTx.
void AddToSpends(const COutPoint &outpoint, const uint256 &wtxid, WalletBatch *batch=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool MarkReplaced(const uint256 &originalHash, const uint256 &newHash)
Mark a transaction as replaced by another transaction.
bool ImportPrivKeys(const std::map< CKeyID, CKey > &privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver, bool update)
Scan active chain for relevant transactions after importing keys.
isminetype IsMine(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool IsFromMe(const CTransaction &tx) const
should probably be renamed to IsRelevantToMe
DBErrors ReorderTransactions()