mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-08-26 06:01:10 +02:00
script: (optimization) introduce sighash midstate caching
This commit is contained in:
@@ -1564,8 +1564,35 @@ bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, cons
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SigHashCache::CacheIndex(int32_t hash_type) const noexcept
|
||||||
|
{
|
||||||
|
// Note that we do not distinguish between BASE and WITNESS_V0 to determine the cache index,
|
||||||
|
// because no input can simultaneously use both.
|
||||||
|
return 3 * !!(hash_type & SIGHASH_ANYONECANPAY) +
|
||||||
|
2 * ((hash_type & 0x1f) == SIGHASH_SINGLE) +
|
||||||
|
1 * ((hash_type & 0x1f) == SIGHASH_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SigHashCache::Load(int32_t hash_type, const CScript& script_code, HashWriter& writer) const noexcept
|
||||||
|
{
|
||||||
|
auto& entry = m_cache_entries[CacheIndex(hash_type)];
|
||||||
|
if (entry.has_value()) {
|
||||||
|
if (script_code == entry->first) {
|
||||||
|
writer = HashWriter(entry->second);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SigHashCache::Store(int32_t hash_type, const CScript& script_code, const HashWriter& writer) noexcept
|
||||||
|
{
|
||||||
|
auto& entry = m_cache_entries[CacheIndex(hash_type)];
|
||||||
|
entry.emplace(script_code, writer);
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int32_t nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
|
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int32_t nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache, SigHashCache* sighash_cache)
|
||||||
{
|
{
|
||||||
assert(nIn < txTo.vin.size());
|
assert(nIn < txTo.vin.size());
|
||||||
|
|
||||||
@@ -1581,6 +1608,13 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
|
|||||||
|
|
||||||
HashWriter ss{};
|
HashWriter ss{};
|
||||||
|
|
||||||
|
// Try to compute using cached SHA256 midstate.
|
||||||
|
if (sighash_cache && sighash_cache->Load(nHashType, scriptCode, ss)) {
|
||||||
|
// Add sighash type and hash.
|
||||||
|
ss << nHashType;
|
||||||
|
return ss.GetHash();
|
||||||
|
}
|
||||||
|
|
||||||
if (sigversion == SigVersion::WITNESS_V0) {
|
if (sigversion == SigVersion::WITNESS_V0) {
|
||||||
uint256 hashPrevouts;
|
uint256 hashPrevouts;
|
||||||
uint256 hashSequence;
|
uint256 hashSequence;
|
||||||
@@ -1627,6 +1661,11 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
|
|||||||
ss << txTmp;
|
ss << txTmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a cache object was provided, store the midstate there.
|
||||||
|
if (sighash_cache != nullptr) {
|
||||||
|
sighash_cache->Store(nHashType, scriptCode, ss);
|
||||||
|
}
|
||||||
|
|
||||||
// Add sighash type and hash.
|
// Add sighash type and hash.
|
||||||
ss << nHashType;
|
ss << nHashType;
|
||||||
return ss.GetHash();
|
return ss.GetHash();
|
||||||
@@ -1661,7 +1700,7 @@ bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vecto
|
|||||||
// Witness sighashes need the amount.
|
// Witness sighashes need the amount.
|
||||||
if (sigversion == SigVersion::WITNESS_V0 && amount < 0) return HandleMissingData(m_mdb);
|
if (sigversion == SigVersion::WITNESS_V0 && amount < 0) return HandleMissingData(m_mdb);
|
||||||
|
|
||||||
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
|
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata, &m_sighash_cache);
|
||||||
|
|
||||||
if (!VerifyECDSASignature(vchSig, pubkey, sighash))
|
if (!VerifyECDSASignature(vchSig, pubkey, sighash))
|
||||||
return false;
|
return false;
|
||||||
|
@@ -239,8 +239,27 @@ extern const HashWriter HASHER_TAPSIGHASH; //!< Hasher with tag "TapSighash" pre
|
|||||||
extern const HashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it.
|
extern const HashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it.
|
||||||
extern const HashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it.
|
extern const HashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it.
|
||||||
|
|
||||||
|
/** Data structure to cache SHA256 midstates for the ECDSA sighash calculations
|
||||||
|
* (bare, P2SH, P2WPKH, P2WSH). */
|
||||||
|
class SigHashCache
|
||||||
|
{
|
||||||
|
/** For each sighash mode (ALL, SINGLE, NONE, ALL|ANYONE, SINGLE|ANYONE, NONE|ANYONE),
|
||||||
|
* optionally store a scriptCode which the hash is for, plus a midstate for the SHA256
|
||||||
|
* computation just before adding the hash_type itself. */
|
||||||
|
std::optional<std::pair<CScript, HashWriter>> m_cache_entries[6];
|
||||||
|
|
||||||
|
/** Given a hash_type, find which of the 6 cache entries is to be used. */
|
||||||
|
int CacheIndex(int32_t hash_type) const noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Load into writer the SHA256 midstate if found in this cache. */
|
||||||
|
[[nodiscard]] bool Load(int32_t hash_type, const CScript& script_code, HashWriter& writer) const noexcept;
|
||||||
|
/** Store into this cache object the provided SHA256 midstate. */
|
||||||
|
void Store(int32_t hash_type, const CScript& script_code, const HashWriter& writer) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int32_t nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
|
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int32_t nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr, SigHashCache* sighash_cache = nullptr);
|
||||||
|
|
||||||
class BaseSignatureChecker
|
class BaseSignatureChecker
|
||||||
{
|
{
|
||||||
@@ -289,6 +308,7 @@ private:
|
|||||||
unsigned int nIn;
|
unsigned int nIn;
|
||||||
const CAmount amount;
|
const CAmount amount;
|
||||||
const PrecomputedTransactionData* txdata;
|
const PrecomputedTransactionData* txdata;
|
||||||
|
mutable SigHashCache m_sighash_cache;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
virtual bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||||
|
Reference in New Issue
Block a user