// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ #include "sigcache.h" #include "pubkey.h" #include "random.h" #include "uint256.h" #include "util.h" #ifdef _WIN32 #undef __cpuid #endif #include #include namespace { /** * Valid signature cache, to avoid doing expensive ECDSA signature checking * twice for every transaction (once when accepted into memory pool, and * again when accepted into the block chain) */ class CSignatureCache { private: //! sigdata_type is (signature hash, signature, public key): typedef boost::tuple, CPubKey> sigdata_type; std::set< sigdata_type> setValid; boost::shared_mutex cs_sigcache; public: bool Get(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) { boost::shared_lock lock(cs_sigcache); sigdata_type k(hash, vchSig, pubKey); std::set::iterator mi = setValid.find(k); if (mi != setValid.end()) return true; return false; } void Set(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) { // DoS prevention: limit cache size to less than 10MB // (~200 bytes per cache entry times 50,000 entries) // Since there can be no more than 20,000 signature operations per block // 50,000 is a reasonable default. int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); if (nMaxCacheSize <= 0) return; boost::unique_lock lock(cs_sigcache); while (static_cast(setValid.size()) > nMaxCacheSize) { // Evict a random entry. Random because that helps // foil would-be DoS attackers who might try to pre-generate // and re-use a set of valid signatures just-slightly-greater // than our cache size. uint256 randomHash = GetRandHash(); std::vector unused; std::set::iterator it = setValid.lower_bound(sigdata_type(randomHash, unused, unused)); if (it == setValid.end()) it = setValid.begin(); setValid.erase(*it); } sigdata_type k(hash, vchSig, pubKey); setValid.insert(k); } }; } bool CachingTransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const { static CSignatureCache signatureCache; if (signatureCache.Get(sighash, vchSig, pubkey)) return true; if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash)) return false; if (store) signatureCache.Set(sighash, vchSig, pubkey); return true; }