Coverage Report

Created: 2026-07-14 18:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/bitcoin/src/consensus/tx_verify.cpp
Line
Count
Source
1
// Copyright (c) 2017-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 <consensus/tx_verify.h>
6
7
#include <chain.h>
8
#include <coins.h>
9
#include <consensus/amount.h>
10
#include <consensus/consensus.h>
11
#include <consensus/validation.h>
12
#include <primitives/transaction.h>
13
#include <script/interpreter.h>
14
#include <util/check.h>
15
#include <util/moneystr.h>
16
17
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
18
2.64M
{
19
2.64M
    if (tx.nLockTime == 0)
  Branch (19:9): [True: 2.52M, False: 122k]
20
2.52M
        return true;
21
122k
    if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
  Branch (21:9): [True: 43.1k, False: 78.9k]
  Branch (21:34): [True: 69.5k, False: 52.5k]
22
43.1k
        return true;
23
24
    // Even if tx.nLockTime isn't satisfied by nBlockHeight/nBlockTime, a
25
    // transaction is still considered final if all inputs' nSequence ==
26
    // SEQUENCE_FINAL (0xffffffff), in which case nLockTime is ignored.
27
    //
28
    // Because of this behavior OP_CHECKLOCKTIMEVERIFY/CheckLockTime() will
29
    // also check that the spending input's nSequence != SEQUENCE_FINAL,
30
    // ensuring that an unsatisfied nLockTime value will actually cause
31
    // IsFinalTx() to return false here:
32
83.3k
    for (const auto& txin : tx.vin) {
  Branch (32:27): [True: 83.3k, False: 75.3k]
33
83.3k
        if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL))
  Branch (33:13): [True: 3.54k, False: 79.8k]
34
3.54k
            return false;
35
83.3k
    }
36
75.3k
    return true;
37
78.9k
}
38
39
std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>& prevHeights, const CBlockIndex& block)
40
664k
{
41
664k
    assert(prevHeights.size() == tx.vin.size());
  Branch (41:5): [True: 664k, False: 0]
42
43
    // Will be set to the equivalent height- and time-based nLockTime
44
    // values that would be necessary to satisfy all relative lock-
45
    // time constraints given our view of block chain history.
46
    // The semantics of nLockTime are the last invalid height/time, so
47
    // use -1 to have the effect of any height or time being valid.
48
664k
    int nMinHeight = -1;
49
664k
    int64_t nMinTime = -1;
50
51
664k
    bool fEnforceBIP68 = tx.version >= 2 && flags & LOCKTIME_VERIFY_SEQUENCE;
  Branch (51:26): [True: 636k, False: 27.9k]
  Branch (51:45): [True: 636k, False: 0]
52
53
    // Do not enforce sequence numbers as a relative lock time
54
    // unless we have been instructed to
55
664k
    if (!fEnforceBIP68) {
  Branch (55:9): [True: 27.9k, False: 636k]
56
27.9k
        return std::make_pair(nMinHeight, nMinTime);
57
27.9k
    }
58
59
1.31M
    for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
  Branch (59:32): [True: 680k, False: 636k]
60
680k
        const CTxIn& txin = tx.vin[txinIndex];
61
62
        // Sequence numbers with the most significant bit set are not
63
        // treated as relative lock-times, nor are they given any
64
        // consensus-enforced meaning at this point.
65
680k
        if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {
  Branch (65:13): [True: 675k, False: 5.42k]
66
            // The height of this input is not relevant for sequence locks
67
675k
            prevHeights[txinIndex] = 0;
68
675k
            continue;
69
675k
        }
70
71
5.42k
        int nCoinHeight = prevHeights[txinIndex];
72
73
5.42k
        if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
  Branch (73:13): [True: 2.57k, False: 2.85k]
74
2.57k
            const int64_t nCoinTime{Assert(block.GetAncestor(std::max(nCoinHeight - 1, 0)))->GetMedianTimePast()};
75
            // NOTE: Subtract 1 to maintain nLockTime semantics
76
            // BIP 68 relative lock times have the semantics of calculating
77
            // the first block or time at which the transaction would be
78
            // valid. When calculating the effective block time or height
79
            // for the entire transaction, we switch to using the
80
            // semantics of nLockTime which is the last invalid block
81
            // time or height.  Thus we subtract 1 from the calculated
82
            // time or height.
83
84
            // Time-based relative lock-times are measured from the
85
            // smallest allowed timestamp of the block containing the
86
            // txout being spent, which is the median time past of the
87
            // block prior.
88
2.57k
            nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);
89
2.85k
        } else {
90
2.85k
            nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);
91
2.85k
        }
92
5.42k
    }
93
94
636k
    return std::make_pair(nMinHeight, nMinTime);
95
664k
}
96
97
bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair)
98
783k
{
99
783k
    assert(block.pprev);
  Branch (99:5): [True: 783k, False: 0]
100
783k
    int64_t nBlockTime = block.pprev->GetMedianTimePast();
101
783k
    if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)
  Branch (101:9): [True: 2.83k, False: 780k]
  Branch (101:44): [True: 2.55k, False: 778k]
102
5.38k
        return false;
103
104
778k
    return true;
105
783k
}
106
107
bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>& prevHeights, const CBlockIndex& block)
108
138k
{
109
138k
    return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block));
110
138k
}
111
112
unsigned int GetLegacySigOpCount(const CTransaction& tx)
113
1.77M
{
114
1.77M
    unsigned int nSigOps = 0;
115
1.77M
    for (const auto& txin : tx.vin)
  Branch (115:27): [True: 1.91M, False: 1.77M]
116
1.91M
    {
117
1.91M
        nSigOps += txin.scriptSig.GetSigOpCount(false);
118
1.91M
    }
119
1.77M
    for (const auto& txout : tx.vout)
  Branch (119:28): [True: 2.52M, False: 1.77M]
120
2.52M
    {
121
2.52M
        nSigOps += txout.scriptPubKey.GetSigOpCount(false);
122
2.52M
    }
123
1.77M
    return nSigOps;
124
1.77M
}
125
126
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
127
658k
{
128
658k
    if (tx.IsCoinBase())
  Branch (128:9): [True: 0, False: 658k]
129
0
        return 0;
130
131
658k
    unsigned int nSigOps = 0;
132
1.36M
    for (unsigned int i = 0; i < tx.vin.size(); i++)
  Branch (132:30): [True: 708k, False: 658k]
133
708k
    {
134
708k
        const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
135
708k
        assert(!coin.IsSpent());
  Branch (135:9): [True: 708k, False: 0]
136
708k
        const CTxOut &prevout = coin.out;
137
708k
        if (prevout.scriptPubKey.IsPayToScriptHash())
  Branch (137:13): [True: 6.64k, False: 701k]
138
6.64k
            nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
139
708k
    }
140
658k
    return nSigOps;
141
658k
}
142
143
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags)
144
712k
{
145
712k
    int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;
146
147
712k
    if (tx.IsCoinBase())
  Branch (147:9): [True: 53.9k, False: 658k]
148
53.9k
        return nSigOps;
149
150
658k
    if (flags & SCRIPT_VERIFY_P2SH) {
  Branch (150:9): [True: 658k, False: 0]
151
658k
        nSigOps += GetP2SHSigOpCount(tx, inputs) * WITNESS_SCALE_FACTOR;
152
658k
    }
153
154
1.36M
    for (unsigned int i = 0; i < tx.vin.size(); i++)
  Branch (154:30): [True: 708k, False: 658k]
155
708k
    {
156
708k
        const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
157
708k
        assert(!coin.IsSpent());
  Branch (157:9): [True: 708k, False: 0]
158
708k
        const CTxOut &prevout = coin.out;
159
708k
        nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, tx.vin[i].scriptWitness, flags);
160
708k
    }
161
658k
    return nSigOps;
162
658k
}
163
164
bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
165
14.9M
{
166
    // are the actual inputs available?
167
14.9M
    if (!inputs.HaveInputs(tx)) {
  Branch (167:9): [True: 8.93k, False: 14.9M]
168
8.93k
        return state.Invalid(TxValidationResult::TX_MISSING_INPUTS, "bad-txns-inputs-missingorspent",
169
8.93k
                         strprintf("%s: inputs missing/spent", __func__));
170
8.93k
    }
171
172
14.9M
    CAmount nValueIn = 0;
173
30.1M
    for (unsigned int i = 0; i < tx.vin.size(); ++i) {
  Branch (173:30): [True: 15.2M, False: 14.9M]
174
15.2M
        const COutPoint &prevout = tx.vin[i].prevout;
175
15.2M
        const Coin& coin = inputs.AccessCoin(prevout);
176
15.2M
        assert(!coin.IsSpent());
  Branch (176:9): [True: 15.2M, False: 0]
177
178
        // If prev is coinbase, check that it's matured
179
15.2M
        if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
  Branch (179:13): [True: 1.91M, False: 13.3M]
  Branch (179:34): [True: 65, False: 1.91M]
180
65
            return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-coinbase",
181
65
                strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
182
65
        }
183
184
        // Check for negative or overflow input values
185
15.2M
        nValueIn += coin.out.nValue;
186
15.2M
        if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
  Branch (186:13): [True: 0, False: 15.2M]
  Branch (186:45): [True: 0, False: 15.2M]
187
0
            return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputvalues-outofrange");
188
0
        }
189
15.2M
    }
190
191
    // `tx.GetValueOut()` won't throw in validation paths because output-range checks run first
192
    // (`bad-txns-vout-negative`, `bad-txns-vout-toolarge`, `bad-txns-txouttotal-toolarge`):
193
    // * `MemPoolAccept::PreChecks`: `CheckTransaction()` is called before this method;
194
    // * `Chainstate::ConnectBlock`: `CheckTransaction()` is called via `CheckBlock()` before this method.
195
14.9M
    const CAmount value_out = tx.GetValueOut();
196
14.9M
    if (nValueIn < value_out) {
  Branch (196:9): [True: 0, False: 14.9M]
197
0
        return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-in-belowout",
198
0
            strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
199
0
    }
200
201
    // Tally transaction fees
202
14.9M
    const CAmount txfee_aux = nValueIn - value_out;
203
14.9M
    if (!MoneyRange(txfee_aux)) {
  Branch (203:9): [True: 0, False: 14.9M]
204
        // Unreachable, given the following preconditions:
205
        // * `value_out` comes from `tx.GetValueOut()`, which throws unless `MoneyRange(value_out)` and asserts `MoneyRange(nValueOut)` on return.
206
        // * `MoneyRange(nValueIn)` was enforced in the input loop.
207
        // * `nValueIn < value_out` was handled above, so `nValueIn >= value_out` here (and `txfee_aux >= 0`).
208
        // Therefore `0 <= txfee_aux = nValueIn - value_out <= nValueIn <= MAX_MONEY`.
209
0
        return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange");
210
0
    }
211
212
14.9M
    txfee = txfee_aux;
213
14.9M
    return true;
214
14.9M
}