#include "net.h"
#include "init.h"
#include "ui_interface.h"
+#include "checkqueue.h"
#include "kernel.h"
#include "zerocoin/Zerocoin.h"
#include <boost/algorithm/string/replace.hpp>
uint256 hashBestChain = 0;
CBlockIndex* pindexBest = NULL;
int64 nTimeBestReceived = 0;
+int nScriptCheckThreads = 0;
CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!tx.ConnectInputs(txdb, mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false, STANDARD_SCRIPT_VERIFY_FLAGS))
+ if (!tx.ConnectInputs(txdb, mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false, true, SIG_SWITCH_TIME < tx.nTime ? STRICT_FLAGS : SOFT_FLAGS))
{
return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
}
return nSigOps;
}
+bool CScriptCheck::operator()() const {
+ const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
+ if (!VerifyScript(scriptSig, scriptPubKey, *ptxTo, nIn, nFlags, nHashType))
+ return error("CScriptCheck() : %s VerifySignature failed", ptxTo->GetHash().ToString().substr(0,10).c_str());
+ return true;
+}
+
bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType)
{
- assert(nIn < txTo.vin.size());
- const CTxIn& txin = txTo.vin[nIn];
- if (txin.prevout.n >= txFrom.vout.size())
- return false;
- const CTxOut& txout = txFrom.vout[txin.prevout.n];
-
- if (txin.prevout.hash != txFrom.GetHash())
- return false;
-
- return VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, flags, nHashType);
+ return CScriptCheck(txFrom, txTo, nIn, flags, nHashType)();
}
bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs, map<uint256, CTxIndex>& mapTestPool, const CDiskTxPos& posThisTx,
- const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, unsigned int flags)
+ const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks)
{
// Take over previous transactions' spent pointers
// fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
// fMiner is true when called from the internal bitcoin miner
// ... both are false when called from CTransaction::AcceptToMemoryPool
- bool fScriptChecks = !(fBlock && pindexBlock->nHeight >= Checkpoints::GetTotalBlocksEstimate());
if (!IsCoinBase())
{
return DoS(100, error("ConnectInputs() : txin values out of range"));
}
+
+ if (pvChecks)
+ pvChecks->reserve(vin.size());
+
// 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.
if (fScriptChecks)
{
// Verify signature
- if (!VerifySignature(txPrev, *this, i, flags, 0))
+ CScriptCheck check(txPrev, *this, i, flags, 0);
+ if (pvChecks)
{
- if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS)
+ pvChecks->push_back(CScriptCheck());
+ check.swap(pvChecks->back());
+ }
+ else if (!check())
+ {
+ if (flags & STRICT_FLAGS)
{
- if (VerifySignature(txPrev, *this, i, flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, 0))
- return error("ConnectInputs() : %s STANDARD_NOT_MANDATORY_VERIFY_FLAGS VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
+ // Don't trigger DoS code in case of STRICT_FLAGS caused failure.
+ CScriptCheck check(txPrev, *this, i, flags & ~STRICT_FLAGS, 0);
+ if (check())
+ return error("ConnectInputs() : %s strict VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
}
- return DoS(100,error("ConnectInputs() : %s STANDARD_MANDATORY_VERIFY_FLAGS VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
+ return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
}
}
return true;
}
+static CCheckQueue<CScriptCheck> scriptcheckqueue(128);
+
+void ThreadScriptCheck(void*) {
+ vnThreadsRunning[THREAD_SCRIPTCHECK]++;
+ RenameThread("novacoin-scriptch");
+ scriptcheckqueue.Thread();
+ vnThreadsRunning[THREAD_SCRIPTCHECK]--;
+}
+
+void ThreadScriptCheckQuit() {
+ scriptcheckqueue.Quit();
+}
+
bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
{
// Check it again in case a previous version let a bad block in, but skip BlockSig checking
// two in the chain that violate it. This prevents exploiting the issue against nodes in their
// initial block download.
bool fEnforceBIP30 = true; // Always active in NovaCoin
+ bool fScriptChecks = pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate();
//// issue here: it doesn't know the version
unsigned int nTxPos;
nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - (2 * GetSizeOfCompactSize(0)) + GetSizeOfCompactSize(vtx.size());
map<uint256, CTxIndex> mapQueuedChanges;
+ CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
+
int64 nFees = 0;
int64 nValueIn = 0;
int64 nValueOut = 0;
if (!tx.IsCoinStake())
nFees += nTxValueIn - nTxValueOut;
- if (!tx.ConnectInputs(txdb, mapInputs, mapQueuedChanges, posThisTx, pindex, true, false, SCRIPT_VERIFY_NOCACHE | SCRIPT_VERIFY_P2SH))
+ std::vector<CScriptCheck> vChecks;
+ if (!tx.ConnectInputs(txdb, mapInputs, mapQueuedChanges, posThisTx, pindex, true, false, fScriptChecks, SCRIPT_VERIFY_NOCACHE | SCRIPT_VERIFY_P2SH, nScriptCheckThreads ? &vChecks : NULL))
return false;
+ control.Add(vChecks);
}
mapQueuedChanges[hashTx] = CTxIndex(posThisTx, tx.vout.size());
}
+ if (!control.Wait())
+ return DoS(100, false);
+
if (IsProofOfWork())
{
int64 nBlockReward = GetProofOfWorkReward(nBits, fProtocol048 ? nFees : 0);