Remove contention on signature cache during block validation

Since block validation happens in parallel, multiple threads may be
accessing the signature cache simultaneously. To prevent contention:
* Turn the signature cache lock into a shared mutex
* Make reading from the cache only acquire a shared lock
* Let block validations not store their results in the cache
This commit is contained in:
Pieter Wuille 2012-12-08 22:49:04 +01:00
parent f9cae832e6
commit ef0f422519
3 changed files with 16 additions and 10 deletions

View File

@ -1627,6 +1627,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
int64 nBIP16SwitchTime = 1333238400; int64 nBIP16SwitchTime = 1333238400;
bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime); bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime);
unsigned int flags = SCRIPT_VERIFY_NOCACHE |
(fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE);
CBlockUndo blockundo; CBlockUndo blockundo;
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
@ -1663,7 +1666,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
nFees += tx.GetValueIn(view)-tx.GetValueOut(); nFees += tx.GetValueIn(view)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks; std::vector<CScriptCheck> vChecks;
if (!tx.CheckInputs(view, fScriptChecks, fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, nScriptCheckThreads ? &vChecks : NULL)) if (!tx.CheckInputs(view, fScriptChecks, flags, nScriptCheckThreads ? &vChecks : NULL))
return false; return false;
control.Add(vChecks); control.Add(vChecks);
} }

View File

@ -16,7 +16,7 @@ using namespace boost;
#include "sync.h" #include "sync.h"
#include "util.h" #include "util.h"
bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags);
@ -1007,7 +1007,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
bool fSuccess = (!fStrictEncodings || (IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey))); bool fSuccess = (!fStrictEncodings || (IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey)));
if (fSuccess) if (fSuccess)
fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType); fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags);
popstack(stack); popstack(stack);
popstack(stack); popstack(stack);
@ -1069,7 +1069,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
// Check signature // Check signature
bool fOk = (!fStrictEncodings || (IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey))); bool fOk = (!fStrictEncodings || (IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey)));
if (fOk) if (fOk)
fOk = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType); fOk = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags);
if (fOk) { if (fOk) {
isig++; isig++;
@ -1199,13 +1199,13 @@ private:
// sigdata_type is (signature hash, signature, public key): // sigdata_type is (signature hash, signature, public key):
typedef boost::tuple<uint256, std::vector<unsigned char>, std::vector<unsigned char> > sigdata_type; typedef boost::tuple<uint256, std::vector<unsigned char>, std::vector<unsigned char> > sigdata_type;
std::set< sigdata_type> setValid; std::set< sigdata_type> setValid;
CCriticalSection cs_sigcache; boost::shared_mutex cs_sigcache;
public: public:
bool bool
Get(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey) Get(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
{ {
LOCK(cs_sigcache); boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
sigdata_type k(hash, vchSig, pubKey); sigdata_type k(hash, vchSig, pubKey);
std::set<sigdata_type>::iterator mi = setValid.find(k); std::set<sigdata_type>::iterator mi = setValid.find(k);
@ -1223,7 +1223,7 @@ public:
int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000); int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
if (nMaxCacheSize <= 0) return; if (nMaxCacheSize <= 0) return;
LOCK(cs_sigcache); boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
while (static_cast<int64>(setValid.size()) > nMaxCacheSize) while (static_cast<int64>(setValid.size()) > nMaxCacheSize)
{ {
@ -1246,7 +1246,7 @@ public:
}; };
bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode,
const CTransaction& txTo, unsigned int nIn, int nHashType) const CTransaction& txTo, unsigned int nIn, int nHashType, int flags)
{ {
static CSignatureCache signatureCache; static CSignatureCache signatureCache;
@ -1271,7 +1271,9 @@ bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CSc
if (!key.Verify(sighash, vchSig)) if (!key.Verify(sighash, vchSig))
return false; return false;
if (!(flags & SCRIPT_VERIFY_NOCACHE))
signatureCache.Set(sighash, vchSig, vchPubKey); signatureCache.Set(sighash, vchSig, vchPubKey);
return true; return true;
} }
@ -1761,7 +1763,7 @@ static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, u
if (sigs.count(pubkey)) if (sigs.count(pubkey))
continue; // Already got a sig for this pubkey continue; // Already got a sig for this pubkey
if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0)) if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0, 0))
{ {
sigs[pubkey] = sig; sigs[pubkey] = sig;
break; break;

View File

@ -32,6 +32,7 @@ enum
SCRIPT_VERIFY_NONE = 0, SCRIPT_VERIFY_NONE = 0,
SCRIPT_VERIFY_P2SH = (1U << 0), SCRIPT_VERIFY_P2SH = (1U << 0),
SCRIPT_VERIFY_STRICTENC = (1U << 1), SCRIPT_VERIFY_STRICTENC = (1U << 1),
SCRIPT_VERIFY_NOCACHE = (1U << 2),
}; };
enum txnouttype enum txnouttype