Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
2501mapTxSpends.erase(iter);2502break;2503}2504}2505}2506for (unsigned int i = 0; i < it->second.GetTx()->vout.size(); ++i) {2507m_txos.erase(COutPoint(hash, i));2508}2509mapWallet.erase(it);2510NotifyTransactionChanged(hash, CT_DELETED);2511}2513MarkDirty();2514}, .on_abort={}});2516return {};2517}2519bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& new_purpose)2520{2521bool fUpdated = false;2522bool is_mine;2523std::optional<AddressPurpose> purpose;2524{2525LOCK(cs_wallet);2526std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);2527fUpdated = mi != m_address_book.end() && !mi->second.IsChange();2529CAddressBookData& record = mi != m_address_book.end() ? mi->second : m_address_book[address];2530record.SetLabel(strName);2531is_mine = IsMine(address);2532if (new_purpose) { /* update purpose only if requested */2533record.purpose = new_purpose;2534}2535purpose = record.purpose;2536}2538const std::string& encoded_dest = EncodeDestination(address);2539if (new_purpose && !batch.WritePurpose(encoded_dest, PurposeToString(*new_purpose))) {2540WalletLogPrintf("Error: fail to write address book 'purpose' entry\n");2541return false;2542}2543if (!batch.WriteName(encoded_dest, strName)) {2544WalletLogPrintf("Error: fail to write address book 'name' entry\n");2545return false;2546}2548// In very old wallets, address purpose may not be recorded so we derive it from IsMine2549NotifyAddressBookChanged(address, strName, is_mine,2550purpose.value_or(is_mine ? AddressPurpose::RECEIVE : AddressPurpose::SEND),2551(fUpdated ? CT_UPDATED : CT_NEW));2552return true;2553}2555bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& purpose)2556{2557WalletBatch batch(GetDatabase());2558return SetAddressBookWithDB(batch, address, strName, purpose);2559}2561bool CWallet::DelAddressBook(const CTxDestination& address)2562{2563return RunWithinTxn(GetDatabase(), /*process_desc=*/"address book entry removal", [&](WalletBatch& batch){2564return DelAddressBookWithDB(batch, address);2565});2566}2568bool CWallet::DelAddressBookWithDB(WalletBatch& batch, const CTxDestination& address)2569{2570const std::string& dest = EncodeDestination(address);2571{2572LOCK(cs_wallet);2573// If we want to delete receiving addresses, we should avoid calling EraseAddressData because it will delete the previously_spent value. Could instead just erase the label so it becomes a change address, and keep the data.2574// NOTE: This isn't a problem for sending addresses because they don't have any data that needs to be kept.2575// When adding new address data, it should be considered here whether to retain or delete it.2576if (IsMine(address)) {2577WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, CLIENT_BUGREPORT);2578return false;2579}2580// Delete data rows associated with this address2581if (!batch.EraseAddressData(address)) {2582WalletLogPrintf("Error: cannot erase address book entry data\n");2583return false;2584}2586// Delete purpose entry2587if (!batch.ErasePurpose(dest)) {2588WalletLogPrintf("Error: cannot erase address book entry purpose\n");2589return false;2590}2592// Delete name entry2593if (!batch.EraseName(dest)) {2594WalletLogPrintf("Error: cannot erase address book entry name\n");2595return false;2596}2598// finally, remove it from the map2599m_address_book.erase(address);2600}2602// All good, signal changes2603NotifyAddressBookChanged(address, "", /*is_mine=*/false, AddressPurpose::SEND, CT_DELETED);2604return true;2605}2607size_t CWallet::KeypoolCountExternalKeys() const2608{2609AssertLockHeld(cs_wallet);2611unsigned int count = 0;2612for (auto spk_man : m_external_spk_managers) {2613count += spk_man.second->GetKeyPoolSize();2614}2616return count;2617}2619unsigned int CWallet::GetKeyPoolSize() const2620{2621AssertLockHeld(cs_wallet);2623unsigned int count = 0;2624for (auto spk_man : GetActiveScriptPubKeyMans()) {2625count += spk_man->GetKeyPoolSize();2626}2627return count;2628}2630bool CWallet::TopUpKeyPool(unsigned int kpSize)2631{2632LOCK(cs_wallet);2633bool res = true;2634for (auto spk_man : GetActiveScriptPubKeyMans()) {2635res &= spk_man->TopUp(kpSize);2636}2637return res;2638}2640util::Result<CTxDestination> CWallet::GetNewDestination(const OutputType type, const std::string& label)2641{2642LOCK(cs_wallet);2643auto spk_man = GetScriptPubKeyMan(type, /*internal=*/false);2644if (!spk_man) {2645return util::Error{strprintf(_("Error: No %s addresses available."), FormatOutputType(type))};2646}2648auto op_dest = spk_man->GetNewDestination(type);2649if (op_dest) {2650SetAddressBook(*op_dest, label, AddressPurpose::RECEIVE);2651}2653return op_dest;2654}2656util::Result<CTxDestination> CWallet::GetNewChangeDestination(const OutputType type)2657{2658LOCK(cs_wallet);2660ReserveDestination reservedest(this, type);2661auto op_dest = reservedest.GetReservedDestination(true);2662if (op_dest) reservedest.KeepDestination();2664return op_dest;2665}2667void CWallet::MarkDestinationsDirty(const std::set<CTxDestination>& destinations) {2668for (auto& entry : mapWallet) {2669CWalletTx& wtx = entry.second;2670if (wtx.m_is_cache_empty) continue;2671for (unsigned int i = 0; i < wtx.GetTx()->vout.size(); i++) {2672CTxDestination dst;2673if (ExtractDestination(wtx.GetTx()->vout[i].scriptPubKey, dst) && destinations.contains(dst)) {2674wtx.MarkDirty();2675break;2676}2677}2678}2679}2681void CWallet::ForEachAddrBookEntry(const ListAddrBookFunc& func) const2682{2683AssertLockHeld(cs_wallet);2684for (const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book) {2685const auto& entry = item.second;2686func(item.first, entry.GetLabel(), entry.IsChange(), entry.purpose);2687}2688}2690std::vector<CTxDestination> CWallet::ListAddrBookAddresses(const std::optional<AddrBookFilter>& _filter) const2691{2692AssertLockHeld(cs_wallet);2693std::vector<CTxDestination> result;2694AddrBookFilter filter = _filter ? *_filter : AddrBookFilter();2695ForEachAddrBookEntry([&result, &filter](const CTxDestination& dest, const std::string& label, bool is_change, const std::optional<AddressPurpose>& purpose) {2696// Filter by change2697if (filter.ignore_change && is_change) return;2698// Filter by label2699if (filter.m_op_label && *filter.m_op_label != label) return;2700// All good2701result.emplace_back(dest);2702});2703return result;2704}2706std::set<std::string> CWallet::ListAddrBookLabels(const std::optional<AddressPurpose> purpose) const2707{2708AssertLockHeld(cs_wallet);2709std::set<std::string> label_set;2710ForEachAddrBookEntry([&](const CTxDestination& _dest, const std::string& _label,2711bool _is_change, const std::optional<AddressPurpose>& _purpose) {2712if (_is_change) return;2713if (!purpose || purpose == _purpose) {2714label_set.insert(_label);2715}2716});2717return label_set;2718}2720util::Result<CTxDestination> ReserveDestination::GetReservedDestination(bool internal)2721{2722m_spk_man = pwallet->GetScriptPubKeyMan(type, internal);2723if (!m_spk_man) {2724return util::Error{strprintf(_("Error: No %s addresses available."), FormatOutputType(type))};2725}2727if (nIndex == -1) {2728int64_t index;2729auto op_address = m_spk_man->GetReservedDestination(type, internal, index);2730if (!op_address) return op_address;2731nIndex = index;2732address = *op_address;2733}2734return address;2735}2737void ReserveDestination::KeepDestination()2738{2739if (nIndex != -1) {2740m_spk_man->KeepDestination(nIndex, type);2741}2742nIndex = -1;2743address = CNoDestination();2744}2746void ReserveDestination::ReturnDestination()2747{2748if (nIndex != -1) {2749m_spk_man->ReturnDestination(nIndex, fInternal, address);2750}