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) 2021-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 <wallet/transaction.h>6#include <wallet/walletdb.h>8#include <consensus/validation.h>9#include <interfaces/chain.h>11using interfaces::FoundBlock;13namespace wallet {14bool CWalletTx::IsMalleation(const CWalletTx& _tx) const15{16return GetTx()->Equals(*_tx.GetTx(), {.include_script_sig = false, .include_witness_data = false});17}19bool CWalletTx::InMempool() const20{21return state<TxStateInMempool>();22}24int64_t CWalletTx::GetTxTime() const25{26int64_t n = nTimeSmart;27return n ? n : nTimeReceived;28}30void CWalletTx::updateState(interfaces::Chain& chain)31{32bool active;33auto lookup_block = [&](const uint256& hash, int& height, TxState& state) {34// If tx block (or conflicting block) was reorged out of chain35// while the wallet was shutdown, change tx status to UNCONFIRMED36// and reset block height, hash, and index. ABANDONED tx don't have37// associated blocks and don't need to be updated. The case where a38// transaction was reorged out while online and then reconfirmed39// while offline is covered by the rescan logic.40if (!chain.findBlock(hash, FoundBlock().inActiveChain(active).height(height)) || !active) {41state = TxStateInactive{};42}43};44if (auto* conf = state<TxStateConfirmed>()) {45lookup_block(conf->confirmed_block_hash, conf->confirmed_block_height, m_state);46} else if (auto* conf = state<TxStateBlockConflicted>()) {47lookup_block(conf->conflicting_block_hash, conf->conflicting_block_height, m_state);48}50// If the above downgraded a previously-confirmed witness variant back to unconfirmed,51// the canonical choice is no longer pinned by confirmation. Re-apply the least-weight rule.52if (!isConfirmed()) RecomputeCanonical();53}55bool CWalletTx::Update(CTransactionRef new_tx, const TxState& new_state, WalletBatch& batch, bool metadata_changed)56{57Assert(new_tx);58if (!Assume(GetHash() == new_tx->GetHash())) {59return false;60}61const auto& [tx_pair, new_variant] = m_txs.emplace(new_tx->GetWitnessHash(), std::move(new_tx));62if (new_variant) {63if (!batch.WriteWtxVariant(GetHash(), tx_pair->second)) {64throw std::ios_base::failure("Unable to write wtxvariant record");65}66}67const auto& [wtxid, tx] = *tx_pair;69if (new_state.index() != m_state.index()) {70m_state = new_state;71if (state<TxStateConfirmed>()) {72m_canonical_wtxid = wtxid;73}74metadata_changed = true;75} else {76assert(TxStateSerializedIndex(m_state) == TxStateSerializedIndex(new_state));77assert(TxStateSerializedBlockHash(m_state) == TxStateSerializedBlockHash(new_state));78}80// While unconfirmed, derive the canonical variant from all known variants81if (!isConfirmed()) {82const Wtxid prev_canonical = m_canonical_wtxid;83RecomputeCanonical();84if (m_canonical_wtxid != prev_canonical) {85metadata_changed = true;86}87}89if (metadata_changed) {90if (!batch.WriteTxMetadata(*this)) {91throw std::ios_base::failure("Unable to write tx record");92}93}95return new_variant || metadata_changed;96}98void CWalletTx::RecomputeCanonical()99{100// Recompute the canonical variant among the witness variants. They share101// the txid but differ in the wtxid. Prefer variant with witness data and102// the least weight.103Assert(!m_txs.empty());105m_canonical_wtxid = std::ranges::min_element(m_txs, std::less{}, [](const auto& entry) {106return std::make_pair(!entry.second->HasWitness(), GetTransactionWeight(*entry.second));107})->first;108}109} // namespace wallet