Skip to content

Commit fa92813

Browse files
author
MarcoFalke
committed
consensus: Explain why fCheckDuplicateInputs can not be skipped and remove it
1 parent d53828c commit fa92813

File tree

4 files changed

+13
-18
lines changed

4 files changed

+13
-18
lines changed

src/consensus/tx_check.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include <primitives/transaction.h>
88
#include <consensus/validation.h>
99

10-
bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs)
10+
bool CheckTransaction(const CTransaction& tx, CValidationState& state)
1111
{
1212
// Basic checks that don't depend on any context
1313
if (tx.vin.empty())
@@ -31,14 +31,15 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
3131
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-txouttotal-toolarge");
3232
}
3333

34-
// Check for duplicate inputs - note that this check is slow so we skip it in CheckBlock
35-
if (fCheckDuplicateInputs) {
36-
std::set<COutPoint> vInOutPoints;
37-
for (const auto& txin : tx.vin)
38-
{
39-
if (!vInOutPoints.insert(txin.prevout).second)
40-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputs-duplicate");
41-
}
34+
// Check for duplicate inputs (see CVE-2018-17144)
35+
// While Consensus::CheckTxInputs does check if all inputs of a tx are available, and UpdateCoins marks all inputs
36+
// of a tx as spent, it does not check if the tx has duplicate inputs.
37+
// Failure to run this check will result in either a crash or an inflation bug, depending on the implementation of
38+
// the underlying coins database.
39+
std::set<COutPoint> vInOutPoints;
40+
for (const auto& txin : tx.vin) {
41+
if (!vInOutPoints.insert(txin.prevout).second)
42+
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputs-duplicate");
4243
}
4344

4445
if (tx.IsCoinBase())

src/consensus/tx_check.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@
1515
class CTransaction;
1616
class CValidationState;
1717

18-
bool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fCheckDuplicateInputs=true);
18+
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
1919

2020
#endif // BITCOIN_CONSENSUS_TX_CHECK_H

src/test/fuzz/transaction.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
4343
}
4444

4545
CValidationState state_with_dupe_check;
46-
const bool valid_with_dupe_check = CheckTransaction(tx, state_with_dupe_check, /* fCheckDuplicateInputs= */ true);
47-
CValidationState state_without_dupe_check;
48-
const bool valid_without_dupe_check = CheckTransaction(tx, state_without_dupe_check, /* fCheckDuplicateInputs= */ false);
49-
if (valid_with_dupe_check) {
50-
assert(valid_without_dupe_check);
51-
}
46+
(void)CheckTransaction(tx, state_with_dupe_check);
5247

5348
const CFeeRate dust_relay_fee{DUST_RELAY_TX_FEE};
5449
std::string reason;

src/validation.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3301,9 +3301,8 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
33013301
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-multiple", "more than one coinbase");
33023302

33033303
// Check transactions
3304-
// Must check for duplicate inputs (see CVE-2018-17144)
33053304
for (const auto& tx : block.vtx)
3306-
if (!CheckTransaction(*tx, state, true))
3305+
if (!CheckTransaction(*tx, state))
33073306
return state.Invalid(state.GetReason(), false, state.GetRejectReason(),
33083307
strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));
33093308

0 commit comments

Comments
 (0)