Coverage Report

Created: 2026-08-14 20:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/wallet/transaction.cpp
Line
Count
Source
1
// Copyright (c) 2021-present The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#include <wallet/transaction.h>
6
7
#include <consensus/validation.h>
8
#include <interfaces/chain.h>
9
10
using interfaces::FoundBlock;
11
12
namespace wallet {
13
bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const
14
4.17k
{
15
4.17k
        CMutableTransaction tx1 {*this->GetTx()};
16
4.17k
        CMutableTransaction tx2 {*_tx.GetTx()};
17
4.21k
        for (auto& txin : tx1.vin) {
18
4.21k
            txin.scriptSig = CScript();
19
4.21k
            txin.scriptWitness.SetNull();
20
4.21k
        }
21
4.22k
        for (auto& txin : tx2.vin) {
22
4.22k
            txin.scriptSig = CScript();
23
4.22k
            txin.scriptWitness.SetNull();
24
4.22k
        }
25
4.17k
        return CTransaction(tx1) == CTransaction(tx2);
26
4.17k
}
27
28
bool CWalletTx::InMempool() const
29
149k
{
30
149k
    return state<TxStateInMempool>();
31
149k
}
32
33
int64_t CWalletTx::GetTxTime() const
34
300k
{
35
300k
    int64_t n = nTimeSmart;
36
300k
    return n ? n : nTimeReceived;
37
300k
}
38
39
void CWalletTx::updateState(interfaces::Chain& chain)
40
8.40k
{
41
8.40k
    bool active;
42
8.40k
    auto lookup_block = [&](const uint256& hash, int& height, TxState& state) {
43
        // If tx block (or conflicting block) was reorged out of chain
44
        // while the wallet was shutdown, change tx status to UNCONFIRMED
45
        // and reset block height, hash, and index. ABANDONED tx don't have
46
        // associated blocks and don't need to be updated. The case where a
47
        // transaction was reorged out while online and then reconfirmed
48
        // while offline is covered by the rescan logic.
49
8.21k
        if (!chain.findBlock(hash, FoundBlock().inActiveChain(active).height(height)) || !active) {
50
362
            state = TxStateInactive{};
51
362
        }
52
8.21k
    };
53
8.40k
    if (auto* conf = state<TxStateConfirmed>()) {
54
8.16k
        lookup_block(conf->confirmed_block_hash, conf->confirmed_block_height, m_state);
55
8.16k
    } else if (auto* conf = state<TxStateBlockConflicted>()) {
56
52
        lookup_block(conf->conflicting_block_hash, conf->conflicting_block_height, m_state);
57
52
    }
58
59
    // If the above downgraded a previously-confirmed witness variant back to unconfirmed,
60
    // the canonical choice is no longer pinned by confirmation. Re-apply the least-weight rule.
61
8.40k
    if (!isConfirmed()) RecomputeCanonical();
62
8.40k
}
63
64
bool CWalletTx::Update(CTransactionRef new_tx, const TxState& new_state)
65
8.60k
{
66
8.60k
    Assert(new_tx);
67
8.60k
    if (!Assume(GetHash() == new_tx->GetHash())) {
68
0
        return false;
69
0
    }
70
8.60k
    bool ret = false;
71
8.60k
    const auto& [tx_pair, inserted] = m_txs.emplace(new_tx->GetWitnessHash(), std::move(new_tx));
72
8.60k
    if (inserted) {
73
3
        ret = true;
74
3
    }
75
8.60k
    const auto& [wtxid, tx] = *tx_pair;
76
77
8.60k
    if (new_state.index() != m_state.index()) {
78
4.42k
        m_state = new_state;
79
4.42k
        if (state<TxStateConfirmed>()) {
80
3.81k
            m_canonical_wtxid = wtxid;
81
3.81k
        }
82
4.42k
        ret = true;
83
4.42k
    } else {
84
4.18k
        assert(TxStateSerializedIndex(m_state) == TxStateSerializedIndex(new_state));
85
4.18k
        assert(TxStateSerializedBlockHash(m_state) == TxStateSerializedBlockHash(new_state));
86
4.18k
    }
87
88
    // While unconfirmed, derive the canonical variant from all known variants
89
8.60k
    if (!isConfirmed()) {
90
2.35k
        const Wtxid prev_canonical = m_canonical_wtxid;
91
2.35k
        RecomputeCanonical();
92
2.35k
        if (m_canonical_wtxid != prev_canonical) {
93
2
            ret = true;
94
2
        }
95
2.35k
    }
96
97
8.60k
    return ret;
98
8.60k
}
99
100
void CWalletTx::RecomputeCanonical()
101
2.95k
{
102
    // Recompute the canonical variant among the witness variants. They share
103
    // the txid but differ in the wtxid. Prefer variant with witness data and
104
    // the least weight.
105
2.95k
    Assert(!m_txs.empty());
106
107
2.95k
    m_canonical_wtxid = std::ranges::min_element(m_txs, std::less{}, [](const auto& entry) {
108
24
                            return std::make_pair(!entry.second->HasWitness(), GetTransactionWeight(*entry.second));
109
24
                        })->first;
110
2.95k
}
111
} // namespace wallet