Prevent pegin double spends from entering the mempool

This bug got introduced with the 0.17 rebase. In 0.14.1 the double pegin
claim check was done in the beginning of the validation logic, where the
coins view was the actual UTXO set. In 0.17, Core moved several checks
because the intermediate method CheckInputs was removed and some logic
moved to tx_verify.cpp, where we also put the pegin check.  In the
mempool acceptance check, however (as opposed to the ConnectBlock
check), CheckTxInputs is called with only a partial UTXO view for
optimization reasons. This commit adds an extra pegin check in the
beginning of the mempool code where we have a full UTXO view.
This commit is contained in:
Steven Roose 2019-05-07 20:14:12 +01:00
parent 50c557083d
commit af2264665e
No known key found for this signature in database
GPG key ID: 2F2A88D7F8D68E87

View file

@ -681,10 +681,27 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
}
// do all inputs exist?
for (const CTxIn& txin : tx.vin) {
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const CTxIn& txin = tx.vin[i];
// ELEMENTS:
// Don't look for coins that only exist in parent chain
// For pegin inputs check whether the pegins have already been claimed before.
// This only checks the UTXO set for already claimed pegins. For mempool conflicts,
// we rely on the GetConflictTx check done above.
if (txin.m_is_pegin) {
// Quick sanity check on witness first.
if (tx.witness.vtxinwit.size() <= i ||
tx.witness.vtxinwit[i].m_pegin_witness.stack.size() < 6 ||
uint256(tx.witness.vtxinwit[i].m_pegin_witness.stack[2]).IsNull() ||
tx.vin[i].prevout.hash.IsNull()) {
return state.Invalid(false, REJECT_INVALID, "pegin-no-witness");
}
std::pair<uint256, COutPoint> pegin = std::make_pair(uint256(tx.witness.vtxinwit[i].m_pegin_witness.stack[2]), tx.vin[i].prevout);
// This assumes non-null prevout and genesis block hash
if (view.IsPeginSpent(pegin)) {
return state.Invalid(false, REJECT_INVALID, "pegin-already-claimed");
}
continue;
}