From: Gavin Andresen Date: Tue, 19 Jun 2012 20:34:10 +0000 (-0400) Subject: Merge branch '0.6.x' of git://gitorious.org/+bitcoin-stable-developers/bitcoin/bitcoi... X-Git-Tag: v0.4.0-unstable~129^2~1 X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=commitdiff_plain;h=23e7583a8c9a0dcee9cbbf3be8bfc453298773f0;hp=-c Merge branch '0.6.x' of git://gitorious.org/+bitcoin-stable-developers/bitcoin/bitcoind-stable into 0.6.3 --- 23e7583a8c9a0dcee9cbbf3be8bfc453298773f0 diff --combined bitcoin-qt.pro index 07f5a61,82d19fa..7f2a5a4 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@@ -1,8 -1,8 +1,8 @@@ TEMPLATE = app TARGET = -VERSION = 0.6.2.2 +VERSION = 0.6.3.0 INCLUDEPATH += src src/json src/qt -DEFINES += QT_GUI BOOST_THREAD_USE_LIB +DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE CONFIG += no_include_pwd # for boost 1.37, add -mt to the boost libraries @@@ -83,7 -83,7 +83,7 @@@ contains(BITCOIN_NEED_QT_PLUGINS, 1) # regenerate src/build.h !windows || contains(USE_BUILD_INFO, 1) { genbuild.depends = FORCE - genbuild.commands = cd $$PWD; share/genbuild.sh $$OUT_PWD/build/build.h + genbuild.commands = cd $$PWD; /bin/sh share/genbuild.sh $$OUT_PWD/build/build.h genbuild.target = genbuildhook PRE_TARGETDEPS += genbuildhook QMAKE_EXTRA_TARGETS += genbuild diff --combined src/checkpoints.cpp index 21d3ce7,6679bc9..67e2c4c --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@@ -1,6 -1,6 +1,6 @@@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying - // file license.txt or http://www.opensource.org/licenses/mit-license.php. + // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include // for 'map_list_of()' #include @@@ -25,11 -25,14 +25,11 @@@ namespace Checkpoint boost::assign::map_list_of ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) - ( 68555, uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a")) - ( 70567, uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a")) ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")) (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")) - (118000, uint256("0x000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553")) (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")) - (140700, uint256("0x000000000000033b512028abb90e1626d8b346fd0ed598ac0a3c371138dce2bd")) (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")) + (185333, uint256("0x00000000000002334c71b8706940c20348af897a9cfc0f1a6dab0d14d4ceb815")) ; bool CheckBlock(int nHeight, const uint256& hash) diff --combined src/db.cpp index f9151f7,2d9d552..c67a34c --- a/src/db.cpp +++ b/src/db.cpp @@@ -1,7 -1,7 +1,7 @@@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying - // file license.txt or http://www.opensource.org/licenses/mit-license.php. + // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "db.h" #include "util.h" @@@ -96,7 -96,6 +96,7 @@@ CDB::CDB(const char *pszFile, const cha dbenv.set_lk_max_locks(10000); dbenv.set_lk_max_objects(10000); dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug + dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); dbenv.set_flags(DB_AUTO_COMMIT, 1); dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); ret = dbenv.open(pathDataDir.string().c_str(), diff --combined src/db.h index dc795d2,faba824..acb531f --- a/src/db.h +++ b/src/db.h @@@ -1,7 -1,7 +1,7 @@@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying - // file license.txt or http://www.opensource.org/licenses/mit-license.php. + // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_DB_H #define BITCOIN_DB_H @@@ -221,7 -221,7 +221,7 @@@ public if (!pdb) return false; DbTxn* ptxn = NULL; - int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_NOSYNC); + int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_WRITE_NOSYNC); if (!ptxn || ret != 0) return false; vTxn.push_back(ptxn); diff --combined src/key.cpp index b6c3f28,dab1eed..18b4672 --- a/src/key.cpp +++ b/src/key.cpp @@@ -1,14 -1,9 +1,14 @@@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying - // file license.txt or http://www.opensource.org/licenses/mit-license.php. + // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include +#include + #include +#include + +#include "key.h" +#include "util.h" // Generate a private key from just the secret parameter int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) @@@ -120,264 -115,3 +120,264 @@@ err if (Q != NULL) EC_POINT_free(Q); return ret; } + +void CKey::SetCompressedPubKey() +{ + EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); + fCompressedPubKey = true; +} + +void CKey::Reset() +{ + fCompressedPubKey = false; + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (pkey == NULL) + throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed"); + fSet = false; +} + +CKey::CKey() +{ + Reset(); +} + +CKey::CKey(const CKey& b) +{ + pkey = EC_KEY_dup(b.pkey); + if (pkey == NULL) + throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed"); + fSet = b.fSet; +} + +CKey& CKey::operator=(const CKey& b) +{ + if (!EC_KEY_copy(pkey, b.pkey)) + throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed"); + fSet = b.fSet; + return (*this); +} + +CKey::~CKey() +{ + EC_KEY_free(pkey); +} + +bool CKey::IsNull() const +{ + return !fSet; +} + +bool CKey::IsCompressed() const +{ + return fCompressedPubKey; +} + +void CKey::MakeNewKey(bool fCompressed) +{ + if (!EC_KEY_generate_key(pkey)) + throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed"); + if (fCompressed) + SetCompressedPubKey(); + fSet = true; +} + +bool CKey::SetPrivKey(const CPrivKey& vchPrivKey) +{ + const unsigned char* pbegin = &vchPrivKey[0]; + if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size())) + return false; + fSet = true; + return true; +} + +bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed) +{ + EC_KEY_free(pkey); + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (pkey == NULL) + throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed"); + if (vchSecret.size() != 32) + throw key_error("CKey::SetSecret() : secret must be 32 bytes"); + BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new()); + if (bn == NULL) + throw key_error("CKey::SetSecret() : BN_bin2bn failed"); + if (!EC_KEY_regenerate_key(pkey,bn)) + { + BN_clear_free(bn); + throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed"); + } + BN_clear_free(bn); + fSet = true; + if (fCompressed || fCompressedPubKey) + SetCompressedPubKey(); + return true; +} + +CSecret CKey::GetSecret(bool &fCompressed) const +{ + CSecret vchRet; + vchRet.resize(32); + const BIGNUM *bn = EC_KEY_get0_private_key(pkey); + int nBytes = BN_num_bytes(bn); + if (bn == NULL) + throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed"); + int n=BN_bn2bin(bn,&vchRet[32 - nBytes]); + if (n != nBytes) + throw key_error("CKey::GetSecret(): BN_bn2bin failed"); + fCompressed = fCompressedPubKey; + return vchRet; +} + +CPrivKey CKey::GetPrivKey() const +{ + int nSize = i2d_ECPrivateKey(pkey, NULL); + if (!nSize) + throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"); + CPrivKey vchPrivKey(nSize, 0); + unsigned char* pbegin = &vchPrivKey[0]; + if (i2d_ECPrivateKey(pkey, &pbegin) != nSize) + throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size"); + return vchPrivKey; +} + +bool CKey::SetPubKey(const std::vector& vchPubKey) +{ + const unsigned char* pbegin = &vchPubKey[0]; + if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size())) + return false; + fSet = true; + if (vchPubKey.size() == 33) + SetCompressedPubKey(); + return true; +} + +std::vector CKey::GetPubKey() const +{ + int nSize = i2o_ECPublicKey(pkey, NULL); + if (!nSize) + throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); + std::vector vchPubKey(nSize, 0); + unsigned char* pbegin = &vchPubKey[0]; + if (i2o_ECPublicKey(pkey, &pbegin) != nSize) + throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); + return vchPubKey; +} + +bool CKey::Sign(uint256 hash, std::vector& vchSig) +{ + unsigned int nSize = ECDSA_size(pkey); + vchSig.resize(nSize); // Make sure it is big enough + if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey)) + { + vchSig.clear(); + return false; + } + vchSig.resize(nSize); // Shrink to fit actual size + return true; +} + +// create a compact signature (65 bytes), which allows reconstructing the used public key +// The format is one header byte, followed by two times 32 bytes for the serialized r and s values. +// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, +// 0x1D = second key with even y, 0x1E = second key with odd y +bool CKey::SignCompact(uint256 hash, std::vector& vchSig) +{ + bool fOk = false; + ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); + if (sig==NULL) + return false; + vchSig.clear(); + vchSig.resize(65,0); + int nBitsR = BN_num_bits(sig->r); + int nBitsS = BN_num_bits(sig->s); + if (nBitsR <= 256 && nBitsS <= 256) + { + int nRecId = -1; + for (int i=0; i<4; i++) + { + CKey keyRec; + keyRec.fSet = true; + if (fCompressedPubKey) + keyRec.SetCompressedPubKey(); + if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) + if (keyRec.GetPubKey() == this->GetPubKey()) + { + nRecId = i; + break; + } + } + + if (nRecId == -1) + throw key_error("CKey::SignCompact() : unable to construct recoverable key"); + + vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0); + BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]); + BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]); + fOk = true; + } + ECDSA_SIG_free(sig); + return fOk; +} + +// reconstruct public key from a compact signature +// This is only slightly more CPU intensive than just verifying it. +// If this function succeeds, the recovered public key is guaranteed to be valid +// (the signature is a valid signature of the given data for that key) +bool CKey::SetCompactSignature(uint256 hash, const std::vector& vchSig) +{ + if (vchSig.size() != 65) + return false; + int nV = vchSig[0]; + if (nV<27 || nV>=35) + return false; + ECDSA_SIG *sig = ECDSA_SIG_new(); + BN_bin2bn(&vchSig[1],32,sig->r); + BN_bin2bn(&vchSig[33],32,sig->s); + + EC_KEY_free(pkey); + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (nV >= 31) + { + SetCompressedPubKey(); + nV -= 4; + } + if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1) + { + fSet = true; + ECDSA_SIG_free(sig); + return true; + } + return false; +} + +bool CKey::Verify(uint256 hash, const std::vector& vchSig) +{ + // -1 = error, 0 = bad sig, 1 = good + if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) + return false; + + return true; +} + +bool CKey::VerifyCompact(uint256 hash, const std::vector& vchSig) +{ + CKey key; + if (!key.SetCompactSignature(hash, vchSig)) + return false; + if (GetPubKey() != key.GetPubKey()) + return false; + + return true; +} + +bool CKey::IsValid() +{ + if (!fSet) + return false; + + bool fCompr; + CSecret secret = GetSecret(fCompr); + CKey key2; + key2.SetSecret(secret, fCompr); + return GetPubKey() == key2.GetPubKey(); +} diff --combined src/key.h index f7255fc,f687f33..bd58c84 --- a/src/key.h +++ b/src/key.h @@@ -1,18 -1,20 +1,18 @@@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying - // file license.txt or http://www.opensource.org/licenses/mit-license.php. + // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_KEY_H #define BITCOIN_KEY_H #include #include #include "allocators.h" #include "uint256.h" +#include // for EC_KEY definition + // secp160k1 // const unsigned int PRIVATE_KEY_SIZE = 192; // const unsigned int PUBLIC_KEY_SIZE = 41; @@@ -36,6 -38,9 +36,6 @@@ // see www.keylength.com // script supports up to 75 for single byte push -int extern EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key); -int extern ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check); - class key_error : public std::runtime_error { public: @@@ -57,50 -62,267 +57,50 @@@ protected bool fSet; bool fCompressedPubKey; - void SetCompressedPubKey() - { - EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); - fCompressedPubKey = true; - } + void SetCompressedPubKey(); public: - void Reset() - { - fCompressedPubKey = false; - pkey = EC_KEY_new_by_curve_name(NID_secp256k1); - if (pkey == NULL) - throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed"); - fSet = false; - } - - CKey() - { - Reset(); - } - - CKey(const CKey& b) - { - pkey = EC_KEY_dup(b.pkey); - if (pkey == NULL) - throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed"); - fSet = b.fSet; - } - - CKey& operator=(const CKey& b) - { - if (!EC_KEY_copy(pkey, b.pkey)) - throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed"); - fSet = b.fSet; - return (*this); - } - - ~CKey() - { - EC_KEY_free(pkey); - } - - bool IsNull() const - { - return !fSet; - } + void Reset(); - bool IsCompressed() const - { - return fCompressedPubKey; - } + CKey(); + CKey(const CKey& b); - void MakeNewKey(bool fCompressed) - { - if (!EC_KEY_generate_key(pkey)) - throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed"); - if (fCompressed) - SetCompressedPubKey(); - fSet = true; - } + CKey& operator=(const CKey& b); - bool SetPrivKey(const CPrivKey& vchPrivKey) - { - const unsigned char* pbegin = &vchPrivKey[0]; - if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size())) - return false; - fSet = true; - return true; - } + ~CKey(); - bool SetSecret(const CSecret& vchSecret, bool fCompressed = false) - { - EC_KEY_free(pkey); - pkey = EC_KEY_new_by_curve_name(NID_secp256k1); - if (pkey == NULL) - throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed"); - if (vchSecret.size() != 32) - throw key_error("CKey::SetSecret() : secret must be 32 bytes"); - BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new()); - if (bn == NULL) - throw key_error("CKey::SetSecret() : BN_bin2bn failed"); - if (!EC_KEY_regenerate_key(pkey,bn)) - { - BN_clear_free(bn); - throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed"); - } - BN_clear_free(bn); - fSet = true; - if (fCompressed || fCompressedPubKey) - SetCompressedPubKey(); - return true; - } + bool IsNull() const; + bool IsCompressed() const; - CSecret GetSecret(bool &fCompressed) const - { - CSecret vchRet; - vchRet.resize(32); - const BIGNUM *bn = EC_KEY_get0_private_key(pkey); - int nBytes = BN_num_bytes(bn); - if (bn == NULL) - throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed"); - int n=BN_bn2bin(bn,&vchRet[32 - nBytes]); - if (n != nBytes) - throw key_error("CKey::GetSecret(): BN_bn2bin failed"); - fCompressed = fCompressedPubKey; - return vchRet; - } + void MakeNewKey(bool fCompressed); + bool SetPrivKey(const CPrivKey& vchPrivKey); + bool SetSecret(const CSecret& vchSecret, bool fCompressed = false); + CSecret GetSecret(bool &fCompressed) const; + CPrivKey GetPrivKey() const; + bool SetPubKey(const std::vector& vchPubKey); + std::vector GetPubKey() const; - CPrivKey GetPrivKey() const - { - int nSize = i2d_ECPrivateKey(pkey, NULL); - if (!nSize) - throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"); - CPrivKey vchPrivKey(nSize, 0); - unsigned char* pbegin = &vchPrivKey[0]; - if (i2d_ECPrivateKey(pkey, &pbegin) != nSize) - throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size"); - return vchPrivKey; - } - - bool SetPubKey(const std::vector& vchPubKey) - { - const unsigned char* pbegin = &vchPubKey[0]; - if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size())) - return false; - fSet = true; - if (vchPubKey.size() == 33) - SetCompressedPubKey(); - return true; - } - - std::vector GetPubKey() const - { - int nSize = i2o_ECPublicKey(pkey, NULL); - if (!nSize) - throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); - std::vector vchPubKey(nSize, 0); - unsigned char* pbegin = &vchPubKey[0]; - if (i2o_ECPublicKey(pkey, &pbegin) != nSize) - throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); - return vchPubKey; - } - - bool Sign(uint256 hash, std::vector& vchSig) - { - unsigned int nSize = ECDSA_size(pkey); - vchSig.resize(nSize); // Make sure it is big enough - if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey)) - { - vchSig.clear(); - return false; - } - vchSig.resize(nSize); // Shrink to fit actual size - return true; - } + bool Sign(uint256 hash, std::vector& vchSig); // create a compact signature (65 bytes), which allows reconstructing the used public key // The format is one header byte, followed by two times 32 bytes for the serialized r and s values. // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, // 0x1D = second key with even y, 0x1E = second key with odd y - bool SignCompact(uint256 hash, std::vector& vchSig) - { - bool fOk = false; - ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); - if (sig==NULL) - return false; - vchSig.clear(); - vchSig.resize(65,0); - int nBitsR = BN_num_bits(sig->r); - int nBitsS = BN_num_bits(sig->s); - if (nBitsR <= 256 && nBitsS <= 256) - { - int nRecId = -1; - for (int i=0; i<4; i++) - { - CKey keyRec; - keyRec.fSet = true; - if (fCompressedPubKey) - keyRec.SetCompressedPubKey(); - if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) - if (keyRec.GetPubKey() == this->GetPubKey()) - { - nRecId = i; - break; - } - } - - if (nRecId == -1) - throw key_error("CKey::SignCompact() : unable to construct recoverable key"); - - vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0); - BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]); - BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]); - fOk = true; - } - ECDSA_SIG_free(sig); - return fOk; - } + bool SignCompact(uint256 hash, std::vector& vchSig); // reconstruct public key from a compact signature // This is only slightly more CPU intensive than just verifying it. // If this function succeeds, the recovered public key is guaranteed to be valid // (the signature is a valid signature of the given data for that key) - bool SetCompactSignature(uint256 hash, const std::vector& vchSig) - { - if (vchSig.size() != 65) - return false; - int nV = vchSig[0]; - if (nV<27 || nV>=35) - return false; - ECDSA_SIG *sig = ECDSA_SIG_new(); - BN_bin2bn(&vchSig[1],32,sig->r); - BN_bin2bn(&vchSig[33],32,sig->s); - - EC_KEY_free(pkey); - pkey = EC_KEY_new_by_curve_name(NID_secp256k1); - if (nV >= 31) - { - SetCompressedPubKey(); - nV -= 4; - } - if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1) - { - fSet = true; - ECDSA_SIG_free(sig); - return true; - } - return false; - } + bool SetCompactSignature(uint256 hash, const std::vector& vchSig); - bool Verify(uint256 hash, const std::vector& vchSig) - { - // -1 = error, 0 = bad sig, 1 = good - if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) - return false; - return true; - } + bool Verify(uint256 hash, const std::vector& vchSig); // Verify a compact signature - bool VerifyCompact(uint256 hash, const std::vector& vchSig) - { - CKey key; - if (!key.SetCompactSignature(hash, vchSig)) - return false; - if (GetPubKey() != key.GetPubKey()) - return false; - return true; - } - - bool IsValid() - { - if (!fSet) - return false; + bool VerifyCompact(uint256 hash, const std::vector& vchSig); - bool fCompr; - CSecret secret = GetSecret(fCompr); - CKey key2; - key2.SetSecret(secret, fCompr); - return GetPubKey() == key2.GetPubKey(); - } + bool IsValid(); }; #endif diff --combined src/main.cpp index 7d2fbd5,c5b0a72..9a7ff16 --- a/src/main.cpp +++ b/src/main.cpp @@@ -1,7 -1,8 +1,8 @@@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying - // file license.txt or http://www.opensource.org/licenses/mit-license.php. + // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "checkpoints.h" #include "db.h" #include "net.h" @@@ -43,7 -44,7 +44,7 @@@ map mapOrphanBlocks multimap mapOrphanBlocksByPrev; map mapOrphanTransactions; -multimap mapOrphanTransactionsByPrev; +map > mapOrphanTransactionsByPrev; // Constant stuff for coinbase transactions we create: CScript COINBASE_FLAGS; @@@ -160,37 -161,17 +161,37 @@@ void static ResendWalletTransactions( // mapOrphanTransactions // -void AddOrphanTx(const CDataStream& vMsg) +bool AddOrphanTx(const CDataStream& vMsg) { CTransaction tx; CDataStream(vMsg) >> tx; uint256 hash = tx.GetHash(); if (mapOrphanTransactions.count(hash)) - return; + return false; + + CDataStream* pvMsg = new CDataStream(vMsg); - CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg); + // Ignore big transactions, to avoid a + // send-big-orphans memory exhaustion attack. If a peer has a legitimate + // large transaction with a missing parent then we assume + // it will rebroadcast it later, after the parent transaction(s) + // have been mined or received. + // 10,000 orphans, each of which is at most 5,000 bytes big is + // at most 500 megabytes of orphans: + if (pvMsg->size() > 5000) + { + printf("ignoring large orphan tx (size: %u, hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str()); + delete pvMsg; + return false; + } + + mapOrphanTransactions[hash] = pvMsg; BOOST_FOREACH(const CTxIn& txin, tx.vin) - mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg)); + mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg)); + + printf("stored orphan tx %s (mapsz %u)\n", hash.ToString().substr(0,10).c_str(), + mapOrphanTransactions.size()); + return true; } void static EraseOrphanTx(uint256 hash) @@@ -202,9 -183,14 +203,9 @@@ CDataStream(*pvMsg) >> tx; BOOST_FOREACH(const CTxIn& txin, tx.vin) { - for (multimap::iterator mi = mapOrphanTransactionsByPrev.lower_bound(txin.prevout.hash); - mi != mapOrphanTransactionsByPrev.upper_bound(txin.prevout.hash);) - { - if ((*mi).second == pvMsg) - mapOrphanTransactionsByPrev.erase(mi++); - else - mi++; - } + mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash); + if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty()) + mapOrphanTransactionsByPrev.erase(txin.prevout.hash); } delete pvMsg; mapOrphanTransactions.erase(hash); @@@ -216,7 -202,9 +217,7 @@@ unsigned int LimitOrphanTxSize(unsigne while (mapOrphanTransactions.size() > nMaxOrphans) { // Evict a random orphan: - std::vector randbytes(32); - RAND_bytes(&randbytes[0], 32); - uint256 randomhash(randbytes); + uint256 randomhash = GetRandHash(); map::iterator it = mapOrphanTransactions.lower_bound(randomhash); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); @@@ -731,7 -719,7 +732,7 @@@ bool CWalletTx::AcceptWalletTransaction return false; } -bool CWalletTx::AcceptWalletTransaction() +bool CWalletTx::AcceptWalletTransaction() { CTxDB txdb("r"); return AcceptWalletTransaction(txdb); @@@ -1142,28 -1130,17 +1143,28 @@@ bool CTransaction::ConnectInputs(MapPre if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile) return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight); + // Check for negative or overflow input values + nValueIn += txPrev.vout[prevout.n].nValue; + if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) + return DoS(100, error("ConnectInputs() : txin values out of range")); + + } + // The first loop above does all the inexpensive checks. + // Only if ALL inputs pass do we perform expensive ECDSA signature checks. + // Helps prevent CPU exhaustion attacks. + for (unsigned int i = 0; i < vin.size(); i++) + { + COutPoint prevout = vin[i].prevout; + assert(inputs.count(prevout.hash) > 0); + CTxIndex& txindex = inputs[prevout.hash].first; + CTransaction& txPrev = inputs[prevout.hash].second; + // Check for conflicts (double-spend) // This doesn't trigger the DoS code on purpose; if it did, it would make it easier // for an attacker to attempt to split the network. if (!txindex.vSpent[prevout.n].IsNull()) 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()); - // Check for negative or overflow input values - nValueIn += txPrev.vout[prevout.n].nValue; - if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) - return DoS(100, error("ConnectInputs() : txin values out of range")); - // Skip ECDSA signature verification when connecting blocks (fBlock=true) // before the last blockchain checkpoint. This is safe because block merkle hashes are // still computed and checked, and any change will be caught at the next checkpoint. @@@ -1513,7 -1490,9 +1514,9 @@@ bool CBlock::SetBestChain(CTxDB& txdb, { uint256 hash = GetHash(); - txdb.TxnBegin(); + if (!txdb.TxnBegin()) + return error("SetBestChain() : TxnBegin failed"); + if (pindexGenesisBlock == NULL && hash == hashGenesisBlock) { txdb.WriteHashBestChain(hash); @@@ -1562,7 -1541,10 +1565,10 @@@ printf("SetBestChain() : ReadFromDisk failed\n"); break; } - txdb.TxnBegin(); + if (!txdb.TxnBegin()) { + printf("SetBestChain() : TxnBegin 2 failed\n"); + break; + } // errors now are not fatal, we still did a reorganisation to a new chain in a valid way if (!block.SetBestChainInner(txdb, pindex)) break; @@@ -1620,7 -1602,8 +1626,8 @@@ bool CBlock::AddToBlockIndex(unsigned i pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork(); CTxDB txdb; - txdb.TxnBegin(); + if (!txdb.TxnBegin()) + return false; txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew)); if (!txdb.TxnCommit()) return false; @@@ -1848,11 -1831,11 +1855,11 @@@ bool CheckDiskSpace(uint64 nAdditionalB if (nFreeBytesAvailable < (uint64)15000000 + nAdditionalBytes) { fShutdown = true; - string strMessage = _("Warning: Disk space is low "); + string strMessage = _("Warning: Disk space is low"); strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION | wxMODAL); - QueueShutdown(); + StartShutdown(); return false; } return true; @@@ -2378,7 -2361,7 +2385,7 @@@ bool static ProcessMessage(CNode* pfrom // at a time so the setAddrKnowns of the chosen nodes prevent repeats static uint256 hashSalt; if (hashSalt == 0) - RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt)); + hashSalt = GetRandHash(); int64 hashAddr = addr.GetHash(); uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60)); hashRand = Hash(BEGIN(hashRand), END(hashRand)); @@@ -2415,6 -2398,14 +2422,14 @@@ return error("message inv size() = %d", vInv.size()); } + // find last block in inv vector + unsigned int nLastBlock = (unsigned int)(-1); + for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) { + if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK) { + nLastBlock = vInv.size() - 1 - nInv; + break; + } + } CTxDB txdb("r"); for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) { @@@ -2428,13 -2419,19 +2443,19 @@@ if (fDebug) printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new"); - // Always request the last block in an inv bundle (even if we already have it), as it is the - // trigger for the other side to send further invs. If we are stuck on a (very long) side chain, - // this is necessary to connect earlier received orphan blocks to the chain again. - if (!fAlreadyHave || (inv.type == MSG_BLOCK && nInv==vInv.size()-1)) + if (!fAlreadyHave) pfrom->AskFor(inv); - if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) + else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) { pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash])); + } else if (nInv == nLastBlock) { + // In case we are on a very long side-chain, it is possible that we already have + // the last block in an inv bundle sent in response to getblocks. Try to detect + // this situation and push another getblocks to continue. + std::vector vGetData(1,inv); + pfrom->PushGetBlocks(mapBlockIndex[inv.hash], uint256(0)); + if (fDebug) + printf("force request: %s\n", inv.ToString().c_str()); + } // Track requests for our stuff Inventory(inv.hash); @@@ -2575,7 -2572,6 +2596,7 @@@ else if (strCommand == "tx") { vector vWorkQueue; + vector vEraseQueue; CDataStream vMsg(vRecv); CTxDB txdb("r"); CTransaction tx; @@@ -2591,45 -2587,37 +2612,45 @@@ RelayMessage(inv, vMsg); mapAlreadyAskedFor.erase(inv); vWorkQueue.push_back(inv.hash); + vEraseQueue.push_back(inv.hash); // Recursively process any orphan transactions that depended on this one for (unsigned int i = 0; i < vWorkQueue.size(); i++) { uint256 hashPrev = vWorkQueue[i]; - for (multimap::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev); - mi != mapOrphanTransactionsByPrev.upper_bound(hashPrev); + for (map::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin(); + mi != mapOrphanTransactionsByPrev[hashPrev].end(); ++mi) { const CDataStream& vMsg = *((*mi).second); CTransaction tx; CDataStream(vMsg) >> tx; CInv inv(MSG_TX, tx.GetHash()); + bool fMissingInputs2 = false; - if (tx.AcceptToMemoryPool(txdb, true)) + if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs2)) { printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); SyncWithWallets(tx, NULL, true); RelayMessage(inv, vMsg); mapAlreadyAskedFor.erase(inv); vWorkQueue.push_back(inv.hash); + vEraseQueue.push_back(inv.hash); + } + else if (!fMissingInputs2) + { + // invalid orphan + vEraseQueue.push_back(inv.hash); + printf(" removed invalid orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); } } } - BOOST_FOREACH(uint256 hash, vWorkQueue) + BOOST_FOREACH(uint256 hash, vEraseQueue) EraseOrphanTx(hash); } else if (fMissingInputs) { - printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); AddOrphanTx(vMsg); // DoS prevention: do not allow mapOrphanTransactions to grow unbounded @@@ -2819,7 -2807,7 +2840,7 @@@ bool ProcessMessages(CNode* pfrom unsigned int nMessageSize = hdr.nMessageSize; if (nMessageSize > MAX_SIZE) { - printf("ProcessMessage(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize); + printf("ProcessMessages(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize); continue; } if (nMessageSize > vRecv.size()) @@@ -2835,7 -2823,7 +2856,7 @@@ memcpy(&nChecksum, &hash, sizeof(nChecksum)); if (nChecksum != hdr.nChecksum) { - printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n", + printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n", strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum); continue; } @@@ -2860,22 -2848,22 +2881,22 @@@ if (strstr(e.what(), "end of data")) { // Allow exceptions from underlength message on vRecv - printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what()); + printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what()); } else if (strstr(e.what(), "size too large")) { // Allow exceptions from overlong size - printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what()); + printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what()); } else { - PrintExceptionContinue(&e, "ProcessMessage()"); + PrintExceptionContinue(&e, "ProcessMessages()"); } } catch (std::exception& e) { - PrintExceptionContinue(&e, "ProcessMessage()"); + PrintExceptionContinue(&e, "ProcessMessages()"); } catch (...) { - PrintExceptionContinue(NULL, "ProcessMessage()"); + PrintExceptionContinue(NULL, "ProcessMessages()"); } if (!fRet) @@@ -2895,7 -2883,7 +2916,7 @@@ bool SendMessages(CNode* pto, bool fSen if (pto->nVersion == 0) return true; - // Keep-alive ping. We send a nonce of zero because we don't use it anywhere + // Keep-alive ping. We send a nonce of zero because we don't use it anywhere // right now. if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) { uint64 nonce = 0; @@@ -2979,7 -2967,7 +3000,7 @@@ // 1/4 of tx invs blast to all immediately static uint256 hashSalt; if (hashSalt == 0) - RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt)); + hashSalt = GetRandHash(); uint256 hashRand = inv.hash ^ hashSalt; hashRand = Hash(BEGIN(hashRand), END(hashRand)); bool fTrickleWait = ((hashRand & 3) != 0); @@@ -3096,7 -3084,7 +3117,7 @@@ void SHA256Transform(void* pstate, void ctx.h[i] = ((uint32_t*)pinit)[i]; SHA256_Update(&ctx, data, sizeof(data)); - for (int i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) ((uint32_t*)pstate)[i] = ctx.h[i]; } @@@ -3222,7 -3210,7 +3243,7 @@@ CBlock* CreateNewBlock(CReserveKey& res dPriority += (double)nValueIn * nConf; if (fDebug && GetBoolArg("-printpriority")) - printf("priority nValueIn=%-12I64d nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority); + printf("priority nValueIn=%-12"PRI64d" nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority); } // Priority is sum(valuein * age) / txsize diff --combined src/makefile.linux-mingw index abc014c,540dacb..960716c --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@@ -27,7 -27,7 +27,7 @@@ LIBS= -l ssl \ -l crypto -DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB +DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE DEBUGFLAGS=-g CFLAGS=-O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) @@@ -69,7 -69,7 +69,7 @@@ OBJS= all: bitcoind.exe obj/build.h: FORCE - ../share/genbuild.sh obj/build.h + /bin/sh ../share/genbuild.sh obj/build.h version.cpp: obj/build.h DEFS += -DHAVE_BUILD_INFO diff --combined src/makefile.mingw index 6bfef0b,1ca5900..37201e3 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@@ -7,12 -7,12 +7,12 @@@ USE_UPNP:= INCLUDEPATHS= \ -I"C:\boost-1.47.0-mgw" \ -I"C:\db-4.8.30.NC-mgw\build_unix" \ - -I"C:\openssl-1.0.0d-mgw\include" + -I"C:\openssl-1.0.1b-mgw\include" LIBPATHS= \ -L"C:\boost-1.47.0-mgw\stage\lib" \ -L"C:\db-4.8.30.NC-mgw\build_unix" \ - -L"C:\openssl-1.0.0d-mgw" + -L"C:\openssl-1.0.1b-mgw" LIBS= \ -l boost_system-mgw45-mt-s-1_47 \ @@@ -23,7 -23,7 +23,7 @@@ -l ssl \ -l crypto -DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB +DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE DEBUGFLAGS=-g CFLAGS=-mthreads -O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) diff --combined src/makefile.osx index 312b6c2,0df1519..11c6248 --- a/src/makefile.osx +++ b/src/makefile.osx @@@ -53,7 -53,7 +53,7 @@@ LIBS += TESTDEFS += -DBOOST_TEST_DYN_LINK endif -DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 +DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DBOOST_SPIRIT_THREADSAFE ifdef RELEASE # Compile for maximum compatibility and smallest size. @@@ -106,7 -106,7 +106,7 @@@ all: bitcoin -include obj-test/*.P obj/build.h: FORCE - ../share/genbuild.sh obj/build.h + /bin/sh ../share/genbuild.sh obj/build.h version.cpp: obj/build.h DEFS += -DHAVE_BUILD_INFO diff --combined src/makefile.unix index d00c12b,5c45258..58331ca --- a/src/makefile.unix +++ b/src/makefile.unix @@@ -4,7 -4,7 +4,7 @@@ USE_UPNP:=0 -DEFS= +DEFS=-DBOOST_SPIRIT_THREADSAFE DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH)) LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH)) @@@ -116,7 -116,7 +116,7 @@@ all: bitcoin -include obj-test/*.P obj/build.h: FORCE - ../share/genbuild.sh obj/build.h + /bin/sh ../share/genbuild.sh obj/build.h version.cpp: obj/build.h DEFS += -DHAVE_BUILD_INFO diff --combined src/script.cpp index 56c2e50,9f45302..ccb19c3 --- a/src/script.cpp +++ b/src/script.cpp @@@ -1,9 -1,8 +1,9 @@@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying - // file license.txt or http://www.opensource.org/licenses/mit-license.php. + // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include using namespace std; using namespace boost; @@@ -13,7 -12,6 +13,7 @@@ #include "bignum.h" #include "key.h" #include "main.h" +#include "util.h" bool CheckSig(vector vchSig, vector vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); @@@ -1101,67 -1099,12 +1101,67 @@@ uint256 SignatureHash(CScript scriptCod } +// 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, std::vector > sigdata_type; + std::set< sigdata_type> setValid; + CCriticalSection cs_sigcache; + +public: + bool + Get(uint256 hash, const std::vector& vchSig, const std::vector& pubKey) + { + 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(uint256 hash, const std::vector& vchSig, const std::vector& pubKey) + { + // DoS prevention: limit cache size to less than 10MB + // (~200 bytes per cache entry times 50,000 entries) + // Since there are a maximum of 20,000 signature operations per block + // 50,000 is a reasonable default. + int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000); + if (nMaxCacheSize <= 0) return; + + 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 CheckSig(vector vchSig, vector vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) { - CKey key; - if (!key.SetPubKey(vchPubKey)) - return false; + static CSignatureCache signatureCache; // Hash type is one byte tacked on to the end of the signature if (vchSig.empty()) @@@ -1172,20 -1115,7 +1172,20 @@@ return false; vchSig.pop_back(); - return key.Verify(SignatureHash(scriptCode, txTo, nIn, nHashType), vchSig); + uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); + + if (signatureCache.Get(sighash, vchSig, vchPubKey)) + return true; + + CKey key; + if (!key.SetPubKey(vchPubKey)) + return false; + + if (!key.Verify(sighash, vchSig)) + return false; + + signatureCache.Set(sighash, vchSig, vchPubKey); + return true; } diff --combined src/util.cpp index d8804c7,dca4197..a407714 --- a/src/util.cpp +++ b/src/util.cpp @@@ -1,7 -1,7 +1,7 @@@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying - // file license.txt or http://www.opensource.org/licenses/mit-license.php. + // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "util.h" #include "strlcpy.h" @@@ -26,6 -26,7 +26,7 @@@ namespace boost #include #include #include + #include #include #include @@@ -174,12 -175,6 +175,12 @@@ int GetRandInt(int nMax return GetRand(nMax); } +uint256 GetRandHash() +{ + uint256 hash; + RAND_bytes((unsigned char*)&hash, sizeof(hash)); + return hash; +} @@@ -215,6 -210,8 +216,8 @@@ inline int OutputDebugStringF(const cha if (fileout) { static bool fStartedNewLine = true; + static boost::mutex mutexDebugLog; + boost::mutex::scoped_lock scoped_lock(mutexDebugLog); // Debug print useful for profiling if (fLogTimestamps && fStartedNewLine) @@@ -849,7 -846,7 +852,7 @@@ boost::filesystem::path GetDefaultDataD #ifdef MAC_OSX // Mac pathRet /= "Library/Application Support"; - filesystem::create_directory(pathRet); + fs::create_directory(pathRet); return pathRet / "Bitcoin"; #else // Unix diff --combined src/util.h index 714084e,780b9db..ef15260 --- a/src/util.h +++ b/src/util.h @@@ -1,7 -1,7 +1,7 @@@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying - // file license.txt or http://www.opensource.org/licenses/mit-license.php. + // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_UTIL_H #define BITCOIN_UTIL_H @@@ -168,7 -168,6 +168,7 @@@ bool SetStartOnSystemStartup(bool fAuto void ShrinkDebugFile(); int GetRandInt(int nMax); uint64 GetRand(uint64 nMax); +uint256 GetRandHash(); int64 GetTime(); void SetMockTime(int64 nMockTimeIn); int64 GetAdjustedTime(); @@@ -218,9 -217,11 +218,11 @@@ public { printf("LOCKCONTENTION: %s\n", pszName); printf("Locker: %s:%d\n", pszFile, nLine); - } #endif lock.lock(); + #ifdef DEBUG_LOCKCONTENTION + } + #endif } } diff --combined src/version.h index c0ec97d,3b26c8f..9718e75 --- a/src/version.h +++ b/src/version.h @@@ -1,6 -1,6 +1,6 @@@ // Copyright (c) 2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying - // file license.txt or http://www.opensource.org/licenses/mit-license.php. + // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_VERSION_H #define BITCOIN_VERSION_H @@@ -10,10 -10,11 +10,11 @@@ // client versioning // - static const int CLIENT_VERSION_MAJOR = 0; - static const int CLIENT_VERSION_MINOR = 6; - static const int CLIENT_VERSION_REVISION = 3; - static const int CLIENT_VERSION_BUILD = 0; + // These need to be macro's, as version.cpp's voodoo requires it + #define CLIENT_VERSION_MAJOR 0 + #define CLIENT_VERSION_MINOR 6 -#define CLIENT_VERSION_REVISION 2 -#define CLIENT_VERSION_BUILD 2 ++#define CLIENT_VERSION_REVISION 3 ++#define CLIENT_VERSION_BUILD 0 static const int CLIENT_VERSION = 1000000 * CLIENT_VERSION_MAJOR