Coverage Report

Created: 2026-08-05 14:35

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