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.
251const Txid& canonical_txid = GetHash();252for (const auto& [wtxid, tx] : variants) {253if (tx->GetHash() != canonical_txid) throw std::runtime_error("variant txid does not match wallet txid");254}255// Merge witness variants256m_txs.insert(variants.begin(), variants.end());257Assert(m_txs.contains(GetWitnessHash()));258}260TxState m_state;262// Set of mempool transactions that conflict263// directly with the transaction, or that conflict264// with an ancestor transaction. This set will be265// empty if state is InMempool or Confirmed, but266// can be nonempty if state is Inactive or267// BlockConflicted.268std::set<Txid> mempool_conflicts;270// Track v3 mempool tx that spends from this tx271// so that we don't try to create another unconfirmed child272std::optional<Txid> truc_child_in_mempool;274template<typename Stream>275void Serialize(Stream& s) const276{277std::map<std::string, std::string> string_values;278if (m_from) string_values["from"] = *m_from;279if (m_message) string_values["message"] = *m_message;280if (m_comment) string_values["comment"] = *m_comment;281if (m_comment_to) string_values["to"] = *m_comment_to;282if (m_replaces_txid) string_values["replaces_txid"] = m_replaces_txid->ToString();283if (m_replaced_by_txid) string_values["replaced_by_txid"] = m_replaced_by_txid->ToString();284string_values["fromaccount"] = "";285if (nOrderPos != -1) string_values["n"] = util::ToString(nOrderPos);286if (nTimeSmart) string_values["timesmart"] = strprintf("%u", nTimeSmart);288std::vector<std::pair<std::string, std::string>> msgs_reqs;289msgs_reqs.reserve(m_messages.size() + m_payment_requests.size());290for (const std::string& msg : m_messages) {291msgs_reqs.emplace_back("Message", msg);292}293for (const std::string& req : m_payment_requests) {294msgs_reqs.emplace_back("PaymentRequest", req);295}297std::vector<uint8_t> dummy_vector1; // Used to be vMerkleBranch298std::vector<uint8_t> dummy_vector2; // Used to be vtxPrev299bool dummy_bool = false; // Used to be fFromMe, and fSpent300uint32_t dummy_int = 0; // Used to be fTimeReceivedIsTxTime301uint256 serializedHash = TxStateSerializedBlockHash(m_state);302int serializedIndex = TxStateSerializedIndex(m_state);303s << TX_WITH_WITNESS(GetTx()) << serializedHash << dummy_vector1 << serializedIndex << dummy_vector2 << string_values << msgs_reqs << dummy_int << nTimeReceived << dummy_bool << dummy_bool;304}306template<typename Stream>307void Unserialize(Stream& s)308{309Init();311std::vector<uint256> dummy_vector1; // Used to be vMerkleBranch312std::vector<CMerkleTx> dummy_vector2; // Used to be vtxPrev313bool dummy_bool; // Used to be fFromMe, and fSpent314uint32_t dummy_int; // Used to be fTimeReceivedIsTxTime315uint256 serialized_block_hash;316int serializedIndex;317std::map<std::string, std::string> string_values;318std::vector<std::pair<std::string, std::string>> msgs_reqs;319CTransactionRef canonical_tx;320s >> TX_WITH_WITNESS(canonical_tx) >> serialized_block_hash >> dummy_vector1 >> serializedIndex >> dummy_vector2 >> string_values >> msgs_reqs >> dummy_int >> nTimeReceived >> dummy_bool >> dummy_bool;321m_canonical_wtxid = canonical_tx->GetWitnessHash();322m_txs.emplace(m_canonical_wtxid, std::move(canonical_tx));324m_state = TxStateInterpretSerialized({serialized_block_hash, serializedIndex});326string_values.erase("fromaccount");327string_values.erase("spent");328for (const auto& [key, value] : string_values) {329if (key == "n") nOrderPos = LocaleIndependentAtoi<int64_t>(value);330else if (key == "timesmart") nTimeSmart = LocaleIndependentAtoi<int64_t>(value);331else if (key == "from") m_from = value;332else if (key == "message") m_message = value;333else if (key == "comment") m_comment = value;334else if (key == "to") m_comment_to = value;335else if (key == "replaces_txid") m_replaces_txid = Txid::FromHex(value);336else if (key == "replaced_by_txid") m_replaced_by_txid = Txid::FromHex(value);337else {338throw std::runtime_error("Unexpected value in CWalletTx strings value map");339}340}342for (const auto& [type, data] : msgs_reqs) {343if (type == "Message") m_messages.emplace_back(data);344else if (type == "PaymentRequest") m_payment_requests.emplace_back(data);345else {346throw std::runtime_error("Unknown type in CWalletTx messages and requests vector");347}348}349}351CTransactionRef GetTx() const { return m_txs.at(m_canonical_wtxid); }353// Update the state of this wallet transaction along with a transaction that may have a different wtxid.354// If the given transaction has a different wtxid, the transaction is stored if it has not been seen before.355// The canonical wtxid is also updated. The tx that is confirmed becomes canonical. For unconfirmed txs,356// those with witnesses are preferred, followed by least weight.357bool Update(CTransactionRef tx, const TxState& new_state, WalletBatch& batch, bool metadata_changed);359//! make sure balances are recalculated360void MarkDirty()361{362m_amounts[DEBIT].Reset();363m_amounts[CREDIT].Reset();364fChangeCached = false;365m_is_cache_empty = true;366m_cached_from_me = std::nullopt;367}369/** True if tx is a malleation of this, i.e. it has the exact same version, locktime,370* input order, input outpoints, input sequences, and outputs. Input scriptSigs and input scriptWitnesses may differ. */371bool IsMalleation(const CWalletTx& tx) const;373bool InMempool() const;375int64_t GetTxTime() const;377template<typename T> const T* state() const { return std::get_if<T>(&m_state); }378template<typename T> T* state() { return std::get_if<T>(&m_state); }380//! Update transaction state when attaching to a chain, filling in heights381//! of conflicted and confirmed blocks382void updateState(interfaces::Chain& chain);384bool isAbandoned() const { return state<TxStateInactive>() && state<TxStateInactive>()->abandoned; }385bool isMempoolConflicted() const { return !mempool_conflicts.empty(); }386bool isBlockConflicted() const { return state<TxStateBlockConflicted>(); }387bool isInactive() const { return state<TxStateInactive>(); }388bool isUnconfirmed() const { return !isAbandoned() && !isBlockConflicted() && !isMempoolConflicted() && !isConfirmed(); }389bool isConfirmed() const { return state<TxStateConfirmed>(); }390const Txid& GetHash() const LIFETIMEBOUND { return GetTx()->GetHash(); }391const Wtxid& GetWitnessHash() const LIFETIMEBOUND { return GetTx()->GetWitnessHash(); }392bool IsCoinBase() const { return GetTx()->IsCoinBase(); }394const std::map<Wtxid, CTransactionRef>& GetTxs() const { return m_txs; }396// Disable copying of CWalletTx objects to prevent bugs where instances get397// copied in and out of the mapWallet map, and fields are updated in the398// wrong copy.399CWalletTx(const CWalletTx&) = delete;400CWalletTx& operator=(const CWalletTx&) = delete;402// Enable the default move constructor403CWalletTx(CWalletTx&&) = default;405private:406void SetDefaults()407{408nTimeReceived = 0;409nTimeSmart = 0;410fChangeCached = false;411nChangeCached = 0;412nOrderPos = -1;413}415void Init()416{417m_txs.clear();418m_canonical_wtxid = Wtxid{};419SetDefaults();420}422Wtxid m_canonical_wtxid;423std::map<Wtxid, CTransactionRef> m_txs;425//! Set m_canonical_wtxid to the best variant under the unconfirmed rule426//! (witnessed preferred, then least weight). Ignores state.427void RecomputeCanonical();428};430struct WalletTxOrderComparator {431bool operator()(const CWalletTx* a, const CWalletTx* b) const432{433return a->nOrderPos < b->nOrderPos;434}435};437class WalletTXO438{439private:440const CWalletTx& m_wtx;441const CTxOut& m_output;443public:444WalletTXO(const CWalletTx& wtx, const CTxOut& output)445: m_wtx(wtx),446m_output(output)447{448Assume(std::ranges::find(wtx.GetTx()->vout, output) != wtx.GetTx()->vout.end());449}451const CWalletTx& GetWalletTx() const { return m_wtx; }453const CTxOut& GetTxOut() const { return m_output; }454};455} // namespace wallet457#endif // BITCOIN_WALLET_TRANSACTION_H