Coverage Report

Created: 2026-08-14 20:23

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
280k
{
25
280k
    if (tx.nLockTime == 0)
26
106k
        return true;
27
174k
    if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
28
173k
        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
107k
{
47
107k
    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
107k
    int nMinHeight = -1;
55
107k
    int64_t nMinTime = -1;
56
57
107k
    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
107k
    if (!fEnforceBIP68) {
62
2.66k
        return std::make_pair(nMinHeight, nMinTime);
63
2.66k
    }
64
65
271k
    for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
66
165k
        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
165k
        if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {
72
            // The height of this input is not relevant for sequence locks
73
48.1k
            prevHeights[txinIndex] = 0;
74
48.1k
            continue;
75
48.1k
        }
76
77
117k
        int nCoinHeight = prevHeights[txinIndex];
78
79
117k
        if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
80
315
            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
315
            nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);
95
117k
        } else {
96
117k
            nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);
97
117k
        }
98
117k
    }
99
100
105k
    return std::make_pair(nMinHeight, nMinTime);
101
107k
}
102
103
bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair)
104
109k
{
105
109k
    assert(block.pprev);
106
109k
    int64_t nBlockTime = block.pprev->GetMedianTimePast();
107
109k
    if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)
108
396
        return false;
109
110
109k
    return true;
111
109k
}
112
113
bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>& prevHeights, const CBlockIndex& block)
114
62.7k
{
115
62.7k
    return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block));
116
62.7k
}
117
118
unsigned int GetLegacySigOpCount(const CTransaction& tx)
119
586k
{
120
586k
    unsigned int nSigOps = 0;
121
586k
    for (const auto& txin : tx.vin)
122
695k
    {
123
695k
        nSigOps += txin.scriptSig.GetSigOpCount(false);
124
695k
    }
125
586k
    for (const auto& txout : tx.vout)
126
1.44M
    {
127
1.44M
        nSigOps += txout.scriptPubKey.GetSigOpCount(false);
128
1.44M
    }
129
586k
    return nSigOps;
130
586k
}
131
132
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
133
106k
{
134
106k
    if (tx.IsCoinBase())
135
1
        return 0;
136
137
106k
    unsigned int nSigOps = 0;
138
273k
    for (unsigned int i = 0; i < tx.vin.size(); i++)
139
166k
    {
140
166k
        const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
141
166k
        assert(!coin.IsSpent());
142
166k
        const CTxOut &prevout = coin.out;
143
166k
        if (prevout.scriptPubKey.IsPayToScriptHash())
144
11.2k
            nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
145
166k
    }
146
106k
    return nSigOps;
147
106k
}
148
149
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags)
150
271k
{
151
271k
    int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;
152
153
271k
    if (tx.IsCoinBase())
154
164k
        return nSigOps;
155
156
106k
    if (flags & SCRIPT_VERIFY_P2SH) {
157
106k
        nSigOps += GetP2SHSigOpCount(tx, inputs) * WITNESS_SCALE_FACTOR;
158
106k
    }
159
160
273k
    for (unsigned int i = 0; i < tx.vin.size(); i++)
161
166k
    {
162
166k
        const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
163
166k
        assert(!coin.IsSpent());
164
166k
        const CTxOut &prevout = coin.out;
165
166k
        nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, tx.vin[i].scriptWitness, flags);
166
166k
    }
167
106k
    return nSigOps;
168
106k
}
169
170
bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
171
11.9M
{
172
    // are the actual inputs available?
173
11.9M
    if (!inputs.HaveInputs(tx)) {
174
323
        return state.Invalid(TxValidationResult::TX_MISSING_INPUTS, "bad-txns-inputs-missingorspent",
175
323
                         strprintf("%s: inputs missing/spent", __func__));
176
323
    }
177
178
11.9M
    CAmount nValueIn = 0;
179
27.4M
    for (unsigned int i = 0; i < tx.vin.size(); ++i) {
180
15.4M
        const COutPoint &prevout = tx.vin[i].prevout;
181
15.4M
        const Coin& coin = inputs.AccessCoin(prevout);
182
15.4M
        assert(!coin.IsSpent());
183
184
        // If prev is coinbase, check that it's matured
185
15.4M
        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
15.4M
        nValueIn += coin.out.nValue;
192
15.4M
        if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
193
1
            return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputvalues-outofrange");
194
1
        }
195
15.4M
    }
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.9M
    const CAmount value_out = tx.GetValueOut();
202
11.9M
    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.9M
    const CAmount txfee_aux = nValueIn - value_out;
209
11.9M
    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.9M
    txfee = txfee_aux;
219
11.9M
    return true;
220
11.9M
}