8 #include <blockfilter.h>
30 #include <txmempool.h>
62 if (value.isStr() && value.get_str() == wallet_name)
return true;
71 if (!setting_value.
isArray())
return true;
74 if (!value.isStr() || value.get_str() != wallet_name) new_value.
push_back(value);
76 if (new_value.
size() == setting_value.
size())
return true;
81 const std::string& wallet_name,
82 std::optional<bool> load_on_startup,
83 std::vector<bilingual_str>& warnings)
85 if (!load_on_startup)
return;
87 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
89 warnings.emplace_back(
Untranslated(
"Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));
111 std::vector<std::shared_ptr<CWallet>>::const_iterator i = std::find(
context.wallets.begin(),
context.wallets.end(),
wallet);
112 if (i !=
context.wallets.end())
return false;
114 wallet->ConnectScriptPubKeyManNotifiers();
115 wallet->NotifyCanGetAddressesChanged();
127 wallet->m_chain_notifications_handler.reset();
129 std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(
context.wallets.begin(),
context.wallets.end(),
wallet);
130 if (i ==
context.wallets.end())
return false;
141 std::vector<bilingual_str> warnings;
161 for (
const std::shared_ptr<CWallet>&
wallet :
context.wallets) {
170 auto it =
context.wallet_load_fns.emplace(
context.wallet_load_fns.end(), std::move(load_wallet));
177 for (
auto& load_wallet :
context.wallet_load_fns) {
192 wallet->WalletLogPrintf(
"Releasing wallet\n");
198 if (g_unloading_wallet_set.erase(
name) == 0) {
212 auto it = g_unloading_wallet_set.insert(
name);
224 while (g_unloading_wallet_set.count(
name) == 1) {
231 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)
250 wallet->postInitProcess();
256 }
catch (
const std::runtime_error& e) {
263 class FastWalletRescanFilter
272 for (
auto spkm :
m_wallet.GetAllScriptPubKeyMans()) {
273 auto desc_spkm{
dynamic_cast<DescriptorScriptPubKeyMan*
>(spkm)};
274 assert(desc_spkm !=
nullptr);
275 AddScriptPubKeys(desc_spkm);
277 if (desc_spkm->IsHDEnabled()) {
283 void UpdateIfNeeded()
287 auto desc_spkm{
dynamic_cast<DescriptorScriptPubKeyMan*
>(
m_wallet.GetScriptPubKeyMan(desc_spkm_id))};
288 assert(desc_spkm !=
nullptr);
289 int32_t current_range_end{desc_spkm->GetEndRange()};
290 if (current_range_end > last_range_end) {
291 AddScriptPubKeys(desc_spkm, last_range_end);
297 std::optional<bool> MatchesBlock(
const uint256& block_hash)
const
313 void AddScriptPubKeys(
const DescriptorScriptPubKeyMan* desc_spkm, int32_t last_range_end = 0)
315 for (
const auto& script_pub_key : desc_spkm->GetScriptPubKeys(last_range_end)) {
316 m_filter_set.emplace(script_pub_key.begin(), script_pub_key.end());
325 if (!result.second) {
346 if (!passphrase.empty()) {
352 error =
Untranslated(
"Private keys must be disabled when using an external signer");
359 error =
Untranslated(
"Descriptor support must be enabled when using an external signer");
366 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.");
390 if (!
wallet->EncryptWallet(passphrase)) {
397 if (!
wallet->Unlock(passphrase)) {
407 wallet->SetupDescriptorScriptPubKeyMans();
409 for (
auto spk_man :
wallet->GetActiveScriptPubKeyMans()) {
410 if (!spk_man->SetupGeneration()) {
426 wallet->postInitProcess();
433 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."));
447 auto wallet_file = wallet_path /
"wallet.dat";
448 std::shared_ptr<CWallet>
wallet;
463 fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
466 }
catch (
const std::exception& e) {
472 fs::remove_all(wallet_path);
486 const auto it = mapWallet.find(hash);
487 if (it == mapWallet.end())
489 return &(it->second);
503 spk_man->UpgradeKeyMetadata();
527 for (
const MasterKeyMap::value_type& pMasterKey :
mapMasterKeys)
529 if(!crypter.
SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
531 if (!crypter.
Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
533 if (
Unlock(_vMasterKey, accept_no_keys)) {
557 if(!crypter.
SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
559 if (!crypter.
Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
564 auto start{SteadyClock::now()};
565 crypter.
SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
566 pMasterKey.second.nDeriveIterations =
static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start));
568 start = SteadyClock::now();
569 crypter.
SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
570 pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations +
static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
572 if (pMasterKey.second.nDeriveIterations < 25000)
573 pMasterKey.second.nDeriveIterations = 25000;
575 WalletLogPrintf(
"Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
577 if (!crypter.
SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
579 if (!crypter.
Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey))
606 if (nWalletVersion >= nVersion)
609 nWalletVersion = nVersion;
613 if (nWalletVersion > 40000)
622 std::set<uint256> result;
625 const auto it = mapWallet.find(txid);
626 if (it == mapWallet.end())
630 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
632 for (
const CTxIn& txin : wtx.
tx->vin)
634 if (mapTxSpends.count(txin.
prevout) <= 1)
636 range = mapTxSpends.equal_range(txin.
prevout);
637 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
638 result.insert(_it->second);
646 const uint256& txid = tx->GetHash();
647 for (
unsigned int i = 0; i < tx->vout.size(); ++i) {
671 int nMinOrderPos = std::numeric_limits<int>::max();
673 for (TxSpends::iterator it = range.first; it != range.second; ++it) {
674 const CWalletTx* wtx = &mapWallet.at(it->second);
686 for (TxSpends::iterator it = range.first; it != range.second; ++it)
688 const uint256& hash = it->second;
690 if (copyFrom == copyTo)
continue;
691 assert(copyFrom &&
"Oldest wallet transaction in range assumed to have been found.");
710 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
711 range = mapTxSpends.equal_range(outpoint);
713 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
714 const uint256& wtxid = it->second;
715 const auto mit = mapWallet.find(wtxid);
716 if (mit != mapWallet.end()) {
718 if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
727 mapTxSpends.insert(std::make_pair(outpoint, wtxid));
736 std::pair<TxSpends::iterator, TxSpends::iterator> range;
737 range = mapTxSpends.equal_range(outpoint);
747 for (
const CTxIn& txin : wtx.
tx->vin)
768 auto start{SteadyClock::now()};
770 kMasterKey.
nDeriveIterations =
static_cast<unsigned int>(25000 * target / (SteadyClock::now() - start));
772 start = SteadyClock::now();
791 delete encrypted_batch;
792 encrypted_batch =
nullptr;
798 auto spk_man = spk_man_pair.second.get();
799 if (!spk_man->Encrypt(_vMasterKey, encrypted_batch)) {
801 delete encrypted_batch;
802 encrypted_batch =
nullptr;
813 delete encrypted_batch;
814 encrypted_batch =
nullptr;
820 delete encrypted_batch;
821 encrypted_batch =
nullptr;
824 Unlock(strWalletPassphrase);
831 if (spk_man->IsHDEnabled()) {
832 if (!spk_man->SetupGeneration(
true)) {
863 typedef std::multimap<int64_t, CWalletTx*>
TxItems;
866 for (
auto& entry : mapWallet)
873 std::vector<int64_t> nOrderPosOffsets;
874 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
881 nOrderPos = nOrderPosNext++;
882 nOrderPosOffsets.push_back(nOrderPos);
889 int64_t nOrderPosOff = 0;
890 for (
const int64_t& nOffsetStart : nOrderPosOffsets)
892 if (nOrderPos >= nOffsetStart)
895 nOrderPos += nOrderPosOff;
896 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
914 int64_t nRet = nOrderPosNext++;
927 for (std::pair<const uint256, CWalletTx>& item : mapWallet)
928 item.second.MarkDirty();
936 auto mi = mapWallet.find(originalHash);
939 assert(mi != mapWallet.end());
975 tx_destinations.insert(dst);
995 assert(spk_man !=
nullptr);
1024 std::set<CTxDestination> tx_destinations;
1026 for (
const CTxIn& txin : tx->vin) {
1035 auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(tx, state));
1037 bool fInsertedNew =
ret.second;
1038 bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
1049 if (state.index() != wtx.
m_state.index()) {
1061 if (tx->HasWitness() && !wtx.
tx->HasWitness()) {
1069 std::vector<CWalletTx*> txs{&wtx};
1073 while (!txs.empty()) {
1076 desc_tx->
m_state = inactive_state;
1081 for (
unsigned int i = 0; i < desc_tx->
tx->vout.size(); ++i) {
1083 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(outpoint);
1084 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
1085 const auto wit = mapWallet.find(it->second);
1086 if (wit != mapWallet.end()) {
1087 txs.push_back(&wit->second);
1095 WalletLogPrintf(
"AddToWallet %s %s%s\n", hash.
ToString(), (fInsertedNew ?
"new" :
""), (fUpdated ?
"update" :
""));
1098 if (fInsertedNew || fUpdated)
1112 if (!strCmd.empty())
1117 ReplaceAll(strCmd,
"%b", conf->confirmed_block_hash.GetHex());
1131 std::thread
t(runCommand, strCmd);
1141 const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(
nullptr,
TxStateInactive{}));
1143 if (!fill_wtx(wtx, ins.second)) {
1150 auto lookup_block = [&](
const uint256& hash,
int& height,
TxState& state) {
1162 lookup_block(conf->confirmed_block_hash, conf->confirmed_block_height, wtx.
m_state);
1164 lookup_block(conf->conflicting_block_hash, conf->conflicting_block_height, wtx.
m_state);
1171 for (
const CTxIn& txin : wtx.
tx->vin) {
1173 if (it != mapWallet.end()) {
1189 if (
auto* conf = std::get_if<TxStateConfirmed>(&state)) {
1191 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.
prevout);
1192 while (range.first != range.second) {
1193 if (range.first->second != tx.
GetHash()) {
1194 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);
1195 MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
1202 bool fExisted = mapWallet.count(tx.
GetHash()) != 0;
1203 if (fExisted && !fUpdate)
return false;
1215 for (
auto &dest : spk_man->MarkUnusedAddresses(txout.
scriptPubKey)) {
1217 if (!dest.internal.has_value()) {
1222 if (!dest.internal.has_value())
continue;
1236 TxState tx_state = std::visit([](
auto&& s) ->
TxState {
return s; }, state);
1241 throw std::runtime_error(
"DB error adding transaction to wallet, write failed");
1258 for (
const CTxIn& txin : tx->vin) {
1260 if (it != mapWallet.end()) {
1261 it->second.MarkDirty();
1271 auto it = mapWallet.find(hashTx);
1272 assert(it != mapWallet.end());
1280 assert(!wtx.isConfirmed());
1281 assert(!wtx.InMempool());
1283 if (!wtx.isConflicted() && !wtx.isAbandoned()) {
1305 int conflictconfirms = (m_last_block_processed_height - conflicting_height + 1) * -1;
1310 if (conflictconfirms >= 0)
1332 std::set<uint256> todo;
1333 std::set<uint256> done;
1335 todo.insert(tx_hash);
1337 while (!todo.empty()) {
1341 auto it = mapWallet.find(now);
1342 assert(it != mapWallet.end());
1345 TxUpdate update_state = try_updating_state(wtx);
1346 if (update_state != TxUpdate::UNCHANGED) {
1350 for (
unsigned int i = 0; i < wtx.
tx->vout.size(); ++i) {
1351 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(
COutPoint(now, i));
1352 for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
1353 if (!done.count(iter->second)) {
1354 todo.insert(iter->second);
1359 if (update_state == TxUpdate::NOTIFY_CHANGED) {
1365 MarkInputsDirty(wtx.
tx);
1385 auto it = mapWallet.find(tx->GetHash());
1386 if (it != mapWallet.end()) {
1393 auto it = mapWallet.find(tx->GetHash());
1394 if (it != mapWallet.end()) {
1433 m_last_block_processed_height = block.
height;
1434 m_last_block_processed = block.
hash;
1441 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1456 m_last_block_processed_height = block.
height - 1;
1459 int disconnect_height = block.
height;
1464 for (
const CTxIn& tx_in : ptx->vin) {
1466 if (mapTxSpends.count(tx_in.
prevout) < 1)
continue;
1468 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(tx_in.
prevout);
1471 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) {
1472 CWalletTx& wtx = mapWallet.find(_it->second)->second;
1476 auto try_updating_state = [&](
CWalletTx& tx) {
1496 void CWallet::BlockUntilSyncedToCurrentChain()
const {
1512 const auto mi = mapWallet.find(txin.
prevout.
hash);
1513 if (mi != mapWallet.end())
1541 result = std::max(result, spk_man_pair.second->IsMine(script));
1562 if (outpoint.
n >= wtx->tx->vout.size()) {
1565 return IsMine(wtx->tx->vout[outpoint.
n]);
1580 throw std::runtime_error(std::string(__func__) +
": value out of range");
1588 bool result =
false;
1590 if (!spk_man->IsHDEnabled())
return false;
1602 if (spk_man && spk_man->CanGetAddresses(
internal)) {
1609 void CWallet::SetWalletFlag(uint64_t
flags)
1614 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1628 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1663 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1695 if (target_weight < txin_weight) {
1698 if (target_weight == txin_weight) {
1703 int64_t add_weight = target_weight - txin_weight;
1713 if ((add_weight >= 253 && add_weight < 263)
1714 || (add_weight > std::numeric_limits<uint16_t>::max() && add_weight <= std::numeric_limits<uint16_t>::max() + 10)
1715 || (add_weight > std::numeric_limits<uint32_t>::max() && add_weight <= std::numeric_limits<uint32_t>::max() + 10)) {
1716 int64_t first_weight = add_weight / 3;
1717 add_weight -= first_weight;
1736 for (
const auto& txout : txouts)
1747 const std::unique_ptr<SigningProvider> provider =
GetSolvingProvider(txout.scriptPubKey);
1748 if (!provider || !
DummySignInput(*provider, txin, txout, can_grind_r, coin_control)) {
1765 LOCK(spk_man->cs_KeyStore);
1766 return spk_man->ImportScripts(scripts, timestamp);
1775 LOCK(spk_man->cs_KeyStore);
1776 return spk_man->ImportPrivKeys(privkey_map, timestamp);
1779 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)
1785 LOCK(spk_man->cs_KeyStore);
1786 return spk_man->ImportPubKeys(ordered_pubkeys, pubkey_map, key_origins, add_keypool,
internal, timestamp);
1789 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)
1795 LOCK(spk_man->cs_KeyStore);
1796 if (!spk_man->ImportScriptPubKeys(script_pub_keys, have_solving_data, timestamp)) {
1801 for (
const CScript& script : script_pub_keys) {
1815 if (new_birth_time < birthtime) {
1833 int start_height = 0;
1874 constexpr
auto INTERVAL_TIME{60s};
1875 auto current_time{reserver.
now()};
1876 auto start_time{reserver.
now()};
1880 uint256 block_hash = start_block;
1883 std::unique_ptr<FastWalletRescanFilter> fast_rescan_filter;
1887 fast_rescan_filter ?
"fast variant using block filters" :
"slow variant inspecting all blocks");
1896 double progress_current = progress_begin;
1897 int block_height = start_height;
1899 if (progress_end - progress_begin > 0.0) {
1900 m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin);
1904 if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
1908 bool next_interval = reserver.
now() >= current_time + INTERVAL_TIME;
1909 if (next_interval) {
1910 current_time = reserver.
now();
1911 WalletLogPrintf(
"Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
1914 bool fetch_block{
true};
1915 if (fast_rescan_filter) {
1916 fast_rescan_filter->UpdateIfNeeded();
1917 auto matches_block{fast_rescan_filter->MatchesBlock(block_hash)};
1918 if (matches_block.has_value()) {
1919 if (*matches_block) {
1924 fetch_block =
false;
1927 LogPrint(
BCLog::SCAN,
"Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.
ToString());
1933 bool block_still_active =
false;
1934 bool next_block =
false;
1945 if (!block_still_active) {
1952 for (
size_t posInBlock = 0; posInBlock < block.
vtx.size(); ++posInBlock) {
1959 if (save_progress && next_interval) {
1974 if (max_height && block_height >= *max_height) {
1985 block_hash = next_block_hash;
1990 const uint256 prev_tip_hash = tip_hash;
1992 if (!max_height && prev_tip_hash != tip_hash) {
2004 WalletLogPrintf(
"Rescan aborted at block %d. Progress=%f\n", block_height, progress_current);
2006 }
else if (block_height &&
chain().shutdownRequested()) {
2007 WalletLogPrintf(
"Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height, progress_current);
2010 WalletLogPrintf(
"Rescan completed in %15dms\n", Ticks<std::chrono::milliseconds>(reserver.
now() - start_time));
2051 result.erase(myHash);
2063 if (!
chain().isReadyToBroadcast())
return false;
2104 int submitted_tx_count = 0;
2111 std::set<CWalletTx*, WalletTxOrderComparator> to_submit;
2112 for (
auto& [txid, wtx] : mapWallet) {
2114 if (!wtx.isUnconfirmed())
continue;
2119 to_submit.insert(&wtx);
2122 for (
auto wtx : to_submit) {
2123 std::string unused_err_string;
2128 if (submitted_tx_count > 0) {
2129 WalletLogPrintf(
"%s: resubmit %u unconfirmed transactions\n", __func__, submitted_tx_count);
2138 if (!pwallet->ShouldResend())
continue;
2139 pwallet->ResubmitWalletTransactions(
true,
false);
2140 pwallet->SetNextResend();
2155 std::map<COutPoint, Coin> coins;
2156 for (
auto& input : tx.
vin) {
2157 const auto mi = mapWallet.find(input.prevout.hash);
2158 if(mi == mapWallet.end() || input.prevout.n >= mi->second.tx->vout.size()) {
2163 coins[input.prevout] =
Coin(wtx.
tx->vout[input.prevout.n], prev_height, wtx.
IsCoinBase());
2165 std::map<int, bilingual_str> input_errors;
2175 if (spk_man->SignTransaction(tx, coins, sighash, input_errors)) {
2191 for (
unsigned int i = 0; i < psbtx.
tx->vin.size(); ++i) {
2192 const CTxIn& txin = psbtx.
tx->vin[i];
2202 const auto it = mapWallet.find(txhash);
2203 if (it != mapWallet.end()) {
2216 int n_signed_this_spkm = 0;
2217 TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm, finalize);
2223 (*n_signed) += n_signed_this_spkm;
2231 for (
const auto& input : psbtx.
inputs) {
2243 if (spk_man_pair.second->CanProvide(script_pub_key, sigdata)) {
2245 return spk_man_pair.second->SignMessage(message, pkhash, str_sig);
2255 return *change_type;
2264 bool any_wpkh{
false};
2266 bool any_pkh{
false};
2268 for (
const auto& recipient : vecSend) {
2269 std::vector<std::vector<uint8_t>> dummy;
2283 if (has_bech32m_spkman && any_tr) {
2288 if (has_bech32_spkman && any_wpkh) {
2293 if (has_p2sh_segwit_spkman && any_sh) {
2299 if (has_legacy_spkman && any_pkh) {
2304 if (has_bech32m_spkman) {
2307 if (has_bech32_spkman) {
2324 wtx.
mapValue = std::move(mapValue);
2333 throw std::runtime_error(std::string(__func__) +
": Wallet db error, transaction commit failed");
2337 for (
const CTxIn& txin : tx->vin) {
2348 std::string err_string;
2350 WalletLogPrintf(
"CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
2365 spk_man_pair.second->RewriteDB();
2375 return nLoadWalletRet;
2382 for (
const uint256& hash : vHashOut) {
2383 const auto& it = mapWallet.find(hash);
2384 wtxOrdered.erase(it->second.m_it_wtxOrdered);
2385 for (
const auto& txin : it->second.tx->vin)
2386 mapTxSpends.erase(txin.prevout);
2387 mapWallet.erase(it);
2396 spk_man_pair.second->RewriteDB();
2402 return nZapSelectTxRet;
2411 bool fUpdated =
false;
2413 std::optional<AddressPurpose> purpose;
2416 std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
2417 fUpdated = (mi != m_address_book.end() && !mi->second.IsChange());
2418 m_address_book[address].SetLabel(strName);
2421 purpose = m_address_book[address].purpose = new_purpose;
2423 purpose = m_address_book[address].purpose;
2455 m_address_book.erase(address);
2469 if (legacy_spk_man) {
2470 return legacy_spk_man->KeypoolCountExternalKeys();
2473 unsigned int count = 0;
2475 count += spk_man.second->GetKeyPoolSize();
2485 unsigned int count = 0;
2487 count += spk_man->GetKeyPoolSize();
2497 res &= spk_man->TopUp(kpSize);
2510 auto op_dest = spk_man->GetNewDestination(type);
2533 return std::nullopt;
2536 std::optional<int64_t> oldest_key{std::numeric_limits<int64_t>::max()};
2538 oldest_key = std::min(oldest_key, spk_man_pair.second->GetOldestKeyPoolTime());
2544 for (
auto& entry : mapWallet) {
2547 for (
unsigned int i = 0; i < wtx.
tx->vout.size(); i++) {
2560 for (
const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book) {
2561 const auto& entry = item.second;
2562 func(item.first, entry.GetLabel(), entry.IsChange(), entry.purpose);
2569 std::vector<CTxDestination> result;
2577 result.emplace_back(dest);
2585 std::set<std::string> label_set;
2587 bool _is_change,
const std::optional<AddressPurpose>& _purpose) {
2588 if (_is_change)
return;
2589 if (!purpose || purpose == _purpose) {
2590 label_set.insert(_label);
2606 if (!op_address)
return op_address;
2636 if (signer_spk_man ==
nullptr) {
2640 return signer_spk_man->DisplayAddress(scriptPubKey, signer);
2648 setLockedCoins.insert(output);
2658 bool was_locked = setLockedCoins.erase(output);
2659 if (batch && was_locked) {
2668 bool success =
true;
2670 for (
auto it = setLockedCoins.begin(); it != setLockedCoins.end(); ++it) {
2673 setLockedCoins.clear();
2680 return setLockedCoins.count(output) > 0;
2686 for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
2687 it != setLockedCoins.end(); it++) {
2689 vOutpts.push_back(outpt);
2697 mapKeyBirth.clear();
2700 std::map<CKeyID, const TxStateConfirmed*> mapKeyFirstBlock;
2707 assert(spk_man !=
nullptr);
2711 for (
const auto& entry : spk_man->mapKeyMetadata) {
2712 if (entry.second.nCreateTime) {
2713 mapKeyBirth[entry.first] = entry.second.nCreateTime;
2719 if (mapKeyBirth.count(keyid) == 0)
2720 mapKeyFirstBlock[keyid] = &max_confirm;
2724 if (mapKeyFirstBlock.empty())
2728 for (
const auto& entry : mapWallet) {
2733 for (
const CTxOut &txout : wtx.
tx->vout) {
2737 auto rit = mapKeyFirstBlock.find(keyid);
2738 if (rit != mapKeyFirstBlock.end() && conf->confirmed_block_height < rit->second->confirmed_block_height) {
2748 for (
const auto& entry : mapKeyFirstBlock) {
2780 std::optional<uint256> block_hash;
2782 block_hash = conf->confirmed_block_hash;
2784 block_hash = conf->conflicting_block_hash;
2790 int64_t block_max_time;
2791 if (
chain().findBlock(*block_hash,
FoundBlock().time(blocktime).maxTime(block_max_time))) {
2792 if (rescanning_old_block) {
2793 nTimeSmart = block_max_time;
2796 int64_t latestEntry = 0;
2799 int64_t latestTolerated = latestNow + 300;
2801 for (
auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
2811 if (nSmartTime <= latestTolerated) {
2812 latestEntry = nSmartTime;
2813 if (nSmartTime > latestNow) {
2814 latestNow = nSmartTime;
2820 nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
2831 if (std::get_if<CNoDestination>(&dest))
2835 if (
auto* data{
util::FindKey(m_address_book, dest)}) data->previously_spent =
false;
2845 m_address_book[dest].previously_spent =
true;
2850 m_address_book[dest].receive_requests[id] = request;
2855 if (
auto* data{
util::FindKey(m_address_book, dest)})
return data->previously_spent;
2861 std::vector<std::string>
values;
2862 for (
const auto& [dest, entry] : m_address_book) {
2863 for (
const auto& [
id, request] : entry.receive_requests) {
2864 values.emplace_back(request);
2873 m_address_book[dest].receive_requests[id] = value;
2880 m_address_book[dest].receive_requests.erase(
id);
2893 fs::file_type path_type = fs::symlink_status(wallet_path).type();
2894 if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory ||
2895 (path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) ||
2898 "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
2899 "database/log.?????????? files can be stored, a location where such a directory could be created, "
2900 "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
2905 return MakeDatabase(wallet_path, options, status, error_string);
2912 const std::string& walletFile = database->Filename();
2914 const auto start{SteadyClock::now()};
2919 walletInstance->m_notify_tx_changed_script =
args.
GetArg(
"-walletnotify",
"");
2922 bool rescan_required =
false;
2923 DBErrors nLoadWalletRet = walletInstance->LoadWallet();
2926 error =
strprintf(
_(
"Error loading %s: Wallet corrupted"), walletFile);
2931 warnings.push_back(
strprintf(
_(
"Error reading %s! All keys read correctly, but transaction data"
2932 " or address book entries might be missing or incorrect."),
2940 error =
strprintf(
_(
"Error loading %s: External signer wallet being loaded without external signer support compiled"), walletFile);
2948 warnings.push_back(
strprintf(
_(
"Error reading %s! Transaction data may be missing or incorrect."
2949 " Rescanning wallet."), walletFile));
2950 rescan_required =
true;
2952 error =
strprintf(
_(
"Unrecognized descriptor found. Loading wallet %s\n\n"
2953 "The wallet might had been created on a newer version.\n"
2954 "Please try running the latest software version.\n"), walletFile);
2957 error =
strprintf(
_(
"Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
2958 "The wallet might have been tampered with or created with malicious intent.\n"), walletFile);
2967 const bool fFirstRun = walletInstance->m_spk_managers.empty() &&
2975 walletInstance->InitWalletFlags(wallet_creation_flags);
2979 walletInstance->SetupLegacyScriptPubKeyMan();
2983 LOCK(walletInstance->cs_wallet);
2985 walletInstance->SetupDescriptorScriptPubKeyMans();
2989 for (
auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
2990 if (!spk_man->SetupGeneration()) {
2991 error =
_(
"Unable to generate initial keys");
3003 error =
strprintf(
_(
"Error loading %s: Private keys can only be disabled during creation"), walletFile);
3006 for (
auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
3007 if (spk_man->HavePrivateKeys()) {
3008 warnings.push_back(
strprintf(
_(
"Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
3014 if (!
args.
GetArg(
"-addresstype",
"").empty()) {
3020 walletInstance->m_default_address_type = parsed.value();
3023 if (!
args.
GetArg(
"-changetype",
"").empty()) {
3029 walletInstance->m_default_change_type = parsed.value();
3039 _(
"This is the minimum transaction fee you pay on every transaction."));
3042 walletInstance->m_min_fee =
CFeeRate{min_tx_fee.value()};
3046 const std::string max_aps_fee{
args.
GetArg(
"-maxapsfee",
"")};
3047 if (max_aps_fee ==
"-1") {
3048 walletInstance->m_max_aps_fee = -1;
3049 }
else if (std::optional<CAmount> max_fee =
ParseMoney(max_aps_fee)) {
3052 _(
"This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
3054 walletInstance->m_max_aps_fee = max_fee.value();
3063 if (!fallback_fee) {
3068 _(
"This is the transaction fee you may pay when fee estimates are not available."));
3070 walletInstance->m_fallback_fee =
CFeeRate{fallback_fee.value()};
3074 walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.
GetFeePerK() != 0;
3083 _(
"This is the transaction fee you may discard if change is smaller than dust at this level"));
3085 walletInstance->m_discard_rate =
CFeeRate{discard_fee.value()};
3095 _(
"This is the transaction fee you will pay if you send a transaction."));
3098 walletInstance->m_pay_tx_fee =
CFeeRate{pay_tx_fee.value(), 1000};
3101 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' (must be at least %s)"),
3113 warnings.push_back(
strprintf(
_(
"%s is set very high! Fees this large could be paid on a single transaction."),
"-maxtxfee"));
3117 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
3122 walletInstance->m_default_max_tx_fee = max_fee.value();
3126 if (std::optional<CAmount> consolidate_feerate =
ParseMoney(
args.
GetArg(
"-consolidatefeerate",
""))) {
3127 walletInstance->m_consolidate_feerate =
CFeeRate(*consolidate_feerate);
3136 _(
"The wallet will avoid paying less than the minimum relay fee."));
3143 walletInstance->WalletLogPrintf(
"Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
3146 walletInstance->TopUpKeyPool();
3149 std::optional<int64_t> time_first_key;
3150 for (
auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
3151 int64_t time = spk_man->GetTimeFirstKey();
3152 if (!time_first_key || time < *time_first_key) time_first_key = time;
3154 if (time_first_key) walletInstance->m_birth_time = *time_first_key;
3161 LOCK(walletInstance->cs_wallet);
3163 walletInstance->WalletLogPrintf(
"setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
3164 walletInstance->WalletLogPrintf(
"mapWallet.size() = %u\n", walletInstance->mapWallet.size());
3165 walletInstance->WalletLogPrintf(
"m_address_book.size() = %u\n", walletInstance->m_address_book.size());
3168 return walletInstance;
3173 LOCK(walletInstance->cs_wallet);
3175 assert(!walletInstance->m_chain || walletInstance->m_chain == &
chain);
3176 walletInstance->m_chain = &
chain;
3186 error =
Untranslated(
"Wallet files should not be reused across chains. Restart bitcoind with -walletcrosschain to override.");
3202 walletInstance->m_attaching_chain =
true;
3203 walletInstance->m_chain_notifications_handler = walletInstance->chain().handleNotifications(walletInstance);
3206 int rescan_height = 0;
3207 if (!rescan_required)
3213 rescan_height = *fork_height;
3221 walletInstance->m_last_block_processed_height = *tip_height;
3223 walletInstance->m_last_block_processed.
SetNull();
3224 walletInstance->m_last_block_processed_height = -1;
3227 if (tip_height && *tip_height != rescan_height)
3231 std::optional<int64_t> time_first_key = walletInstance->m_birth_time.load();
3232 if (time_first_key) {
3239 rescan_height = *tip_height;
3247 int block_height = *tip_height;
3248 while (block_height > 0 &&
chain.
haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
3252 if (rescan_height != block_height) {
3263 _(
"Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)") :
3265 "Error loading wallet. Wallet requires blocks to be downloaded, "
3266 "and software does not currently support loading wallets while "
3267 "blocks are being downloaded out of order when using assumeutxo "
3268 "snapshots. Wallet should be able to load successfully after "
3269 "node sync reaches height %s"), block_height);
3275 walletInstance->WalletLogPrintf(
"Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
3280 error =
_(
"Failed to rescan the wallet during initialization");
3284 walletInstance->m_attaching_chain =
false;
3286 walletInstance->GetDatabase().IncrementUpdateCounter();
3288 walletInstance->m_attaching_chain =
false;
3295 const auto& address_book_it = m_address_book.find(dest);
3296 if (address_book_it == m_address_book.end())
return nullptr;
3297 if ((!allow_change) && address_book_it->second.IsChange()) {
3300 return &address_book_it->second;
3312 if (version < prev_version) {
3313 error =
strprintf(
_(
"Cannot downgrade wallet from version %i to version %i. Wallet version unchanged."), prev_version, version);
3321 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);
3329 if (!spk_man->Upgrade(prev_version, version,
error)) {
3386 assert(chain_depth >= 0);
3409 return vMasterKey.empty();
3419 if (!vMasterKey.empty()) {
3420 memory_cleanse(vMasterKey.data(), vMasterKey.size() *
sizeof(decltype(vMasterKey)::value_type));
3434 if (!spk_man_pair.second->CheckDecryptionKey(vMasterKeyIn, accept_no_keys)) {
3438 vMasterKey = vMasterKeyIn;
3446 std::set<ScriptPubKeyMan*> spk_mans;
3447 for (
bool internal : {
false,
true}) {
3451 spk_mans.insert(spk_man);
3460 std::set<ScriptPubKeyMan*> spk_mans;
3462 spk_mans.insert(spk_man_pair.second.get());
3470 std::map<OutputType, ScriptPubKeyMan*>::const_iterator it = spk_managers.find(type);
3471 if (it == spk_managers.end()) {
3479 std::set<ScriptPubKeyMan*> spk_mans;
3482 if (spk_man_pair.second->CanProvide(script, sigdata)) {
3483 spk_mans.insert(spk_man_pair.second.get());
3506 if (spk_man_pair.second->CanProvide(script, sigdata)) {
3507 return spk_man_pair.second->GetSolvingProvider(script);
3515 std::vector<WalletDescriptor> descs;
3518 LOCK(desc_spk_man->cs_desc_man);
3519 descs.push_back(desc_spk_man->GetWalletDescriptor());
3562 uint256 id = spk_manager->GetID();
3581 spk_man->NotifyFirstKeyTimeChanged.connect(std::bind(&
CWallet::FirstKeyTimeChanged,
this, std::placeholders::_1, std::placeholders::_2));
3600 for (
bool internal : {
false,
true}) {
3605 throw std::runtime_error(std::string(__func__) +
": Wallet is locked, cannot setup new descriptors");
3607 if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey,
nullptr)) {
3608 throw std::runtime_error(std::string(__func__) +
": Could not encrypt new descriptors");
3611 spk_manager->SetupDescriptorGeneration(master_key,
t,
internal);
3612 uint256 id = spk_manager->GetID();
3642 if (!signer_res.
isObject())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3643 for (
bool internal : {
false,
true}) {
3644 const UniValue& descriptor_vals = signer_res.
find_value(
internal ?
"internal" :
"receive");
3645 if (!descriptor_vals.
isArray())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3647 const std::string& desc_str = desc_val.getValStr();
3649 std::string desc_error;
3650 std::unique_ptr<Descriptor> desc =
Parse(desc_str, keys, desc_error,
false);
3651 if (desc ==
nullptr) {
3652 throw std::runtime_error(std::string(__func__) +
": Invalid descriptor \"" + desc_str +
"\" (" + desc_error +
")");
3654 if (!desc->GetOutputType()) {
3659 spk_manager->SetupDescriptor(std::move(desc));
3660 uint256 id = spk_manager->GetID();
3672 throw std::runtime_error(std::string(__func__) +
": writing active ScriptPubKeyMan id failed");
3687 spk_mans[type] = spk_man;
3689 const auto it = spk_mans_other.find(type);
3690 if (it != spk_mans_other.end() && it->second == spk_man) {
3691 spk_mans_other.erase(type);
3700 if (spk_man !=
nullptr && spk_man->GetID() ==
id) {
3704 throw std::runtime_error(std::string(__func__) +
": erasing active ScriptPubKeyMan id failed");
3708 spk_mans.erase(type);
3720 return spk_man !=
nullptr;
3740 return std::nullopt;
3745 return std::nullopt;
3749 if (!desc_spk_man) {
3750 throw std::runtime_error(std::string(__func__) +
": unexpected ScriptPubKeyMan type.");
3753 LOCK(desc_spk_man->cs_desc_man);
3754 const auto& type = desc_spk_man->GetWalletDescriptor().descriptor->GetOutputType();
3755 assert(type.has_value());
3765 WalletLogPrintf(
"Cannot add WalletDescriptor to a non-descriptor wallet\n");
3772 spk_man->UpdateWalletDescriptor(desc);
3775 spk_man = new_spk_man.get();
3778 uint256 id = new_spk_man->GetID();
3783 for (
const auto& entry : signing_provider.
keys) {
3784 const CKey& key = entry.second;
3785 spk_man->AddDescriptorKey(key, key.
GetPubKey());
3789 if (!spk_man->TopUp()) {
3797 auto script_pub_keys = spk_man->GetScriptPubKeys();
3798 if (script_pub_keys.empty()) {
3799 WalletLogPrintf(
"Could not generate scriptPubKeys (cache is empty)\n");
3804 for (
const auto& script : script_pub_keys) {
3814 spk_man->WriteDescriptor();
3823 WalletLogPrintf(
"Migrating wallet storage database from BerkeleyDB to SQLite.\n");
3826 error =
_(
"Error: This wallet already uses SQLite");
3831 std::unique_ptr<DatabaseBatch> batch =
m_database->MakeBatch();
3832 std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor();
3833 std::vector<std::pair<SerializeData, SerializeData>> records;
3835 error =
_(
"Error: Unable to begin reading all records in the database");
3842 status = cursor->Next(ss_key, ss_value);
3848 records.emplace_back(key, value);
3853 error =
_(
"Error: Unable to read all records in the database");
3859 fs::path db_dir = db_path.parent_path();
3861 fs::remove(db_path);
3868 std::unique_ptr<WalletDatabase> new_db =
MakeDatabase(db_dir, opts, db_status,
error);
3875 bool began = batch->TxnBegin();
3877 for (
const auto& [key, value] : records) {
3885 bool committed = batch->TxnCommit();
3898 if (res == std::nullopt) {
3899 error =
_(
"Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
3900 return std::nullopt;
3911 error =
_(
"Error: This wallet is already a descriptor wallet");
3917 error =
_(
"Error: Duplicate descriptors created during migration. Your wallet may be corrupted.");
3920 uint256 id = desc_spkm->GetID();
3948 std::vector<uint256> txids_to_delete;
3958 error =
_(
"Error: Could not add watchonly tx to watchonly wallet");
3962 txids_to_delete.push_back(wtx->GetHash());
3967 error =
strprintf(
_(
"Error: Transaction %s in wallet cannot be identified to belong to migrated wallets"), wtx->GetHash().GetHex());
3972 if (txids_to_delete.size() > 0) {
3973 std::vector<uint256> deleted_txids;
3975 error =
_(
"Error: Could not delete watchonly transactions");
3978 if (deleted_txids != txids_to_delete) {
3979 error =
_(
"Error: Not all watchonly txs could be deleted");
3983 for (
const uint256& txid : deleted_txids) {
3989 std::vector<CTxDestination> dests_to_delete;
3990 for (
const auto& addr_pair : m_address_book) {
3993 if (!
IsMine(addr_pair.first)) {
3999 std::string label = addr_pair.second.GetLabel();
4000 data.
watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4001 if (!addr_pair.second.IsChange()) {
4004 dests_to_delete.push_back(addr_pair.first);
4012 std::string label = addr_pair.second.GetLabel();
4013 data.
solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4014 if (!addr_pair.second.IsChange()) {
4015 data.
solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
4017 dests_to_delete.push_back(addr_pair.first);
4022 error =
_(
"Error: Address book data in wallet cannot be identified to belong to migrated wallets");
4030 std::string label = addr_pair.second.GetLabel();
4031 data.
watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4032 if (!addr_pair.second.IsChange()) {
4040 std::string label = addr_pair.second.GetLabel();
4041 data.
solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4042 if (!addr_pair.second.IsChange()) {
4043 data.
solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
4054 for (
const auto& [destination, addr_book_data] :
wallet.m_address_book) {
4056 auto label{addr_book_data.GetLabel()};
4058 if (addr_book_data.purpose) batch.WritePurpose(address,
PurposeToString(*addr_book_data.purpose));
4059 if (!label.empty()) batch.WriteName(address, label);
4066 if (dests_to_delete.size() > 0) {
4067 for (
const auto& dest : dests_to_delete) {
4069 error =
_(
"Error: Unable to remove watchonly address book data");
4094 std::optional<MigrationData> data =
wallet.GetDescriptorsForLegacy(
error);
4095 if (data == std::nullopt)
return false;
4098 if (data->watch_descs.size() > 0 || data->solvable_descs.size() > 0) {
4111 if (data->watch_descs.size() > 0) {
4112 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the watched scripts\n");
4115 std::vector<bilingual_str> warnings;
4116 std::string wallet_name =
wallet.GetName() +
"_watchonly";
4119 error =
_(
"Error: Failed to create new watchonly wallet");
4122 res.watchonly_wallet = data->watchonly_wallet;
4123 LOCK(data->watchonly_wallet->cs_wallet);
4126 for (
const auto& [desc_str, creation_time] : data->watch_descs) {
4129 std::string parse_err;
4130 std::unique_ptr<Descriptor> desc =
Parse(desc_str, keys, parse_err,
true);
4132 assert(!desc->IsRange());
4136 data->watchonly_wallet->AddWalletDescriptor(w_desc, keys,
"",
false);
4142 if (data->solvable_descs.size() > 0) {
4143 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the unwatched solvable scripts\n");
4146 std::vector<bilingual_str> warnings;
4147 std::string wallet_name =
wallet.GetName() +
"_solvables";
4150 error =
_(
"Error: Failed to create new watchonly wallet");
4153 res.solvables_wallet = data->solvable_wallet;
4154 LOCK(data->solvable_wallet->cs_wallet);
4157 for (
const auto& [desc_str, creation_time] : data->solvable_descs) {
4160 std::string parse_err;
4161 std::unique_ptr<Descriptor> desc =
Parse(desc_str, keys, parse_err,
true);
4163 assert(!desc->IsRange());
4167 data->solvable_wallet->AddWalletDescriptor(w_desc, keys,
"",
false);
4186 std::vector<bilingual_str> warnings;
4191 return util::Error{
_(
"Unable to unload the wallet before migrating")};
4210 if (!local_wallet) {
4215 if (!local_wallet->GetLegacyScriptPubKeyMan()) {
4216 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4222 fs::path backup_path = this_wallet_dir / backup_filename;
4224 return util::Error{
_(
"Error: Unable to make a backup of your wallet")};
4228 bool success =
false;
4230 LOCK(local_wallet->cs_wallet);
4233 if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
4234 if (passphrase.find(
'\0') == std::string::npos) {
4235 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
4237 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase entered was incorrect. "
4238 "The passphrase contains a null character (ie - a zero byte). "
4239 "If this passphrase was set with a version of this software prior to 25.0, "
4240 "please try again with only the characters up to — but not including — "
4241 "the first null character.")};
4254 assert(local_wallet.use_count() == 1);
4255 local_wallet.reset();
4262 fs::copy_file(backup_path, temp_backup_location, fs::copy_options::none);
4265 std::vector<fs::path> wallet_dirs;
4266 wallet_dirs.push_back(
fs::PathFromString(local_wallet->GetDatabase().Filename()).parent_path());
4269 assert(local_wallet.use_count() == 1);
4270 local_wallet.reset();
4273 std::vector<std::shared_ptr<CWallet>> created_wallets;
4278 for (std::shared_ptr<CWallet>& w : created_wallets) {
4279 wallet_dirs.push_back(
fs::PathFromString(w->GetDatabase().Filename()).parent_path());
4283 for (std::shared_ptr<CWallet>& w : created_wallets) {
4285 error +=
_(
"\nUnable to cleanup failed migration");
4292 for (
fs::path& dir : wallet_dirs) {
4293 fs::remove_all(dir);
4298 std::vector<bilingual_str> warnings;
4300 error +=
_(
"\nUnable to restore backup of wallet.");
4305 fs::copy_file(temp_backup_location, backup_path, fs::copy_options::none);
4306 fs::remove(temp_backup_location);
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 std::vector< CTxOut > vout
const uint256 & GetHash() const
const std::vector< CTxIn > vin
An input of a transaction.
CScriptWitness scriptWitness
Only serialized through CTransaction.
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.
An interface to be implemented by keystores that support signing.
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 bool updateRwSetting(const std::string &name, const util::SettingsValue &value, bool write=true)=0
Write a setting to <datadir>/settings.json.
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 util::SettingsValue getRwSetting(const std::string &name)=0
Return <datadir>/settings.json setting value.
virtual bool havePruned()=0
Check if any block has been pruned.
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 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)
bool HasInputWeight(const COutPoint &outpoint) const
Returns true if the input weight is set.
int64_t GetInputWeight(const COutPoint &outpoint) const
Returns the input weight.
bool fAllowWatchOnly
Includes watch only addresses which are solvable.
bool IsExternalSelected(const COutPoint &output) const
Returns true if the given output is selected as an external input.
FlatSigningProvider m_external_provider
SigningProvider that has pubkeys and scripts to do spend size estimation for external inputs.
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
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(std::string 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
mapValue_t mapValue
Key/value map with information about the transaction.
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
const uint256 & GetHash() const
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::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 int64_t GetTransactionInputWeight(const CTxIn &txin)
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.
bool DummySignInput(const SigningProvider &provider, CTxIn &tx_in, const CTxOut &txout, bool can_grind_r, const CCoinControl *coin_control)
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 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
bool DummySignTx(CMutableTransaction &txNew, const std::vector< CTxOut > &txouts, const CCoinControl *coin_control=nullptr) const
void blockConnected(const interfaces::BlockInfo &block) override
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)
void chainStateFlushed(const CBlockLocator &loc) override
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()
bool AddToWalletIfInvolvingMe(const CTransactionRef &tx, const SyncTxState &state, bool fUpdate, bool rescanning_old_block) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Add a transaction to the wallet, or update it.
void UpgradeDescriptorCache() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Upgrade DescriptorCaches.