diff options
author | Gavin Andresen <gavinandresen@gmail.com> | 2012-05-16 11:26:56 -0400 |
---|---|---|
committer | Gavin Andresen <gavinandresen@gmail.com> | 2012-05-18 10:41:18 -0400 |
commit | 4add41a2a6fa1229277e00e01a8b4111e7cb21d6 (patch) | |
tree | e14aa5904fa0d5597074ee80585db52ff3789612 /src/main.cpp | |
parent | 7a15109c043f8182cc996bf762f0a62c72646ff9 (diff) |
Further DoS prevention: Verify signatures last
Loop over all inputs doing inexpensive validity checks first,
and then loop over them a second time doing expensive signature
checks. This helps prevent possible CPU exhaustion attacks
where an attacker tries to make a victim waste time checking
signatures for invalid transactions.
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/src/main.cpp b/src/main.cpp index a878d1e5be..263f1e6fee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1142,17 +1142,28 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs, if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile) return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight); + // Check for negative or overflow input values + nValueIn += txPrev.vout[prevout.n].nValue; + if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) + return DoS(100, error("ConnectInputs() : txin values out of range")); + + } + // The first loop above does all the inexpensive checks. + // Only if ALL inputs pass do we perform expensive ECDSA signature checks. + // Helps prevent CPU exhaustion attacks. + for (unsigned int i = 0; i < vin.size(); i++) + { + COutPoint prevout = vin[i].prevout; + assert(inputs.count(prevout.hash) > 0); + CTxIndex& txindex = inputs[prevout.hash].first; + CTransaction& txPrev = inputs[prevout.hash].second; + // Check for conflicts (double-spend) // This doesn't trigger the DoS code on purpose; if it did, it would make it easier // for an attacker to attempt to split the network. if (!txindex.vSpent[prevout.n].IsNull()) return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str()); - // Check for negative or overflow input values - nValueIn += txPrev.vout[prevout.n].nValue; - if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) - return DoS(100, error("ConnectInputs() : txin values out of range")); - // Skip ECDSA signature verification when connecting blocks (fBlock=true) // before the last blockchain checkpoint. This is safe because block merkle hashes are // still computed and checked, and any change will be caught at the next checkpoint. |