diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2012-12-08 22:49:04 +0100 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2013-01-08 02:00:59 +0100 |
commit | ef0f422519de4a3ce47d923e5f8f90cd12349f3e (patch) | |
tree | ba208bc61340c76ceba465a05afe1391ea217086 /src | |
parent | f9cae832e6f56c6abe89b3bf05d1f176c2a7c913 (diff) |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/main.cpp | 5 | ||||
-rw-r--r-- | src/script.cpp | 20 | ||||
-rw-r--r-- | src/script.h | 1 |
3 files changed, 16 insertions, 10 deletions
diff --git a/src/main.cpp b/src/main.cpp index 18a1c59e14..92be0cfd38 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1627,6 +1627,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust int64 nBIP16SwitchTime = 1333238400; bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime); + unsigned int flags = SCRIPT_VERIFY_NOCACHE | + (fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE); + CBlockUndo blockundo; 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(); 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; control.Add(vChecks); } diff --git a/src/script.cpp b/src/script.cpp index 52a8f2c117..70adf1f9dc 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -16,7 +16,7 @@ using namespace boost; #include "sync.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))); if (fSuccess) - fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType); + fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags); popstack(stack); popstack(stack); @@ -1069,7 +1069,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // Check signature bool fOk = (!fStrictEncodings || (IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey))); if (fOk) - fOk = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType); + fOk = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags); if (fOk) { isig++; @@ -1199,13 +1199,13 @@ private: // sigdata_type is (signature hash, signature, public key): typedef boost::tuple<uint256, std::vector<unsigned char>, std::vector<unsigned char> > sigdata_type; std::set< sigdata_type> setValid; - CCriticalSection cs_sigcache; + boost::shared_mutex cs_sigcache; public: bool 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); std::set<sigdata_type>::iterator mi = setValid.find(k); @@ -1223,7 +1223,7 @@ public: int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000); if (nMaxCacheSize <= 0) return; - LOCK(cs_sigcache); + boost::unique_lock<boost::shared_mutex> lock(cs_sigcache); while (static_cast<int64>(setValid.size()) > nMaxCacheSize) { @@ -1246,7 +1246,7 @@ public: }; 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; @@ -1271,7 +1271,9 @@ bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CSc if (!key.Verify(sighash, vchSig)) return false; - signatureCache.Set(sighash, vchSig, vchPubKey); + if (!(flags & SCRIPT_VERIFY_NOCACHE)) + signatureCache.Set(sighash, vchSig, vchPubKey); + return true; } @@ -1761,7 +1763,7 @@ static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, u if (sigs.count(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; break; diff --git a/src/script.h b/src/script.h index f7cf7e8e9e..ae316b33c4 100644 --- a/src/script.h +++ b/src/script.h @@ -32,6 +32,7 @@ enum SCRIPT_VERIFY_NONE = 0, SCRIPT_VERIFY_P2SH = (1U << 0), SCRIPT_VERIFY_STRICTENC = (1U << 1), + SCRIPT_VERIFY_NOCACHE = (1U << 2), }; enum txnouttype |