Mercurial > hg > bitcoin
changeset 1778:67d2dbff4c26 draft
Only store transactions with missing inputs in the orphan pool.
All previous versions of bitcoin could store some types of
invalid transactions in the orphan-transaction list.
author | Gavin Andresen <gavinandresen@gmail.com> |
---|---|
date | Wed, 18 Jan 2012 13:36:44 -0500 |
parents | addcc9fb01f5 |
children | bd04dd07d875 dbaa16606437 |
files | src/main.cpp src/main.h |
diffstat | 2 files changed, 22 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/src/main.cpp +++ b/src/main.cpp @@ -492,8 +492,11 @@ { MapPrevTx mapInputs; map<uint256, CTxIndex> mapUnused; - if (!FetchInputs(txdb, mapUnused, false, false, mapInputs)) + bool fInvalid = false; + if (!FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid)) { + if (fInvalid) + return error("AcceptToMemoryPool() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str()); if (pfMissingInputs) *pfMissingInputs = true; return error("AcceptToMemoryPool() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str()); @@ -546,8 +549,6 @@ // This is done last to help prevent CPU exhaustion denial-of-service attacks. if (!ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false)) { - if (pfMissingInputs) - *pfMissingInputs = true; return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str()); } } @@ -923,8 +924,14 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTestPool, - bool fBlock, bool fMiner, MapPrevTx& inputsRet) + bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid) { + // FetchInputs can return false either because we just haven't seen some inputs + // (in which case the transaction should be stored as an orphan) + // or because the transaction is malformed (in which case the transaction should + // be dropped). If tx is definitely invalid, fInvalid will be set to true. + fInvalid = false; + if (IsCoinBase()) return true; // Coinbase transactions have no inputs to fetch. @@ -980,7 +987,12 @@ const CTxIndex& txindex = inputsRet[prevout.hash].first; const CTransaction& txPrev = inputsRet[prevout.hash].second; if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size()) + { + // Revisit this if/when transaction replacement is implemented and allows + // adding inputs: + fInvalid = true; return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str())); + } } return true; @@ -1203,7 +1215,8 @@ MapPrevTx mapInputs; if (!tx.IsCoinBase()) { - if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs)) + bool fInvalid; + if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs, fInvalid)) return false; int nTxOps = tx.GetSigOpCount(mapInputs); @@ -3063,7 +3076,8 @@ // because we're already processing them in order of dependency map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool); MapPrevTx mapInputs; - if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs)) + bool fInvalid; + if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs, fInvalid)) continue; int64 nFees = tx.GetValueIn(mapInputs)-tx.GetValueOut();
--- a/src/main.h +++ b/src/main.h @@ -684,10 +684,11 @@ @param[in] fBlock True if being called to add a new best-block to the chain @param[in] fMiner True if being called by CreateNewBlock @param[out] inputsRet Pointers to this transaction's inputs + @param[out] fInvalid returns true if transaction is invalid @return Returns true if all inputs are in txdb or mapTestPool */ bool FetchInputs(CTxDB& txdb, const std::map<uint256, CTxIndex>& mapTestPool, - bool fBlock, bool fMiner, MapPrevTx& inputsRet); + bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid); /** Sanity check previous transactions, then, if all checks succeed, mark them as spent by this transaction.