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.
251* support but now serves as a cached IsMine value. Wallet code should252* not rely on this field being set.253*/254std::optional<AddressPurpose> purpose;256/**257* Whether coins with this address have previously been spent. Set when the258* the wallet avoid_reuse option is enabled and this is an IsMine address259* that has already received funds and spent them. This is used during coin260* selection to increase privacy by not creating different transactions261* that spend from the same addresses.262*/263bool previously_spent{false};265/**266* Map containing data about previously generated receive requests267* requesting funds to be sent to this address. Only present for IsMine268* addresses. Map keys are decimal numbers uniquely identifying each269* request, and map values are serialized RecentRequestEntry objects270* containing BIP21 URI information including message and amount.271*/272std::map<std::string, std::string> receive_requests{};274/** Accessor methods. */275bool IsChange() const { return !label.has_value(); }276std::string GetLabel() const { return label ? *label : std::string{}; }277void SetLabel(std::string name) { label = std::move(name); }278};280inline std::string PurposeToString(AddressPurpose p)281{282switch(p) {283case AddressPurpose::RECEIVE: return "receive";284case AddressPurpose::SEND: return "send";285case AddressPurpose::REFUND: return "refund";286} // no default case, so the compiler can warn about missing cases287assert(false);288}290inline std::optional<AddressPurpose> PurposeFromString(std::string_view s)291{292if (s == "receive") return AddressPurpose::RECEIVE;293else if (s == "send") return AddressPurpose::SEND;294else if (s == "refund") return AddressPurpose::REFUND;295return {};296}298struct CRecipient299{300CTxDestination dest;301CAmount nAmount;302bool fSubtractFeeFromAmount;303};305class WalletRescanReserver; //forward declarations for ScanForWalletTransactions/RescanFromTime306/**307* A CWallet maintains a set of transactions and balances, and provides the ability to create new transactions.308*/309class CWallet final : public WalletStorage, public interfaces::Chain::Notifications310{311private:312CKeyingMaterial vMasterKey GUARDED_BY(cs_wallet);314bool Unlock(const CKeyingMaterial& vMasterKeyIn);316std::atomic<bool> fAbortRescan{false};317std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver318std::atomic<bool> m_scanning_with_passphrase{false};319std::atomic<SteadyClock::time_point> m_scanning_start{SteadyClock::time_point{}};320std::atomic<double> m_scanning_progress{0};321friend class WalletRescanReserver;323/** The next scheduled rebroadcast of wallet transactions. */324NodeClock::time_point m_next_resend{GetDefaultNextResend()};325/** Whether this wallet will submit newly created transactions to the node's mempool and326* prompt rebroadcasts (see ResendWalletTransactions()). */327bool fBroadcastTransactions = false;328// Local time that the tip block was received. Used to schedule wallet rebroadcasts.329std::atomic<int64_t> m_best_block_time {0};331// First created key time. Used to skip blocks prior to this time.332// 'std::numeric_limits<int64_t>::max()' if wallet is blank.333std::atomic<int64_t> m_birth_time{std::numeric_limits<int64_t>::max()};335/**336* Used to keep track of spent outpoints, and337* detect and report conflicts (double-spends or338* mutated transactions where the mutant gets mined).339*/340typedef std::unordered_multimap<COutPoint, Txid, SaltedOutpointHasher> TxSpends;341TxSpends mapTxSpends GUARDED_BY(cs_wallet);342void AddToSpends(const COutPoint& outpoint, const Txid& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);343void AddToSpends(const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);345/**346* Add a transaction to the wallet, or update it. confirm.block_* should347* be set when the transaction was known to be included in a block. When348* block_hash.IsNull(), then wallet state is not updated in AddToWallet, but349* notifications happen and cached balances are marked dirty.350*351* TODO: One exception to this is that the abandoned state is cleared under the352* assumption that any further notification of a transaction that was considered353* abandoned is an indication that it is not safe to be considered abandoned.354* Abandoned state should probably be more carefully tracked via different355* chain notifications or by checking mempool presence when necessary.356*357* Should be called with rescanning_old_block set to true, if the transaction is358* not discovered in real time, but during a rescan of old blocks.359*/360bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const SyncTxState& state, bool rescanning_old_block) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);362/** Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */363void MarkConflicted(const uint256& hashBlock, int conflicting_height, const Txid& hashTx);365enum class TxUpdate { UNCHANGED, CHANGED, NOTIFY_CHANGED };367using TryUpdatingStateFn = std::function<TxUpdate(CWalletTx& wtx)>;369/** Mark a transaction (and its in-wallet descendants) as a particular tx state. */370void RecursiveUpdateTxState(const Txid& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);371void RecursiveUpdateTxState(WalletBatch* batch, const Txid& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);373/** Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed */374void MarkInputsDirty(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);376/** Collects all wallet txs that differ from wtx only in their scriptSigs (i.e. different tx id malleated variants)377* plus wtx itself. Sorted by the order in which they were inserted in the wallet (CWalletTx::nOrderPos) */378std::set<CWalletTx*, WalletTxOrderComparator> GetMalleatedVariants(const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);380void SyncMalleatedTxMetadata(WalletBatch& batch, const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);382bool SyncTransaction(const CTransactionRef& tx, const SyncTxState& state, bool rescanning_old_block = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);384/** WalletFlags set on this wallet. */385std::atomic<uint64_t> m_wallet_flags{0};387bool SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& strPurpose);389//! Unsets a wallet flag and saves it to disk390void UnsetWalletFlagWithDB(WalletBatch& batch, uint64_t flag);392//! Unset the blank wallet flag and saves it to disk393void UnsetBlankWalletFlag(WalletBatch& batch) override;395/** Interface for accessing chain state. */396interfaces::Chain* m_chain;398/** Wallet name: relative directory name or "" for default wallet. */399std::string m_name;401/** Internal database handle. */402std::unique_ptr<WalletDatabase> m_database;404/**405* The following is used to keep track of how far behind the wallet is406* from the chain sync, and to allow clients to block on us being caught up.407*408* Processed hash is a pointer on node's tip and doesn't imply that the wallet409* has scanned sequentially all blocks up to this one.410*/411uint256 m_last_block_processed GUARDED_BY(cs_wallet);413/** Height of last block processed is used by wallet to know depth of transactions414* without relying on Chain interface beyond asynchronous updates. For safety, we415* initialize it to -1. Height is a pointer on node's tip and doesn't imply416* that the wallet has scanned sequentially all blocks up to this one.417*/418int m_last_block_processed_height GUARDED_BY(cs_wallet) = -1;420std::map<OutputType, ScriptPubKeyMan*> m_external_spk_managers;421std::map<OutputType, ScriptPubKeyMan*> m_internal_spk_managers;423// Indexed by a unique identifier produced by each ScriptPubKeyMan using424// ScriptPubKeyMan::GetID. In many cases it will be the hash of an internal structure425std::map<uint256, std::unique_ptr<ScriptPubKeyMan>> m_spk_managers;427// Appends spk managers into the main 'm_spk_managers'.428// Must be the only method adding data to it.429void AddScriptPubKeyMan(const uint256& id, std::unique_ptr<ScriptPubKeyMan> spkm_man);431// Same as 'AddActiveScriptPubKeyMan' but designed for use within a batch transaction context432void AddActiveScriptPubKeyManWithDb(WalletBatch& batch, uint256 id, OutputType type, bool internal);434/** Store wallet flags */435void SetWalletFlagWithDB(WalletBatch& batch, uint64_t flags);437//! Cache of descriptor ScriptPubKeys used for IsMine. Maps ScriptPubKey to set of spkms438std::unordered_map<CScript, std::vector<ScriptPubKeyMan*>, SaltedSipHasher> m_cached_spks;440//! Set of both spent and unspent transaction outputs owned by this wallet441std::unordered_map<COutPoint, WalletTXO, SaltedOutpointHasher> m_txos GUARDED_BY(cs_wallet);443/**444* Catch wallet up to current chain, scanning new blocks, updating the best445* block locator and m_last_block_processed, and registering for446* notifications about new blocks and transactions.447*/448static bool AttachChain(const std::shared_ptr<CWallet>& wallet, interfaces::Chain& chain, bool rescan_required, bilingual_str& error, std::vector<bilingual_str>& warnings);450static NodeClock::time_point GetDefaultNextResend();452// Update last block processed in memory only453void SetLastBlockProcessedInMem(int block_height, uint256 block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);455//! Update mempool conflicts for TRUC sibling transactions456void UpdateTrucSiblingConflicts(const CWalletTx& parent_wtx, const Txid& child_txid, bool add_conflict) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);458public:459/**460* Main wallet lock.461* This lock protects all the fields added by CWallet.462*/463mutable RecursiveMutex cs_wallet;465WalletDatabase& GetDatabase() const override466{467assert(static_cast<bool>(m_database));468return *m_database;469}471/** Get a name for this wallet for logging/debugging purposes.472*/473const std::string& GetName() const { return m_name; }475typedef std::map<unsigned int, CMasterKey> MasterKeyMap;476MasterKeyMap mapMasterKeys;477unsigned int nMasterKeyMaxID = 0;479/** Construct wallet with specified name and database implementation. */480CWallet(interfaces::Chain* chain, const std::string& name, std::unique_ptr<WalletDatabase> database)481: m_chain(chain),482m_name(name),483m_database(std::move(database))484{485}487~CWallet()488{489// Should not have slots connected at this point.490assert(NotifyUnload.empty());491}493bool IsLocked() const override;494bool Lock();496/** Interface to assert chain access */497bool HaveChain() const { return m_chain ? true : false; }499/** Map from txid to CWalletTx for all transactions this wallet is500* interested in, including received and sent transactions. */
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.