Changeset View
Changeset View
Standalone View
Standalone View
src/script/scriptcache.cpp
Show First 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | uint32_t operator()(const ScriptCacheKey &k) const { | ||||
arr[3] = d[12] ^ d[16] ^ d[20] ^ d[24]; | arr[3] = d[12] ^ d[16] ^ d[20] ^ d[24]; | ||||
std::memcpy(&u, arr, 4); | std::memcpy(&u, arr, 4); | ||||
} | } | ||||
return u; | return u; | ||||
} | } | ||||
}; | }; | ||||
static CuckooCache::cache<ScriptCacheElement, ScriptCacheHasher> | static CuckooCache::cache<ScriptCacheElement, ScriptCacheHasher> | ||||
scriptExecutionCache; | g_scriptExecutionCache; | ||||
static uint256 scriptExecutionCacheNonce(GetRandHash()); | static CSHA256 g_scriptExecutionCacheHasher; | ||||
void InitScriptExecutionCache() { | void InitScriptExecutionCache() { | ||||
// Setup the salted hasher | |||||
uint256 nonce = GetRandHash(); | |||||
// We want the nonce to be 64 bytes long to force the hasher to process | |||||
// this chunk, which makes later hash computations more efficient. We | |||||
// just write our 32-byte entropy twice to fill the 64 bytes. | |||||
g_scriptExecutionCacheHasher.Write(nonce.begin(), 32); | |||||
g_scriptExecutionCacheHasher.Write(nonce.begin(), 32); | |||||
// nMaxCacheSize is unsigned. If -maxscriptcachesize is set to zero, | // nMaxCacheSize is unsigned. If -maxscriptcachesize is set to zero, | ||||
// setup_bytes creates the minimum possible cache (2 elements). | // setup_bytes creates the minimum possible cache (2 elements). | ||||
size_t nMaxCacheSize = | size_t nMaxCacheSize = | ||||
std::min( | std::min( | ||||
std::max(int64_t(0), gArgs.GetArg("-maxscriptcachesize", | std::max(int64_t(0), gArgs.GetArg("-maxscriptcachesize", | ||||
DEFAULT_MAX_SCRIPT_CACHE_SIZE)), | DEFAULT_MAX_SCRIPT_CACHE_SIZE)), | ||||
MAX_MAX_SCRIPT_CACHE_SIZE) * | MAX_MAX_SCRIPT_CACHE_SIZE) * | ||||
(size_t(1) << 20); | (size_t(1) << 20); | ||||
size_t nElems = scriptExecutionCache.setup_bytes(nMaxCacheSize); | size_t nElems = g_scriptExecutionCache.setup_bytes(nMaxCacheSize); | ||||
LogPrintf("Using %zu MiB out of %zu requested for script execution cache, " | LogPrintf("Using %zu MiB out of %zu requested for script execution cache, " | ||||
"able to store %zu elements\n", | "able to store %zu elements\n", | ||||
(nElems * sizeof(uint256)) >> 20, nMaxCacheSize >> 20, nElems); | (nElems * sizeof(uint256)) >> 20, nMaxCacheSize >> 20, nElems); | ||||
} | } | ||||
ScriptCacheKey::ScriptCacheKey(const CTransaction &tx, uint32_t flags) { | ScriptCacheKey::ScriptCacheKey(const CTransaction &tx, uint32_t flags) { | ||||
std::array<uint8_t, 32> hash; | std::array<uint8_t, 32> hash; | ||||
// We only use the first 19 bytes of nonce to avoid a second SHA round - | CSHA256 hasher = g_scriptExecutionCacheHasher; | ||||
// giving us 19 + 32 + 4 = 55 bytes (+ 8 + 1 = 64) | hasher.Write(tx.GetHash().begin(), 32) | ||||
static_assert(55 - sizeof(flags) - 32 >= 128 / 8, | |||||
"Want at least 128 bits of nonce for script execution cache"); | |||||
CSHA256() | |||||
.Write(scriptExecutionCacheNonce.begin(), 55 - sizeof(flags) - 32) | |||||
.Write(tx.GetHash().begin(), 32) | |||||
.Write((uint8_t *)&flags, sizeof(flags)) | .Write((uint8_t *)&flags, sizeof(flags)) | ||||
.Finalize(hash.begin()); | .Finalize(hash.begin()); | ||||
assert(data.size() < hash.size()); | assert(data.size() < hash.size()); | ||||
std::copy(hash.begin(), hash.begin() + data.size(), data.begin()); | std::copy(hash.begin(), hash.begin() + data.size(), data.begin()); | ||||
} | } | ||||
bool IsKeyInScriptCache(ScriptCacheKey key, bool erase, int &nSigChecksOut) { | bool IsKeyInScriptCache(ScriptCacheKey key, bool erase, int &nSigChecksOut) { | ||||
// TODO: Remove this requirement by making CuckooCache not require external | // TODO: Remove this requirement by making CuckooCache not require external | ||||
// locks | // locks | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
ScriptCacheElement elem(key, 0); | ScriptCacheElement elem(key, 0); | ||||
bool ret = scriptExecutionCache.get(elem, erase); | bool ret = g_scriptExecutionCache.get(elem, erase); | ||||
nSigChecksOut = elem.nSigChecks; | nSigChecksOut = elem.nSigChecks; | ||||
return ret; | return ret; | ||||
} | } | ||||
void AddKeyInScriptCache(ScriptCacheKey key, int nSigChecks) { | void AddKeyInScriptCache(ScriptCacheKey key, int nSigChecks) { | ||||
// TODO: Remove this requirement by making CuckooCache not require external | // TODO: Remove this requirement by making CuckooCache not require external | ||||
// locks | // locks | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
ScriptCacheElement elem(key, nSigChecks); | ScriptCacheElement elem(key, nSigChecks); | ||||
scriptExecutionCache.insert(elem); | g_scriptExecutionCache.insert(elem); | ||||
} | } |