Changeset View
Changeset View
Standalone View
Standalone View
src/consensus/tx_check.cpp
Show First 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | bool CheckRegularTransaction(const CTransaction &tx, CValidationState &state) { | ||||
std::unordered_set<COutPoint, SaltedOutpointHasher> vInOutPoints; | std::unordered_set<COutPoint, SaltedOutpointHasher> vInOutPoints; | ||||
for (const auto &txin : tx.vin) { | for (const auto &txin : tx.vin) { | ||||
if (txin.prevout.IsNull()) { | if (txin.prevout.IsNull()) { | ||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, | return state.Invalid(ValidationInvalidReason::CONSENSUS, false, | ||||
REJECT_INVALID, "bad-txns-prevout-null"); | REJECT_INVALID, "bad-txns-prevout-null"); | ||||
} | } | ||||
// Check for duplicate inputs (see CVE-2018-17144) | |||||
// While Consensus::CheckTxInputs does check if all inputs of a tx are | |||||
// available, and UpdateCoins marks all inputs of a tx as spent, it does | |||||
// not check if the tx has duplicate inputs. Failure to run this check | |||||
// will result in either a crash or an inflation bug, depending on the | |||||
// implementation of the underlying coins database. | |||||
if (!vInOutPoints.insert(txin.prevout).second) { | if (!vInOutPoints.insert(txin.prevout).second) { | ||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, | return state.Invalid(ValidationInvalidReason::CONSENSUS, false, | ||||
REJECT_INVALID, "bad-txns-inputs-duplicate"); | REJECT_INVALID, "bad-txns-inputs-duplicate"); | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } |