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 uint256& 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());
982 assert(wtx.mapValue.count(
"replaced_by_txid") == 0);
984 wtx.mapValue[
"replaced_by_txid"] = newHash.
ToString();
993 WalletLogPrintf(
"%s: Updating batch tx %s failed\n", __func__, wtx.GetHash().ToString());
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);
1090 if (state.index() != wtx.
m_state.index()) {
1102 if (tx->HasWitness() && !wtx.
tx->HasWitness()) {
1110 std::vector<CWalletTx*> txs{&wtx};
1114 while (!txs.empty()) {
1117 desc_tx->
m_state = inactive_state;
1122 for (
unsigned int i = 0; i < desc_tx->
tx->vout.size(); ++i) {
1124 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(outpoint);
1125 for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
1126 const auto wit = mapWallet.find(it->second);
1127 if (wit != mapWallet.end()) {
1128 txs.push_back(&wit->second);
1139 if (fInsertedNew || fUpdated)
1153 if (!strCmd.empty())
1158 ReplaceAll(strCmd,
"%b", conf->confirmed_block_hash.GetHex());
1172 std::thread
t(runCommand, strCmd);
1182 const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(
nullptr,
TxStateInactive{}));
1184 if (!fill_wtx(wtx, ins.second)) {
1191 auto lookup_block = [&](
const uint256& hash,
int& height,
TxState& state) {
1203 lookup_block(conf->confirmed_block_hash, conf->confirmed_block_height, wtx.
m_state);
1205 lookup_block(conf->conflicting_block_hash, conf->conflicting_block_height, wtx.
m_state);
1212 for (
const CTxIn& txin : wtx.
tx->vin) {
1214 if (it != mapWallet.end()) {
1234 if (
auto* conf = std::get_if<TxStateConfirmed>(&state)) {
1236 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.
prevout);
1237 while (range.first != range.second) {
1238 if (range.first->second != tx.
GetHash()) {
1239 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);
1240 MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
1247 bool fExisted = mapWallet.count(tx.
GetHash()) != 0;
1248 if (fExisted && !fUpdate)
return false;
1260 for (
auto &dest : spk_man->MarkUnusedAddresses(txout.
scriptPubKey)) {
1262 if (!dest.internal.has_value()) {
1267 if (!dest.internal.has_value())
continue;
1281 TxState tx_state = std::visit([](
auto&& s) ->
TxState {
return s; }, state);
1286 throw std::runtime_error(
"DB error adding transaction to wallet, write failed");
1303 for (
const CTxIn& txin : tx->vin) {
1305 if (it != mapWallet.end()) {
1306 it->second.MarkDirty();
1316 auto it = mapWallet.find(hashTx);
1317 assert(it != mapWallet.end());
1325 assert(!wtx.isConfirmed());
1326 assert(!wtx.InMempool());
1328 if (!wtx.isConflicted() && !wtx.isAbandoned()) {
1354 if (m_last_block_processed_height < 0 || conflicting_height < 0) {
1357 int conflictconfirms = (m_last_block_processed_height - conflicting_height + 1) * -1;
1358 if (conflictconfirms >= 0)
1380 std::set<uint256> todo;
1381 std::set<uint256> done;
1383 todo.insert(tx_hash);
1385 while (!todo.empty()) {
1389 auto it = mapWallet.find(now);
1390 assert(it != mapWallet.end());
1393 TxUpdate update_state = try_updating_state(wtx);
1394 if (update_state != TxUpdate::UNCHANGED) {
1398 for (
unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
1399 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(
COutPoint(now, i));
1400 for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
1401 if (!done.count(iter->second)) {
1402 todo.insert(iter->second);
1407 if (update_state == TxUpdate::NOTIFY_CHANGED) {
1413 MarkInputsDirty(wtx.tx);
1433 auto it = mapWallet.find(tx->GetHash());
1434 if (it != mapWallet.end()) {
1441 auto it = mapWallet.find(tx->GetHash());
1442 if (it != mapWallet.end()) {
1484 m_last_block_processed_height = block.
height;
1485 m_last_block_processed = block.
hash;
1492 for (
size_t index = 0; index < block.
data->
vtx.size(); index++) {
1507 m_last_block_processed_height = block.
height - 1;
1510 int disconnect_height = block.
height;
1515 for (
const CTxIn& tx_in : ptx->vin) {
1517 if (mapTxSpends.count(tx_in.
prevout) < 1)
continue;
1519 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(tx_in.
prevout);
1522 for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) {
1523 CWalletTx& wtx = mapWallet.find(_it->second)->second;
1527 auto try_updating_state = [&](
CWalletTx& tx) {
1547 void CWallet::BlockUntilSyncedToCurrentChain()
const {
1563 const auto mi = mapWallet.find(txin.
prevout.
hash);
1564 if (mi != mapWallet.end())
1592 result = std::max(result, spk_man_pair.second->IsMine(script));
1613 if (outpoint.
n >= wtx->tx->vout.size()) {
1616 return IsMine(wtx->tx->vout[outpoint.
n]);
1631 throw std::runtime_error(std::string(__func__) +
": value out of range");
1639 bool result =
false;
1641 if (!spk_man->IsHDEnabled())
return false;
1653 if (spk_man && spk_man->CanGetAddresses(
internal)) {
1660 void CWallet::SetWalletFlag(uint64_t
flags)
1665 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1679 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1714 throw std::runtime_error(std::string(__func__) +
": writing wallet flags failed");
1726 LOCK(spk_man->cs_KeyStore);
1727 return spk_man->ImportScripts(scripts, timestamp);
1736 LOCK(spk_man->cs_KeyStore);
1737 return spk_man->ImportPrivKeys(privkey_map, timestamp);
1740 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)
1746 LOCK(spk_man->cs_KeyStore);
1747 return spk_man->ImportPubKeys(ordered_pubkeys, pubkey_map, key_origins, add_keypool,
internal, timestamp);
1750 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)
1756 LOCK(spk_man->cs_KeyStore);
1757 if (!spk_man->ImportScriptPubKeys(script_pub_keys, have_solving_data, timestamp)) {
1762 for (
const CScript& script : script_pub_keys) {
1776 if (time < birthtime) {
1794 int start_height = 0;
1835 constexpr
auto INTERVAL_TIME{60s};
1836 auto current_time{reserver.
now()};
1837 auto start_time{reserver.
now()};
1841 uint256 block_hash = start_block;
1844 std::unique_ptr<FastWalletRescanFilter> fast_rescan_filter;
1848 fast_rescan_filter ?
"fast variant using block filters" :
"slow variant inspecting all blocks");
1857 double progress_current = progress_begin;
1858 int block_height = start_height;
1860 if (progress_end - progress_begin > 0.0) {
1861 m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin);
1865 if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
1869 bool next_interval = reserver.
now() >= current_time + INTERVAL_TIME;
1870 if (next_interval) {
1871 current_time = reserver.
now();
1872 WalletLogPrintf(
"Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
1875 bool fetch_block{
true};
1876 if (fast_rescan_filter) {
1877 fast_rescan_filter->UpdateIfNeeded();
1878 auto matches_block{fast_rescan_filter->MatchesBlock(block_hash)};
1879 if (matches_block.has_value()) {
1880 if (*matches_block) {
1881 LogPrint(
BCLog::SCAN,
"Fast rescan: inspect block %d [%s] (filter matched)\n", block_height, block_hash.ToString());
1885 fetch_block =
false;
1888 LogPrint(
BCLog::SCAN,
"Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.ToString());
1894 bool block_still_active =
false;
1895 bool next_block =
false;
1906 if (!block_still_active) {
1913 for (
size_t posInBlock = 0; posInBlock < block.
vtx.size(); ++posInBlock) {
1920 if (save_progress && next_interval) {
1935 if (max_height && block_height >= *max_height) {
1946 block_hash = next_block_hash;
1951 const uint256 prev_tip_hash = tip_hash;
1953 if (!max_height && prev_tip_hash != tip_hash) {
1965 WalletLogPrintf(
"Rescan aborted at block %d. Progress=%f\n", block_height, progress_current);
1967 }
else if (block_height &&
chain().shutdownRequested()) {
1968 WalletLogPrintf(
"Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height, progress_current);
1971 WalletLogPrintf(
"Rescan completed in %15dms\n", Ticks<std::chrono::milliseconds>(reserver.
now() - start_time));
2012 result.erase(myHash);
2024 if (!
chain().isReadyToBroadcast())
return false;
2065 int submitted_tx_count = 0;
2072 std::set<CWalletTx*, WalletTxOrderComparator> to_submit;
2073 for (
auto& [txid, wtx] : mapWallet) {
2075 if (!wtx.isUnconfirmed())
continue;
2080 to_submit.insert(&wtx);
2083 for (
auto wtx : to_submit) {
2084 std::string unused_err_string;
2089 if (submitted_tx_count > 0) {
2090 WalletLogPrintf(
"%s: resubmit %u unconfirmed transactions\n", __func__, submitted_tx_count);
2099 if (!pwallet->ShouldResend())
continue;
2100 pwallet->ResubmitWalletTransactions(
true,
false);
2101 pwallet->SetNextResend();
2116 std::map<COutPoint, Coin> coins;
2117 for (
auto& input : tx.
vin) {
2118 const auto mi = mapWallet.find(input.prevout.hash);
2119 if(mi == mapWallet.end() || input.prevout.n >= mi->second.tx->vout.size()) {
2124 coins[input.prevout] =
Coin(wtx.
tx->vout[input.prevout.n], prev_height, wtx.
IsCoinBase());
2126 std::map<int, bilingual_str> input_errors;
2136 if (spk_man->SignTransaction(tx, coins,
sighash, input_errors)) {
2152 for (
unsigned int i = 0; i < psbtx.
tx->vin.size(); ++i) {
2153 const CTxIn& txin = psbtx.
tx->vin[i];
2163 const auto it = mapWallet.find(txhash);
2164 if (it != mapWallet.end()) {
2177 int n_signed_this_spkm = 0;
2178 TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm, finalize);
2184 (*n_signed) += n_signed_this_spkm;
2192 for (
const auto& input : psbtx.
inputs) {
2204 if (spk_man_pair.second->CanProvide(script_pub_key, sigdata)) {
2206 return spk_man_pair.second->SignMessage(message, pkhash, str_sig);
2216 return *change_type;
2225 bool any_wpkh{
false};
2227 bool any_pkh{
false};
2229 for (
const auto& recipient : vecSend) {
2230 if (std::get_if<WitnessV1Taproot>(&recipient.dest)) {
2232 }
else if (std::get_if<WitnessV0KeyHash>(&recipient.dest)) {
2234 }
else if (std::get_if<ScriptHash>(&recipient.dest)) {
2236 }
else if (std::get_if<PKHash>(&recipient.dest)) {
2242 if (has_bech32m_spkman && any_tr) {
2247 if (has_bech32_spkman && any_wpkh) {
2252 if (has_p2sh_segwit_spkman && any_sh) {
2258 if (has_legacy_spkman && any_pkh) {
2263 if (has_bech32m_spkman) {
2266 if (has_bech32_spkman) {
2283 wtx.
mapValue = std::move(mapValue);
2292 throw std::runtime_error(std::string(__func__) +
": Wallet db error, transaction commit failed");
2296 for (
const CTxIn& txin : tx->vin) {
2307 std::string err_string;
2309 WalletLogPrintf(
"CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
2324 spk_man_pair.second->RewriteDB();
2334 return nLoadWalletRet;
2341 for (
const uint256& hash : vHashOut) {
2342 const auto& it = mapWallet.find(hash);
2343 wtxOrdered.erase(it->second.m_it_wtxOrdered);
2344 for (
const auto& txin : it->second.tx->vin)
2345 mapTxSpends.erase(txin.prevout);
2346 mapWallet.erase(it);
2355 spk_man_pair.second->RewriteDB();
2361 return nZapSelectTxRet;
2370 bool fUpdated =
false;
2372 std::optional<AddressPurpose> purpose;
2375 std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
2376 fUpdated = (mi != m_address_book.end() && !mi->second.IsChange());
2377 m_address_book[address].SetLabel(strName);
2380 purpose = m_address_book[address].purpose = new_purpose;
2382 purpose = m_address_book[address].purpose;
2414 m_address_book.erase(address);
2428 if (legacy_spk_man) {
2429 return legacy_spk_man->KeypoolCountExternalKeys();
2432 unsigned int count = 0;
2434 count += spk_man.second->GetKeyPoolSize();
2444 unsigned int count = 0;
2446 count += spk_man->GetKeyPoolSize();
2456 res &= spk_man->TopUp(kpSize);
2469 auto op_dest = spk_man->GetNewDestination(type);
2492 return std::nullopt;
2495 std::optional<int64_t> oldest_key{std::numeric_limits<int64_t>::max()};
2497 oldest_key = std::min(oldest_key, spk_man_pair.second->GetOldestKeyPoolTime());
2503 for (
auto& entry : mapWallet) {
2506 for (
unsigned int i = 0; i < wtx.
tx->vout.size(); i++) {
2519 for (
const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book) {
2520 const auto& entry = item.second;
2521 func(item.first, entry.GetLabel(), entry.IsChange(), entry.purpose);
2528 std::vector<CTxDestination> result;
2536 result.emplace_back(dest);
2544 std::set<std::string> label_set;
2546 bool _is_change,
const std::optional<AddressPurpose>& _purpose) {
2547 if (_is_change)
return;
2548 if (!purpose || purpose == _purpose) {
2549 label_set.insert(_label);
2566 if (!op_address)
return op_address;
2597 if (signer_spk_man ==
nullptr) {
2601 return signer_spk_man->DisplayAddress(scriptPubKey, signer);
2609 setLockedCoins.insert(output);
2619 bool was_locked = setLockedCoins.erase(output);
2620 if (batch && was_locked) {
2629 bool success =
true;
2631 for (
auto it = setLockedCoins.begin(); it != setLockedCoins.end(); ++it) {
2634 setLockedCoins.clear();
2641 return setLockedCoins.count(output) > 0;
2647 for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
2648 it != setLockedCoins.end(); it++) {
2650 vOutpts.push_back(outpt);
2658 mapKeyBirth.clear();
2661 std::map<CKeyID, const TxStateConfirmed*> mapKeyFirstBlock;
2668 assert(spk_man !=
nullptr);
2672 for (
const auto& entry : spk_man->mapKeyMetadata) {
2673 if (entry.second.nCreateTime) {
2674 mapKeyBirth[entry.first] = entry.second.nCreateTime;
2680 if (mapKeyBirth.count(keyid) == 0)
2681 mapKeyFirstBlock[keyid] = &max_confirm;
2685 if (mapKeyFirstBlock.empty())
2689 for (
const auto& entry : mapWallet) {
2694 for (
const CTxOut &txout : wtx.
tx->vout) {
2698 auto rit = mapKeyFirstBlock.find(keyid);
2699 if (rit != mapKeyFirstBlock.end() && conf->confirmed_block_height < rit->second->confirmed_block_height) {
2709 for (
const auto& entry : mapKeyFirstBlock) {
2741 std::optional<uint256> block_hash;
2743 block_hash = conf->confirmed_block_hash;
2745 block_hash = conf->conflicting_block_hash;
2751 int64_t block_max_time;
2752 if (
chain().findBlock(*block_hash,
FoundBlock().time(blocktime).maxTime(block_max_time))) {
2753 if (rescanning_old_block) {
2754 nTimeSmart = block_max_time;
2757 int64_t latestEntry = 0;
2760 int64_t latestTolerated = latestNow + 300;
2762 for (
auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
2772 if (nSmartTime <= latestTolerated) {
2773 latestEntry = nSmartTime;
2774 if (nSmartTime > latestNow) {
2775 latestNow = nSmartTime;
2781 nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
2792 if (std::get_if<CNoDestination>(&dest))
2796 if (
auto* data{
common::FindKey(m_address_book, dest)}) data->previously_spent =
false;
2806 m_address_book[dest].previously_spent =
true;
2811 m_address_book[dest].receive_requests[id] = request;
2816 if (
auto* data{
common::FindKey(m_address_book, dest)})
return data->previously_spent;
2822 std::vector<std::string>
values;
2823 for (
const auto& [dest, entry] : m_address_book) {
2824 for (
const auto& [
id, request] : entry.receive_requests) {
2825 values.emplace_back(request);
2834 m_address_book[dest].receive_requests[id] = value;
2841 m_address_book[dest].receive_requests.erase(
id);
2854 fs::file_type path_type = fs::symlink_status(wallet_path).type();
2855 if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory ||
2856 (path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) ||
2859 "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and " 2860 "database/log.?????????? files can be stored, a location where such a directory could be created, " 2861 "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
2866 return MakeDatabase(wallet_path, options, status, error_string);
2873 const std::string& walletFile = database->Filename();
2875 const auto start{SteadyClock::now()};
2880 walletInstance->m_notify_tx_changed_script =
args.
GetArg(
"-walletnotify",
"");
2883 bool rescan_required =
false;
2884 DBErrors nLoadWalletRet = walletInstance->LoadWallet();
2887 error =
strprintf(
_(
"Error loading %s: Wallet corrupted"), walletFile);
2892 warnings.push_back(
strprintf(
_(
"Error reading %s! All keys read correctly, but transaction data" 2893 " or address metadata may be missing or incorrect."),
2901 error =
strprintf(
_(
"Error loading %s: External signer wallet being loaded without external signer support compiled"), walletFile);
2909 warnings.push_back(
strprintf(
_(
"Error reading %s! Transaction data may be missing or incorrect." 2910 " Rescanning wallet."), walletFile));
2911 rescan_required =
true;
2913 error =
strprintf(
_(
"Unrecognized descriptor found. Loading wallet %s\n\n" 2914 "The wallet might had been created on a newer version.\n" 2915 "Please try running the latest software version.\n"), walletFile);
2918 error =
strprintf(
_(
"Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n" 2919 "The wallet might have been tampered with or created with malicious intent.\n"), walletFile);
2928 const bool fFirstRun = walletInstance->m_spk_managers.empty() &&
2936 walletInstance->InitWalletFlags(wallet_creation_flags);
2940 walletInstance->SetupLegacyScriptPubKeyMan();
2944 LOCK(walletInstance->cs_wallet);
2946 walletInstance->SetupDescriptorScriptPubKeyMans();
2950 for (
auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
2951 if (!spk_man->SetupGeneration()) {
2952 error =
_(
"Unable to generate initial keys");
2964 error =
strprintf(
_(
"Error loading %s: Private keys can only be disabled during creation"), walletFile);
2967 for (
auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
2968 if (spk_man->HavePrivateKeys()) {
2969 warnings.push_back(
strprintf(
_(
"Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
2975 if (!
args.
GetArg(
"-addresstype",
"").empty()) {
2981 walletInstance->m_default_address_type = parsed.value();
2984 if (!
args.
GetArg(
"-changetype",
"").empty()) {
2990 walletInstance->m_default_change_type = parsed.value();
3000 _(
"This is the minimum transaction fee you pay on every transaction."));
3003 walletInstance->m_min_fee =
CFeeRate{min_tx_fee.value()};
3007 const std::string max_aps_fee{
args.
GetArg(
"-maxapsfee",
"")};
3008 if (max_aps_fee ==
"-1") {
3009 walletInstance->m_max_aps_fee = -1;
3010 }
else if (std::optional<CAmount> max_fee =
ParseMoney(max_aps_fee)) {
3013 _(
"This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
3015 walletInstance->m_max_aps_fee = max_fee.value();
3024 if (!fallback_fee) {
3029 _(
"This is the transaction fee you may pay when fee estimates are not available."));
3031 walletInstance->m_fallback_fee =
CFeeRate{fallback_fee.value()};
3035 walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.
GetFeePerK() != 0;
3044 _(
"This is the transaction fee you may discard if change is smaller than dust at this level"));
3046 walletInstance->m_discard_rate =
CFeeRate{discard_fee.value()};
3056 _(
"This is the transaction fee you will pay if you send a transaction."));
3059 walletInstance->m_pay_tx_fee =
CFeeRate{pay_tx_fee.value(), 1000};
3062 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' (must be at least %s)"),
3074 warnings.push_back(
strprintf(
_(
"%s is set very high! Fees this large could be paid on a single transaction."),
"-maxtxfee"));
3078 error =
strprintf(
_(
"Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
3083 walletInstance->m_default_max_tx_fee = max_fee.value();
3087 if (std::optional<CAmount> consolidate_feerate =
ParseMoney(
args.
GetArg(
"-consolidatefeerate",
""))) {
3088 walletInstance->m_consolidate_feerate =
CFeeRate(*consolidate_feerate);
3097 _(
"The wallet will avoid paying less than the minimum relay fee."));
3104 walletInstance->WalletLogPrintf(
"Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
3107 walletInstance->TopUpKeyPool();
3110 std::optional<int64_t> time_first_key;
3111 for (
auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
3112 int64_t time = spk_man->GetTimeFirstKey();
3113 if (!time_first_key || time < *time_first_key) time_first_key = time;
3115 if (time_first_key) walletInstance->MaybeUpdateBirthTime(*time_first_key);
3122 LOCK(walletInstance->cs_wallet);
3124 walletInstance->WalletLogPrintf(
"setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
3125 walletInstance->WalletLogPrintf(
"mapWallet.size() = %u\n", walletInstance->mapWallet.size());
3126 walletInstance->WalletLogPrintf(
"m_address_book.size() = %u\n", walletInstance->m_address_book.size());
3129 return walletInstance;
3134 LOCK(walletInstance->cs_wallet);
3136 assert(!walletInstance->m_chain || walletInstance->m_chain == &
chain);
3137 walletInstance->m_chain = &
chain;
3143 if (batch.ReadBestBlock(locator) && locator.vHave.size() > 0 &&
chain.
getHeight()) {
3147 error =
Untranslated(
"Wallet files should not be reused across chains. Restart bitcoind with -walletcrosschain to override.");
3163 walletInstance->m_attaching_chain =
true;
3164 walletInstance->m_chain_notifications_handler = walletInstance->chain().handleNotifications(walletInstance);
3167 int rescan_height = 0;
3168 if (!rescan_required)
3172 if (batch.ReadBestBlock(locator)) {
3174 rescan_height = *fork_height;
3182 walletInstance->m_last_block_processed_height = *tip_height;
3184 walletInstance->m_last_block_processed.
SetNull();
3185 walletInstance->m_last_block_processed_height = -1;
3188 if (tip_height && *tip_height != rescan_height)
3192 std::optional<int64_t> time_first_key = walletInstance->m_birth_time.load();
3193 if (time_first_key) {
3200 rescan_height = *tip_height;
3208 int block_height = *tip_height;
3209 while (block_height > 0 &&
chain.
haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
3213 if (rescan_height != block_height) {
3224 _(
"Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)") :
3226 "Error loading wallet. Wallet requires blocks to be downloaded, " 3227 "and software does not currently support loading wallets while " 3228 "blocks are being downloaded out of order when using assumeutxo " 3229 "snapshots. Wallet should be able to load successfully after " 3230 "node sync reaches height %s"), block_height);
3236 walletInstance->WalletLogPrintf(
"Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
3241 error =
_(
"Failed to rescan the wallet during initialization");
3245 walletInstance->m_attaching_chain =
false;
3247 walletInstance->GetDatabase().IncrementUpdateCounter();
3249 walletInstance->m_attaching_chain =
false;
3256 const auto& address_book_it = m_address_book.find(dest);
3257 if (address_book_it == m_address_book.end())
return nullptr;
3258 if ((!allow_change) && address_book_it->second.IsChange()) {
3261 return &address_book_it->second;
3273 if (version < prev_version) {
3274 error =
strprintf(
_(
"Cannot downgrade wallet from version %i to version %i. Wallet version unchanged."), prev_version, version);
3282 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);
3290 if (!spk_man->Upgrade(prev_version, version,
error)) {
3347 assert(chain_depth >= 0);
3370 return vMasterKey.empty();
3380 if (!vMasterKey.empty()) {
3381 memory_cleanse(vMasterKey.data(), vMasterKey.size() *
sizeof(decltype(vMasterKey)::value_type));
3395 if (!spk_man_pair.second->CheckDecryptionKey(vMasterKeyIn, accept_no_keys)) {
3399 vMasterKey = vMasterKeyIn;
3407 std::set<ScriptPubKeyMan*> spk_mans;
3408 for (
bool internal : {
false,
true}) {
3412 spk_mans.insert(spk_man);
3421 std::set<ScriptPubKeyMan*> spk_mans;
3423 spk_mans.insert(spk_man_pair.second.get());
3431 std::map<OutputType, ScriptPubKeyMan*>::const_iterator it = spk_managers.find(type);
3432 if (it == spk_managers.end()) {
3440 std::set<ScriptPubKeyMan*> spk_mans;
3443 if (spk_man_pair.second->CanProvide(script, sigdata)) {
3444 spk_mans.insert(spk_man_pair.second.get());
3467 if (spk_man_pair.second->CanProvide(script, sigdata)) {
3468 return spk_man_pair.second->GetSolvingProvider(script);
3476 std::vector<WalletDescriptor> descs;
3478 if (
const auto desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man)) {
3479 LOCK(desc_spk_man->cs_desc_man);
3480 descs.push_back(desc_spk_man->GetWalletDescriptor());
3525 uint256 id = spk_manager->GetID();
3563 for (
bool internal : {
false,
true}) {
3568 throw std::runtime_error(std::string(__func__) +
": Wallet is locked, cannot setup new descriptors");
3570 if (!spk_manager->CheckDecryptionKey(vMasterKey) && !spk_manager->Encrypt(vMasterKey,
nullptr)) {
3571 throw std::runtime_error(std::string(__func__) +
": Could not encrypt new descriptors");
3574 spk_manager->SetupDescriptorGeneration(master_key,
t,
internal);
3575 uint256 id = spk_manager->GetID();
3605 if (!signer_res.
isObject())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3606 for (
bool internal : {
false,
true}) {
3607 const UniValue& descriptor_vals = signer_res.
find_value(
internal ?
"internal" :
"receive");
3608 if (!descriptor_vals.
isArray())
throw std::runtime_error(std::string(__func__) +
": Unexpected result");
3610 const std::string& desc_str = desc_val.
getValStr();
3612 std::string desc_error;
3613 std::unique_ptr<Descriptor> desc =
Parse(desc_str, keys, desc_error,
false);
3614 if (desc ==
nullptr) {
3615 throw std::runtime_error(std::string(__func__) +
": Invalid descriptor \"" + desc_str +
"\" (" + desc_error +
")");
3617 if (!desc->GetOutputType()) {
3622 spk_manager->SetupDescriptor(std::move(desc));
3623 uint256 id = spk_manager->GetID();
3635 throw std::runtime_error(std::string(__func__) +
": writing active ScriptPubKeyMan id failed");
3650 spk_mans[type] = spk_man;
3652 const auto it = spk_mans_other.find(type);
3653 if (it != spk_mans_other.end() && it->second == spk_man) {
3654 spk_mans_other.erase(type);
3663 if (spk_man !=
nullptr && spk_man->GetID() == id) {
3667 throw std::runtime_error(std::string(__func__) +
": erasing active ScriptPubKeyMan id failed");
3671 spk_mans.erase(type);
3683 return spk_man !=
nullptr;
3703 return std::nullopt;
3708 return std::nullopt;
3712 if (!desc_spk_man) {
3713 throw std::runtime_error(std::string(__func__) +
": unexpected ScriptPubKeyMan type.");
3716 LOCK(desc_spk_man->cs_desc_man);
3717 const auto& type = desc_spk_man->GetWalletDescriptor().descriptor->GetOutputType();
3718 assert(type.has_value());
3728 WalletLogPrintf(
"Cannot add WalletDescriptor to a non-descriptor wallet\n");
3735 spk_man->UpdateWalletDescriptor(desc);
3738 spk_man = new_spk_man.get();
3741 uint256 id = new_spk_man->GetID();
3746 for (
const auto& entry : signing_provider.
keys) {
3747 const CKey& key = entry.second;
3748 spk_man->AddDescriptorKey(key, key.
GetPubKey());
3752 if (!spk_man->TopUp()) {
3760 auto script_pub_keys = spk_man->GetScriptPubKeys();
3761 if (script_pub_keys.empty()) {
3762 WalletLogPrintf(
"Could not generate scriptPubKeys (cache is empty)\n");
3767 for (
const auto& script : script_pub_keys) {
3777 spk_man->WriteDescriptor();
3786 WalletLogPrintf(
"Migrating wallet storage database from BerkeleyDB to SQLite.\n");
3789 error =
_(
"Error: This wallet already uses SQLite");
3794 std::unique_ptr<DatabaseBatch> batch =
m_database->MakeBatch();
3795 std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor();
3796 std::vector<std::pair<SerializeData, SerializeData>> records;
3798 error =
_(
"Error: Unable to begin reading all records in the database");
3805 status = cursor->Next(ss_key, ss_value);
3811 records.emplace_back(key, value);
3816 error =
_(
"Error: Unable to read all records in the database");
3823 fs::remove(db_path);
3834 std::unique_ptr<WalletDatabase> new_db =
MakeDatabase(wallet_path, opts, db_status,
error);
3841 bool began = batch->TxnBegin();
3843 for (
const auto& [key, value] : records) {
3844 if (!batch->Write(
Span{key},
Span{value})) {
3851 bool committed = batch->TxnCommit();
3864 if (res == std::nullopt) {
3865 error =
_(
"Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
3866 return std::nullopt;
3877 error =
_(
"Error: This wallet is already a descriptor wallet");
3882 std::set<CTxDestination> not_migrated_dests;
3890 error =
_(
"Error: Duplicate descriptors created during migration. Your wallet may be corrupted.");
3893 uint256 id = desc_spkm->GetID();
3921 std::vector<uint256> txids_to_delete;
3922 std::unique_ptr<WalletBatch> watchonly_batch;
3924 watchonly_batch = std::make_unique<WalletBatch>(data.
watchonly_wallet->GetDatabase());
3938 const uint256& hash = wtx->GetHash();
3941 if (!new_tx) return false;
3942 ins_wtx.SetTx(to_copy_wtx.tx);
3943 ins_wtx.CopyFrom(to_copy_wtx);
3946 error =
strprintf(
_(
"Error: Could not add watchonly tx %s to watchonly wallet"), wtx->GetHash().GetHex());
3951 txids_to_delete.push_back(hash);
3956 error =
strprintf(
_(
"Error: Transaction %s in wallet cannot be identified to belong to migrated wallets"), wtx->GetHash().GetHex());
3960 watchonly_batch.reset();
3962 if (txids_to_delete.size() > 0) {
3963 std::vector<uint256> deleted_txids;
3965 error =
_(
"Error: Could not delete watchonly transactions");
3968 if (deleted_txids != txids_to_delete) {
3969 error =
_(
"Error: Not all watchonly txs could be deleted");
3973 for (
const uint256& txid : deleted_txids) {
3979 std::vector<CTxDestination> dests_to_delete;
3980 for (
const auto& addr_pair : m_address_book) {
3983 if (!
IsMine(addr_pair.first)) {
3989 std::string label = addr_pair.second.GetLabel();
3990 data.
watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
3991 if (!addr_pair.second.IsChange()) {
3994 dests_to_delete.push_back(addr_pair.first);
4002 std::string label = addr_pair.second.GetLabel();
4003 data.
solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4004 if (!addr_pair.second.IsChange()) {
4005 data.
solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
4007 dests_to_delete.push_back(addr_pair.first);
4013 if (not_migrated_dests.count(addr_pair.first) > 0) {
4014 dests_to_delete.push_back(addr_pair.first);
4019 error =
_(
"Error: Address book data in wallet cannot be identified to belong to migrated wallets");
4027 std::string label = addr_pair.second.GetLabel();
4028 data.
watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4029 if (!addr_pair.second.IsChange()) {
4036 std::string label = addr_pair.second.GetLabel();
4037 data.
solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4038 if (!addr_pair.second.IsChange()) {
4039 data.
solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
4049 for (
const auto& [destination, addr_book_data] :
wallet.m_address_book) {
4051 std::optional<std::string> label = addr_book_data.IsChange() ? std::nullopt : std::make_optional(addr_book_data.GetLabel());
4053 if (addr_book_data.purpose) batch.WritePurpose(address,
PurposeToString(*addr_book_data.purpose));
4054 if (label) batch.WriteName(address, *label);
4061 if (dests_to_delete.size() > 0) {
4062 for (
const auto& dest : dests_to_delete) {
4064 error =
_(
"Error: Unable to remove watchonly address book data");
4089 std::optional<MigrationData> data =
wallet.GetDescriptorsForLegacy(
error);
4090 if (data == std::nullopt)
return false;
4093 if (data->watch_descs.size() > 0 || data->solvable_descs.size() > 0) {
4110 if (data->watch_descs.size() > 0) {
4111 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the watched scripts\n");
4114 std::vector<bilingual_str> warnings;
4115 std::string wallet_name =
wallet.GetName() +
"_watchonly";
4123 if (!data->watchonly_wallet) {
4124 error =
_(
"Error: Failed to create new watchonly wallet");
4127 res.watchonly_wallet = data->watchonly_wallet;
4128 LOCK(data->watchonly_wallet->cs_wallet);
4131 for (
const auto& [desc_str, creation_time] : data->watch_descs) {
4134 std::string parse_err;
4135 std::unique_ptr<Descriptor> desc =
Parse(desc_str, keys, parse_err,
true);
4137 assert(!desc->IsRange());
4141 data->watchonly_wallet->AddWalletDescriptor(w_desc, keys,
"",
false);
4147 if (data->solvable_descs.size() > 0) {
4148 wallet.WalletLogPrintf(
"Making a new watchonly wallet containing the unwatched solvable scripts\n");
4151 std::vector<bilingual_str> warnings;
4152 std::string wallet_name =
wallet.GetName() +
"_solvables";
4160 if (!data->solvable_wallet) {
4161 error =
_(
"Error: Failed to create new watchonly wallet");
4164 res.solvables_wallet = data->solvable_wallet;
4165 LOCK(data->solvable_wallet->cs_wallet);
4168 for (
const auto& [desc_str, creation_time] : data->solvable_descs) {
4171 std::string parse_err;
4172 std::unique_ptr<Descriptor> desc =
Parse(desc_str, keys, parse_err,
true);
4174 assert(!desc->IsRange());
4178 data->solvable_wallet->AddWalletDescriptor(w_desc, keys,
"",
false);
4197 std::vector<bilingual_str> warnings;
4202 return util::Error{
_(
"Unable to unload the wallet before migrating")};
4221 if (!local_wallet) {
4226 if (!local_wallet->GetLegacyScriptPubKeyMan()) {
4227 return util::Error{
_(
"Error: This wallet is already a descriptor wallet")};
4233 fs::path backup_path = this_wallet_dir / backup_filename;
4235 return util::Error{
_(
"Error: Unable to make a backup of your wallet")};
4239 bool success =
false;
4241 LOCK(local_wallet->cs_wallet);
4244 if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
4245 if (passphrase.find(
'\0') == std::string::npos) {
4246 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
4248 return util::Error{
Untranslated(
"Error: Wallet decryption failed, the wallet passphrase entered was incorrect. " 4249 "The passphrase contains a null character (ie - a zero byte). " 4250 "If this passphrase was set with a version of this software prior to 25.0, " 4251 "please try again with only the characters up to — but not including — " 4252 "the first null character.")};
4267 std::set<fs::path> wallet_dirs;
4270 const auto& reload_wallet = [&](std::shared_ptr<CWallet>& to_reload) {
4271 assert(to_reload.use_count() == 1);
4272 std::string
name = to_reload->GetName();
4273 wallet_dirs.insert(
fs::PathFromString(to_reload->GetDatabase().Filename()).parent_path());
4276 return to_reload !=
nullptr;
4279 success = reload_wallet(local_wallet);
4280 res.
wallet = local_wallet;
4295 fs::copy_file(backup_path, temp_backup_location, fs::copy_options::none);
4298 std::vector<std::shared_ptr<CWallet>> created_wallets;
4299 if (local_wallet) created_wallets.push_back(std::move(local_wallet));
4304 for (std::shared_ptr<CWallet>& w : created_wallets) {
4309 for (std::shared_ptr<CWallet>& w : created_wallets) {
4310 if (w->HaveChain()) {
4313 error +=
_(
"\nUnable to cleanup failed migration");
4319 assert(w.use_count() == 1);
4325 for (
const fs::path& dir : wallet_dirs) {
4326 fs::remove_all(dir);
4331 std::vector<bilingual_str> warnings;
4333 error +=
_(
"\nUnable to restore backup of wallet.");
4338 fs::copy_file(temp_backup_location, backup_path, fs::copy_options::none);
4339 fs::remove(temp_backup_location);
std::unique_ptr< WalletDatabase > MakeDatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
std::shared_ptr< const CTransaction > CTransactionRef
uint256 last_failed_block
Height of the most recent block that could not be scanned due to read errors or pruning.
void ReturnDestination()
Return reserved address.
void SyncTransaction(const CTransactionRef &tx, const SyncTxState &state, bool update_tx=true, bool rescanning_old_block=false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
virtual bool haveBlockOnDisk(int height)=0
Check that the block is available on disk (i.e.
NodeClock::time_point m_next_resend
The next scheduled rebroadcast of wallet transactions.
static const std::string sighash
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by create_directories if the requested directory exists.
bool UpgradeWallet(int version, bilingual_str &error)
Upgrade the wallet.
Helper for findBlock to selectively return pieces of block data.
enum wallet::CWallet::ScanResult::@17 status
Private key encryption is done based on a CMasterKey, which holds a salt and random encryption key...
std::optional< DatabaseFormat > require_format
static path PathFromString(const std::string &string)
Convert byte string to path object.
static UniValue Parse(std::string_view raw)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
void MaybeUpdateBirthTime(int64_t time)
Updates wallet birth time if 'time' is below it.
void AddToSpends(const COutPoint &outpoint, const uint256 &wtxid, WalletBatch *batch=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::string GetDisplayName() const override
Returns a bracketed wallet name for displaying in logs, will return [default wallet] if the wallet ha...
void push_back(UniValue val)
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
bool CanSupportFeature(enum WalletFeature wf) const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
check whether we support the named feature
std::atomic< bool > fAbortRescan
State of transaction added to mempool.
std::vector< CTxDestination > ListAddrBookAddresses(const std::optional< AddrBookFilter > &filter) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Filter and retrieve destinations stored in the addressbook.
void ReadDatabaseArgs(const ArgsManager &args, DatabaseOptions &options)
void chainStateFlushed(ChainstateRole role, const CBlockLocator &loc) override
virtual bool updateRwSetting(const std::string &name, const common::SettingsValue &value, bool write=true)=0
Write a setting to <datadir>/settings.json.
interfaces::Chain & chain() const
Interface for accessing chain state.
std::chrono::time_point< NodeClock > time_point
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Enables interaction with an external signing device or service, such as a hardware wallet...
mapValue_t mapValue
Key/value map with information about the transaction.
void MarkDirty()
make sure balances are recalculated
bool EraseAddressReceiveRequest(WalletBatch &batch, const CTxDestination &dest, const std::string &id) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool EraseAddressData(const CTxDestination &dest)
const std::vector< UniValue > & getValues() const
bool CanGetAddresses(bool internal=false) const
int64_t nIndex
The index of the address's key in the keypool.
std::map< OutputType, ScriptPubKeyMan * > m_external_spk_managers
constexpr CAmount HIGH_TX_FEE_PER_KB
Discourage users to set fees higher than this amount (in satoshis) per kB.
virtual std::optional< int > getHeight()=0
Get current chain height, not including genesis block (returns 0 if chain only contains genesis block...
bool ImportScripts(const std::set< CScript > scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bilingual_str AmountErrMsg(const std::string &optname, const std::string &strValue)
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...
bool HasEncryptionKeys() const override
#define LogPrint(category,...)
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
const CAddressBookData * FindAddressBookEntry(const CTxDestination &, bool allow_change=false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
virtual bool Backup(const std::string &strDest) const =0
Back up the entire database to a file.
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination corresponds to one with an address.
bool SubmitTxMemoryPoolAndRelay(CWalletTx &wtx, std::string &err_string, bool relay) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Pass this transaction to node for mempool insertion and relay to peers if flag set to true...
int GetTxBlocksToMaturity(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::optional< int > last_scanned_height
bool DoMigration(CWallet &wallet, WalletContext &context, bilingual_str &error, MigrationResult &res) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
void UpgradeDescriptorCache() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Upgrade DescriptorCaches.
bool LoadToWallet(const uint256 &hash, const UpdateWalletTxFn &fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
isminetype IsMine(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool IsAddressPreviouslySpent(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::set< uint256 > GetConflicts(const uint256 &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get wallet transactions that conflict with given transaction (spend same outputs) ...
virtual uint256 getBlockHash(int height)=0
Get block hash. Height must be valid or this function will abort.
int64_t IncOrderPosNext(WalletBatch *batch=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Increment the next transaction order id.
DBErrors
Error statuses for the wallet database.
bool ApplyMigrationData(MigrationData &data, bilingual_str &error) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Adds the ScriptPubKeyMans given in MigrationData to this wallet, removes LegacyScriptPubKeyMan, and where needed, moves tx and address book entries to watchonly_wallet or solvable_wallet.
virtual CBlockLocator getActiveChainLocator(const uint256 &block_hash)=0
Return a locator that refers to a block in the active chain.
uint256 last_scanned_block
Hash and height of most recent block that was successfully scanned.
RecursiveMutex cs_KeyStore
std::map< std::string, std::string > mapValue_t
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
void LoadAddressReceiveRequest(const CTxDestination &dest, const std::string &id, const std::string &request) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Appends payment request to destination.
CPubKey GetPubKey() const
Compute the public key from a private key.
bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector< unsigned char > &chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
bool SetAddressReceiveRequest(WalletBatch &batch, const CTxDestination &dest, const std::string &id, const std::string &value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
virtual bool hasBlockFilterIndex(BlockFilterType filter_type)=0
Returns whether a block filter index is available.
GCSFilter::ElementSet m_filter_set
std::string m_notify_tx_changed_script
Notify external script when a wallet transaction comes in or is updated (handled by -walletnotify) ...
bool MigrateToSQLite(bilingual_str &error) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Move all records from the BDB database to a new SQLite database for storage.
std::map< CKeyID, CKey > keys
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.
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)
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
std::optional< MigrationData > MigrateToDescriptor()
Get the DescriptorScriptPubKeyMans (with private keys) that have the same scriptPubKeys as this Legac...
MemPoolRemovalReason
Reason why a transaction was removed from the mempool, this is passed to the notification signal...
virtual void Flush()=0
Make sure all changes are flushed to database file.
std::vector< std::pair< std::string, std::string > > vOrderForm
const std::string & GetName() const
Get a name for this wallet for logging/debugging purposes.
void transactionAddedToMempool(const CTransactionRef &tx) override
std::shared_ptr< CWallet > LoadWallet(WalletContext &context, const std::string &name, std::optional< bool > load_on_start, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
struct containing information needed for migrating legacy wallets to descriptor wallets ...
std::atomic< int64_t > m_birth_time
bool MoneyRange(const CAmount &nValue)
#define CHECK_NONFATAL(condition)
Identity function.
bool Encrypt(const CKeyingMaterial &vchPlaintext, std::vector< unsigned char > &vchCiphertext) const
bool WriteAddressReceiveRequest(const CTxDestination &dest, const std::string &id, const std::string &receive_request)
bool IsLegacy() const
Determine if we are a legacy wallet.
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
bool WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
bool m_is_cache_empty
This flag is true if all m_amounts caches are empty.
Removed for conflict with in-block transaction.
DBErrors ZapSelectTx(std::vector< uint256 > &vHashIn, std::vector< uint256 > &vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
MasterKeyMap mapMasterKeys
WalletDatabase & GetDatabase() const override
static const int COINBASE_MATURITY
Coinbase transaction outputs can only be spent after this number of new blocks (network rule) ...
static const unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
std::string PurposeToString(AddressPurpose p)
bool TxnAbort()
Abort current transaction.
bool fInternal
Whether this is from the internal (change output) keypool.
std::optional< int64_t > GetOldestKeyPoolTime() const
const CWallet *const pwallet
The wallet to reserve from.
SigningResult SignMessage(const std::string &message, const PKHash &pkhash, std::string &str_sig) const
void DeactivateScriptPubKeyMan(uint256 id, OutputType type, bool internal)
Remove specified ScriptPubKeyMan from set of active SPK managers.
std::string TxStateString(const T &state)
Return TxState or SyncTxState as a string for logging or debugging.
bool DelAddressBook(const CTxDestination &address)
CTxDestination address
The destination.
RecursiveMutex cs_wallet
Main wallet lock.
bool SignTransaction(CMutableTransaction &tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Fetch the inputs and sign with SIGHASH_ALL.
bool m_pre_split
Whether this key was generated for a keypool before the wallet was upgraded to HD-split.
State of transaction not confirmed or conflicting with a known block and not in the mempool...
bool RemoveWalletSetting(interfaces::Chain &chain, const std::string &wallet_name)
Remove wallet name from persistent configuration so it will not be loaded on startup.
virtual void Close()=0
Flush to the database file and close the database.
const UniValue & get_array() const
std::variant< TxStateConfirmed, TxStateInMempool, TxStateInactive > SyncTxState
Subset of states transaction sync logic is implemented to handle.
RAII object to check and reserve a wallet rescan.
std::unique_ptr< Wallet > MakeWallet(wallet::WalletContext &context, const std::shared_ptr< wallet::CWallet > &wallet)
Return implementation of Wallet interface.
std::multimap< int64_t, CWalletTx * > TxItems
bool WriteLockedUTXO(const COutPoint &output)
bool DeleteRecords()
Delete all the records ofthis LegacyScriptPubKeyMan from disk.
static GlobalMutex g_loading_wallet_mutex
A version of CTransaction with the PSBT format.
bool isConflicted() const
bool WriteMinVersion(int nVersion)
std::vector< std::string > GetAddressReceiveRequests() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
const CWalletTx * GetWalletTx(const uint256 &hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool reserve(bool with_passphrase=false)
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
static const int64_t values[]
A selection of numbers that do not trigger int64_t overflow when added/subtracted.
std::shared_ptr< CWallet > solvable_wallet
Access to the wallet database.
ScriptPubKeyMan * GetScriptPubKeyMan(const OutputType &type, bool internal) const
Get the ScriptPubKeyMan for the given OutputType and internal/external chain.
std::atomic< uint64_t > m_wallet_flags
WalletFlags set on this wallet.
A key from a CWallet's keypool.
RecursiveMutex m_relock_mutex
boost::signals2::signal< void(const uint256 &hashTx, ChangeType status)> NotifyTransactionChanged
Wallet transaction added, removed or updated.
State of transaction confirmed in a block.
bool IsEquivalentTo(const CWalletTx &tx) const
True if only scriptSigs are different.
bool fBroadcastTransactions
Whether this wallet will submit newly created transactions to the node's mempool and prompt rebroadca...
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.
bool WriteOrderPosNext(int64_t nOrderPosNext)
int conflicting_block_height
fs::path GetWalletDir()
Get the path of the wallet directory.
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.
Taproot only; implied when sighash byte is missing, and equivalent to SIGHASH_ALL.
virtual bool Rewrite(const char *pszSkip=nullptr)=0
Rewrite the entire database on disk, with the exception of key pszSkip if non-zero.
LegacyScriptPubKeyMan * GetLegacyScriptPubKeyMan() const
Get the LegacyScriptPubKeyMan which is used for all types, internal, and external.
const std::string & getValStr() const
static void UpdateWalletSetting(interfaces::Chain &chain, const std::string &wallet_name, std::optional< bool > load_on_startup, std::vector< bilingual_str > &warnings)
void GetKeyBirthTimes(std::map< CKeyID, int64_t > &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
static constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
std::set< ScriptPubKeyMan * > GetAllScriptPubKeyMans() const
Returns all unique ScriptPubKeyMans.
virtual double guessVerificationProgress(const uint256 &block_hash)=0
Estimate fraction of total transactions verified if blocks up to the specified block hash are verifie...
bool EncryptWallet(const SecureString &strWalletPassphrase)
static NodeClock::time_point GetDefaultNextResend()
Flag set when a wallet contains no HD seed and no private keys, scripts, addresses, and other watch only things, and is therefore "blank.".
constexpr CAmount HIGH_MAX_TX_FEE
-maxtxfee will warn if called with a higher fee than this amount (in satoshis)
int64_t nTime
The time at which the key was generated. Set in AddKeypoolPubKeyWithDB.
static constexpr auto OUTPUT_TYPES
void updatedBlockTip() override
const std::vector< CTxIn > vin
std::optional< bool > IsInternalScriptPubKeyMan(ScriptPubKeyMan *spk_man) const
Returns whether the provided ScriptPubKeyMan is internal.
int64_t GetTxTime() const
void SyncMetaData(std::pair< TxSpends::iterator, TxSpends::iterator >) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool LockCoin(const COutPoint &output, WalletBatch *batch=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
constexpr unsigned char * begin()
bool WriteBestBlock(const CBlockLocator &locator)
static const bool DEFAULT_WALLET_RBF
-walletrbf default
void MaybeResendWalletTxs(WalletContext &context)
Called periodically by the schedule thread.
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.
static const bool DEFAULT_SPEND_ZEROCONF_CHANGE
Default for -spendzeroconfchange.
std::map< uint256, std::unique_ptr< ScriptPubKeyMan > > m_spk_managers
boost::signals2::signal< void(bool fHaveWatchOnly)> NotifyWatchonlyChanged
Watch-only address added.
int64_t CAmount
Amount in satoshis (Can be negative)
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...
bool DisplayAddress(const CTxDestination &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Display address on an external signer.
const UniValue & find_value(std::string_view key) const
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 LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor &desc)
Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it.
bool Decrypt(const std::vector< unsigned char > &vchCiphertext, CKeyingMaterial &vchPlaintext) const
A transaction with a bunch of additional info that only the owner cares about.
interfaces::Chain * m_chain
Interface for accessing chain state.
std::function< TxUpdate(CWalletTx &wtx)> TryUpdatingStateFn
CWallet(interfaces::Chain *chain, const std::string &name, std::unique_ptr< WalletDatabase > database)
Construct wallet with specified name and database implementation.
void LoadAddressPreviouslySpent(const CTxDestination &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Marks destination as previously spent.
bool EraseName(const std::string &strAddress)
std::string ToString(const T &t)
Locale-independent version of std::to_string.
DescriptorScriptPubKeyMan * GetDescriptorScriptPubKeyMan(const WalletDescriptor &desc) const
Return the DescriptorScriptPubKeyMan for a WalletDescriptor if it is already in the wallet...
bool SetAddressPreviouslySpent(WalletBatch &batch, const CTxDestination &dest, bool used) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Block data sent with blockConnected, blockDisconnected notifications.
bool IsLocked() const override
Indicates that the wallet needs an external signer.
void SetupLegacyScriptPubKeyMan()
Make a LegacyScriptPubKeyMan and set it for all types, internal, and external.
DBErrors LoadWallet(CWallet *pwallet)
bool MarkReplaced(const uint256 &originalHash, const uint256 &newHash)
Mark a transaction as replaced by another transaction.
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
virtual bool hasAssumedValidChain()=0
Return true if an assumed-valid chain is in use.
std::underlying_type< isminetype >::type isminefilter
used for bitflags of isminetype
void AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
Adds the active ScriptPubKeyMan for the specified type and internal.
bool ShouldResend() const
Return true if all conditions for periodically resending transactions are met.
std::set< CKeyID > GetKeys() const override
std::set< ScriptPubKeyMan * > GetActiveScriptPubKeyMans() const
Returns all unique ScriptPubKeyMans in m_internal_spk_managers and m_external_spk_managers.
virtual bool isInMempool(const uint256 &txid)=0
Check if transaction is in mempool.
std::shared_ptr< CWallet > wallet
bool TxnCommit()
Commit current transaction.
static std::string PathToString(const path &path)
Convert path object to a byte string.
SecureString create_passphrase
bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256 &id, bool internal)
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a scriptPubKey for the destination.
CPubKey vchPubKey
The public key.
std::multimap< int64_t, CWalletTx * >::const_iterator m_it_wtxOrdered
bool fInternal
Whether this keypool entry is in the internal keypool (for change outputs)
int64_t m_keypool_size
Number of pre-generated keys/scripts by each spkm (part of the look-ahead process, used to detect payments)
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.
const uint256 * prev_hash
ChainstateRole
This enum describes the various roles a specific Chainstate instance can take.
std::vector< CKeyID > GetAffectedKeys(const CScript &spk, const SigningProvider &provider)
bool GetBroadcastTransactions() const
Inquire whether this wallet broadcasts transactions.
bool WriteAddressPreviouslySpent(const CTxDestination &dest, bool previously_spent)
An input of a transaction.
static constexpr uint64_t KNOWN_WALLET_FLAGS
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get last block processed height.
void SetMinVersion(enum WalletFeature, WalletBatch *batch_in=nullptr) override
signify that a particular wallet feature is now used.
std::string ShellEscape(const std::string &arg)
static const unsigned int DEFAULT_TX_CONFIRM_TARGET
-txconfirmtarget default
Double ended buffer combining vector and stream-like interfaces.
void MarkInputsDirty(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed.
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.
void Flush()
Flush wallet (bitdb flush)
bool WriteTx(const CWalletTx &wtx)
std::map< OutputType, ScriptPubKeyMan * > m_internal_spk_managers
const uint256 & GetHash() const
bilingual_str _(const char *psz)
Translation function.
bool ChangeWalletPassphrase(const SecureString &strOldWalletPassphrase, const SecureString &strNewWalletPassphrase)
util::Result< CTxDestination > GetReservedDestination(bool internal)
Reserve an address.
virtual void ReloadDbEnv()=0
std::optional< OutputType > ParseOutputType(const std::string &type)
void blockDisconnected(const interfaces::BlockInfo &block) override
bilingual_str AmountHighWarn(const std::string &optname)
void blockConnected(ChainstateRole role, const interfaces::BlockInfo &block) override
std::shared_ptr< Descriptor > descriptor
An encapsulated public key.
CAmount m_default_max_tx_fee
Absolute maximum transaction fee (in satoshis) used by default for the wallet.
isminetype
IsMine() return codes, which depend on ScriptPubKeyMan implementation.
std::string ToString(const FeeEstimateMode &fee_estimate_mode=FeeEstimateMode::BTC_KVB) const
std::chrono::duration< double, std::chrono::milliseconds::period > MillisecondsDouble
bool IsFromMe(const CTransaction &tx) const
should probably be renamed to IsRelevantToMe
void NotifyWalletLoaded(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver, bool update)
Scan active chain for relevant transactions after importing keys.
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
const std::vector< CTxOut > vout
std::optional< CAmount > ParseMoney(const std::string &money_string)
Parse an amount denoted in full coins.
WalletFeature
(client) version numbers for particular wallet features
Indicate that this wallet supports DescriptorScriptPubKeyMan.
bool AbandonTransaction(const uint256 &hashTx)
unsigned int ComputeTimeSmart(const CWalletTx &wtx, bool rescanning_old_block) const
Compute smart timestamp for a transaction being added to the wallet.
virtual bool findBlock(const uint256 &hash, const FoundBlock &block={})=0
Return whether node has the block and optionally return block metadata or contents.
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 BackupWallet(const std::string &strDest) const
static int TxStateSerializedIndex(const TxState &state)
Get TxState serialized block index. Inverse of TxStateInterpretSerialized.
virtual void waitForNotificationsIfTipChanged(const uint256 &old_tip)=0
Wait for pending notifications to be processed unless block hash points to the current chain tip...
std::unique_ptr< Handler > MakeCleanupHandler(std::function< void()> cleanup)
Return handler wrapping a cleanup function.
std::set< uint256 > GetTxConflicts(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
void transactionRemovedFromMempool(const CTransactionRef &tx, MemPoolRemovalReason reason) override
unsigned int GetKeyPoolSize() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool WriteWalletFlags(const uint64_t flags)
#define WAIT_LOCK(cs, name)
An output of a transaction.
void ReplaceAll(std::string &in_out, const std::string &search, const std::string &substitute)
unsigned int nDeriveIterations
std::string ToString() const
bool IsTxImmatureCoinBase(const CWalletTx &wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool UnlockCoin(const COutPoint &output, WalletBatch *batch=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::string m_name
Wallet name: relative directory name or "" for default wallet.
bool IsWalletFlagSet(uint64_t flag) const override
check if a certain wallet flag is set
An outpoint - a combination of a transaction hash and an index n into its vout.
void UnsetBlankWalletFlag(WalletBatch &batch) override
Unset the blank wallet flag and saves it to disk.
bool Unlock(const CKeyingMaterial &vMasterKeyIn, bool accept_no_keys=false)
static const std::unordered_set< OutputType > LEGACY_OUTPUT_TYPES
OutputTypes supported by the LegacyScriptPubKeyMan.
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.
int confirmed_block_height
std::unordered_set< CScript, SaltedSipHasher > GetNotMineScriptPubKeys() const
Retrieves scripts that were imported by bugs into the legacy spkm and are simply invalid, such as a sh(sh(pkh())) script, or not watched.
void UnloadWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly unload and delete the wallet.
util::Result< MigrationResult > MigrateLegacyToDescriptor(const std::string &wallet_name, const SecureString &passphrase, WalletContext &context)
Do all steps to migrate a legacy wallet to a descriptor wallet.
boost::signals2::signal< void(const std::string &title, int nProgress)> ShowProgress
Show progress e.g.
std::vector< PSBTInput > inputs
bool AddWalletSetting(interfaces::Chain &chain, const std::string &wallet_name)
Add wallet name to persistent configuration so it will be loaded on startup.
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
void ForEachAddrBookEntry(const ListAddrBookFunc &func) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::shared_ptr< CWallet > solvables_wallet
bool ErasePurpose(const std::string &strAddress)
static uint256 TxStateSerializedBlockHash(const TxState &state)
Get TxState serialized block hash. Inverse of TxStateInterpretSerialized.
uint256 GetID() const override
UniValue GetDescriptors(const int account)
Get receive and change Descriptor(s) from device for a given account.
void UpgradeDescriptorCache()
std::unordered_set< Element, ByteVectorHash > ElementSet
unsigned int nDerivationMethod
0 = EVP_sha512() 1 = scrypt()
ScriptPubKeyMan * m_spk_man
The ScriptPubKeyMan to reserve from. Based on type when GetReservedDestination is called...
Descriptor with some wallet metadata.
void Close()
Close wallet database.
virtual void KeepDestination(int64_t index, const OutputType &type)
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
static CTransactionRef MakeTransactionRef(Tx &&txIn)
static const bool DEFAULT_WALLETBROADCAST
void postInitProcess()
Wallet post-init setup Gives the wallet a chance to register repetitive tasks and complete post-init ...
static void ReleaseWallet(CWallet *wallet)
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
const std::string & FormatOutputType(OutputType type)
std::shared_ptr< CWallet > GetWallet(WalletContext &context, const std::string &name)
std::map< uint256, int32_t > m_last_range_ends
Map for keeping track of each range descriptor's last seen end range.
std::atomic< int64_t > m_best_block_time
bool ImportPrivKeys(const std::map< CKeyID, CKey > &privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool Unlock(const SecureString &strWalletPassphrase, bool accept_no_keys=false)
static time_point now() noexcept
Return current system time or mocked time, if set.
unsigned int fTimeReceivedIsTxTime
void WalletLogPrintf(const char *fmt, Params... parameters) const
Prepends the wallet name in logging output to ease debugging in multi-wallet use cases.
#define EXCLUSIVE_LOCKS_REQUIRED(...)
std::vector< CTransactionRef > vtx
void ResubmitWalletTransactions(bool relay, bool force)
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
static ExternalSigner GetExternalSigner()
void SetSeed(Span< const std::byte > seed)
bool TransactionCanBeAbandoned(const uint256 &hashTx) const
Return whether transaction can be abandoned.
bool TopUpKeyPool(unsigned int kpSize=0)
bool CanGrindR() const
Whether the (external) signer performs R-value signature grinding.
bool SetAddressBookWithDB(WalletBatch &batch, const CTxDestination &address, const std::string &strName, const std::optional< AddressPurpose > &strPurpose)
bool IsLockedCoin(const COutPoint &output) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
State of rejected transaction that conflicts with a confirmed block.
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
void KeepDestination()
Keep the address. Do not return its key to the keypool when this object goes out of scope...
bool error(const char *fmt, const Args &... args)
bool IsSpent(const COutPoint &outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Outpoint is spent if any non-conflicted transaction spends it:
std::function< bool(CWalletTx &wtx, bool new_tx)> UpdateWalletTxFn
Callback for updating transaction metadata in mapWallet.
Serialized script, used inside transaction inputs and outputs.
void LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
Loads an active ScriptPubKeyMan for the specified type and internal.
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
bool fFromMe
From me flag is set to 1 for transactions that were created by the wallet on this bitcoin node...
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 AddScriptPubKeyMan(const uint256 &id, std::unique_ptr< ScriptPubKeyMan > spkm_man)
std::shared_ptr< CWallet > watchonly_wallet
virtual util::Result< CTxDestination > GetReservedDestination(const OutputType type, bool internal, int64_t &index, CKeyPool &keypool)
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
bool EraseAddressReceiveRequest(const CTxDestination &dest, const std::string &id)
std::set< ScriptPubKeyMan * > GetScriptPubKeyMans(const CScript &script) const
Get all the ScriptPubKeyMans for a script.
size_t KeypoolCountExternalKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
boost::signals2::signal< void(CWallet *wallet)> NotifyStatusChanged
Wallet status (encrypted, locked) changed.
std::optional< std::string > m_op_label
static void NotifyTransactionChanged(WalletModel *walletmodel, const uint256 &hash, ChangeType status)
const uint256 & GetHash() const
virtual void initMessage(const std::string &message)=0
Send init message.
A reference to a CKey: the Hash160 of its serialized public key.
std::string GetHex() const
unsigned int nTimeSmart
Stable timestamp that never changes, and reflects the order a transaction was added to the wallet...
std::unique_ptr< interfaces::Handler > HandleLoadWallet(WalletContext &context, LoadWalletFn load_wallet)
bool TxnBegin()
Begin a new transaction.
WalletContext struct containing references to state shared between CWallet instances, like the reference to the chain interface, and the list of opened wallets.
A wrapper to reserve an address from a wallet.
DBErrors ReorderTransactions()
std::vector< unsigned char > vchSalt
bool HaveChain() const
Interface to assert chain access.
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
bool LoadWalletFlags(uint64_t flags)
Loads the flags into the wallet.
void SetSpentKeyState(WalletBatch &batch, const uint256 &hash, unsigned int n, bool used, std::set< CTxDestination > &tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
#define AssertLockNotHeld(cs)
const unsigned int WALLET_CRYPTO_KEY_SIZE
std::optional< MigrationData > GetDescriptorsForLegacy(bilingual_str &error) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get all of the descriptors from a legacy wallet.
static void RefreshMempoolStatus(CWalletTx &tx, interfaces::Chain &chain)
Refresh mempool status so the wallet is in an internally consistent state and immediately knows the t...
Encryption/decryption context with key information.
interfaces::Chain * chain
std::vector< WalletDescriptor > GetWalletDescriptors(const CScript &script) const
Get the wallet descriptors for a script.
bool WriteName(const std::string &strAddress, const std::string &strName)
std::string EncodeDestination(const CTxDestination &dest)
A mutable version of CTransaction.
std::shared_ptr< CWallet > watchonly_wallet
uint256 GetLastBlockHash() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool UnlockAllCoins() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool PSBTInputSigned(const PSBTInput &input)
Checks whether a PSBTInput is already signed by checking for non-null finalized fields.
std::unique_ptr< WalletDatabase > m_database
Internal database handle.
Tp rand_uniform_delay(const Tp &time, typename Tp::duration range)
Return the time point advanced by a uniform random duration.
void UnsetWalletFlag(uint64_t flag)
Unsets a single wallet flag.
void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo.
static GlobalMutex g_wallet_release_mutex
int GetVersion() const
get the current wallet format (the oldest client version guaranteed to understand this wallet) ...
static auto quoted(const std::string &s)
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 ...
FoundBlock & height(int &height)
virtual void ReturnDestination(int64_t index, bool internal, const CTxDestination &addr)
unsigned int nTimeReceived
time received by this node
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...
std::vector< unsigned char > vchCryptedKey
An encapsulated private key.
A Span is an object that can refer to a contiguous sequence of objects.
The basic transaction that is broadcasted on the network and contained in blocks. ...
Different type to mark Mutex at global scope.
static const bool DEFAULT_WALLETCROSSCHAIN
std::shared_ptr< CWallet > wallet
constexpr CAmount HIGH_APS_FEE
discourage APS fee higher than this amount
int64_t nOrderPos
position in ordered transaction list
OutputType m_default_address_type
void RemoveUnnecessaryTransactions(PartiallySignedTransaction &psbtx, const int &sighash_type)
Reduces the size of the PSBT by dropping unnecessary non_witness_utxos (i.e.
bool EraseLockedUTXO(const COutPoint &output)
std::optional< CMutableTransaction > tx
virtual CBlockLocator getTipLocator()=0
Get locator for the current chain tip.
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::optional< AddressPurpose > &purpose)
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)
std::shared_ptr< CWallet > CreateWallet(WalletContext &context, const std::string &name, std::optional< bool > load_on_start, DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
static bool exists(const path &p)
boost::signals2::signal< void(const CTxDestination &address, const std::string &label, bool isMine, AddressPurpose purpose, ChangeType status)> NotifyAddressBookChanged
Address book entry changed.
bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal)
static path u8path(const std::string &utf8_str)
std::shared_ptr< CWallet > RestoreWallet(WalletContext &context, const fs::path &backup_file, const std::string &wallet_name, std::optional< bool > load_on_start, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
util::Result< CTxDestination > GetNewDestination(const OutputType type, const std::string label)
unsigned int nMasterKeyMaxID
int64_t GetTime()
DEPRECATED, see GetTime.
unsigned int chain_time_max
DBErrors ZapSelectTx(std::vector< uint256 > &vHashIn, std::vector< uint256 > &vHashOut)
virtual common::SettingsValue getRwSetting(const std::string &name)=0
Return <datadir>/settings.json setting value.
const unsigned int WALLET_CRYPTO_SALT_SIZE
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
static path absolute(const path &p)
const CKeyingMaterial & GetEncryptionKey() const override
std::shared_ptr< CWallet > GetDefaultWallet(WalletContext &context, size_t &count)
bool WritePurpose(const std::string &strAddress, const std::string &purpose)
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &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...
std::atomic< double > m_scanning_progress
static std::set< std::string > g_loading_wallet_set GUARDED_BY(g_loading_wallet_mutex)
virtual CFeeRate relayMinFee()=0
Relay current minimum fee (from -minrelaytxfee and -incrementalrelayfee settings).
void SetTx(CTransactionRef arg)
void ConnectScriptPubKeyManNotifiers()
Connect the signals from ScriptPubKeyMans to the signals in CWallet.
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
void ListLockedCoins(std::vector< COutPoint > &vOutpts) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool HasWalletDescriptor(const WalletDescriptor &desc) const
std::variant< TxStateConfirmed, TxStateInMempool, TxStateConflicted, TxStateInactive, TxStateUnrecognized > TxState
All possible CWalletTx states.
WalletFeature GetClosestWalletFeature(int version)
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.
#define PACKAGE_BUGREPORT
static std::condition_variable g_wallet_release_cv
boost::signals2::signal< void()> NotifyCanGetAddressesChanged
Keypool has new keys.
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.
virtual bool havePruned()=0
Check if any block has been pruned.
util::Result< CTxDestination > GetNewChangeDestination(const OutputType type)
std::vector< unsigned char, secure_allocator< unsigned char > > CKeyingMaterial
void UnsetWalletFlagWithDB(WalletBatch &batch, uint64_t flag)
Unsets a wallet flag and saves it to disk.
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.
Clock::time_point now() const
std::unique_ptr< WalletDatabase > MakeWalletDatabase(const std::string &name, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error_string)
#define Assert(val)
Identity function.
std::function< void(std::unique_ptr< interfaces::Wallet > wallet)> LoadWalletFn
bool IsSpentKey(const CScript &scriptPubKey) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::vector< std::unique_ptr< DescriptorScriptPubKeyMan > > desc_spkms
static bool copy_file(const path &from, const path &to, copy_options options)
void GetStrongRandBytes(Span< unsigned char > bytes) noexcept
Gather entropy from various sources, feed it into the internal PRNG, and generate random data using i...
OutputType TransactionChangeType(const std::optional< OutputType > &change_type, const std::vector< CRecipient > &vecSend) const
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)
bool IsValid() const
Check whether this private key is valid.
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...
LegacyScriptPubKeyMan * GetOrCreateLegacyScriptPubKeyMan()
void SetupDescriptorScriptPubKeyMans() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
std::atomic< bool > m_attaching_chain
CAmount GetDebit(const CTxIn &txin, const isminefilter &filter) const
Returns amount of debit if the input matches the filter, otherwise returns 0.
PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction &psbt)
Compute a PrecomputedTransactionData object from a psbt.
auto FindKey(Map &&map, Key &&key) -> decltype(&map.at(key))
Map lookup helper.
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...
std::unique_ptr< SigningProvider > GetSolvingProvider(const CScript &script) const
Get the SigningProvider for a script.