Coverage Report

Created: 2026-09-14 20:36

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
#include <wallet/walletdb.h>
7
8
#include <consensus/validation.h>
9
#include <interfaces/chain.h>
10
11
using interfaces::FoundBlock;
12
13
namespace wallet {
14
bool CWalletTx::IsMalleation(const CWalletTx& _tx) const
15
54
{
16
54
    return GetTx()->Equals(*_tx.GetTx(), {.include_script_sig = false, .include_witness_data = false});
17
54
}
18
19
bool CWalletTx::InMempool() const
20
149k
{
21
149k
    return state<TxStateInMempool>();
22
149k
}
23
24
int64_t CWalletTx::GetTxTime() const
25
296k
{
26
296k
    int64_t n = nTimeSmart;
27
296k
    return n ? n : nTimeReceived;
28
296k
}
29
30
void CWalletTx::updateState(interfaces::Chain& chain)
31
9.27k
{
32
9.27k
    bool active;
33
9.27k
    auto lookup_block = [&](const uint256& hash, int& height, TxState& state) {
34
        // If tx block (or conflicting block) was reorged out of chain
35
        // while the wallet was shutdown, change tx status to UNCONFIRMED
36
        // and reset block height, hash, and index. ABANDONED tx don't have
37
        // associated blocks and don't need to be updated. The case where a
38
        // transaction was reorged out while online and then reconfirmed
39
        // while offline is covered by the rescan logic.
40
9.06k
        if (!chain.findBlock(hash, FoundBlock().inActiveChain(active).height(height)) || !active) {
41
362
            state = TxStateInactive{};
42
362
        }
43
9.06k
    };
44
9.27k
    if (auto* conf = state<TxStateConfirmed>()) {
45
8.81k
        lookup_block(conf->confirmed_block_hash, conf->confirmed_block_height, m_state);
46
8.81k
    } else if (auto* conf = state<TxStateBlockConflicted>()) {
47
242
        lookup_block(conf->conflicting_block_hash, conf->conflicting_block_height, m_state);
48
242
    }
49
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.
52
9.27k
    if (!isConfirmed()) RecomputeCanonical();
53
9.27k
}
54
55
bool CWalletTx::Update(CTransactionRef new_tx, const TxState& new_state, WalletBatch& batch, bool metadata_changed)
56
8.80k
{
57
8.80k
    Assert(new_tx);
58
8.80k
    if (!Assume(GetHash() == new_tx->GetHash())) {
59
0
        return false;
60
0
    }
61
8.80k
    const auto& [tx_pair, new_variant] = m_txs.emplace(new_tx->GetWitnessHash(), std::move(new_tx));
62
8.80k
    if (new_variant) {
63
3
        if (!batch.WriteWtxVariant(GetHash(), tx_pair->second)) {
64
0
            throw std::ios_base::failure("Unable to write wtxvariant record");
65
0
        }
66
3
    }
67
8.80k
    const auto& [wtxid, tx] = *tx_pair;
68
69
8.80k
    if (new_state.index() != m_state.index()) {
70
4.52k
        m_state = new_state;
71
4.52k
        if (state<TxStateConfirmed>()) {
72
3.90k
            m_canonical_wtxid = wtxid;
73
3.90k
        }
74
4.52k
        metadata_changed = true;
75
4.52k
    } else {
76
4.27k
        assert(TxStateSerializedIndex(m_state) == TxStateSerializedIndex(new_state));
77
4.27k
        assert(TxStateSerializedBlockHash(m_state) == TxStateSerializedBlockHash(new_state));
78
4.27k
    }
79
80
    // While unconfirmed, derive the canonical variant from all known variants
81
8.80k
    if (!isConfirmed()) {
82
2.45k
        const Wtxid prev_canonical = m_canonical_wtxid;
83
2.45k
        RecomputeCanonical();
84
2.45k
        if (m_canonical_wtxid != prev_canonical) {
85
2
            metadata_changed = true;
86
2
        }
87
2.45k
    }
88
89
8.80k
    if (metadata_changed) {
90
4.52k
        if (!batch.WriteTxMetadata(*this)) {
91
0
            throw std::ios_base::failure("Unable to write tx record");
92
0
        }
93
4.52k
    }
94
95
8.80k
    return new_variant || metadata_changed;
96
8.80k
}
97
98
void CWalletTx::RecomputeCanonical()
99
3.27k
{
100
    // Recompute the canonical variant among the witness variants. They share
101
    // the txid but differ in the wtxid. Prefer variant with witness data and
102
    // the least weight.
103
3.27k
    Assert(!m_txs.empty());
104
105
3.27k
    m_canonical_wtxid = std::ranges::min_element(m_txs, std::less{}, [](const auto& entry) {
106
24
                            return std::make_pair(!entry.second->HasWitness(), GetTransactionWeight(*entry.second));
107
24
                        })->first;
108
3.27k
}
109
} // namespace wallet