// 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 "serverchecker.h" #include "script/cc.h" #include "cc/eval.h" #include "pubkey.h" #include "random.h" #include "uint256.h" #include "util.h" #undef __cpuid #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_serverchecker; public: bool Get(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) { boost::shared_lock lock(cs_serverchecker); 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("-maxservercheckersize", 50000); if (nMaxCacheSize <= 0) return; boost::unique_lock lock(cs_serverchecker); 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 ServerTransactionSignatureChecker::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; } /* * The reason that these functions are here is that the what used to be the * CachingTransactionSignatureChecker, now the ServerTransactionSignatureChecker, * is an entry point that the server uses to validate signatures and which is not * included as part of bitcoin common libs. Since Crypto-Condtions eval methods * may call server code (GetTransaction etc), the best way to get it to run this * code without pulling the whole bitcoin server code into bitcoin common was * using this class. Thus it has been renamed to ServerTransactionSignatureChecker. */ int ServerTransactionSignatureChecker::CheckEvalCondition(const CC *cond) const { //fprintf(stderr,"call RunCCeval from ServerTransactionSignatureChecker::CheckEvalCondition\n"); return RunCCEval(cond, *txTo, nIn); }