diff options
-rw-r--r-- | bitcoin-qt.pro | 6 | ||||
-rw-r--r-- | src/bitcoinrpc.cpp | 60 | ||||
-rw-r--r-- | src/checkpoints.cpp | 65 | ||||
-rw-r--r-- | src/checkpoints.h | 29 | ||||
-rw-r--r-- | src/crypter.cpp | 2 | ||||
-rw-r--r-- | src/crypter.h | 2 | ||||
-rw-r--r-- | src/init.cpp | 24 | ||||
-rw-r--r-- | src/main.cpp | 81 | ||||
-rw-r--r-- | src/main.h | 2 | ||||
-rw-r--r-- | src/makefile.linux-mingw | 2 | ||||
-rw-r--r-- | src/makefile.mingw | 2 | ||||
-rw-r--r-- | src/makefile.osx | 2 | ||||
-rw-r--r-- | src/makefile.unix | 2 | ||||
-rw-r--r-- | src/makefile.vc | 6 | ||||
-rw-r--r-- | src/net.cpp | 39 | ||||
-rw-r--r-- | src/net.h | 1 | ||||
-rw-r--r-- | src/qt/askpassphrasedialog.cpp | 11 | ||||
-rw-r--r-- | src/qt/res/icons/address-book.png | bin | 1851 -> 1916 bytes | |||
-rw-r--r-- | src/qt/res/icons/overview.png | bin | 7936 -> 7455 bytes | |||
-rw-r--r-- | src/qt/walletmodel.cpp | 6 | ||||
-rw-r--r-- | src/qt/walletmodel.h | 9 | ||||
-rw-r--r-- | src/test/Checkpoints_tests.cpp | 34 | ||||
-rw-r--r-- | src/test/DoS_tests.cpp | 50 | ||||
-rw-r--r-- | src/test/test_bitcoin.cpp | 1 | ||||
-rw-r--r-- | src/util.h | 4 | ||||
-rw-r--r-- | src/wallet.cpp | 6 | ||||
-rw-r--r-- | src/wallet.h | 6 |
27 files changed, 348 insertions, 104 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 7444ff4ac1..66b53c2367 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -88,6 +88,7 @@ HEADERS += src/qt/bitcoingui.h \ src/qt/bitcoinaddressvalidator.h \ src/base58.h \ src/bignum.h \ + src/checkpoints.h \ src/util.h \ src/uint256.h \ src/serialize.h \ @@ -152,6 +153,7 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \ src/init.cpp \ src/net.cpp \ src/irc.cpp \ + src/checkpoints.cpp \ src/db.cpp \ src/json/json_spirit_writer.cpp \ src/json/json_spirit_value.cpp \ @@ -249,7 +251,7 @@ isEmpty(BOOST_INCLUDE_PATH) { macx:BOOST_INCLUDE_PATH = /opt/local/include } -windows:LIBS += -lws2_32 -lgdi32 +windows:LIBS += -lws2_32 windows:DEFINES += WIN32 windows:RC_FILE = src/qt/res/bitcoin-qt.rc @@ -264,6 +266,8 @@ macx:TARGET = "Bitcoin-Qt" INCLUDEPATH += $$BOOST_INCLUDE_PATH $$BDB_INCLUDE_PATH $$OPENSSL_INCLUDE_PATH LIBS += $$join(BOOST_LIB_PATH,,-L,) $$join(BDB_LIB_PATH,,-L,) $$join(OPENSSL_LIB_PATH,,-L,) LIBS += -lssl -lcrypto -ldb_cxx$$BDB_LIB_SUFFIX +# -lgdi32 has to happen after -lcrypto (see #681) +windows:LIBS += -lgdi32 LIBS += -lboost_system$$BOOST_LIB_SUFFIX -lboost_filesystem$$BOOST_LIB_SUFFIX -lboost_program_options$$BOOST_LIB_SUFFIX -lboost_thread$$BOOST_THREAD_LIB_SUFFIX contains(RELEASE, 1) { diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 2857b7575e..bb8d8e2d77 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -36,6 +36,8 @@ void ThreadRPCServer2(void* parg); typedef Value(*rpcfn_type)(const Array& params, bool fHelp); extern map<string, rpcfn_type> mapCallTable; +static std::string strRPCUserColonPass; + static int64 nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; @@ -1453,21 +1455,16 @@ Value walletpassphrase(const Array& params, bool fHelp) throw JSONRPCError(-17, "Error: Wallet is already unlocked."); // Note that the walletpassphrase is stored in params[0] which is not mlock()ed - string strWalletPass; + SecureString strWalletPass; strWalletPass.reserve(100); - mlock(&strWalletPass[0], strWalletPass.capacity()); - strWalletPass = params[0].get_str(); + // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) + // Alternately, find a way to make params[0] mlock()'d to begin with. + strWalletPass = params[0].get_str().c_str(); if (strWalletPass.length() > 0) { if (!pwalletMain->Unlock(strWalletPass)) - { - fill(strWalletPass.begin(), strWalletPass.end(), '\0'); - munlock(&strWalletPass[0], strWalletPass.capacity()); throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect."); - } - fill(strWalletPass.begin(), strWalletPass.end(), '\0'); - munlock(&strWalletPass[0], strWalletPass.capacity()); } else throw runtime_error( @@ -1493,15 +1490,15 @@ Value walletpassphrasechange(const Array& params, bool fHelp) if (!pwalletMain->IsCrypted()) throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called."); - string strOldWalletPass; + // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string) + // Alternately, find a way to make params[0] mlock()'d to begin with. + SecureString strOldWalletPass; strOldWalletPass.reserve(100); - mlock(&strOldWalletPass[0], strOldWalletPass.capacity()); - strOldWalletPass = params[0].get_str(); + strOldWalletPass = params[0].get_str().c_str(); - string strNewWalletPass; + SecureString strNewWalletPass; strNewWalletPass.reserve(100); - mlock(&strNewWalletPass[0], strNewWalletPass.capacity()); - strNewWalletPass = params[1].get_str(); + strNewWalletPass = params[1].get_str().c_str(); if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1) throw runtime_error( @@ -1509,17 +1506,7 @@ Value walletpassphrasechange(const Array& params, bool fHelp) "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>."); if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) - { - fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0'); - fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0'); - munlock(&strOldWalletPass[0], strOldWalletPass.capacity()); - munlock(&strNewWalletPass[0], strNewWalletPass.capacity()); throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect."); - } - fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0'); - fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0'); - munlock(&strOldWalletPass[0], strOldWalletPass.capacity()); - munlock(&strNewWalletPass[0], strNewWalletPass.capacity()); return Value::null; } @@ -1564,10 +1551,11 @@ Value encryptwallet(const Array& params, bool fHelp) throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command"); #endif - string strWalletPass; + // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) + // Alternately, find a way to make params[0] mlock()'d to begin with. + SecureString strWalletPass; strWalletPass.reserve(100); - mlock(&strWalletPass[0], strWalletPass.capacity()); - strWalletPass = params[0].get_str(); + strWalletPass = params[0].get_str().c_str(); if (strWalletPass.length() < 1) throw runtime_error( @@ -1575,13 +1563,7 @@ Value encryptwallet(const Array& params, bool fHelp) "Encrypts the wallet with <passphrase>."); if (!pwalletMain->EncryptWallet(strWalletPass)) - { - fill(strWalletPass.begin(), strWalletPass.end(), '\0'); - munlock(&strWalletPass[0], strWalletPass.capacity()); throw JSONRPCError(-16, "Error: Failed to encrypt the wallet."); - } - fill(strWalletPass.begin(), strWalletPass.end(), '\0'); - munlock(&strWalletPass[0], strWalletPass.capacity()); // BDB seems to have a bad habit of writing old data into // slack space in .dat files; that is bad if the old data is @@ -2043,12 +2025,7 @@ bool HTTPAuthorized(map<string, string>& mapHeaders) return false; string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64); string strUserPass = DecodeBase64(strUserPass64); - string::size_type nColon = strUserPass.find(":"); - if (nColon == string::npos) - return false; - string strUser = strUserPass.substr(0, nColon); - string strPassword = strUserPass.substr(nColon+1); - return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]); + return strUserPass == strRPCUserColonPass; } // @@ -2181,7 +2158,8 @@ void ThreadRPCServer2(void* parg) { printf("ThreadRPCServer started\n"); - if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "") + strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; + if (strRPCUserColonPass == ":") { string strWhatAmI = "To use bitcoind"; if (mapArgs.count("-server")) diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp new file mode 100644 index 0000000000..c7e054df37 --- /dev/null +++ b/src/checkpoints.cpp @@ -0,0 +1,65 @@ +// Copyright (c) 2011 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. + +#include <boost/assign/list_of.hpp> // for 'map_list_of()' +#include <boost/foreach.hpp> + +#include "headers.h" +#include "checkpoints.h" + +namespace Checkpoints +{ + typedef std::map<int, uint256> MapCheckpoints; + + // + // What makes a good checkpoint block? + // + Is surrounded by blocks with reasonable timestamps + // (no blocks before with a timestamp after, none after with + // timestamp before) + // + Contains no strange transactions + // + static MapCheckpoints mapCheckpoints = + 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")) + ; + + bool CheckBlock(int nHeight, const uint256& hash) + { + if (fTestNet) return true; // Testnet has no checkpoints + + MapCheckpoints::const_iterator i = mapCheckpoints.find(nHeight); + if (i == mapCheckpoints.end()) return true; + return hash == i->second; + } + + int GetTotalBlocksEstimate() + { + if (fTestNet) return 0; + + return mapCheckpoints.rbegin()->first; + } + + CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex) + { + if (fTestNet) return NULL; + + int64 nResult; + BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints) + { + const uint256& hash = i.second; + std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash); + if (t != mapBlockIndex.end()) + return t->second; + } + return NULL; + } +} diff --git a/src/checkpoints.h b/src/checkpoints.h new file mode 100644 index 0000000000..9d52da404f --- /dev/null +++ b/src/checkpoints.h @@ -0,0 +1,29 @@ +// Copyright (c) 2011 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. +#ifndef BITCOIN_CHECKPOINT_H +#define BITCOIN_CHECKPOINT_H + +#include <map> +#include "util.h" + +class uint256; +class CBlockIndex; + +// +// Block-chain checkpoints are compiled-in sanity checks. +// They are updated every release or three. +// +namespace Checkpoints +{ + // Returns true if block passes checkpoint checks + bool CheckBlock(int nHeight, const uint256& hash); + + // Return conservative estimate of total number of blocks, 0 if unknown + int GetTotalBlocksEstimate(); + + // Returns last CBlockIndex* in mapBlockIndex that is a checkpoint + CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex); +} + +#endif diff --git a/src/crypter.cpp b/src/crypter.cpp index bee7a3624b..7f53e22f1e 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -15,7 +15,7 @@ #include "main.h" #include "util.h" -bool CCrypter::SetKeyFromPassphrase(const std::string& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod) +bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod) { if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE) return false; diff --git a/src/crypter.h b/src/crypter.h index e8ca30a8cc..d7f8a39d83 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -65,7 +65,7 @@ private: bool fKeySet; public: - bool SetKeyFromPassphrase(const std::string &strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod); + bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod); bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext); bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext); bool SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV); diff --git a/src/init.cpp b/src/init.cpp index a6d0ab56e3..dd8bdf5598 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -172,10 +172,10 @@ bool AppInit2(int argc, char* argv[]) string strUsage = string() + _("Bitcoin version") + " " + FormatFullVersion() + "\n\n" + _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" + - " bitcoin [options] \t " + "\n" + - " bitcoin [options] <command> [params]\t " + _("Send command to -server or bitcoind\n") + - " bitcoin [options] help \t\t " + _("List commands\n") + - " bitcoin [options] help <command> \t\t " + _("Get help for a command\n") + + " bitcoind [options] \t " + "\n" + + " bitcoind [options] <command> [params]\t " + _("Send command to -server or bitcoind\n") + + " bitcoind [options] help \t\t " + _("List commands\n") + + " bitcoind [options] help <command> \t\t " + _("Get help for a command\n") + _("Options:\n") + " -conf=<file> \t\t " + _("Specify configuration file (default: bitcoin.conf)\n") + " -pid=<file> \t\t " + _("Specify pid file (default: bitcoind.pid)\n") + @@ -186,11 +186,16 @@ bool AppInit2(int argc, char* argv[]) " -timeout=<n> \t " + _("Specify connection timeout (in milliseconds)\n") + " -proxy=<ip:port> \t " + _("Connect through socks4 proxy\n") + " -dns \t " + _("Allow DNS lookups for addnode and connect\n") + + " -port=<port> \t\t " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)\n") + + " -maxconnections=<n>\t " + _("Maintain at most <n> connections to peers (default: 125)\n") + " -addnode=<ip> \t " + _("Add a node to connect to\n") + " -connect=<ip> \t\t " + _("Connect only to the specified node\n") + " -nolisten \t " + _("Don't accept connections from outside\n") + + " -nodnsseed \t " + _("Don't bootstrap list of peers using DNS\n") + " -banscore=<n> \t " + _("Threshold for disconnecting misbehaving peers (default: 100)\n") + " -bantime=<n> \t " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)\n") + + " -maxreceivebuffer=<n>\t " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)\n") + + " -maxsendbuffer=<n>\t " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)\n") + #ifdef USE_UPNP #if USE_UPNP " -noupnp \t " + _("Don't attempt to use UPnP to map the listening port\n") + @@ -206,6 +211,12 @@ bool AppInit2(int argc, char* argv[]) " -daemon \t\t " + _("Run in the background as a daemon and accept commands\n") + #endif " -testnet \t\t " + _("Use the test network\n") + + " -debug \t\t " + _("Output extra debugging information\n") + + " -logtimestamps \t " + _("Prepend debug output with timestamp\n") + + " -printtoconsole \t " + _("Send trace/debug info to console instead of debug.log file\n") + +#ifdef WIN32 + " -printtodebugger \t " + _("Send trace/debug info to debugger\n") + +#endif " -rpcuser=<user> \t " + _("Username for JSON-RPC connections\n") + " -rpcpassword=<pw>\t " + _("Password for JSON-RPC connections\n") + " -rpcport=<port> \t\t " + _("Listen for JSON-RPC connections on <port> (default: 8332)\n") + @@ -476,11 +487,6 @@ bool AppInit2(int argc, char* argv[]) } } - if (GetBoolArg("-nodnsseed")) - printf("DNS seeding disabled\n"); - else - DNSAddressSeed(); - if (mapArgs.count("-paytxfee")) { if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee)) diff --git a/src/main.cpp b/src/main.cpp index 47f1090727..a7871fcc16 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #include "headers.h" +#include "checkpoints.h" #include "db.h" #include "net.h" #include "init.h" @@ -29,7 +30,6 @@ map<COutPoint, CInPoint> mapNextTx; map<uint256, CBlockIndex*> mapBlockIndex; uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); -const int nTotalBlocksEstimate = 140700; // Conservative estimate of total nr of blocks on main chain const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download" CBlockIndex* pindexGenesisBlock = NULL; int nBestHeight = -1; @@ -659,11 +659,32 @@ int64 static GetBlockValue(int nHeight, int64 nFees) return nSubsidy + nFees; } +static const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks +static const int64 nTargetSpacing = 10 * 60; +static const int64 nInterval = nTargetTimespan / nTargetSpacing; + +// +// minimum amount of work that could possibly be required nTime after +// minimum work required was nBase +// +unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) +{ + CBigNum bnResult; + bnResult.SetCompact(nBase); + while (nTime > 0 && bnResult < bnProofOfWorkLimit) + { + // Maximum 400% adjustment... + bnResult *= 4; + // ... in best-case exactly 4-times-normal target time + nTime -= nTargetTimespan*4; + } + if (bnResult > bnProofOfWorkLimit) + bnResult = bnProofOfWorkLimit; + return bnResult.GetCompact(); +} + unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast) { - const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks - const int64 nTargetSpacing = 10 * 60; - const int64 nInterval = nTargetTimespan / nTargetSpacing; // Genesis block if (pindexLast == NULL) @@ -721,28 +742,15 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits) return true; } -// Return conservative estimate of total number of blocks, 0 if unknown -int GetTotalBlocksEstimate() -{ - if(fTestNet) - { - return 0; - } - else - { - return nTotalBlocksEstimate; - } -} - // Return maximum amount of blocks that other nodes claim to have int GetNumBlocksOfPeers() { - return std::max(cPeerBlockCounts.median(), GetTotalBlocksEstimate()); + return std::max(cPeerBlockCounts.median(), Checkpoints::GetTotalBlocksEstimate()); } bool IsInitialBlockDownload() { - if (pindexBest == NULL || nBestHeight < (GetTotalBlocksEstimate()-nInitialBlockThreshold)) + if (pindexBest == NULL || nBestHeight < (Checkpoints::GetTotalBlocksEstimate()-nInitialBlockThreshold)) return true; static int64 nLastUpdate; static CBlockIndex* pindexLastBest; @@ -1317,17 +1325,8 @@ bool CBlock::AcceptBlock() return DoS(10, error("AcceptBlock() : contains a non-final transaction")); // Check that the block chain matches the known block chain up to a checkpoint - if (!fTestNet) - if ((nHeight == 11111 && hash != uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) || - (nHeight == 33333 && hash != uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) || - (nHeight == 68555 && hash != uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a")) || - (nHeight == 70567 && hash != uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a")) || - (nHeight == 74000 && hash != uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")) || - (nHeight == 105000 && hash != uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")) || - (nHeight == 118000 && hash != uint256("0x000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553")) || - (nHeight == 134444 && hash != uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")) || - (nHeight == 140700 && hash != uint256("0x000000000000033b512028abb90e1626d8b346fd0ed598ac0a3c371138dce2bd"))) - return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight)); + if (!Checkpoints::CheckBlock(nHeight, hash)) + return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight)); // Write block to history file if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK))) @@ -1362,6 +1361,28 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) if (!pblock->CheckBlock()) return error("ProcessBlock() : CheckBlock FAILED"); + CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); + if (pcheckpoint && pblock->hashPrevBlock != hashBestChain) + { + // Extra checks to prevent "fill up memory by spamming with bogus blocks" + int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime; + if (deltaTime < 0) + { + pfrom->Misbehaving(100); + return error("ProcessBlock() : block with timestamp before last checkpoint"); + } + CBigNum bnNewBlock; + bnNewBlock.SetCompact(pblock->nBits); + CBigNum bnRequired; + bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); + if (bnNewBlock > bnRequired) + { + pfrom->Misbehaving(100); + return error("ProcessBlock() : block with too little proof-of-work"); + } + } + + // If don't already have its previous block, shunt it off to holding area until we get it if (!mapBlockIndex.count(pblock->hashPrevBlock)) { diff --git a/src/main.h b/src/main.h index 60ca318381..3870cee864 100644 --- a/src/main.h +++ b/src/main.h @@ -99,7 +99,7 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey); bool CheckProofOfWork(uint256 hash, unsigned int nBits); -int GetTotalBlocksEstimate(); +unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); int GetNumBlocksOfPeers(); bool IsInitialBlockDownload(); std::string GetWarnings(std::string strFor); diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index 29b433f851..61f8d4881f 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -32,6 +32,7 @@ CFLAGS=-O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATH HEADERS = \ base58.h \ bignum.h \ + checkpoints.h \ crypter.h \ db.h \ headers.h \ @@ -61,6 +62,7 @@ endif LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l shlwapi OBJS= \ + obj/checkpoints.o \ obj/crypter.o \ obj/db.o \ obj/init.o \ diff --git a/src/makefile.mingw b/src/makefile.mingw index 95d09f8770..2cb78d97e6 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -29,6 +29,7 @@ CFLAGS=-mthreads -O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(I HEADERS = \ base58.h \ bignum.h \ + checkpoints.h \ crypter.h \ db.h \ headers.h \ @@ -58,6 +59,7 @@ endif LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l shlwapi OBJS= \ + obj/checkpoints.o \ obj/crypter.o \ obj/db.o \ obj/init.o \ diff --git a/src/makefile.osx b/src/makefile.osx index 7830f3bad5..de71887935 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -49,6 +49,7 @@ CFLAGS=-mmacosx-version-min=10.5 -arch i386 -O3 -Wno-invalid-offsetof -Wformat $ HEADERS = \ base58.h \ bignum.h \ + checkpoints.h \ crypter.h \ db.h \ headers.h \ @@ -69,6 +70,7 @@ HEADERS = \ wallet.h OBJS= \ + obj/checkpoints.o \ obj/crypter.o \ obj/db.o \ obj/init.o \ diff --git a/src/makefile.unix b/src/makefile.unix index 5f841ea0fe..6c48199546 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -87,6 +87,7 @@ xCXXFLAGS=-pthread -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(HARDEN HEADERS = \ base58.h \ bignum.h \ + checkpoints.h \ crypter.h \ db.h \ headers.h \ @@ -107,6 +108,7 @@ HEADERS = \ wallet.h OBJS= \ + obj/checkpoints.o \ obj/crypter.o \ obj/db.o \ obj/init.o \ diff --git a/src/makefile.vc b/src/makefile.vc index c7e8578a95..60f1e09633 100644 --- a/src/makefile.vc +++ b/src/makefile.vc @@ -43,6 +43,7 @@ CFLAGS=/MD /c /nologo /EHsc /GR /Zm300 $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) HEADERS = \ base58.h \ bignum.h \ + checkpoints.h \ crypter.h \ db.h \ headers.h \ @@ -65,6 +66,7 @@ HEADERS = \ wallet.h OBJS= \ + obj\checkpoints.o \ obj\crypter.o \ obj\db.o \ obj\init.o \ @@ -87,6 +89,8 @@ all: bitcoind.exe .cpp{obj}.obj: cl $(CFLAGS) /DGUI /Fo$@ %s +obj\checkpoints.obj: $(HEADERS) + obj\util.obj: $(HEADERS) obj\script.obj: $(HEADERS) @@ -116,6 +120,8 @@ obj\uibase.obj: $(HEADERS) .cpp{obj\nogui}.obj: cl $(CFLAGS) /Fo$@ %s +obj\nogui\checkpoints.obj: $(HEADERS) + obj\nogui\util.obj: $(HEADERS) obj\nogui\script.obj: $(HEADERS) diff --git a/src/net.cpp b/src/net.cpp index 0c28eaa379..199fb407f2 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -32,6 +32,7 @@ void ThreadOpenConnections2(void* parg); #ifdef USE_UPNP void ThreadMapPort2(void* parg); #endif +void ThreadDNSAddressSeed2(void* parg); bool OpenNetworkConnection(const CAddress& addrConnect); @@ -1213,8 +1214,28 @@ static const char *strDNSSeed[] = { "dnsseed.bluematt.me", }; -void DNSAddressSeed() +void ThreadDNSAddressSeed(void* parg) { + IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg)); + try + { + vnThreadsRunning[6]++; + ThreadDNSAddressSeed2(parg); + vnThreadsRunning[6]--; + } + catch (std::exception& e) { + vnThreadsRunning[6]--; + PrintException(&e, "ThreadDNSAddressSeed()"); + } catch (...) { + vnThreadsRunning[6]--; + throw; // support pthread_cancel() + } + printf("ThreadDNSAddressSeed exiting\n"); +} + +void ThreadDNSAddressSeed2(void* parg) +{ + printf("ThreadDNSAddressSeed started\n"); int found = 0; if (!fTestNet) @@ -1247,6 +1268,15 @@ void DNSAddressSeed() + + + + + + + + + unsigned int pnSeed[] = { 0x6884ac63, 0x3ffecead, 0x2919b953, 0x0942fe50, 0x7a1d922e, 0xcdd6734a, 0x953a5bb6, 0x2c46922e, @@ -1757,6 +1787,12 @@ void StartNode(void* parg) // Start threads // + if (GetBoolArg("-nodnsseed")) + printf("DNS seeding disabled\n"); + else + if (!CreateThread(ThreadDNSAddressSeed, NULL)) + printf("Error: CreateThread(ThreadDNSAddressSeed) failed\n"); + // Map ports with UPnP if (fHaveUPnP) MapPort(fUseUPnP); @@ -1803,6 +1839,7 @@ bool StopNode() if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n"); if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n"); if (fHaveUPnP && vnThreadsRunning[5] > 0) printf("ThreadMapPort still running\n"); + if (vnThreadsRunning[6] > 0) printf("ThreadDNSAddressSeed still running\n"); while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0) Sleep(20); Sleep(50); @@ -40,7 +40,6 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0); void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1); bool AnySubscribed(unsigned int nChannel); void MapPort(bool fMapPort); -void DNSAddressSeed(); bool BindListenPort(std::string& strError=REF(std::string())); void StartNode(void* parg); bool StopNode(); diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index a574ef925b..24f622d637 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -71,16 +71,17 @@ void AskPassphraseDialog::setModel(WalletModel *model) void AskPassphraseDialog::accept() { - std::string oldpass, newpass1, newpass2; + SecureString oldpass, newpass1, newpass2; if(!model) return; - // TODO: mlock memory / munlock on return so they will not be swapped out, really need "mlockedstring" wrapper class to do this safely oldpass.reserve(MAX_PASSPHRASE_SIZE); newpass1.reserve(MAX_PASSPHRASE_SIZE); newpass2.reserve(MAX_PASSPHRASE_SIZE); - oldpass.assign(ui->passEdit1->text().toStdString()); - newpass1.assign(ui->passEdit2->text().toStdString()); - newpass2.assign(ui->passEdit3->text().toStdString()); + // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) + // Alternately, find a way to make this input mlock()'d to begin with. + oldpass.assign(ui->passEdit1->text().toStdString().c_str()); + newpass1.assign(ui->passEdit2->text().toStdString().c_str()); + newpass2.assign(ui->passEdit3->text().toStdString().c_str()); switch(mode) { diff --git a/src/qt/res/icons/address-book.png b/src/qt/res/icons/address-book.png Binary files differindex dbfc28ab3d..d41dbe6539 100644 --- a/src/qt/res/icons/address-book.png +++ b/src/qt/res/icons/address-book.png diff --git a/src/qt/res/icons/overview.png b/src/qt/res/icons/overview.png Binary files differindex 3b90fe5569..ee2511f01d 100644 --- a/src/qt/res/icons/overview.png +++ b/src/qt/res/icons/overview.png diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 2f989661f0..f028f10f6c 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -200,7 +200,7 @@ WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const } } -bool WalletModel::setWalletEncrypted(bool encrypted, const std::string &passphrase) +bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase) { if(encrypted) { @@ -214,7 +214,7 @@ bool WalletModel::setWalletEncrypted(bool encrypted, const std::string &passphra } } -bool WalletModel::setWalletLocked(bool locked, const std::string &passPhrase) +bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase) { if(locked) { @@ -228,7 +228,7 @@ bool WalletModel::setWalletLocked(bool locked, const std::string &passPhrase) } } -bool WalletModel::changePassphrase(const std::string &oldPass, const std::string &newPass) +bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass) { bool retval; CRITICAL_BLOCK(wallet->cs_wallet) diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 43b96f6d0e..89e8cdd2a0 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -2,7 +2,8 @@ #define WALLETMODEL_H #include <QObject> -#include <string> + +#include "util.h" class OptionsModel; class AddressTableModel; @@ -72,10 +73,10 @@ public: SendCoinsReturn sendCoins(const QList<SendCoinsRecipient> &recipients); // Wallet encryption - bool setWalletEncrypted(bool encrypted, const std::string &passphrase); + bool setWalletEncrypted(bool encrypted, const SecureString &passphrase); // Passphrase only needed when unlocking - bool setWalletLocked(bool locked, const std::string &passPhrase=std::string()); - bool changePassphrase(const std::string &oldPass, const std::string &newPass); + bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString()); + bool changePassphrase(const SecureString &oldPass, const SecureString &newPass); // RAI object for unlocking wallet, returned by requestUnlock() class UnlockContext diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp new file mode 100644 index 0000000000..0d8a366d7a --- /dev/null +++ b/src/test/Checkpoints_tests.cpp @@ -0,0 +1,34 @@ +// +// Unit tests for block-chain checkpoints +// +#include <boost/assign/list_of.hpp> // for 'map_list_of()' +#include <boost/test/unit_test.hpp> +#include <boost/foreach.hpp> + +#include "../checkpoints.h" +#include "../util.h" + +using namespace std; + +BOOST_AUTO_TEST_SUITE(Checkpoints_tests) + +BOOST_AUTO_TEST_CASE(sanity) +{ + uint256 p11111 = uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"); + uint256 p140700 = uint256("0x000000000000033b512028abb90e1626d8b346fd0ed598ac0a3c371138dce2bd"); + BOOST_CHECK(Checkpoints::CheckBlock(11111, p11111)); + BOOST_CHECK(Checkpoints::CheckBlock(140700, p140700)); + + + // Wrong hashes at checkpoints should fail: + BOOST_CHECK(!Checkpoints::CheckBlock(11111, p140700)); + BOOST_CHECK(!Checkpoints::CheckBlock(140700, p11111)); + + // ... but any hash not at a checkpoint should succeed: + BOOST_CHECK(Checkpoints::CheckBlock(11111+1, p140700)); + BOOST_CHECK(Checkpoints::CheckBlock(140700+1, p11111)); + + BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 140700); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index e60bb742dd..01e6691254 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -1,6 +1,7 @@ // // Unit tests for denial-of-service detection/prevention code // +#include <boost/assign/list_of.hpp> // for 'map_list_of()' #include <boost/test/unit_test.hpp> #include <boost/foreach.hpp> @@ -64,5 +65,54 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) BOOST_CHECK(!CNode::IsBanned(addr.ip)); } +static bool CheckNBits(unsigned int nbits1, int64 time1, unsigned int nbits2, int64 time2) +{ + if (time1 > time2) + return CheckNBits(nbits2, time2, nbits1, time1); + int64 deltaTime = time2-time1; + + CBigNum required; + required.SetCompact(ComputeMinWork(nbits1, deltaTime)); + CBigNum have; + have.SetCompact(nbits2); + return (have <= required); +} + +BOOST_AUTO_TEST_CASE(DoS_checknbits) +{ + using namespace boost::assign; // for 'map_list_of()' + + // Timestamps,nBits from the bitcoin blockchain. + // These are the block-chain checkpoint blocks + typedef std::map<int64, unsigned int> BlockData; + BlockData chainData = + map_list_of(1239852051,486604799)(1262749024,486594666) + (1279305360,469854461)(1280200847,469830746)(1281678674,469809688) + (1296207707,453179945)(1302624061,453036989)(1309640330,437004818) + (1313172719,436789733); + + // Make sure CheckNBits considers every combination of block-chain-lock-in-points + // "sane": + BOOST_FOREACH(const BlockData::value_type& i, chainData) + { + BOOST_FOREACH(const BlockData::value_type& j, chainData) + { + BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first)); + } + } + + // Test a couple of insane combinations: + BlockData::value_type firstcheck = *(chainData.begin()); + BlockData::value_type lastcheck = *(chainData.rbegin()); + + // First checkpoint difficulty at or a while after the last checkpoint time should fail when + // compared to last checkpoint + BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*10, lastcheck.second, lastcheck.first)); + BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*60*24*14, lastcheck.second, lastcheck.first)); + + // ... but OK if enough time passed for difficulty to adjust downward: + BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first)); + +} BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 8863aad478..39a7c88e13 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -13,6 +13,7 @@ #include "util_tests.cpp" #include "base58_tests.cpp" #include "miner_tests.cpp" +#include "Checkpoints_tests.cpp" CWallet* pwalletMain; diff --git a/src/util.h b/src/util.h index 4c966486f7..1ef0e6f15c 100644 --- a/src/util.h +++ b/src/util.h @@ -292,6 +292,10 @@ public: +// This is exactly like std::string, but with a custom allocator. +// (secure_allocator<> is defined in serialize.h) +typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString; + diff --git a/src/wallet.cpp b/src/wallet.cpp index af80cc16d5..28babdb3e2 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -42,7 +42,7 @@ bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector return false; } -bool CWallet::Unlock(const string& strWalletPassphrase) +bool CWallet::Unlock(const SecureString& strWalletPassphrase) { if (!IsLocked()) return false; @@ -63,7 +63,7 @@ bool CWallet::Unlock(const string& strWalletPassphrase) return false; } -bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase) +bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase) { bool fWasLocked = IsLocked(); @@ -122,7 +122,7 @@ public: ) }; -bool CWallet::EncryptWallet(const string& strWalletPassphrase) +bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) { if (IsCrypted()) return false; diff --git a/src/wallet.h b/src/wallet.h index 19de803390..ca7cf67317 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -70,9 +70,9 @@ public: // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) bool LoadCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); } - bool Unlock(const std::string& strWalletPassphrase); - bool ChangeWalletPassphrase(const std::string& strOldWalletPassphrase, const std::string& strNewWalletPassphrase); - bool EncryptWallet(const std::string& strWalletPassphrase); + bool Unlock(const SecureString& strWalletPassphrase); + bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); + bool EncryptWallet(const SecureString& strWalletPassphrase); bool AddToWallet(const CWalletTx& wtxIn); bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false); |