Changeset View
Changeset View
Standalone View
Standalone View
src/script/scriptcache.h
// Copyright (c) 2017 - The Bitcoin Developers | // Copyright (c) 2017 - The Bitcoin Developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#ifndef BITCOIN_SCRIPT_SCRIPTCACHE_H | #ifndef BITCOIN_SCRIPT_SCRIPTCACHE_H | ||||
#define BITCOIN_SCRIPT_SCRIPTCACHE_H | #define BITCOIN_SCRIPT_SCRIPTCACHE_H | ||||
#include <uint256.h> | #include <script/script_metrics.h> | ||||
#include <array> | |||||
#include <cstdint> | #include <cstdint> | ||||
class CTransaction; | class CTransaction; | ||||
/** | |||||
* The script cache is a map using a key/value element, that caches the | |||||
* success of executing a specific transaction's input scripts under a | |||||
* specific set of flags, along with any associated information learned | |||||
* during execution. | |||||
* | |||||
* The key is slightly shorter than a power-of-two size to make room for | |||||
* the value. | |||||
*/ | |||||
class ScriptCacheKey { | |||||
std::array<uint8_t, 30> data; | |||||
public: | |||||
ScriptCacheKey() = default; | |||||
ScriptCacheKey(const ScriptCacheKey &rhs) = default; | |||||
ScriptCacheKey(const CTransaction &tx, uint32_t flags); | |||||
bool operator==(const ScriptCacheKey &rhs) const { | |||||
return rhs.data == data; | |||||
} | |||||
friend class ScriptCacheHasher; | |||||
}; | |||||
// DoS prevention: limit cache size to 32MB (over 1000000 entries on 64-bit | // DoS prevention: limit cache size to 32MB (over 1000000 entries on 64-bit | ||||
// systems). Due to how we count cache size, actual memory usage is slightly | // systems). Due to how we count cache size, actual memory usage is slightly | ||||
// more (~32.25 MB) | // more (~32.25 MB) | ||||
static const unsigned int DEFAULT_MAX_SCRIPT_CACHE_SIZE = 32; | static const unsigned int DEFAULT_MAX_SCRIPT_CACHE_SIZE = 32; | ||||
// Maximum sig cache size allowed | // Maximum sig cache size allowed | ||||
static const int64_t MAX_MAX_SCRIPT_CACHE_SIZE = 16384; | static const int64_t MAX_MAX_SCRIPT_CACHE_SIZE = 16384; | ||||
/** Initializes the script-execution cache */ | /** Initializes the script-execution cache */ | ||||
void InitScriptExecutionCache(); | void InitScriptExecutionCache(); | ||||
/** Compute the cache key for a given transaction and flags. */ | /** | ||||
uint256 GetScriptCacheKey(const CTransaction &tx, uint32_t flags); | * Check if a given key is in the cache, and if so, return its values. | ||||
* (if not found, metricsOut may or may not be set to an arbitrary value) | |||||
/** Check if a given key is in the cache. */ | */ | ||||
bool IsKeyInScriptCache(uint256 key, bool erase); | bool IsKeyInScriptCache(ScriptCacheKey key, bool erase, | ||||
ScriptExecutionMetrics &metricsOut); | |||||
/** Add an entry in the cache. */ | |||||
void AddKeyInScriptCache(uint256 key); | constexpr int SCRIPT_CACHE_MAX_SIGCHECKS = UINT16_MAX; | ||||
/** | |||||
* Try to store a given key with values in the cache. Due to limited storage | |||||
* bits, the cache can only store values in certain ranges: | |||||
* | |||||
* 0 <= metricsIn.nSigChecks <= SCRIPT_CACHE_MAX_SIGCHECKS | |||||
* | |||||
* If any value is out of range, this will return false rather than storing this | |||||
* item into the cache. Otherwise it returns true. | |||||
*/ | |||||
bool TryAddKeyInScriptCache(ScriptCacheKey key, ScriptExecutionMetrics metrics); | |||||
/** | |||||
* Add an entry in the cache. | |||||
*/ | |||||
static inline void AddKeyInScriptCache(ScriptCacheKey key, | |||||
ScriptExecutionMetrics metrics) { | |||||
if (!TryAddKeyInScriptCache(key, metrics)) { | |||||
throw std::range_error("metrics out of range"); | |||||
} | |||||
} | |||||
#endif // BITCOIN_SCRIPT_SCRIPTCACHE_H | #endif // BITCOIN_SCRIPT_SCRIPTCACHE_H |