Inside Bitcoin
Opening the selected file…
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.
1// Copyright (c) 2018-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <interfaces/wallet.h>7#include <common/args.h>8#include <consensus/amount.h>9#include <interfaces/chain.h>10#include <interfaces/handler.h>11#include <node/types.h>12#include <primitives/transaction.h>13#include <rpc/server.h>14#include <scheduler.h>15#include <support/allocators/secure.h>16#include <sync.h>17#include <uint256.h>18#include <util/check.h>19#include <util/translation.h>20#include <util/ui_change_type.h>21#include <wallet/coincontrol.h>22#include <wallet/context.h>23#include <wallet/export.h>24#include <wallet/feebumper.h>25#include <wallet/fees.h>26#include <wallet/load.h>27#include <wallet/receive.h>28#include <wallet/rpc/wallet.h>29#include <wallet/spend.h>30#include <wallet/wallet.h>32#include <memory>33#include <string>34#include <utility>35#include <vector>37using common::PSBTError;38using interfaces::Chain;39using interfaces::FoundBlock;40using interfaces::Handler;41using interfaces::MakeSignalHandler;42using interfaces::Wallet;43using interfaces::WalletAddress;44using interfaces::WalletBalances;45using interfaces::WalletLoader;46using interfaces::WalletMigrationResult;47using interfaces::WalletTx;48using interfaces::WalletTxOut;49using interfaces::WalletTxStatus;51namespace wallet {52// All members of the classes in this namespace are intentionally public, as the53// classes themselves are private.54namespace {55//! Construct wallet tx struct.56WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)57{58LOCK(wallet.cs_wallet);59WalletTx result;60result.tx = wtx.GetTx();61result.txin_is_mine.reserve(result.tx->vin.size());62for (const auto& txin : result.tx->vin) {63result.txin_is_mine.emplace_back(InputIsMine(wallet, txin));64}65result.txout_is_mine.reserve(result.tx->vout.size());66result.txout_address.reserve(result.tx->vout.size());67result.txout_address_is_mine.reserve(result.tx->vout.size());68for (const auto& txout : result.tx->vout) {69result.txout_is_mine.emplace_back(wallet.IsMine(txout));70result.txout_is_change.push_back(OutputIsChange(wallet, txout));71result.txout_address.emplace_back();72result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ?73wallet.IsMine(result.txout_address.back()) :74false);75}76result.credit = CachedTxGetCredit(wallet, wtx, /*avoid_reuse=*/true);77result.debit = CachedTxGetDebit(wallet, wtx, /*avoid_reuse=*/true);78result.change = CachedTxGetChange(wallet, wtx);79result.time = wtx.GetTxTime();80result.from = wtx.m_from;81result.message = wtx.m_message;82result.comment = wtx.m_comment;83result.comment_to = wtx.m_comment_to;84result.is_coinbase = wtx.IsCoinBase();85return result;86}88//! Construct wallet tx status struct.89WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx)90EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)91{92AssertLockHeld(wallet.cs_wallet);94WalletTxStatus result;95result.block_height =96wtx.state<TxStateConfirmed>() ? wtx.state<TxStateConfirmed>()->confirmed_block_height :97wtx.state<TxStateBlockConflicted>() ? wtx.state<TxStateBlockConflicted>()->conflicting_block_height :98std::numeric_limits<int>::max();99result.blocks_to_maturity = wallet.GetTxBlocksToMaturity(wtx);100result.depth_in_main_chain = wallet.GetTxDepthInMainChain(wtx);101result.time_received = wtx.nTimeReceived;102result.lock_time = wtx.GetTx()->nLockTime;103result.is_trusted = CachedTxIsTrusted(wallet, wtx);104result.is_abandoned = wtx.isAbandoned();105result.is_coinbase = wtx.IsCoinBase();106result.is_in_main_chain = wtx.isConfirmed();107return result;108}110//! Construct wallet TxOut struct.111WalletTxOut MakeWalletTxOut(const CWallet& wallet,112const CWalletTx& wtx,113int n,114int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)115{116WalletTxOut result;117result.txout = wtx.GetTx()->vout[n];118result.time = wtx.GetTxTime();119result.depth_in_main_chain = depth;120result.is_spent = wallet.IsSpent(COutPoint(wtx.GetHash(), n));121return result;122}124WalletTxOut MakeWalletTxOut(const CWallet& wallet,125const COutput& output) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)126{127WalletTxOut result;128result.txout = output.txout;129result.time = output.time;130result.depth_in_main_chain = output.depth;131result.is_spent = wallet.IsSpent(output.outpoint);132return result;133}135class WalletImpl : public Wallet136{137public:138explicit WalletImpl(WalletContext& context, const std::shared_ptr<CWallet>& wallet) : m_context(context), m_wallet(wallet) {}140bool encryptWallet(const SecureString& wallet_passphrase) override141{142return m_wallet->EncryptWallet(wallet_passphrase);143}144bool isCrypted() override { return m_wallet->HasEncryptionKeys(); }145bool lock() override { return m_wallet->Lock(); }146bool unlock(const SecureString& wallet_passphrase) override { return m_wallet->Unlock(wallet_passphrase); }147bool isLocked() override { return m_wallet->IsLocked(); }148bool changeWalletPassphrase(const SecureString& old_wallet_passphrase,149const SecureString& new_wallet_passphrase) override150{151return m_wallet->ChangeWalletPassphrase(old_wallet_passphrase, new_wallet_passphrase);152}153void abortRescan() override { m_wallet->AbortRescan(); }154bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); }155std::string getWalletName() override { return m_wallet->GetName(); }156util::Result<CTxDestination> getNewDestination(const OutputType type, const std::string& label) override157{158LOCK(m_wallet->cs_wallet);159return m_wallet->GetNewDestination(type, label);160}161bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) override162{163std::unique_ptr<SigningProvider> provider = m_wallet->GetSolvingProvider(script);164if (provider) {165return provider->GetPubKey(address, pub_key);166}167return false;168}169SigningResult signMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) override170{171return m_wallet->SignMessage(message, pkhash, str_sig);172}173bool isSpendable(const CTxDestination& dest) override174{175LOCK(m_wallet->cs_wallet);176return m_wallet->IsMine(dest);177}178bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::optional<AddressPurpose>& purpose) override179{180return m_wallet->SetAddressBook(dest, name, purpose);181}182bool delAddressBook(const CTxDestination& dest) override183{184return m_wallet->DelAddressBook(dest);185}186bool getAddress(const CTxDestination& dest,187std::string* name,188AddressPurpose* purpose) override189{190LOCK(m_wallet->cs_wallet);191const auto& entry = m_wallet->FindAddressBookEntry(dest, /*allow_change=*/false);192if (!entry) return false; // addr not found193if (name) {194*name = entry->GetLabel();195}196if (purpose) {197// In very old wallets, address purpose may not be recorded so we derive it from IsMine198*purpose = entry->purpose.value_or(m_wallet->IsMine(dest) ? AddressPurpose::RECEIVE : AddressPurpose::SEND);199}200return true;201}202std::vector<WalletAddress> getAddresses() override203{204LOCK(m_wallet->cs_wallet);205std::vector<WalletAddress> result;206m_wallet->ForEachAddrBookEntry([&](const CTxDestination& dest, const std::string& label, bool is_change, const std::optional<AddressPurpose>& purpose) EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet) {207if (is_change) return;208bool is_mine = m_wallet->IsMine(dest);209// In very old wallets, address purpose may not be recorded so we derive it from IsMine210result.emplace_back(dest, is_mine, purpose.value_or(is_mine ? AddressPurpose::RECEIVE : AddressPurpose::SEND), label);211});212return result;213}214std::vector<std::string> getAddressReceiveRequests() override {215LOCK(m_wallet->cs_wallet);216return m_wallet->GetAddressReceiveRequests();217}218bool setAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& value) override {219// Note: The setAddressReceiveRequest interface used by the GUI to store220// receive requests is a little awkward and could be improved in the221// future:222//223// - The same method is used to save requests and erase them, but224// having separate methods could be clearer and prevent bugs.225//226// - Request ids are passed as strings even though they are generated as227// integers.228//229// - Multiple requests can be stored for the same address, but it might230// be better to only allow one request or only keep the current one.231LOCK(m_wallet->cs_wallet);232WalletBatch batch{m_wallet->GetDatabase()};233return value.empty() ? m_wallet->EraseAddressReceiveRequest(batch, dest, id)234: m_wallet->SetAddressReceiveRequest(batch, dest, id, value);235}236util::Result<void> displayAddress(const CTxDestination& dest) override237{238LOCK(m_wallet->cs_wallet);239return m_wallet->DisplayAddress(dest);240}241bool lockCoin(const COutPoint& output, const bool write_to_db) override242{243LOCK(m_wallet->cs_wallet);244return m_wallet->LockCoin(output, write_to_db);245}246bool unlockCoin(const COutPoint& output) override247{248LOCK(m_wallet->cs_wallet);249return m_wallet->UnlockCoin(output);250}