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.
2751nIndex = -1;2752address = CNoDestination();2753}2755util::Result<void> CWallet::DisplayAddress(const CTxDestination& dest)2756{2757CScript scriptPubKey = GetScriptForDestination(dest);2758for (const auto& spk_man : GetScriptPubKeyMans(scriptPubKey)) {2759auto signer_spk_man = dynamic_cast<ExternalSignerScriptPubKeyMan *>(spk_man);2760if (signer_spk_man == nullptr) {2761continue;2762}2763auto signer{ExternalSignerScriptPubKeyMan::GetExternalSigner()};2764if (!signer) throw std::runtime_error(util::ErrorString(signer).original);2765return signer_spk_man->DisplayAddress(dest, *signer);2766}2767return util::Error{_("There is no ScriptPubKeyManager for this address")};2768}2770void CWallet::LoadLockedCoin(const COutPoint& coin, bool persistent)2771{2772AssertLockHeld(cs_wallet);2773m_locked_coins.emplace(coin, persistent);2774}2776bool CWallet::LockCoin(const COutPoint& output, bool persist)2777{2778AssertLockHeld(cs_wallet);2779LoadLockedCoin(output, persist);2780if (persist) {2781WalletBatch batch(GetDatabase());2782return batch.WriteLockedUTXO(output);2783}2784return true;2785}2787bool CWallet::UnlockCoin(const COutPoint& output)2788{2789AssertLockHeld(cs_wallet);2790auto locked_coin_it = m_locked_coins.find(output);2791if (locked_coin_it != m_locked_coins.end()) {2792bool persisted = locked_coin_it->second;2793m_locked_coins.erase(locked_coin_it);2794if (persisted) {2795WalletBatch batch(GetDatabase());2796return batch.EraseLockedUTXO(output);2797}2798}2799return true;2800}2802bool CWallet::UnlockAllCoins()2803{2804AssertLockHeld(cs_wallet);2805bool success = true;2806WalletBatch batch(GetDatabase());2807for (const auto& [coin, persistent] : m_locked_coins) {2808if (persistent) success = success && batch.EraseLockedUTXO(coin);2809}2810m_locked_coins.clear();2811return success;2812}2814bool CWallet::IsLockedCoin(const COutPoint& output) const2815{2816AssertLockHeld(cs_wallet);2817return m_locked_coins.contains(output);2818}2820void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const2821{2822AssertLockHeld(cs_wallet);2823for (const auto& [coin, _] : m_locked_coins) {2824vOutpts.push_back(coin);2825}2826}2828/**2829* Compute smart timestamp for a transaction being added to the wallet.2830*2831* Logic:2832* - If sending a transaction, assign its timestamp to the current time.2833* - If receiving a transaction outside a block, assign its timestamp to the2834* current time.2835* - If receiving a transaction during a rescanning process, assign all its2836* (not already known) transactions' timestamps to the block time.2837* - If receiving a block with a future timestamp, assign all its (not already2838* known) transactions' timestamps to the current time.2839* - If receiving a block with a past timestamp, before the most recent known2840* transaction (that we care about), assign all its (not already known)2841* transactions' timestamps to the same timestamp as that most-recent-known2842* transaction.2843* - If receiving a block with a past timestamp, but after the most recent known2844* transaction, assign all its (not already known) transactions' timestamps to2845* the block time.2846*2847* For more information see CWalletTx::nTimeSmart,2848* https://bitcointalk.org/?topic=54527, or2849* https://github.com/bitcoin/bitcoin/pull/1393.2850*/2851unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx, bool rescanning_old_block) const2852{2853std::optional<uint256> block_hash;2854if (auto* conf = wtx.state<TxStateConfirmed>()) {2855block_hash = conf->confirmed_block_hash;2856} else if (auto* conf = wtx.state<TxStateBlockConflicted>()) {2857block_hash = conf->conflicting_block_hash;2858}2860unsigned int nTimeSmart = wtx.nTimeReceived;2861if (block_hash) {2862int64_t blocktime;2863int64_t block_max_time;2864if (chain().findBlock(*block_hash, FoundBlock().time(blocktime).maxTime(block_max_time))) {2865if (rescanning_old_block) {2866nTimeSmart = block_max_time;2867} else {2868int64_t latestNow = wtx.nTimeReceived;2869int64_t latestEntry = 0;2871// Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future2872int64_t latestTolerated = latestNow + 300;2873const TxItems& txOrdered = wtxOrdered;2874for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {2875CWalletTx* const pwtx = it->second;2876if (pwtx == &wtx) {2877continue;2878}2879int64_t nSmartTime;2880nSmartTime = pwtx->nTimeSmart;2881if (!nSmartTime) {2882nSmartTime = pwtx->nTimeReceived;2883}2884if (nSmartTime <= latestTolerated) {2885latestEntry = nSmartTime;2886if (nSmartTime > latestNow) {2887latestNow = nSmartTime;2888}2889break;2890}2891}2893nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));2894}2895} else {2896WalletLogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), block_hash->ToString());2897}2898}2899return nTimeSmart;2900}2902bool CWallet::SetAddressPreviouslySpent(WalletBatch& batch, const CTxDestination& dest, bool used)2903{2904if (std::get_if<CNoDestination>(&dest))2905return false;2907if (!used) {2908if (auto* data{common::FindKey(m_address_book, dest)}) data->previously_spent = false;2909return batch.WriteAddressPreviouslySpent(dest, false);2910}2912LoadAddressPreviouslySpent(dest);2913return batch.WriteAddressPreviouslySpent(dest, true);2914}2916void CWallet::LoadAddressPreviouslySpent(const CTxDestination& dest)2917{2918m_address_book[dest].previously_spent = true;2919}2921void CWallet::LoadAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& request)2922{2923m_address_book[dest].receive_requests[id] = request;2924}2926bool CWallet::IsAddressPreviouslySpent(const CTxDestination& dest) const2927{2928if (auto* data{common::FindKey(m_address_book, dest)}) return data->previously_spent;2929return false;2930}2932std::vector<std::string> CWallet::GetAddressReceiveRequests() const2933{2934std::vector<std::string> values;2935for (const auto& [dest, entry] : m_address_book) {2936for (const auto& [id, request] : entry.receive_requests) {2937values.emplace_back(request);2938}2939}2940return values;2941}2943bool CWallet::SetAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id, const std::string& value)2944{2945if (!batch.WriteAddressReceiveRequest(dest, id, value)) return false;2946m_address_book[dest].receive_requests[id] = value;2947return true;2948}2950bool CWallet::EraseAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id)2951{2952if (!batch.EraseAddressReceiveRequest(dest, id)) return false;2953m_address_book[dest].receive_requests.erase(id);2954return true;2955}2957util::Result<fs::path> GetWalletPath(const std::string& name)2958{2959const fs::path name_path = fs::PathFromString(name);2961// 'name' must be a normalized path, i.e. no . or .. except at the root2962if (name_path != name_path.lexically_normal()) {2963return util::Error{Untranslated("Wallet name given as a path must be normalized")};2964}2966// 'name' cannot begin with ./ or ../2967if (!name_path.empty() && (*name_path.begin() == fs::PathFromString(".") || *name_path.begin() == fs::PathFromString(".."))) {2968return util::Error{Untranslated("Wallet name given as a relative path cannot begin with ./ or ../, for wallets not in the walletdir, please use an absolute path.")};2969}2971// Disallow path at root2972if (name_path.has_root_path() && name_path.root_path() == name_path) {2973return util::Error{Untranslated("Wallet name cannot be the root path")};2974}2976// Do some checking on wallet path. It should be either a:2977//2978// 1. Path where a directory can be created.2979// 2. Path to an existing directory.2980// 3. Path to a symlink to a directory.2981// 4. For backwards compatibility, the name of a data file in -walletdir.2982const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), name_path);2983fs::file_type path_type = fs::symlink_status(wallet_path).type();2984if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory ||2985(path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) ||2986(path_type == fs::file_type::regular && name_path.filename() == name_path))) {2987return util::Error{Untranslated(strprintf(2988"Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "2989"database/log.?????????? files can be stored, a location where such a directory could be created, "2990"or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",2991name, fs::quoted(fs::PathToString(GetWalletDir()))))};2992}2993return wallet_path;2994}2996std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error_string)2997{2998const auto& wallet_path = GetWalletPath(name);2999if (!wallet_path) {3000error_string = util::ErrorString(wallet_path);