<NME> util.h
<BEF> // Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

/**
 * Server/client environment: argument handling, config file parsing,
 * logging, thread wrappers
 */
#ifndef BITCOIN_UTIL_H
#define BITCOIN_UTIL_H
#define for_loop                for (;;)

#if defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#endif

#include "compat.h"
#include "tinyformat.h"
#include "utiltime.h"

#include <atomic>
#include <exception>
#include <map>
#include <stdint.h>
#include <string>
#include <unordered_map>
#include <vector>

#include <boost/filesystem/path.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/optional.hpp>

#include <boost/bind/bind.hpp>
// workaround for boost::placeholders namespace missing during use
namespace boost { namespace placeholders {}}
using namespace boost::placeholders;

static const bool DEFAULT_LOGTIMEMICROS = false;
static const bool DEFAULT_LOGIPS        = false;
static const bool DEFAULT_LOGTIMESTAMPS = true;

/** Signals for translation. */
class CTranslationInterface
{
public:
    /** Translate a message to the native language of the user. */
    boost::signals2::signal<std::string (const char* psz)> Translate;
};
extern bool fMasternodeMode;
extern bool fLiteMode;
extern int nWalletBackups;

extern const std::map<std::string, std::vector<std::string> >& mapMultiArgs;
extern bool fDebug;
extern bool fPrintToConsole;
extern bool fPrintToDebugLog;
extern bool fNoDebug;

extern bool fLogTimestamps;
extern bool fLogTimeMicros;
extern bool fLogIPs;
extern std::atomic<bool> fReopenDebugLog;
extern CTranslationInterface translationInterface;

/** Flag to indicate, whether the Elysium log file should be reopened. */
extern std::atomic<bool> fReopenElysiumLog;

extern const char * const BITCOIN_CONF_FILENAME;
extern const char * const BITCOIN_PID_FILENAME;

extern bool fSkipMnpayoutCheck;

/**
 * Translation function: Call Translate signal on UI interface, which returns a boost::optional result.
 * If no translation slot is registered, nothing is returned, and simply return the input.
 */
inline std::string _(const char* psz)
{
    boost::optional<std::string> rv = translationInterface.Translate(psz);
    return rv ? (*rv) : psz;
}

inline int roundint(double d)
{
    return (int)(d > 0 ? d + 0.5 : d - 0.5);
}

inline int64_t roundint64(double d)
{
    return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);
}

void SetupEnvironment();
bool SetupNetworking();

/** Return true if log accepts specified category */
bool LogAcceptCategory(const char* category);
/** Send a string to the log output */
int LogPrintStr(const std::string &str);

#define LogPrint(category, ...) do { \
    if (LogAcceptCategory((category))) { \
        LogPrintStr(tfm::format(__VA_ARGS__)); \
    } \
} while(0)

#define LogPrintf(...) do { \
    LogPrintStr(tfm::format(__VA_ARGS__)); \
} while(0)

template<typename... Args>
bool error(const char* fmt, const Args&... args)
{
    LogPrintStr("ERROR: " + tfm::format(fmt, args...) + "\n");
    return false;
}

void PrintExceptionContinue(const std::exception_ptr pex, const char* pszThread);
void ParseParameters(int argc, const char*const argv[]);
void FileCommit(FILE *file);
bool TruncateFile(FILE *file, unsigned int length);
int RaiseFileDescriptorLimit(int nMinFD);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest);
bool TryCreateDirectory(const boost::filesystem::path& p);
boost::filesystem::path GetDefaultDataDirForCoinName(const std::string &coinName);
boost::filesystem::path GetDefaultDataDir();
const boost::filesystem::path &GetDataDir(bool fNetSpecific = true);
const boost::filesystem::path &GetBackupsDir();
bool RenameDirectoriesFromZcoinToFiro();
void ClearDatadirCache();
boost::filesystem::path GetConfigFile(const std::string& confPath);
#ifndef WIN32
boost::filesystem::path GetPidFile();
void CreatePidFile(const boost::filesystem::path &path, pid_t pid);
#endif
void ReadConfigFile(const std::string& confPath);
#ifdef WIN32
boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
void OpenDebugLog();
void ShrinkDebugFile();
void runCommand(const std::string& strCommand);

inline bool IsSwitchChar(char c)
{
#ifdef WIN32
    return c == '-' || c == '/';
#else
    return c == '-';
#endif
}

/**
 * Return true if the given argument has been manually set
 *
 * @param strArg Argument to get (e.g. "-foo")
 * @return true if the argument has been set
 */
bool IsArgSet(const std::string& strArg);

void ShrinkDebugFile();
int GetRandInt(int nMax);
uint64 GetRand(uint64 nMax);
int64 GetTime();
void SetMockTime(int64 nMockTimeIn);
int64 GetAdjustedTime();
std::string GetArg(const std::string& strArg, const std::string& strDefault);

/**
 * Return integer argument or default value
 *
 * @param strArg Argument to get (e.g. "-foo")
 * @param default (e.g. 1)
 * @return command-line argument (0 if invalid number) or default value
 */
int64_t GetArg(const std::string& strArg, int64_t nDefault);

/**
 * Return boolean argument or default value
 *
 * @param strArg Argument to get (e.g. "-foo")
 * @param default (true or false)
 * @return command-line argument or default value
 */
bool GetBoolArg(const std::string& strArg, bool fDefault);

/**
 * Return boost:optional<bool> for a specified argument
 *
 * @param strArg Argument to get (e.g. "-foo")
 * @return command-line argument or default value
 */
boost::optional<bool> GetOptBoolArg(const std::string& strArg);

/**
 * Set an argument if it doesn't already have a value
 *
 * @param strArg Argument to set (e.g. "-foo")
 * @param strValue Value (e.g. "1")
 * @return true if argument gets set, false if it already had a value
 */
bool SoftSetArg(const std::string& strArg, const std::string& strValue);

/**
 * Set a boolean argument if it doesn't already have a value
 *
 * @param strArg Argument to set (e.g. "-foo")
 * @param fValue Value (e.g. false)
 * @return true if argument gets set, false if it already had a value
 */
bool SoftSetBoolArg(const std::string& strArg, bool fValue);

// Forces a arg setting, used only in testing
void ForceSetArg(const std::string& strArg, const std::string& strValue);

/**
 * Format a string to be used as group of options in help messages
 *
 * @param message Group name (e.g. "RPC server options:")
 * @return the formatted string
 */
std::string HelpMessageGroup(const std::string& message);

/**
 * Format a string to be used as option description in help messages
 *
 * @param option Option message (e.g. "-rpcuser=<user>")
 * @param message Option description (e.g. "Username for JSON-RPC connections")
 * @return the formatted string
 */
std::string HelpMessageOpt(const std::string& option, const std::string& message);

/**
 * Return the number of physical cores available on the current system.
 * @note This does not count virtual cores, such as those provided by HyperThreading
 * when boost is newer than 1.56.
 */
int GetNumCores();
void SetThreadPriority(int nPriority);

void RenameThread(const char* name);
std::string GetThreadName();

namespace ctpl {
    class thread_pool;
}
void RenameThreadPool(ctpl::thread_pool& tp, const char* baseName);


/**
 * .. and a wrapper that just calls func once
 */
template <typename Callable> void TraceThread(const char* name,  Callable func)
{
    std::string s = strprintf("firo-%s", name);
    RenameThread(s.c_str());
    try
    {
        LogPrintf("%s thread start\n", name);
        func();
        LogPrintf("%s thread exit\n", name);
    }
    catch (const boost::thread_interrupted&)
    {
        LogPrintf("%s thread interrupt\n", name);
        throw;
    }
    catch (...) {
        PrintExceptionContinue(std::current_exception(), name);
        throw;
    }
}

std::string CopyrightHolders(const std::string& strPrefix);

#endif // BITCOIN_UTIL_H

<MSG> Merge branch 'optimize'

<DFF> @@ -164,6 +164,7 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
 void ShrinkDebugFile();
 int GetRandInt(int nMax);
 uint64 GetRand(uint64 nMax);
+uint256 GetRandHash();
 int64 GetTime();
 void SetMockTime(int64 nMockTimeIn);
 int64 GetAdjustedTime();

{'commit': 'diff --git a/src/key.cpp b/src/key.cpp\nindex dab1eed2e..4172d6be5 100644\n--- a/src/key.cpp\n+++ b/src/key.cpp\n@@ -2,8 +2,15 @@\n // Distributed under the MIT/X11 software license, see the accompanying\n // file COPYING or http://www.opensource.org/licenses/mit-license.php.\n \n-#include <openssl/ec.h>\n+#include <map>\n+\n+#include <boost/tuple/tuple.hpp>\n #include <openssl/ecdsa.h>\n+#include <openssl/obj_mac.h>\n+\n+#include "key.h"\n+#include "sync.h"\n+#include "util.h"\n \n // Generate a private key from just the secret parameter\n int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)\n@@ -115,3 +122,326 @@ err:\n     if (Q != NULL) EC_POINT_free(Q);\n     return ret;\n }\n+\n+void CKey::SetCompressedPubKey()\n+{\n+    EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);\n+    fCompressedPubKey = true;\n+}\n+\n+void CKey::Reset()\n+{\n+    fCompressedPubKey = false;\n+    pkey = EC_KEY_new_by_curve_name(NID_secp256k1);\n+    if (pkey == NULL)\n+        throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");\n+    fSet = false;\n+}\n+\n+CKey::CKey()\n+{\n+    Reset();\n+}\n+\n+CKey::CKey(const CKey& b)\n+{\n+    pkey = EC_KEY_dup(b.pkey);\n+    if (pkey == NULL)\n+        throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");\n+    fSet = b.fSet;\n+}\n+\n+CKey& CKey::operator=(const CKey& b)\n+{\n+    if (!EC_KEY_copy(pkey, b.pkey))\n+        throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");\n+    fSet = b.fSet;\n+    return (*this);\n+}\n+\n+CKey::~CKey()\n+{\n+    EC_KEY_free(pkey);\n+}\n+\n+bool CKey::IsNull() const\n+{\n+    return !fSet;\n+}\n+\n+bool CKey::IsCompressed() const\n+{\n+    return fCompressedPubKey;\n+}\n+\n+void CKey::MakeNewKey(bool fCompressed)\n+{\n+    if (!EC_KEY_generate_key(pkey))\n+        throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");\n+    if (fCompressed)\n+        SetCompressedPubKey();\n+    fSet = true;\n+}\n+\n+bool CKey::SetPrivKey(const CPrivKey& vchPrivKey)\n+{\n+    const unsigned char* pbegin = &vchPrivKey[0];\n+    if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))\n+        return false;\n+    fSet = true;\n+    return true;\n+}\n+\n+bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed)\n+{\n+    EC_KEY_free(pkey);\n+    pkey = EC_KEY_new_by_curve_name(NID_secp256k1);\n+    if (pkey == NULL)\n+        throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");\n+    if (vchSecret.size() != 32)\n+        throw key_error("CKey::SetSecret() : secret must be 32 bytes");\n+    BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());\n+    if (bn == NULL)\n+        throw key_error("CKey::SetSecret() : BN_bin2bn failed");\n+    if (!EC_KEY_regenerate_key(pkey,bn))\n+    {\n+        BN_clear_free(bn);\n+        throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");\n+    }\n+    BN_clear_free(bn);\n+    fSet = true;\n+    if (fCompressed || fCompressedPubKey)\n+        SetCompressedPubKey();\n+    return true;\n+}\n+\n+CSecret CKey::GetSecret(bool &fCompressed) const\n+{\n+    CSecret vchRet;\n+    vchRet.resize(32);\n+    const BIGNUM *bn = EC_KEY_get0_private_key(pkey);\n+    int nBytes = BN_num_bytes(bn);\n+    if (bn == NULL)\n+        throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");\n+    int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);\n+    if (n != nBytes)\n+        throw key_error("CKey::GetSecret(): BN_bn2bin failed");\n+    fCompressed = fCompressedPubKey;\n+    return vchRet;\n+}\n+\n+CPrivKey CKey::GetPrivKey() const\n+{\n+    int nSize = i2d_ECPrivateKey(pkey, NULL);\n+    if (!nSize)\n+        throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");\n+    CPrivKey vchPrivKey(nSize, 0);\n+    unsigned char* pbegin = &vchPrivKey[0];\n+    if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)\n+        throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");\n+    return vchPrivKey;\n+}\n+\n+bool CKey::SetPubKey(const std::vector<unsigned char>& vchPubKey)\n+{\n+    const unsigned char* pbegin = &vchPubKey[0];\n+    if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))\n+        return false;\n+    fSet = true;\n+    if (vchPubKey.size() == 33)\n+        SetCompressedPubKey();\n+    return true;\n+}\n+\n+std::vector<unsigned char> CKey::GetPubKey() const\n+{\n+    int nSize = i2o_ECPublicKey(pkey, NULL);\n+    if (!nSize)\n+        throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");\n+    std::vector<unsigned char> vchPubKey(nSize, 0);\n+    unsigned char* pbegin = &vchPubKey[0];\n+    if (i2o_ECPublicKey(pkey, &pbegin) != nSize)\n+        throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");\n+    return vchPubKey;\n+}\n+\n+bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)\n+{\n+    unsigned int nSize = ECDSA_size(pkey);\n+    vchSig.resize(nSize); // Make sure it is big enough\n+    if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))\n+    {\n+        vchSig.clear();\n+        return false;\n+    }\n+    vchSig.resize(nSize); // Shrink to fit actual size\n+    return true;\n+}\n+\n+// create a compact signature (65 bytes), which allows reconstructing the used public key\n+// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.\n+// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,\n+//                  0x1D = second key with even y, 0x1E = second key with odd y\n+bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)\n+{\n+    bool fOk = false;\n+    ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);\n+    if (sig==NULL)\n+        return false;\n+    vchSig.clear();\n+    vchSig.resize(65,0);\n+    int nBitsR = BN_num_bits(sig->r);\n+    int nBitsS = BN_num_bits(sig->s);\n+    if (nBitsR <= 256 && nBitsS <= 256)\n+    {\n+        int nRecId = -1;\n+        for (int i=0; i<4; i++)\n+        {\n+            CKey keyRec;\n+            keyRec.fSet = true;\n+            if (fCompressedPubKey)\n+                keyRec.SetCompressedPubKey();\n+            if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)\n+                if (keyRec.GetPubKey() == this->GetPubKey())\n+                {\n+                    nRecId = i;\n+                    break;\n+                }\n+        }\n+\n+        if (nRecId == -1)\n+            throw key_error("CKey::SignCompact() : unable to construct recoverable key");\n+\n+        vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);\n+        BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);\n+        BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);\n+        fOk = true;\n+    }\n+    ECDSA_SIG_free(sig);\n+    return fOk;\n+}\n+\n+// reconstruct public key from a compact signature\n+// This is only slightly more CPU intensive than just verifying it.\n+// If this function succeeds, the recovered public key is guaranteed to be valid\n+// (the signature is a valid signature of the given data for that key)\n+bool CKey::SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)\n+{\n+    if (vchSig.size() != 65)\n+        return false;\n+    int nV = vchSig[0];\n+    if (nV<27 || nV>=35)\n+        return false;\n+    ECDSA_SIG *sig = ECDSA_SIG_new();\n+    BN_bin2bn(&vchSig[1],32,sig->r);\n+    BN_bin2bn(&vchSig[33],32,sig->s);\n+\n+    EC_KEY_free(pkey);\n+    pkey = EC_KEY_new_by_curve_name(NID_secp256k1);\n+    if (nV >= 31)\n+    {\n+        SetCompressedPubKey();\n+        nV -= 4;\n+    }\n+    if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)\n+    {\n+        fSet = true;\n+        ECDSA_SIG_free(sig);\n+        return true;\n+    }\n+    return false;\n+}\n+\n+// Valid signature cache, to avoid doing expensive ECDSA signature checking\n+// twice for every transaction (once when accepted into memory pool, and\n+// again when accepted into the block chain)\n+\n+// sigdata_type is (signature hash, signature, public key):\n+typedef boost::tuple<uint256, std::vector<unsigned char>, std::vector<unsigned char> > sigdata_type;\n+static std::set< sigdata_type> setValidSigCache;\n+static CCriticalSection cs_sigcache;\n+\n+static bool\n+GetValidSigCache(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)\n+{\n+    LOCK(cs_sigcache);\n+\n+    sigdata_type k(hash, vchSig, pubKey);\n+    std::set<sigdata_type>::iterator mi = setValidSigCache.find(k);\n+    if (mi != setValidSigCache.end())\n+        return true;\n+    return false;\n+}\n+\n+static void\n+SetValidSigCache(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)\n+{\n+    // DoS prevention: limit cache size to less than 10MB\n+    // (~200 bytes per cache entry times 50,000 entries)\n+    // Since there are a maximum of 20,000 signature operations per block\n+    // 50,000 is a reasonable default.\n+    int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000);\n+    if (nMaxCacheSize <= 0) return;\n+\n+    LOCK(cs_sigcache);\n+\n+    while (setValidSigCache.size() > nMaxCacheSize)\n+    {\n+        // Evict a random entry. Random because that helps\n+        // foil would-be DoS attackers who might try to pre-generate\n+        // and re-use a set of valid signatures just-slightly-greater\n+        // than our cache size.\n+        uint256 randomHash = GetRandHash();\n+        std::vector<unsigned char> unused;\n+        std::set<sigdata_type>::iterator it =\n+            setValidSigCache.lower_bound(sigdata_type(randomHash, unused, unused));\n+        if (it == setValidSigCache.end())\n+            it = setValidSigCache.begin();\n+        setValidSigCache.erase(*it);\n+    }\n+\n+    sigdata_type k(hash, vchSig, pubKey);\n+    setValidSigCache.insert(k);\n+}\n+\n+\n+bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig)\n+{\n+    if (GetValidSigCache(hash, vchSig, GetPubKey()))\n+        return true;\n+\n+    // -1 = error, 0 = bad sig, 1 = good\n+    if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)\n+        return false;\n+\n+    // good sig\n+    SetValidSigCache(hash, vchSig, GetPubKey());\n+    return true;\n+}\n+\n+bool CKey::VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)\n+{\n+    if (GetValidSigCache(hash, vchSig, GetPubKey()))\n+        return true;\n+\n+    CKey key;\n+    if (!key.SetCompactSignature(hash, vchSig))\n+        return false;\n+    if (GetPubKey() != key.GetPubKey())\n+        return false;\n+\n+    SetValidSigCache(hash, vchSig, GetPubKey());\n+    return true;\n+}\n+\n+bool CKey::IsValid()\n+{\n+    if (!fSet)\n+        return false;\n+\n+    bool fCompr;\n+    CSecret secret = GetSecret(fCompr);\n+    CKey key2;\n+    key2.SetSecret(secret, fCompr);\n+    return GetPubKey() == key2.GetPubKey();\n+}\ndiff --git a/src/key.h b/src/key.h\nindex f687f334c..bd58c8437 100644\n--- a/src/key.h\n+++ b/src/key.h\n@@ -8,13 +8,11 @@\n #include <stdexcept>\n #include <vector>\n \n-#include <openssl/ec.h>\n-#include <openssl/ecdsa.h>\n-#include <openssl/obj_mac.h>\n-\n #include "allocators.h"\n #include "uint256.h"\n \n+#include <openssl/ec.h> // for EC_KEY definition\n+\n // secp160k1\n // const unsigned int PRIVATE_KEY_SIZE = 192;\n // const unsigned int PUBLIC_KEY_SIZE  = 41;\n@@ -38,9 +36,6 @@\n // see www.keylength.com\n // script supports up to 75 for single byte push\n \n-int extern EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key);\n-int extern ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check);\n-\n class key_error : public std::runtime_error\n {\n public:\n@@ -62,267 +57,50 @@ protected:\n     bool fSet;\n     bool fCompressedPubKey;\n \n-    void SetCompressedPubKey()\n-    {\n-        EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);\n-        fCompressedPubKey = true;\n-    }\n+    void SetCompressedPubKey();\n \n public:\n \n-    void Reset()\n-    {\n-        fCompressedPubKey = false;\n-        pkey = EC_KEY_new_by_curve_name(NID_secp256k1);\n-        if (pkey == NULL)\n-            throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");\n-        fSet = false;\n-    }\n-\n-    CKey()\n-    {\n-        Reset();\n-    }\n-\n-    CKey(const CKey& b)\n-    {\n-        pkey = EC_KEY_dup(b.pkey);\n-        if (pkey == NULL)\n-            throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");\n-        fSet = b.fSet;\n-    }\n-\n-    CKey& operator=(const CKey& b)\n-    {\n-        if (!EC_KEY_copy(pkey, b.pkey))\n-            throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");\n-        fSet = b.fSet;\n-        return (*this);\n-    }\n-\n-    ~CKey()\n-    {\n-        EC_KEY_free(pkey);\n-    }\n-\n-    bool IsNull() const\n-    {\n-        return !fSet;\n-    }\n+    void Reset();\n \n-    bool IsCompressed() const\n-    {\n-        return fCompressedPubKey;\n-    }\n+    CKey();\n+    CKey(const CKey& b);\n \n-    void MakeNewKey(bool fCompressed)\n-    {\n-        if (!EC_KEY_generate_key(pkey))\n-            throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");\n-        if (fCompressed)\n-            SetCompressedPubKey();\n-        fSet = true;\n-    }\n+    CKey& operator=(const CKey& b);\n \n-    bool SetPrivKey(const CPrivKey& vchPrivKey)\n-    {\n-        const unsigned char* pbegin = &vchPrivKey[0];\n-        if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))\n-            return false;\n-        fSet = true;\n-        return true;\n-    }\n+    ~CKey();\n \n-    bool SetSecret(const CSecret& vchSecret, bool fCompressed = false)\n-    {\n-        EC_KEY_free(pkey);\n-        pkey = EC_KEY_new_by_curve_name(NID_secp256k1);\n-        if (pkey == NULL)\n-            throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");\n-        if (vchSecret.size() != 32)\n-            throw key_error("CKey::SetSecret() : secret must be 32 bytes");\n-        BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());\n-        if (bn == NULL)\n-            throw key_error("CKey::SetSecret() : BN_bin2bn failed");\n-        if (!EC_KEY_regenerate_key(pkey,bn))\n-        {\n-            BN_clear_free(bn);\n-            throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");\n-        }\n-        BN_clear_free(bn);\n-        fSet = true;\n-        if (fCompressed || fCompressedPubKey)\n-            SetCompressedPubKey();\n-        return true;\n-    }\n+    bool IsNull() const;\n+    bool IsCompressed() const;\n \n-    CSecret GetSecret(bool &fCompressed) const\n-    {\n-        CSecret vchRet;\n-        vchRet.resize(32);\n-        const BIGNUM *bn = EC_KEY_get0_private_key(pkey);\n-        int nBytes = BN_num_bytes(bn);\n-        if (bn == NULL)\n-            throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");\n-        int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);\n-        if (n != nBytes) \n-            throw key_error("CKey::GetSecret(): BN_bn2bin failed");\n-        fCompressed = fCompressedPubKey;\n-        return vchRet;\n-    }\n+    void MakeNewKey(bool fCompressed);\n+    bool SetPrivKey(const CPrivKey& vchPrivKey);\n+    bool SetSecret(const CSecret& vchSecret, bool fCompressed = false);\n+    CSecret GetSecret(bool &fCompressed) const;\n+    CPrivKey GetPrivKey() const;\n+    bool SetPubKey(const std::vector<unsigned char>& vchPubKey);\n+    std::vector<unsigned char> GetPubKey() const;\n \n-    CPrivKey GetPrivKey() const\n-    {\n-        int nSize = i2d_ECPrivateKey(pkey, NULL);\n-        if (!nSize)\n-            throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");\n-        CPrivKey vchPrivKey(nSize, 0);\n-        unsigned char* pbegin = &vchPrivKey[0];\n-        if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)\n-            throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");\n-        return vchPrivKey;\n-    }\n-\n-    bool SetPubKey(const std::vector<unsigned char>& vchPubKey)\n-    {\n-        const unsigned char* pbegin = &vchPubKey[0];\n-        if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))\n-            return false;\n-        fSet = true;\n-        if (vchPubKey.size() == 33)\n-            SetCompressedPubKey();\n-        return true;\n-    }\n-\n-    std::vector<unsigned char> GetPubKey() const\n-    {\n-        int nSize = i2o_ECPublicKey(pkey, NULL);\n-        if (!nSize)\n-            throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");\n-        std::vector<unsigned char> vchPubKey(nSize, 0);\n-        unsigned char* pbegin = &vchPubKey[0];\n-        if (i2o_ECPublicKey(pkey, &pbegin) != nSize)\n-            throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");\n-        return vchPubKey;\n-    }\n-\n-    bool Sign(uint256 hash, std::vector<unsigned char>& vchSig)\n-    {\n-        unsigned int nSize = ECDSA_size(pkey);\n-        vchSig.resize(nSize); // Make sure it is big enough\n-        if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))\n-        {\n-            vchSig.clear();\n-            return false;\n-        }\n-        vchSig.resize(nSize); // Shrink to fit actual size\n-        return true;\n-    }\n+    bool Sign(uint256 hash, std::vector<unsigned char>& vchSig);\n \n     // create a compact signature (65 bytes), which allows reconstructing the used public key\n     // The format is one header byte, followed by two times 32 bytes for the serialized r and s values.\n     // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,\n     //                  0x1D = second key with even y, 0x1E = second key with odd y\n-    bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)\n-    {\n-        bool fOk = false;\n-        ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);\n-        if (sig==NULL)\n-            return false;\n-        vchSig.clear();\n-        vchSig.resize(65,0);\n-        int nBitsR = BN_num_bits(sig->r);\n-        int nBitsS = BN_num_bits(sig->s);\n-        if (nBitsR <= 256 && nBitsS <= 256)\n-        {\n-            int nRecId = -1;\n-            for (int i=0; i<4; i++)\n-            {\n-                CKey keyRec;\n-                keyRec.fSet = true;\n-                if (fCompressedPubKey)\n-                    keyRec.SetCompressedPubKey();\n-                if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)\n-                    if (keyRec.GetPubKey() == this->GetPubKey())\n-                    {\n-                        nRecId = i;\n-                        break;\n-                    }\n-            }\n-\n-            if (nRecId == -1)\n-                throw key_error("CKey::SignCompact() : unable to construct recoverable key");\n-\n-            vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);\n-            BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);\n-            BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);\n-            fOk = true;\n-        }\n-        ECDSA_SIG_free(sig);\n-        return fOk;\n-    }\n+    bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig);\n \n     // reconstruct public key from a compact signature\n     // This is only slightly more CPU intensive than just verifying it.\n     // If this function succeeds, the recovered public key is guaranteed to be valid\n     // (the signature is a valid signature of the given data for that key)\n-    bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)\n-    {\n-        if (vchSig.size() != 65)\n-            return false;\n-        int nV = vchSig[0];\n-        if (nV<27 || nV>=35)\n-            return false;\n-        ECDSA_SIG *sig = ECDSA_SIG_new();\n-        BN_bin2bn(&vchSig[1],32,sig->r);\n-        BN_bin2bn(&vchSig[33],32,sig->s);\n-\n-        EC_KEY_free(pkey);\n-        pkey = EC_KEY_new_by_curve_name(NID_secp256k1);\n-        if (nV >= 31)\n-        {\n-            SetCompressedPubKey();\n-            nV -= 4;\n-        }\n-        if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)\n-        {\n-            fSet = true;\n-            ECDSA_SIG_free(sig);\n-            return true;\n-        }\n-        return false;\n-    }\n+    bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig);\n \n-    bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig)\n-    {\n-        // -1 = error, 0 = bad sig, 1 = good\n-        if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)\n-            return false;\n-        return true;\n-    }\n+    bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig);\n \n     // Verify a compact signature\n-    bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)\n-    {\n-        CKey key;\n-        if (!key.SetCompactSignature(hash, vchSig))\n-            return false;\n-        if (GetPubKey() != key.GetPubKey())\n-            return false;\n-        return true;\n-    }\n-\n-    bool IsValid()\n-    {\n-        if (!fSet)\n-            return false;\n+    bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig);\n \n-        bool fCompr;\n-        CSecret secret = GetSecret(fCompr);\n-        CKey key2;\n-        key2.SetSecret(secret, fCompr);\n-        return GetPubKey() == key2.GetPubKey();\n-    }\n+    bool IsValid();\n };\n \n #endif\ndiff --git a/src/main.cpp b/src/main.cpp\nindex 9b38d9efb..8900115ef 100644\n--- a/src/main.cpp\n+++ b/src/main.cpp\n@@ -44,7 +44,7 @@ map<uint256, CBlock*> mapOrphanBlocks;\n multimap<uint256, CBlock*> mapOrphanBlocksByPrev;\n \n map<uint256, CDataStream*> mapOrphanTransactions;\n-multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;\n+map<uint256, map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;\n \n // Constant stuff for coinbase transactions we create:\n CScript COINBASE_FLAGS;\n@@ -161,17 +161,37 @@ void static ResendWalletTransactions()\n // mapOrphanTransactions\n //\n \n-void AddOrphanTx(const CDataStream& vMsg)\n+bool AddOrphanTx(const CDataStream& vMsg)\n {\n     CTransaction tx;\n     CDataStream(vMsg) >> tx;\n     uint256 hash = tx.GetHash();\n     if (mapOrphanTransactions.count(hash))\n-        return;\n+        return false;\n+\n+    CDataStream* pvMsg = new CDataStream(vMsg);\n \n-    CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg);\n+    // Ignore big transactions, to avoid a\n+    // send-big-orphans memory exhaustion attack. If a peer has a legitimate\n+    // large transaction with a missing parent then we assume\n+    // it will rebroadcast it later, after the parent transaction(s)\n+    // have been mined or received.\n+    // 10,000 orphans, each of which is at most 5,000 bytes big is\n+    // at most 500 megabytes of orphans:\n+    if (pvMsg->size() > 5000)\n+    {\n+        delete pvMsg;\n+        printf("ignoring large orphan tx (size: %u, hash: %s)\\n", pvMsg->size(), hash.ToString().substr(0,10).c_str());\n+        return false;\n+    }\n+\n+    mapOrphanTransactions[hash] = pvMsg;\n     BOOST_FOREACH(const CTxIn& txin, tx.vin)\n-        mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));\n+        mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg));\n+\n+    printf("stored orphan tx %s (mapsz %u)\\n", hash.ToString().substr(0,10).c_str(),\n+        mapOrphanTransactions.size());\n+    return true;\n }\n \n void static EraseOrphanTx(uint256 hash)\n@@ -183,14 +203,9 @@ void static EraseOrphanTx(uint256 hash)\n     CDataStream(*pvMsg) >> tx;\n     BOOST_FOREACH(const CTxIn& txin, tx.vin)\n     {\n-        for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(txin.prevout.hash);\n-             mi != mapOrphanTransactionsByPrev.upper_bound(txin.prevout.hash);)\n-        {\n-            if ((*mi).second == pvMsg)\n-                mapOrphanTransactionsByPrev.erase(mi++);\n-            else\n-                mi++;\n-        }\n+        mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash);\n+        if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty())\n+            mapOrphanTransactionsByPrev.erase(txin.prevout.hash);\n     }\n     delete pvMsg;\n     mapOrphanTransactions.erase(hash);\n@@ -202,9 +217,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)\n     while (mapOrphanTransactions.size() > nMaxOrphans)\n     {\n         // Evict a random orphan:\n-        std::vector<unsigned char> randbytes(32);\n-        RAND_bytes(&randbytes[0], 32);\n-        uint256 randomhash(randbytes);\n+        uint256 randomhash = GetRandHash();\n         map<uint256, CDataStream*>::iterator it = mapOrphanTransactions.lower_bound(randomhash);\n         if (it == mapOrphanTransactions.end())\n             it = mapOrphanTransactions.begin();\n@@ -1155,17 +1168,28 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs,\n                     if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)\n                         return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);\n \n+            // Check for negative or overflow input values\n+            nValueIn += txPrev.vout[prevout.n].nValue;\n+            if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))\n+                return DoS(100, error("ConnectInputs() : txin values out of range"));\n+\n+        }\n+        // The first loop above does all the inexpensive checks.\n+        // Only if ALL inputs pass do we perform expensive ECDSA signature checks.\n+        // Helps prevent CPU exhaustion attacks.\n+        for (unsigned int i = 0; i < vin.size(); i++)\n+        {\n+            COutPoint prevout = vin[i].prevout;\n+            assert(inputs.count(prevout.hash) > 0);\n+            CTxIndex& txindex = inputs[prevout.hash].first;\n+            CTransaction& txPrev = inputs[prevout.hash].second;\n+\n             // Check for conflicts (double-spend)\n             // This doesn\'t trigger the DoS code on purpose; if it did, it would make it easier\n             // for an attacker to attempt to split the network.\n             if (!txindex.vSpent[prevout.n].IsNull())\n                 return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str());\n \n-            // Check for negative or overflow input values\n-            nValueIn += txPrev.vout[prevout.n].nValue;\n-            if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))\n-                return DoS(100, error("ConnectInputs() : txin values out of range"));\n-\n             // Skip ECDSA signature verification when connecting blocks (fBlock=true)\n             // before the last blockchain checkpoint. This is safe because block merkle hashes are\n             // still computed and checked, and any change will be caught at the next checkpoint.\n@@ -2460,7 +2484,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)\n                     // at a time so the setAddrKnowns of the chosen nodes prevent repeats\n                     static uint256 hashSalt;\n                     if (hashSalt == 0)\n-                        RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));\n+                        hashSalt = GetRandHash();\n                     int64 hashAddr = addr.GetHash();\n                     uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));\n                     hashRand = Hash(BEGIN(hashRand), END(hashRand));\n@@ -2676,6 +2700,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)\n     else if (strCommand == "tx")\n     {\n         vector<uint256> vWorkQueue;\n+        vector<uint256> vEraseQueue;\n         CDataStream vMsg(vRecv);\n         CTxDB txdb("r");\n         CTransaction tx;\n@@ -2691,32 +2716,41 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)\n             RelayMessage(inv, vMsg);\n             mapAlreadyAskedFor.erase(inv);\n             vWorkQueue.push_back(inv.hash);\n+            vEraseQueue.push_back(inv.hash);\n \n             // Recursively process any orphan transactions that depended on this one\n             for (unsigned int i = 0; i < vWorkQueue.size(); i++)\n             {\n                 uint256 hashPrev = vWorkQueue[i];\n-                for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev);\n-                     mi != mapOrphanTransactionsByPrev.upper_bound(hashPrev);\n+                for (map<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin();\n+                     mi != mapOrphanTransactionsByPrev[hashPrev].end();\n                      ++mi)\n                 {\n                     const CDataStream& vMsg = *((*mi).second);\n                     CTransaction tx;\n                     CDataStream(vMsg) >> tx;\n                     CInv inv(MSG_TX, tx.GetHash());\n+                    bool fMissingInputs2 = false;\n \n-                    if (tx.AcceptToMemoryPool(txdb, true))\n+                    if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs2))\n                     {\n                         printf("   accepted orphan tx %s\\n", inv.hash.ToString().substr(0,10).c_str());\n                         SyncWithWallets(tx, NULL, true);\n                         RelayMessage(inv, vMsg);\n                         mapAlreadyAskedFor.erase(inv);\n                         vWorkQueue.push_back(inv.hash);\n+                        vEraseQueue.push_back(inv.hash);\n+                    }\n+                    else if (!fMissingInputs2)\n+                    {\n+                        // invalid orphan\n+                        vEraseQueue.push_back(inv.hash);\n+                        printf("   removed invalid orphan tx %s\\n", inv.hash.ToString().substr(0,10).c_str());\n                     }\n                 }\n             }\n \n-            BOOST_FOREACH(uint256 hash, vWorkQueue)\n+            BOOST_FOREACH(uint256 hash, vEraseQueue)\n                 EraseOrphanTx(hash);\n         }\n         else if (fMissingInputs)\n@@ -3072,7 +3106,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)\n                     // 1/4 of tx invs blast to all immediately\n                     static uint256 hashSalt;\n                     if (hashSalt == 0)\n-                        RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));\n+                        hashSalt = GetRandHash();\n                     uint256 hashRand = inv.hash ^ hashSalt;\n                     hashRand = Hash(BEGIN(hashRand), END(hashRand));\n                     bool fTrickleWait = ((hashRand & 3) != 0);\ndiff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp\nindex 04e2a95d7..7defd23f8 100644\n--- a/src/test/DoS_tests.cpp\n+++ b/src/test/DoS_tests.cpp\n@@ -1,7 +1,10 @@\n //\n // Unit tests for denial-of-service detection/prevention code\n //\n+#include <algorithm>\n+\n #include <boost/assign/list_of.hpp> // for \'map_list_of()\'\n+#include <boost/date_time/posix_time/posix_time_types.hpp>\n #include <boost/test/unit_test.hpp>\n #include <boost/foreach.hpp>\n \n@@ -13,10 +16,10 @@\n #include <stdint.h>\n \n // Tests this internal-to-main.cpp method:\n-extern void AddOrphanTx(const CDataStream& vMsg);\n+extern bool AddOrphanTx(const CDataStream& vMsg);\n extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);\n extern std::map<uint256, CDataStream*> mapOrphanTransactions;\n-extern std::multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;\n+extern std::map<uint256, std::map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;\n \n CService ip(uint32_t i)\n {\n@@ -57,7 +60,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)\n     BOOST_CHECK(!CNode::IsBanned(addr1));\n     dummyNode1.Misbehaving(1);\n     BOOST_CHECK(CNode::IsBanned(addr1));\n-    mapArgs["-banscore"] = "100";\n+    mapArgs.erase("-banscore");\n }\n \n BOOST_AUTO_TEST_CASE(DoS_bantime)\n@@ -129,18 +132,10 @@ BOOST_AUTO_TEST_CASE(DoS_checknbits)\n     \n }\n \n-static uint256 RandomHash()\n-{\n-    std::vector<unsigned char> randbytes(32);\n-    RAND_bytes(&randbytes[0], 32);\n-    uint256 randomhash(randbytes);\n-    return randomhash;\n-}\n-\n CTransaction RandomOrphan()\n {\n     std::map<uint256, CDataStream*>::iterator it;\n-    it = mapOrphanTransactions.lower_bound(RandomHash());\n+    it = mapOrphanTransactions.lower_bound(GetRandHash());\n     if (it == mapOrphanTransactions.end())\n         it = mapOrphanTransactions.begin();\n     const CDataStream* pvMsg = it->second;\n@@ -162,7 +157,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)\n         CTransaction tx;\n         tx.vin.resize(1);\n         tx.vin[0].prevout.n = 0;\n-        tx.vin[0].prevout.hash = RandomHash();\n+        tx.vin[0].prevout.hash = GetRandHash();\n         tx.vin[0].scriptSig << OP_1;\n         tx.vout.resize(1);\n         tx.vout[0].nValue = 1*CENT;\n@@ -192,6 +187,32 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)\n         AddOrphanTx(ds);\n     }\n \n+    // This really-big orphan should be ignored:\n+    for (int i = 0; i < 10; i++)\n+    {\n+        CTransaction txPrev = RandomOrphan();\n+\n+        CTransaction tx;\n+        tx.vout.resize(1);\n+        tx.vout[0].nValue = 1*CENT;\n+        tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());\n+        tx.vin.resize(500);\n+        for (int j = 0; j < tx.vin.size(); j++)\n+        {\n+            tx.vin[j].prevout.n = j;\n+            tx.vin[j].prevout.hash = txPrev.GetHash();\n+        }\n+        SignSignature(keystore, txPrev, tx, 0);\n+        // Re-use same signature for other inputs\n+        // (they don\'t have to be valid for this test)\n+        for (int j = 1; j < tx.vin.size(); j++)\n+            tx.vin[j].scriptSig = tx.vin[0].scriptSig;\n+\n+        CDataStream ds(SER_DISK, CLIENT_VERSION);\n+        ds << tx;\n+        BOOST_CHECK(!AddOrphanTx(ds));\n+    }\n+\n     // Test LimitOrphanTxSize() function:\n     LimitOrphanTxSize(40);\n     BOOST_CHECK(mapOrphanTransactions.size() <= 40);\n@@ -202,4 +223,92 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)\n     BOOST_CHECK(mapOrphanTransactionsByPrev.empty());\n }\n \n+BOOST_AUTO_TEST_CASE(DoS_checkSig)\n+{\n+    // Test signature caching code (see key.cpp Verify() methods)\n+\n+    CKey key;\n+    key.MakeNewKey(true);\n+    CBasicKeyStore keystore;\n+    keystore.AddKey(key);\n+\n+    // 100 orphan transactions:\n+    static const int NPREV=100;\n+    CTransaction orphans[NPREV];\n+    for (int i = 0; i < NPREV; i++)\n+    {\n+        CTransaction& tx = orphans[i];\n+        tx.vin.resize(1);\n+        tx.vin[0].prevout.n = 0;\n+        tx.vin[0].prevout.hash = GetRandHash();\n+        tx.vin[0].scriptSig << OP_1;\n+        tx.vout.resize(1);\n+        tx.vout[0].nValue = 1*CENT;\n+        tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());\n+\n+        CDataStream ds(SER_DISK, CLIENT_VERSION);\n+        ds << tx;\n+        AddOrphanTx(ds);\n+    }\n+\n+    // Create a transaction that depends on orphans:\n+    CTransaction tx;\n+    tx.vout.resize(1);\n+    tx.vout[0].nValue = 1*CENT;\n+    tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());\n+    tx.vin.resize(NPREV);\n+    for (int j = 0; j < tx.vin.size(); j++)\n+    {\n+        tx.vin[j].prevout.n = 0;\n+        tx.vin[j].prevout.hash = orphans[j].GetHash();\n+    }\n+    // Creating signatures primes the cache:\n+    boost::posix_time::ptime mst1 = boost::posix_time::microsec_clock::local_time();\n+    for (int j = 0; j < tx.vin.size(); j++)\n+        BOOST_CHECK(SignSignature(keystore, orphans[j], tx, j));\n+    boost::posix_time::ptime mst2 = boost::posix_time::microsec_clock::local_time();\n+    boost::posix_time::time_duration msdiff = mst2 - mst1;\n+    long nOneValidate = msdiff.total_milliseconds();\n+    if (fDebug) printf("DoS_Checksig sign: %ld\\n", nOneValidate);\n+\n+    // ... now validating repeatedly should be quick:\n+    // 2.8GHz machine, -g build: Sign takes ~760ms,\n+    // uncached Verify takes ~250ms, cached Verify takes ~50ms\n+    // (for 100 single-signature inputs)\n+    mst1 = boost::posix_time::microsec_clock::local_time();\n+    for (int i = 0; i < 5; i++)\n+        for (int j = 0; j < tx.vin.size(); j++)\n+            BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));\n+    mst2 = boost::posix_time::microsec_clock::local_time();\n+    msdiff = mst2 - mst1;\n+    long nManyValidate = msdiff.total_milliseconds();\n+    if (fDebug) printf("DoS_Checksig five: %ld\\n", nManyValidate);\n+\n+    BOOST_CHECK_MESSAGE(nManyValidate < nOneValidate, "Signature cache timing failed");\n+\n+    // Empty a signature, validation should fail:\n+    CScript save = tx.vin[0].scriptSig;\n+    tx.vin[0].scriptSig = CScript();\n+    BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));\n+    tx.vin[0].scriptSig = save;\n+\n+    // Swap signatures, validation should fail:\n+    std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);\n+    BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));\n+    BOOST_CHECK(!VerifySignature(orphans[1], tx, 1, true, SIGHASH_ALL));\n+    std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);\n+\n+    // Exercise -maxsigcachesize code:\n+    mapArgs["-maxsigcachesize"] = "10";\n+    // Generate a new, different signature for vin[0] to trigger cache clear:\n+    CScript oldSig = tx.vin[0].scriptSig;\n+    BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0));\n+    BOOST_CHECK(tx.vin[0].scriptSig != oldSig);\n+    for (int j = 0; j < tx.vin.size(); j++)\n+        BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));\n+    mapArgs.erase("-maxsigcachesize");\n+\n+    LimitOrphanTxSize(0);\n+}\n+\n BOOST_AUTO_TEST_SUITE_END()\ndiff --git a/src/util.cpp b/src/util.cpp\nindex 9e7a8c034..08e3625b3 100644\n--- a/src/util.cpp\n+++ b/src/util.cpp\n@@ -176,6 +176,12 @@ int GetRandInt(int nMax)\n     return GetRand(nMax);\n }\n \n+uint256 GetRandHash()\n+{\n+    uint256 hash;\n+    RAND_bytes((unsigned char*)&hash, sizeof(hash));\n+    return hash;\n+}\n \n \n \ndiff --git a/src/util.h b/src/util.h\nindex 47065d842..5b58147ce 100644\n--- a/src/util.h\n+++ b/src/util.h\n@@ -164,6 +164,7 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);\n void ShrinkDebugFile();\n int GetRandInt(int nMax);\n uint64 GetRand(uint64 nMax);\n+uint256 GetRandHash();\n int64 GetTime();\n void SetMockTime(int64 nMockTimeIn);\n int64 GetAdjustedTime();\n', 'commit_subject': "Merge branch 'optimize'", 'repo_name': 'zcoinofficial/zcoin', 'committer': {'name': 'Gavin Andresen', 'email': '19a45ba432ebf68c5c553ec17ef341bff6a9e1b9@gmail.com', 'time_sec': '1337699580', 'tz_offset': '-240', 'date': {'seconds': '1337699580'}}, 'commit_tree': '7ae2c230153ba3f844122c2045f5db8a14560fd7', 'commit_message': "Merge branch 'optimize'\n", 'language_name': 'Java', 'license': 'mit', 'hunks': '@@ -164,6 +164,7 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);\n void ShrinkDebugFile();\n int GetRandInt(int nMax);\n uint64 GetRand(uint64 nMax);\n+uint256 GetRandHash();\n int64 GetTime();\n void SetMockTime(int64 nMockTimeIn);\n int64 GetAdjustedTime();\n', 'addition_count': 1, 'deletion_count': 0, 'src_file': 'a/src/util.h', 'tgt_file': 'b/src/util.h', 'file_extension': '.h', 'before_file': '// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n/**\n * Server/client environment: argument handling, config file parsing,\n * logging, thread wrappers\n */\n#ifndef BITCOIN_UTIL_H\n#define BITCOIN_UTIL_H\n#define for_loop                for (;;)\n\n#if defined(HAVE_CONFIG_H)\n#include "config/bitcoin-config.h"\n#endif\n\n#include "compat.h"\n#include "tinyformat.h"\n#include "utiltime.h"\n\n#include <atomic>\n#include <exception>\n#include <map>\n#include <stdint.h>\n#include <string>\n#include <unordered_map>\n#include <vector>\n\n#include <boost/filesystem/path.hpp>\n#include <boost/signals2/signal.hpp>\n#include <boost/thread/exceptions.hpp>\n#include <boost/optional.hpp>\n\n#include <boost/bind/bind.hpp>\n// workaround for boost::placeholders namespace missing during use\nnamespace boost { namespace placeholders {}}\nusing namespace boost::placeholders;\n\nstatic const bool DEFAULT_LOGTIMEMICROS = false;\nstatic const bool DEFAULT_LOGIPS        = false;\nstatic const bool DEFAULT_LOGTIMESTAMPS = true;\n\n/** Signals for translation. */\nclass CTranslationInterface\n{\npublic:\n    /** Translate a message to the native language of the user. */\n    boost::signals2::signal<std::string (const char* psz)> Translate;\n};\nextern bool fMasternodeMode;\nextern bool fLiteMode;\nextern int nWalletBackups;\n\nextern const std::map<std::string, std::vector<std::string> >& mapMultiArgs;\nextern bool fDebug;\nextern bool fPrintToConsole;\nextern bool fPrintToDebugLog;\nextern bool fNoDebug;\n\nextern bool fLogTimestamps;\nextern bool fLogTimeMicros;\nextern bool fLogIPs;\nextern std::atomic<bool> fReopenDebugLog;\nextern CTranslationInterface translationInterface;\n\n/** Flag to indicate, whether the Elysium log file should be reopened. */\nextern std::atomic<bool> fReopenElysiumLog;\n\nextern const char * const BITCOIN_CONF_FILENAME;\nextern const char * const BITCOIN_PID_FILENAME;\n\nextern bool fSkipMnpayoutCheck;\n\n/**\n * Translation function: Call Translate signal on UI interface, which returns a boost::optional result.\n * If no translation slot is registered, nothing is returned, and simply return the input.\n */\ninline std::string _(const char* psz)\n{\n    boost::optional<std::string> rv = translationInterface.Translate(psz);\n    return rv ? (*rv) : psz;\n}\n\ninline int roundint(double d)\n{\n    return (int)(d > 0 ? d + 0.5 : d - 0.5);\n}\n\ninline int64_t roundint64(double d)\n{\n    return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);\n}\n\nvoid SetupEnvironment();\nbool SetupNetworking();\n\n/** Return true if log accepts specified category */\nbool LogAcceptCategory(const char* category);\n/** Send a string to the log output */\nint LogPrintStr(const std::string &str);\n\n#define LogPrint(category, ...) do { \\\n    if (LogAcceptCategory((category))) { \\\n        LogPrintStr(tfm::format(__VA_ARGS__)); \\\n    } \\\n} while(0)\n\n#define LogPrintf(...) do { \\\n    LogPrintStr(tfm::format(__VA_ARGS__)); \\\n} while(0)\n\ntemplate<typename... Args>\nbool error(const char* fmt, const Args&... args)\n{\n    LogPrintStr("ERROR: " + tfm::format(fmt, args...) + "\\n");\n    return false;\n}\n\nvoid PrintExceptionContinue(const std::exception_ptr pex, const char* pszThread);\nvoid ParseParameters(int argc, const char*const argv[]);\nvoid FileCommit(FILE *file);\nbool TruncateFile(FILE *file, unsigned int length);\nint RaiseFileDescriptorLimit(int nMinFD);\nvoid AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);\nbool RenameOver(boost::filesystem::path src, boost::filesystem::path dest);\nbool TryCreateDirectory(const boost::filesystem::path& p);\nboost::filesystem::path GetDefaultDataDirForCoinName(const std::string &coinName);\nboost::filesystem::path GetDefaultDataDir();\nconst boost::filesystem::path &GetDataDir(bool fNetSpecific = true);\nconst boost::filesystem::path &GetBackupsDir();\nbool RenameDirectoriesFromZcoinToFiro();\nvoid ClearDatadirCache();\nboost::filesystem::path GetConfigFile(const std::string& confPath);\n#ifndef WIN32\nboost::filesystem::path GetPidFile();\nvoid CreatePidFile(const boost::filesystem::path &path, pid_t pid);\n#endif\nvoid ReadConfigFile(const std::string& confPath);\n#ifdef WIN32\nboost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);\n#endif\nvoid OpenDebugLog();\nvoid ShrinkDebugFile();\nvoid runCommand(const std::string& strCommand);\n\ninline bool IsSwitchChar(char c)\n{\n#ifdef WIN32\n    return c == \'-\' || c == \'/\';\n#else\n    return c == \'-\';\n#endif\n}\n\n/**\n * Return true if the given argument has been manually set\n *\n * @param strArg Argument to get (e.g. "-foo")\n * @return true if the argument has been set\n */\nbool IsArgSet(const std::string& strArg);\n\nvoid ShrinkDebugFile();\nint GetRandInt(int nMax);\nuint64 GetRand(uint64 nMax);\nint64 GetTime();\nvoid SetMockTime(int64 nMockTimeIn);\nint64 GetAdjustedTime();\nstd::string GetArg(const std::string& strArg, const std::string& strDefault);\n\n/**\n * Return integer argument or default value\n *\n * @param strArg Argument to get (e.g. "-foo")\n * @param default (e.g. 1)\n * @return command-line argument (0 if invalid number) or default value\n */\nint64_t GetArg(const std::string& strArg, int64_t nDefault);\n\n/**\n * Return boolean argument or default value\n *\n * @param strArg Argument to get (e.g. "-foo")\n * @param default (true or false)\n * @return command-line argument or default value\n */\nbool GetBoolArg(const std::string& strArg, bool fDefault);\n\n/**\n * Return boost:optional<bool> for a specified argument\n *\n * @param strArg Argument to get (e.g. "-foo")\n * @return command-line argument or default value\n */\nboost::optional<bool> GetOptBoolArg(const std::string& strArg);\n\n/**\n * Set an argument if it doesn\'t already have a value\n *\n * @param strArg Argument to set (e.g. "-foo")\n * @param strValue Value (e.g. "1")\n * @return true if argument gets set, false if it already had a value\n */\nbool SoftSetArg(const std::string& strArg, const std::string& strValue);\n\n/**\n * Set a boolean argument if it doesn\'t already have a value\n *\n * @param strArg Argument to set (e.g. "-foo")\n * @param fValue Value (e.g. false)\n * @return true if argument gets set, false if it already had a value\n */\nbool SoftSetBoolArg(const std::string& strArg, bool fValue);\n\n// Forces a arg setting, used only in testing\nvoid ForceSetArg(const std::string& strArg, const std::string& strValue);\n\n/**\n * Format a string to be used as group of options in help messages\n *\n * @param message Group name (e.g. "RPC server options:")\n * @return the formatted string\n */\nstd::string HelpMessageGroup(const std::string& message);\n\n/**\n * Format a string to be used as option description in help messages\n *\n * @param option Option message (e.g. "-rpcuser=<user>")\n * @param message Option description (e.g. "Username for JSON-RPC connections")\n * @return the formatted string\n */\nstd::string HelpMessageOpt(const std::string& option, const std::string& message);\n\n/**\n * Return the number of physical cores available on the current system.\n * @note This does not count virtual cores, such as those provided by HyperThreading\n * when boost is newer than 1.56.\n */\nint GetNumCores();\nvoid SetThreadPriority(int nPriority);\n\nvoid RenameThread(const char* name);\nstd::string GetThreadName();\n\nnamespace ctpl {\n    class thread_pool;\n}\nvoid RenameThreadPool(ctpl::thread_pool& tp, const char* baseName);\n\n\n/**\n * .. and a wrapper that just calls func once\n */\ntemplate <typename Callable> void TraceThread(const char* name,  Callable func)\n{\n    std::string s = strprintf("firo-%s", name);\n    RenameThread(s.c_str());\n    try\n    {\n        LogPrintf("%s thread start\\n", name);\n        func();\n        LogPrintf("%s thread exit\\n", name);\n    }\n    catch (const boost::thread_interrupted&)\n    {\n        LogPrintf("%s thread interrupt\\n", name);\n        throw;\n    }\n    catch (...) {\n        PrintExceptionContinue(std::current_exception(), name);\n        throw;\n    }\n}\n\nstd::string CopyrightHolders(const std::string& strPrefix);\n\n#endif // BITCOIN_UTIL_H\n', 'message': "Merge branch 'optimize'\n", 'author_name': 'Gavin Andresen', 'lang': 'h'}