Coverage Report

Created: 2026-08-05 14:35

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.47k
{
15
4.47k
        CMutableTransaction tx1 {*this->GetTx()};
16
4.47k
        CMutableTransaction tx2 {*_tx.GetTx()};
17
4.51k
        for (auto& txin : tx1.vin) {
18
4.51k
            txin.scriptSig = CScript();
19
4.51k
            txin.scriptWitness.SetNull();
20
4.51k
        }
21
4.52k
        for (auto& txin : tx2.vin) {
22
4.52k
            txin.scriptSig = CScript();
23
4.52k
            txin.scriptWitness.SetNull();
24
4.52k
        }
25
4.47k
        return CTransaction(tx1) == CTransaction(tx2);
26
4.47k
}
27
28
bool CWalletTx::InMempool() const
29
149k
{
30
149k
    return state<TxStateInMempool>();
31
149k
}
32
33
int64_t CWalletTx::GetTxTime() const
34
296k
{
35
296k
    int64_t n = nTimeSmart;
36
296k
    return n ? n : nTimeReceived;
37
296k
}
38
39
void CWalletTx::updateState(interfaces::Chain& chain)
40
8.02k
{
41
8.02k
    bool active;
42
8.02k
    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
7.83k
        if (!chain.findBlock(hash, FoundBlock().inActiveChain(active).height(height)) || !active) {
50
362
            state = TxStateInactive{};
51
362
        }
52
7.83k
    };
53
8.02k
    if (auto* conf = state<TxStateConfirmed>()) {
54
7.78k
        lookup_block(conf->confirmed_block_hash, conf->confirmed_block_height, m_state);
55
7.78k
    } 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.02k
    if (!isConfirmed()) RecomputeCanonical();
62
8.02k
}
63
64
bool CWalletTx::Update(CTransactionRef new_tx, const TxState& new_state)
65
8.56k
{
66
8.56k
    Assert(new_tx);
67
8.56k
    if (!Assume(GetHash() == new_tx->GetHash())) {
68
0
        return false;
69
0
    }
70
8.56k
    bool ret = false;
71
8.56k
    const auto& [tx_pair, inserted] = m_txs.emplace(new_tx->GetWitnessHash(), std::move(new_tx));
72
8.56k
    if (inserted) {
73
3
        ret = true;
74
3
    }
75
8.56k
    const auto& [wtxid, tx] = *tx_pair;
76
77
8.56k
    if (new_state.index() != m_state.index()) {
78
4.41k
        m_state = new_state;
79
4.41k
        if (state<TxStateConfirmed>()) {
80
3.80k
            m_canonical_wtxid = wtxid;
81
3.80k
        }
82
4.41k
        ret = true;
83
4.41k
    } else {
84
4.14k
        assert(TxStateSerializedIndex(m_state) == TxStateSerializedIndex(new_state));
85
4.14k
        assert(TxStateSerializedBlockHash(m_state) == TxStateSerializedBlockHash(new_state));
86
4.14k
    }
87
88
    // While unconfirmed, derive the canonical variant from all known variants
89
8.56k
    if (!isConfirmed()) {
90
2.30k
        const Wtxid prev_canonical = m_canonical_wtxid;
91
2.30k
        RecomputeCanonical();
92
2.30k
        if (m_canonical_wtxid != prev_canonical) {
93
2
            ret = true;
94
2
        }
95
2.30k
    }
96
97
8.56k
    return ret;
98
8.56k
}
99
100
void CWalletTx::RecomputeCanonical()
101
2.90k
{
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.90k
    Assert(!m_txs.empty());
106
107
    // Returns true if 'a' should be preferred over 'b'
108
2.90k
    auto is_better = [](const CTransactionRef& a, const CTransactionRef& b) {
109
        // A witnessed variant always beats a witnessless one
110
12
        if (a->HasWitness() != b->HasWitness()) return a->HasWitness();
111
        // Otherwise the lighter one wins
112
12
        return GetTransactionWeight(*a) < GetTransactionWeight(*b);
113
12
    };
114
115
2.90k
    auto it = m_txs.begin();
116
2.90k
    auto best_wtxid = it->first;
117
2.90k
    const CTransactionRef* best = &it->second;
118
2.90k
    it = std::next(it);
119
2.91k
    for (; it != m_txs.end(); it = std::next(it)) {
120
12
        if (is_better(it->second, *best)) {
121
0
            best = &it->second;
122
0
            best_wtxid = it->first;
123
0
        }
124
12
    }
125
2.90k
    m_canonical_wtxid = best_wtxid;
126
2.90k
}
127
} // namespace wallet