diff options
46 files changed, 947 insertions, 434 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index e78318e28e..2ca142add6 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -24,6 +24,8 @@ UI_DIR = build contains(RELEASE, 1) { # Mac: compile for maximum compatibility (10.5, 32-bit) macx:QMAKE_CXXFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk + macx:QMAKE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk + macx:QMAKE_OBJECTIVE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk !windows:!macx { # Linux: static link @@ -142,6 +144,7 @@ HEADERS += src/qt/bitcoingui.h \ src/compat.h \ src/sync.h \ src/util.h \ + src/hash.h \ src/uint256.h \ src/serialize.h \ src/main.h \ @@ -195,7 +198,8 @@ HEADERS += src/qt/bitcoingui.h \ src/netbase.h \ src/clientversion.h \ src/txdb.h \ - src/leveldb.h + src/leveldb.h \ + src/threadsafety.h SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \ src/qt/transactiontablemodel.cpp \ diff --git a/doc/build-osx.txt b/doc/build-osx.txt index af16162a59..fd878043c0 100644 --- a/doc/build-osx.txt +++ b/doc/build-osx.txt @@ -44,7 +44,7 @@ sudo port install qrencode 4. Now you should be able to build bitcoind: cd bitcoin/src -make -f makefile.osx USE_IPV6=1 +make -f makefile.osx Run: ./bitcoind --help # for a list of command-line options. diff --git a/doc/build-unix.txt b/doc/build-unix.txt index 2e0b53cf77..a1e24ff5d1 100644 --- a/doc/build-unix.txt +++ b/doc/build-unix.txt @@ -36,8 +36,8 @@ turned off by default. Set USE_UPNP to a different value to control this: USE_UPNP=0 (the default) UPnP support turned off by default at runtime USE_UPNP=1 UPnP support turned on by default at runtime -IPv6 support may be enabled by setting: - USE_IPV6=1 Enable IPv6 support +IPv6 support may be disabled by setting: + USE_IPV6=0 Disable IPv6 support Licenses of statically linked libraries: Berkeley DB New BSD license with additional requirement that linked diff --git a/doc/readme-qt.rst b/doc/readme-qt.rst index f6adbd8fdd..b0fdd4d810 100644 --- a/doc/readme-qt.rst +++ b/doc/readme-qt.rst @@ -8,7 +8,11 @@ Debian ------- First, make sure that the required packages for Qt4 development of your -distribution are installed, for Debian and Ubuntu these are: +distribution are installed, these are + +:: + +for Debian and Ubuntu <= 11.10 : :: @@ -16,6 +20,14 @@ distribution are installed, for Debian and Ubuntu these are: libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ libssl-dev libdb4.8++-dev +for Ubuntu >= 12.04 (please read the 'Berkely DB version warning' below): + +:: + + apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \ + libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ + libssl-dev libdb++-dev libminiupnpc-dev + then execute the following: :: diff --git a/src/addrman.cpp b/src/addrman.cpp index 4428cd169a..780edde90f 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "addrman.h" +#include "hash.h" using namespace std; diff --git a/src/bignum.h b/src/bignum.h index 96b1b2e6ae..1ee7a99934 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -131,7 +131,9 @@ public: if (sn < (int64)0) { - // Since the minimum signed integer cannot be represented as positive so long as its type is signed, and it's not well-defined what happens if you make it unsigned before negating it, we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate + // Since the minimum signed integer cannot be represented as positive so long as its type is signed, + // and it's not well-defined what happens if you make it unsigned before negating it, + // we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate n = -(sn + 1); ++n; fNegative = true; @@ -262,28 +264,68 @@ public: return vch; } + // The "compact" format is a representation of a whole + // number N using an unsigned 32bit number similar to a + // floating point format. + // The most significant 8 bits are the unsigned exponent of base 256. + // This exponent can be thought of as "number of bytes of N". + // The lower 23 bits are the mantissa. + // Bit number 24 (0x800000) represents the sign of N. + // N = (-1^sign) * mantissa * 256^(exponent-3) + // + // Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). + // MPI uses the most significant bit of the first byte as sign. + // Thus 0x1234560000 is compact (0x05123456) + // and 0xc0de000000 is compact (0x0600c0de) + // (0x05c0de00) would be -0x40de000000 + // + // Bitcoin only uses this "compact" format for encoding difficulty + // targets, which are unsigned 256bit quantities. Thus, all the + // complexities of the sign bit and using base 256 are probably an + // implementation accident. + // + // This implementation directly uses shifts instead of going + // through an intermediate MPI representation. CBigNum& SetCompact(unsigned int nCompact) { unsigned int nSize = nCompact >> 24; - std::vector<unsigned char> vch(4 + nSize); - vch[3] = nSize; - if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff; - if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff; - if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff; - BN_mpi2bn(&vch[0], vch.size(), this); + bool fNegative =(nCompact & 0x00800000) != 0; + unsigned int nWord = nCompact & 0x007fffff; + if (nSize <= 3) + { + nWord >>= 8*(3-nSize); + BN_set_word(this, nWord); + } + else + { + BN_set_word(this, nWord); + BN_lshift(this, this, 8*(nSize-3)); + } + BN_set_negative(this, fNegative); return *this; } unsigned int GetCompact() const { - unsigned int nSize = BN_bn2mpi(this, NULL); - std::vector<unsigned char> vch(nSize); - nSize -= 4; - BN_bn2mpi(this, &vch[0]); - unsigned int nCompact = nSize << 24; - if (nSize >= 1) nCompact |= (vch[4] << 16); - if (nSize >= 2) nCompact |= (vch[5] << 8); - if (nSize >= 3) nCompact |= (vch[6] << 0); + unsigned int nSize = BN_num_bytes(this); + unsigned int nCompact = 0; + if (nSize <= 3) + nCompact = BN_get_word(this) << 8*(3-nSize); + else + { + CBigNum bn; + BN_rshift(&bn, this, 8*(nSize-3)); + nCompact = BN_get_word(&bn); + } + // The 0x00800000 bit denotes the sign. + // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. + if (nCompact & 0x00800000) + { + nCompact >>= 8; + nSize++; + } + nCompact |= nSize << 24; + nCompact |= (BN_is_negative(this) ? 0x00800000 : 0); return nCompact; } diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 07b616438e..41850d8bb8 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -254,6 +254,8 @@ static const CRPCCommand vRPCCommands[] = { "sendrawtransaction", &sendrawtransaction, false, false }, { "gettxoutsetinfo", &gettxoutsetinfo, true, false }, { "gettxout", &gettxout, true, false }, + { "lockunspent", &lockunspent, false, false }, + { "listlockunspent", &listlockunspent, false, false }, }; CRPCTable::CRPCTable() @@ -769,7 +771,7 @@ void ThreadRPCServer2(void* parg) strWhatAmI.c_str(), GetConfigFile().string().c_str(), EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()), - _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL); + "", CClientUIInterface::MSG_ERROR); StartShutdown(); return; } @@ -860,7 +862,7 @@ void ThreadRPCServer2(void* parg) } if (!fListening) { - uiInterface.ThreadSafeMessageBox(strerr, _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL); + uiInterface.ThreadSafeMessageBox(strerr, "", CClientUIInterface::MSG_ERROR); StartShutdown(); return; } @@ -1215,6 +1217,9 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true); if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]); if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]); + if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]); + if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]); + if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]); return params; } diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index dc4dc303a8..44050ae1bb 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -177,6 +177,8 @@ extern json_spirit::Value getinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value lockunspent(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listlockunspent(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value createrawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp); diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 8208854962..4d2096ef07 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -30,6 +30,7 @@ namespace Checkpoints (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")) (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")) (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")) + (210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")) ; static MapCheckpoints mapCheckpointsTestnet = @@ -39,6 +40,9 @@ namespace Checkpoints bool CheckBlock(int nHeight, const uint256& hash) { + if (!GetBoolArg("-checkpoints", true)) + return true; + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); MapCheckpoints::const_iterator i = checkpoints.find(nHeight); @@ -48,6 +52,9 @@ namespace Checkpoints int GetTotalBlocksEstimate() { + if (!GetBoolArg("-checkpoints", true)) + return 0; + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); return checkpoints.rbegin()->first; @@ -55,6 +62,9 @@ namespace Checkpoints CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex) { + if (!GetBoolArg("-checkpoints", true)) + return NULL; + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints) diff --git a/src/hash.h b/src/hash.h new file mode 100644 index 0000000000..bc013139bb --- /dev/null +++ b/src/hash.h @@ -0,0 +1,116 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_HASH_H +#define BITCOIN_HASH_H + +#include "uint256.h" +#include "serialize.h" + +#include <openssl/sha.h> +#include <openssl/ripemd.h> + +template<typename T1> +inline uint256 Hash(const T1 pbegin, const T1 pend) +{ + static unsigned char pblank[1]; + uint256 hash1; + SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1); + uint256 hash2; + SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; +} + +class CHashWriter +{ +private: + SHA256_CTX ctx; + +public: + int nType; + int nVersion; + + void Init() { + SHA256_Init(&ctx); + } + + CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) { + Init(); + } + + CHashWriter& write(const char *pch, size_t size) { + SHA256_Update(&ctx, pch, size); + return (*this); + } + + // invalidates the object + uint256 GetHash() { + uint256 hash1; + SHA256_Final((unsigned char*)&hash1, &ctx); + uint256 hash2; + SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; + } + + template<typename T> + CHashWriter& operator<<(const T& obj) { + // Serialize to this stream + ::Serialize(*this, obj, nType, nVersion); + return (*this); + } +}; + + +template<typename T1, typename T2> +inline uint256 Hash(const T1 p1begin, const T1 p1end, + const T2 p2begin, const T2 p2end) +{ + static unsigned char pblank[1]; + uint256 hash1; + SHA256_CTX ctx; + SHA256_Init(&ctx); + SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0])); + SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0])); + SHA256_Final((unsigned char*)&hash1, &ctx); + uint256 hash2; + SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; +} + +template<typename T1, typename T2, typename T3> +inline uint256 Hash(const T1 p1begin, const T1 p1end, + const T2 p2begin, const T2 p2end, + const T3 p3begin, const T3 p3end) +{ + static unsigned char pblank[1]; + uint256 hash1; + SHA256_CTX ctx; + SHA256_Init(&ctx); + SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0])); + SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0])); + SHA256_Update(&ctx, (p3begin == p3end ? pblank : (unsigned char*)&p3begin[0]), (p3end - p3begin) * sizeof(p3begin[0])); + SHA256_Final((unsigned char*)&hash1, &ctx); + uint256 hash2; + SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; +} + +template<typename T> +uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION) +{ + CHashWriter ss(nType, nVersion); + ss << obj; + return ss.GetHash(); +} + +inline uint160 Hash160(const std::vector<unsigned char>& vch) +{ + uint256 hash1; + SHA256(&vch[0], vch.size(), (unsigned char*)&hash1); + uint160 hash2; + RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); + return hash2; +} + +#endif diff --git a/src/init.cpp b/src/init.cpp index 06f7359f80..eb3222fff1 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "txdb.h" #include "walletdb.h" #include "bitcoinrpc.h" @@ -9,6 +10,7 @@ #include "init.h" #include "util.h" #include "ui_interface.h" + #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> #include <boost/filesystem/convenience.hpp> @@ -209,17 +211,16 @@ int main(int argc, char* argv[]) bool static InitError(const std::string &str) { - uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::MODAL); + uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR); return false; } bool static InitWarning(const std::string &str) { - uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL); + uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING); return true; } - bool static Bind(const CService &addr, unsigned int flags) { if (!(flags & BF_EXPLICIT) && IsLimited(addr)) return false; @@ -257,6 +258,7 @@ std::string HelpMessage() " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n" + " -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n" + " -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" + + " -checkpoints " + _("Only accept block chain matching built-in checkpoints (default: 1)") + "\n" + " -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n" + " -bind=<addr> " + _("Bind to given address and always listen on it. Use [host]:port notation for IPv6") + "\n" + " -dnsseed " + _("Find peers using DNS lookup (default: 1 unless -connect)") + "\n" + @@ -299,7 +301,7 @@ std::string HelpMessage() " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n" + " -checkblocks=<n> " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" + " -checklevel=<n> " + _("How thorough the block verification is (0-6, default: 1)") + "\n" + - " -loadblock=<file> " + _("Imports blocks from external blk000?.dat file") + "\n" + + " -loadblock=<file> " + _("Imports blocks from external blk000??.dat file") + "\n" + " -reindex " + _("Rebuild blockchain index from current blk000??.dat files") + "\n" + "\n" + _("Block creation options:") + "\n" + @@ -344,10 +346,8 @@ void ThreadImport(void *data) { if (fReindex) { CImportingNow imp; int nFile = 0; - while (!fShutdown) { - CDiskBlockPos pos; - pos.nFile = nFile; - pos.nPos = 0; + while (!fRequestShutdown) { + CDiskBlockPos pos(nFile, 0); FILE *file = OpenBlockFile(pos, true); if (!file) break; @@ -355,7 +355,7 @@ void ThreadImport(void *data) { LoadExternalBlockFile(file, &pos); nFile++; } - if (!fShutdown) { + if (!fRequestShutdown) { pblocktree->WriteReindexing(false); fReindex = false; printf("Reindexing finished\n"); @@ -364,7 +364,7 @@ void ThreadImport(void *data) { // hardcoded $DATADIR/bootstrap.dat filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat"; - if (filesystem::exists(pathBootstrap) && !fShutdown) { + if (filesystem::exists(pathBootstrap) && !fRequestShutdown) { FILE *file = fopen(pathBootstrap.string().c_str(), "rb"); if (file) { CImportingNow imp; @@ -377,7 +377,7 @@ void ThreadImport(void *data) { // -loadblock= BOOST_FOREACH(boost::filesystem::path &path, import->vFiles) { - if (fShutdown) + if (fRequestShutdown) break; FILE *file = fopen(path.string().c_str(), "rb"); if (file) { @@ -482,6 +482,7 @@ bool AppInit2() // ********************************************************* Step 3: parameter-to-internal-flags fDebug = GetBoolArg("-debug"); + fBenchmark = GetBoolArg("-benchmark"); // -debug implies fDebug* if (fDebug) @@ -570,7 +571,7 @@ bool AppInit2() printf("Bitcoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str()); printf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION)); if (!fLogTimestamps) - printf("Startup time: %s\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); + printf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", GetTime()).c_str()); printf("Default data directory %s\n", GetDefaultDataDir().string().c_str()); printf("Used data directory %s\n", strDataDir.c_str()); std::ostringstream strErrors; @@ -608,7 +609,7 @@ bool AppInit2() " Original wallet.dat saved as wallet.{timestamp}.bak in %s; if" " your balance or transactions are incorrect you should" " restore from a backup."), strDataDir.c_str()); - uiInterface.ThreadSafeMessageBox(msg, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL); + InitWarning(msg); } if (r == CDBEnv::RECOVER_FAIL) return InitError(_("wallet.dat corrupt, salvage failed")); @@ -808,7 +809,7 @@ bool AppInit2() { string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data" " or address book entries might be missing or incorrect.")); - uiInterface.ThreadSafeMessageBox(msg, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL); + InitWarning(msg); } else if (nLoadWalletRet == DB_TOO_NEW) strErrors << _("Error loading wallet.dat: Wallet requires newer version of Bitcoin") << "\n"; @@ -866,7 +867,7 @@ bool AppInit2() if (walletdb.ReadBestBlock(locator)) pindexRescan = locator.GetBlockIndex(); } - if (pindexBest != pindexRescan) + if (pindexBest && pindexBest != pindexRescan) { uiInterface.InitMessage(_("Rescanning...")); printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); @@ -914,7 +915,7 @@ bool AppInit2() //// debug print printf("mapBlockIndex.size() = %"PRIszu"\n", mapBlockIndex.size()); - printf("nBestHeight = %d\n", nBestHeight); + printf("nBestHeight = %d\n", nBestHeight); printf("setKeyPool.size() = %"PRIszu"\n", pwalletMain->setKeyPool.size()); printf("mapWallet.size() = %"PRIszu"\n", pwalletMain->mapWallet.size()); printf("mapAddressBook.size() = %"PRIszu"\n", pwalletMain->mapAddressBook.size()); @@ -11,7 +11,7 @@ #include "allocators.h" #include "serialize.h" #include "uint256.h" -#include "util.h" +#include "hash.h" #include <openssl/ec.h> // for EC_KEY definition diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform index dd982236fd..566d1f83a4 100755 --- a/src/leveldb/build_detect_platform +++ b/src/leveldb/build_detect_platform @@ -119,6 +119,16 @@ case "$TARGET_OS" in PLATFORM_EXTRALIBS="-lboost_system-mt-s -lboost_filesystem-mt-s -lboost_thread_win32-mt-s" CROSS_COMPILE=true ;; + NATIVE_WINDOWS) + PLATFORM=OS_WINDOWS + COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS -DBOOST_THREAD_USE_LIB" + PLATFORM_CXXFLAGS="" + PLATFORM_LDFLAGS="" + PLATFORM_SHARED_CFLAGS="" + PLATFORM_SOURCES="port/port_win.cc util/env_boost.cc util/win_logger.cc" + PLATFORM_EXTRALIBS="-lboost_system-mgw45-mt-s-1_50 -lboost_filesystem-mgw45-mt-s-1_50 -lboost_thread-mgw45-mt-s-1_50 -lboost_chrono-mgw45-mt-s-1_50" + CROSS_COMPILE=true + ;; *) echo "Unknown platform!" >&2 exit 1 diff --git a/src/main.cpp b/src/main.cpp index 808c213d63..96bdabd586 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,6 +42,7 @@ set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; // may contain int64 nTimeBestReceived = 0; bool fImporting = false; bool fReindex = false; +bool fBenchmark = false; unsigned int nCoinCacheSize = 5000; CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have @@ -818,7 +819,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx) } -bool CTxMemPool::remove(CTransaction &tx) +bool CTxMemPool::remove(const CTransaction &tx, bool fRecursive) { // Remove transaction from memory pool { @@ -826,6 +827,13 @@ bool CTxMemPool::remove(CTransaction &tx) uint256 hash = tx.GetHash(); if (mapTx.count(hash)) { + if (fRecursive) { + for (unsigned int i = 0; i < tx.vout.size(); i++) { + std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(hash, i)); + if (it != mapNextTx.end()) + remove(*it->second.ptx, true); + } + } BOOST_FOREACH(const CTxIn& txin, tx.vin) mapNextTx.erase(txin.prevout); mapTx.erase(hash); @@ -835,6 +843,21 @@ bool CTxMemPool::remove(CTransaction &tx) return true; } +bool CTxMemPool::removeConflicts(const CTransaction &tx) +{ + // Remove transactions which depend on inputs of tx, recursively + LOCK(cs); + BOOST_FOREACH(const CTxIn &txin, tx.vin) { + std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(txin.prevout); + if (it != mapNextTx.end()) { + const CTransaction &txConflict = *it->second.ptx; + if (txConflict != tx) + remove(txConflict, true); + } + } + return true; +} + void CTxMemPool::clear() { LOCK(cs); @@ -998,21 +1021,16 @@ CBlockIndex* FindBlockByHeight(int nHeight) return pblockindex; } -bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions) +bool CBlock::ReadFromDisk(const CBlockIndex* pindex) { - if (!fReadTransactions) - { - *this = pindex->GetBlockHeader(); - return true; - } - if (!ReadFromDisk(pindex->GetBlockPos(), fReadTransactions)) + if (!ReadFromDisk(pindex->GetBlockPos())) return false; if (GetHash() != pindex->GetBlockHash()) return error("CBlock::ReadFromDisk() : GetHash() doesn't match index"); return true; } -uint256 static GetOrphanRoot(const CBlock* pblock) +uint256 static GetOrphanRoot(const CBlockHeader* pblock) { // Work back to the first block in the orphan chain while (mapOrphanBlocks.count(pblock->hashPrevBlock)) @@ -1059,7 +1077,7 @@ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) return bnResult.GetCompact(); } -unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlock *pblock) +unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock) { unsigned int nProofOfWorkLimit = bnProofOfWorkLimit.GetCompact(); @@ -1169,11 +1187,11 @@ void static InvalidChainFound(CBlockIndex* pindexNew) } printf("InvalidChainFound: invalid block=%s height=%d work=%s date=%s\n", BlockHashStr(pindexNew->GetBlockHash()).c_str(), pindexNew->nHeight, - pindexNew->bnChainWork.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", + pindexNew->bnChainWork.ToString().c_str(), DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", pindexNew->GetBlockTime()).c_str()); printf("InvalidChainFound: current best=%s height=%d work=%s date=%s\n", BlockHashStr(hashBestChain).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), - DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); + DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", pindexBest->GetBlockTime()).c_str()); if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6) printf("InvalidChainFound: Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n"); } @@ -1198,7 +1216,7 @@ bool ConnectBestBlock() { pindexNewBest = *it; } - if (pindexNewBest == pindexBest) + if (pindexNewBest == pindexBest || (pindexBest && pindexNewBest->bnChainWork == pindexBest->bnChainWork)) return true; // nothing to do // check ancestry @@ -1223,9 +1241,12 @@ bool ConnectBestBlock() { if (pindexTest->pprev == NULL || pindexTest->pnext != NULL) { reverse(vAttach.begin(), vAttach.end()); - BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) + BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) { + if (fRequestShutdown) + break; if (!SetBestChain(pindexSwitch)) return false; + } return true; } pindexTest = pindexTest->pprev; @@ -1233,7 +1254,7 @@ bool ConnectBestBlock() { } while(true); } -void CBlock::UpdateTime(const CBlockIndex* pindexPrev) +void CBlockHeader::UpdateTime(const CBlockIndex* pindexPrev) { nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); @@ -1518,17 +1539,19 @@ void static FlushBlockFile() { LOCK(cs_LastBlockFile); - CDiskBlockPos posOld; - posOld.nFile = nLastBlockFile; - posOld.nPos = 0; + CDiskBlockPos posOld(nLastBlockFile, 0); FILE *fileOld = OpenBlockFile(posOld); - FileCommit(fileOld); - fclose(fileOld); + if (fileOld) { + FileCommit(fileOld); + fclose(fileOld); + } fileOld = OpenUndoFile(posOld); - FileCommit(fileOld); - fclose(fileOld); + if (fileOld) { + FileCommit(fileOld); + fclose(fileOld); + } } bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize); @@ -1571,12 +1594,16 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust CBlockUndo blockundo; + int64 nStart = GetTimeMicros(); int64 nFees = 0; + int nInputs = 0; unsigned int nSigOps = 0; for (unsigned int i=0; i<vtx.size(); i++) { + const CTransaction &tx = vtx[i]; + nInputs += tx.vin.size(); nSigOps += tx.GetLegacySigOpCount(); if (nSigOps > MAX_BLOCK_SIGOPS) return DoS(100, error("ConnectBlock() : too many sigops")); @@ -1607,7 +1634,11 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust return error("ConnectBlock() : UpdateInputs failed"); if (!tx.IsCoinBase()) blockundo.vtxundo.push_back(txundo); + } + int64 nTime = GetTimeMicros() - nStart; + if (fBenchmark) + printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1)); if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees)) return error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)); @@ -1650,7 +1681,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust bool SetBestChain(CBlockIndex* pindexNew) { - CCoinsViewCache &view = *pcoinsTip; + // All modifications to the coin state will be done in this cache. + // Only when all have succeeded, we push it to pcoinsTip. + CCoinsViewCache view(*pcoinsTip, true); // special case for attaching the genesis block // note that no ConnectBlock is called, so its coinbase output is non-spendable @@ -1670,7 +1703,7 @@ bool SetBestChain(CBlockIndex* pindexNew) // Find the fork (typically, there is none) CBlockIndex* pfork = view.GetBestBlock(); CBlockIndex* plonger = pindexNew; - while (pfork != plonger) + while (pfork && pfork != plonger) { while (plonger->nHeight > pfork->nHeight) if (!(plonger = plonger->pprev)) @@ -1703,15 +1736,17 @@ bool SetBestChain(CBlockIndex* pindexNew) CBlock block; if (!block.ReadFromDisk(pindex)) return error("SetBestBlock() : ReadFromDisk for disconnect failed"); - CCoinsViewCache viewTemp(view, true); - if (!block.DisconnectBlock(pindex, viewTemp)) + int64 nStart = GetTimeMicros(); + if (!block.DisconnectBlock(pindex, view)) return error("SetBestBlock() : DisconnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str()); - if (!viewTemp.Flush()) - return error("SetBestBlock() : Cache flush failed after disconnect"); + if (fBenchmark) + printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); - // Queue memory transactions to resurrect + // Queue memory transactions to resurrect. + // We only do this for blocks after the last checkpoint (reorganisation before that + // point should only happen with -reindex/-loadblock, or a misbehaving peer. BOOST_FOREACH(const CTransaction& tx, block.vtx) - if (!tx.IsCoinBase()) + if (!tx.IsCoinBase() && pindex->nHeight > Checkpoints::GetTotalBlocksEstimate()) vResurrect.push_back(tx); } @@ -1721,26 +1756,35 @@ bool SetBestChain(CBlockIndex* pindexNew) CBlock block; if (!block.ReadFromDisk(pindex)) return error("SetBestBlock() : ReadFromDisk for connect failed"); - CCoinsViewCache viewTemp(view, true); - if (!block.ConnectBlock(pindex, viewTemp)) { + int64 nStart = GetTimeMicros(); + if (!block.ConnectBlock(pindex, view)) { InvalidChainFound(pindexNew); InvalidBlockFound(pindex); return error("SetBestBlock() : ConnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str()); } - if (!viewTemp.Flush()) - return error("SetBestBlock() : Cache flush failed after connect"); + if (fBenchmark) + printf("- Connect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); // Queue memory transactions to delete BOOST_FOREACH(const CTransaction& tx, block.vtx) vDelete.push_back(tx); } + // Flush changes to global coin state + int64 nStart = GetTimeMicros(); + int nModified = view.GetCacheSize(); + if (!view.Flush()) + return error("SetBestBlock() : unable to modify coin state"); + int64 nTime = GetTimeMicros() - nStart; + if (fBenchmark) + printf("- Flush %i transactions: %.2fms (%.4fms/tx)\n", nModified, 0.001 * nTime, 0.001 * nTime / nModified); + // Make sure it's successfully written to disk before changing memory structure bool fIsInitialDownload = IsInitialBlockDownload(); - if (!fIsInitialDownload || view.GetCacheSize() > nCoinCacheSize) { + if (!fIsInitialDownload || pcoinsTip->GetCacheSize() > nCoinCacheSize) { FlushBlockFile(); pblocktree->Sync(); - if (!view.Flush()) + if (!pcoinsTip->Flush()) return false; } @@ -1759,11 +1803,13 @@ bool SetBestChain(CBlockIndex* pindexNew) // Resurrect memory transactions that were in the disconnected branch BOOST_FOREACH(CTransaction& tx, vResurrect) - tx.AcceptToMemoryPool(false); + tx.AcceptToMemoryPool(); // Delete redundant memory transactions that are in the connected branch - BOOST_FOREACH(CTransaction& tx, vDelete) + BOOST_FOREACH(CTransaction& tx, vDelete) { mempool.remove(tx); + mempool.removeConflicts(tx); + } // Update best block in wallet (so we can detect restored wallets) if (!fIsInitialDownload) @@ -1782,7 +1828,7 @@ bool SetBestChain(CBlockIndex* pindexNew) nTransactionsUpdated++; printf("SetBestChain: new best=%s height=%d work=%s tx=%lu date=%s\n", BlockHashStr(hashBestChain).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), (unsigned long)pindexNew->nChainTx, - DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); + DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", pindexBest->GetBlockTime()).c_str()); // Check the version of the last 100 blocks to see if we need to upgrade: if (!fIsInitialDownload) @@ -1874,6 +1920,7 @@ bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeigh nLastBlockFile = pos.nFile; infoLastBlockFile.SetNull(); pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile); + fUpdatedLast = true; } } else { while (infoLastBlockFile.nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { @@ -1895,12 +1942,16 @@ bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeigh unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; unsigned int nNewChunks = (infoLastBlockFile.nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; if (nNewChunks > nOldChunks) { - FILE *file = OpenBlockFile(pos); - if (file) { - printf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); - AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos); - fclose(file); + if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos)) { + FILE *file = OpenBlockFile(pos); + if (file) { + printf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); + AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos); + fclose(file); + } } + else + return error("FindBlockPos() : out of disk space"); } } @@ -1937,12 +1988,16 @@ bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize) unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; unsigned int nNewChunks = (nNewSize + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; if (nNewChunks > nOldChunks) { - FILE *file = OpenUndoFile(pos); - if (file) { - printf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); - AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); - fclose(file); + if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) { + FILE *file = OpenUndoFile(pos); + if (file) { + printf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); + AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); + fclose(file); + } } + else + return error("FindUndoPos() : out of disk space"); } return true; @@ -2067,12 +2122,8 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp) // Write block to history file unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION); CDiskBlockPos blockPos; - if (dbp == NULL) { - if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION))) - return error("AcceptBlock() : out of disk space"); - } else { + if (dbp != NULL) blockPos = *dbp; - } if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL)) return error("AcceptBlock() : FindBlockPos failed"); if (dbp == NULL) @@ -2202,10 +2253,10 @@ bool CheckDiskSpace(uint64 nAdditionalBytes) if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes) { fShutdown = true; - string strMessage = _("Warning: Disk space is low!"); + string strMessage = _("Error: Disk space is low!"); strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); - uiInterface.ThreadSafeMessageBox(strMessage, "Bitcoin", CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL); + uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_ERROR); StartShutdown(); return false; } @@ -2299,13 +2350,18 @@ bool static LoadBlockIndexDB() if (pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile)) printf("LoadBlockIndex(): last block file: %s\n", infoLastBlockFile.ToString().c_str()); + // Load bnBestInvalidWork, OK if it doesn't exist + pblocktree->ReadBestInvalidWork(bnBestInvalidWork); + + // Check whether we need to continue reindexing + bool fReindexing = false; + pblocktree->ReadReindexing(fReindexing); + fReindex |= fReindexing; + // Load hashBestChain pointer to end of best chain pindexBest = pcoinsTip->GetBestBlock(); if (pindexBest == NULL) - { - if (pindexGenesisBlock == NULL) - return true; - } + return true; hashBestChain = pindexBest->GetBlockHash(); nBestHeight = pindexBest->nHeight; bnBestChainWork = pindexBest->bnChainWork; @@ -2319,15 +2375,7 @@ bool static LoadBlockIndexDB() } printf("LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n", BlockHashStr(hashBestChain).c_str(), nBestHeight, - DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); - - // Load bnBestInvalidWork, OK if it doesn't exist - pblocktree->ReadBestInvalidWork(bnBestInvalidWork); - - // Check whether we need to continue reindexing - bool fReindexing = false; - pblocktree->ReadReindexing(fReindexing); - fReindex |= fReindexing; + DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", pindexBest->GetBlockTime()).c_str()); // Verify blocks in the best chain int nCheckLevel = GetArg("-checklevel", 1); @@ -2490,7 +2538,7 @@ void PrintBlockTree() printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"", pindex->nHeight, pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos, - DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(), + DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", block.GetBlockTime()).c_str(), block.vtx.size()); PrintWallets(block); @@ -2529,7 +2577,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) } } uint64 nRewind = blkdat.GetPos(); - while (blkdat.good() && !blkdat.eof() && !fShutdown) { + while (blkdat.good() && !blkdat.eof() && !fRequestShutdown) { blkdat.SetPos(nRewind); nRewind++; // start one byte further next time, in case of failure blkdat.SetLimit(); // remove former limit @@ -3072,6 +3120,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pindex = pindex->pnext; } + // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end vector<CBlock> vHeaders; int nLimit = 2000; printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), BlockHashStr(hashStop).c_str()); @@ -3685,7 +3734,6 @@ public: CBlock* CreateNewBlock(CReserveKey& reservekey) { - // Create new block auto_ptr<CBlock> pblock(new CBlock()); if (!pblock.get()) @@ -3735,6 +3783,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) // Priority order to process transactions list<COrphan> vOrphan; // list memory doesn't move map<uint256, vector<COrphan*> > mapDependers; + bool fPrintPriority = GetBoolArg("-printpriority"); // This vector will be sorted into a priority queue: vector<TxPriority> vecPriority; @@ -3881,7 +3930,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) nBlockSigOps += nTxSigOps; nFees += nTxFees; - if (fDebug && GetBoolArg("-printpriority")) + if (fPrintPriority) { printf("priority %.1f feeperkb %.1f txid %s\n", dPriority, dFeePerKb, tx.GetHash().ToString().c_str()); diff --git a/src/main.h b/src/main.h index 8327141266..8bceffbaf9 100644 --- a/src/main.h +++ b/src/main.h @@ -89,6 +89,7 @@ extern std::set<CWallet*> setpwalletRegistered; extern unsigned char pchMessageStart[4]; extern bool fImporting; extern bool fReindex; +extern bool fBenchmark; extern unsigned int nCoinCacheSize; // Settings @@ -151,7 +152,7 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits); unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); /** Get the number of active peers */ int GetNumBlocksOfPeers(); -/** Check whether we are doin an inital block download (synchronizing from disk or network) */ +/** Check whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(); /** Format a string that describes several potential problems detected by the core */ std::string GetWarnings(std::string strFor); @@ -192,6 +193,15 @@ public: READWRITE(VARINT(nPos)); ) + CDiskBlockPos() { + SetNull(); + } + + CDiskBlockPos(int nFileIn, unsigned int nPosIn) { + nFile = nFileIn; + nPos = nPosIn; + } + friend bool operator==(const CDiskBlockPos &a, const CDiskBlockPos &b) { return (a.nFile == b.nFile && a.nPos == b.nPos); } @@ -1071,7 +1081,7 @@ public: * in the block is a special one that creates a new coin owned by the creator * of the block. */ -class CBlock +class CBlockHeader { public: // header @@ -1083,17 +1093,7 @@ public: unsigned int nBits; unsigned int nNonce; - // network and disk - std::vector<CTransaction> vtx; - - // memory only - mutable std::vector<uint256> vMerkleTree; - - // Denial-of-service detection: - mutable int nDoS; - bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } - - CBlock() + CBlockHeader() { SetNull(); } @@ -1107,25 +1107,16 @@ public: READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); - - // ConnectBlock depends on vtx being last so it can calculate offset - if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY))) - READWRITE(vtx); - else if (fRead) - const_cast<CBlock*>(this)->vtx.clear(); ) void SetNull() { - nVersion = CBlock::CURRENT_VERSION; + nVersion = CBlockHeader::CURRENT_VERSION; hashPrevBlock = 0; hashMerkleRoot = 0; nTime = 0; nBits = 0; nNonce = 0; - vtx.clear(); - vMerkleTree.clear(); - nDoS = 0; } bool IsNull() const @@ -1144,7 +1135,45 @@ public: } void UpdateTime(const CBlockIndex* pindexPrev); +}; + +class CBlock : public CBlockHeader +{ +public: + // network and disk + std::vector<CTransaction> vtx; + + // memory only + mutable std::vector<uint256> vMerkleTree; + + // Denial-of-service detection: + mutable int nDoS; + bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } + + CBlock() + { + SetNull(); + } + CBlock(const CBlockHeader &header) + { + SetNull(); + *((CBlockHeader*)this) = header; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(*(CBlockHeader*)this); + READWRITE(vtx); + ) + + void SetNull() + { + CBlockHeader::SetNull(); + vtx.clear(); + vMerkleTree.clear(); + nDoS = 0; + } uint256 BuildMerkleTree() const { @@ -1229,7 +1258,7 @@ public: return true; } - bool ReadFromDisk(const CDiskBlockPos &pos, bool fReadTransactions = true) + bool ReadFromDisk(const CDiskBlockPos &pos) { SetNull(); @@ -1237,8 +1266,6 @@ public: CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); if (!filein) return error("CBlock::ReadFromDisk() : OpenBlockFile failed"); - if (!fReadTransactions) - filein.nType |= SER_BLOCKHEADERONLY; // Read block try { @@ -1285,7 +1312,7 @@ public: bool ConnectBlock(CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false); // Read a block from disk - bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true); + bool ReadFromDisk(const CBlockIndex* pindex); // Add this block to the block index, and if necessary, switch the active block chain to this bool AddToBlockIndex(const CDiskBlockPos &pos); @@ -1450,7 +1477,7 @@ public: nNonce = 0; } - CBlockIndex(CBlock& block) + CBlockIndex(CBlockHeader& block) { phashBlock = NULL; pprev = NULL; @@ -1476,8 +1503,7 @@ public: if (nStatus & BLOCK_HAVE_DATA) { ret.nFile = nFile; ret.nPos = nDataPos; - } else - ret.SetNull(); + } return ret; } @@ -1486,14 +1512,13 @@ public: if (nStatus & BLOCK_HAVE_UNDO) { ret.nFile = nFile; ret.nPos = nUndoPos; - } else - ret.SetNull(); + } return ret; } - CBlock GetBlockHeader() const + CBlockHeader GetBlockHeader() const { - CBlock block; + CBlockHeader block; block.nVersion = nVersion; if (pprev) block.hashPrevBlock = pprev->GetBlockHash(); @@ -1637,7 +1662,7 @@ public: uint256 GetBlockHash() const { - CBlock block; + CBlockHeader block; block.nVersion = nVersion; block.hashPrevBlock = hashPrev; block.hashMerkleRoot = hashMerkleRoot; @@ -1814,7 +1839,8 @@ public: bool accept(CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs); bool addUnchecked(const uint256& hash, CTransaction &tx); - bool remove(CTransaction &tx); + bool remove(const CTransaction &tx, bool fRecursive = false); + bool removeConflicts(const CTransaction &tx); void clear(); void queryHashes(std::vector<uint256>& vtxid); void pruneSpent(const uint256& hash, CCoins &coins); diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index 64268dd0aa..47dc7c5c40 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -92,7 +92,7 @@ LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a DEFS += -I"$(CURDIR)/leveldb/include" DEFS += -I"$(CURDIR)/leveldb/helpers" leveldb/libleveldb.a: - @echo "Building LevelDB ..." && cd leveldb && CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$(INCLUDEPATHS)" LDFLAGS="-L$(LIBPATHS)" make libleveldb.a libmemenv.a && i586-mingw32msvc-ranlib libleveldb.a && i586-mingw32msvc-ranlib libmemenv.a && cd .. + @echo "Building LevelDB ..." && cd leveldb && CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$(INCLUDEPATHS)" LDFLAGS="-L$(LIBPATHS)" $(MAKE) libleveldb.a libmemenv.a && i586-mingw32msvc-ranlib libleveldb.a && i586-mingw32msvc-ranlib libmemenv.a && cd .. obj/leveldb.o: leveldb/libleveldb.a obj/build.h: FORCE diff --git a/src/makefile.mingw b/src/makefile.mingw index 85d63e9ceb..22d65d6703 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -96,8 +96,8 @@ DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) # TODO: If this fails, try adding a ranlib libleveldb.a && ranlib libmemenv.a leveldb/libleveldb.a: - cd leveldb && make libleveldb.a libmemenv.a && cd .. -obj/leveldb.o: leveldb/libleveldb.lib + cd leveldb && $(MAKE) libleveldb.a libmemenv.a && cd .. +obj/leveldb.o: leveldb/libleveldb.a obj/%.o: %.cpp $(HEADERS) g++ -c $(CFLAGS) -o $@ $< diff --git a/src/makefile.osx b/src/makefile.osx index 9629545c0a..25164c8679 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -128,7 +128,7 @@ LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) leveldb/libleveldb.a: - @echo "Building LevelDB ..." && cd leveldb && make libleveldb.a libmemenv.a && cd .. + @echo "Building LevelDB ..." && cd leveldb && $(MAKE) libleveldb.a libmemenv.a && cd .. obj/leveldb.o: leveldb/libleveldb.a # auto-generated dependencies: diff --git a/src/makefile.unix b/src/makefile.unix index 653f512e82..9e17e8ace2 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -144,7 +144,7 @@ LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) leveldb/libleveldb.a: - @echo "Building LevelDB ..." && cd leveldb && make libleveldb.a libmemenv.a && cd .. + @echo "Building LevelDB ..." && cd leveldb && $(MAKE) libleveldb.a libmemenv.a && cd .. obj/leveldb.o: leveldb/libleveldb.a # auto-generated dependencies: @@ -18,6 +18,7 @@ #include "netbase.h" #include "protocol.h" #include "addrman.h" +#include "hash.h" class CNode; class CBlockIndex; @@ -305,7 +306,8 @@ public: - void BeginMessage(const char* pszCommand) + // TODO: Document the postcondition of this function. Is cs_vSend locked? + void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend) { ENTER_CRITICAL_SECTION(cs_vSend); if (nHeaderStart != -1) @@ -317,7 +319,8 @@ public: printf("sending: %s ", pszCommand); } - void AbortMessage() + // TODO: Document the precondition of this function. Is cs_vSend locked? + void AbortMessage() UNLOCK_FUNCTION(cs_vSend) { if (nHeaderStart < 0) return; @@ -330,7 +333,8 @@ public: printf("(aborted)\n"); } - void EndMessage() + // TODO: Document the precondition of this function. Is cs_vSend locked? + void EndMessage() UNLOCK_FUNCTION(cs_vSend) { if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) { @@ -362,19 +366,6 @@ public: LEAVE_CRITICAL_SECTION(cs_vSend); } - void EndMessageAbortIfEmpty() - { - if (nHeaderStart < 0) - return; - int nSize = vSend.size() - nMessageStart; - if (nSize > 0) - EndMessage(); - else - AbortMessage(); - } - - - void PushVersion(); diff --git a/src/netbase.cpp b/src/netbase.cpp index 9e7307204a..4f31ce9cf3 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -6,6 +6,7 @@ #include "netbase.h" #include "util.h" #include "sync.h" +#include "hash.h" #ifndef WIN32 #include <sys/fcntl.h> diff --git a/src/noui.cpp b/src/noui.cpp index db25f2d285..204e76aba7 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -2,20 +2,37 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "ui_interface.h" #include "init.h" #include "bitcoinrpc.h" #include <string> -static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) +static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style) { + std::string strCaption; + // Check for usage of predefined caption + switch (style) { + case CClientUIInterface::MSG_ERROR: + strCaption += _("Error"); + break; + case CClientUIInterface::MSG_WARNING: + strCaption += _("Warning"); + break; + case CClientUIInterface::MSG_INFORMATION: + strCaption += _("Information"); + break; + default: + strCaption += caption; // Use supplied caption + } + printf("%s: %s\n", caption.c_str(), message.c_str()); - fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); + fprintf(stderr, "%s: %s\n", strCaption.c_str(), message.c_str()); return 4; } -static bool noui_ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) +static bool noui_ThreadSafeAskFee(int64 /*nFeeRequired*/) { return true; } diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index cd1764a53f..dbdfade0b1 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -7,7 +7,6 @@ #include "optionsmodel.h" #include "guiutil.h" #include "guiconstants.h" - #include "init.h" #include "ui_interface.h" #include "qtipcserver.h" @@ -35,18 +34,18 @@ Q_IMPORT_PLUGIN(qtaccessiblewidgets) static BitcoinGUI *guiref; static QSplashScreen *splashref; -static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) +static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style) { // Message from network thread if(guiref) { bool modal = (style & CClientUIInterface::MODAL); - // in case of modal message, use blocking connection to wait for user to click OK - QMetaObject::invokeMethod(guiref, "error", + // In case of modal message, use blocking connection to wait for user to click a button + QMetaObject::invokeMethod(guiref, "message", modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(caption)), Q_ARG(QString, QString::fromStdString(message)), - Q_ARG(bool, modal)); + Q_ARG(unsigned int, style)); } else { @@ -55,12 +54,13 @@ static void ThreadSafeMessageBox(const std::string& message, const std::string& } } -static bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) +static bool ThreadSafeAskFee(int64 nFeeRequired) { if(!guiref) return false; if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon) return true; + bool payFee = false; QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(), diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 0198a92c05..9cd22ed297 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -25,6 +25,7 @@ #include "notificator.h" #include "guiutil.h" #include "rpcconsole.h" +#include "ui_interface.h" #ifdef Q_OS_MAC #include "macdockiconhandler.h" @@ -89,7 +90,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): // Create the toolbars createToolBars(); - // Create the tray icon (or setup the dock icon) + // Create system tray icon and notification createTrayIcon(); // Create tabs @@ -353,12 +354,17 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) // Just attach " [testnet]" to the existing tooltip trayIcon->setToolTip(trayIcon->toolTip() + QString(" ") + tr("[testnet]")); trayIcon->setIcon(QIcon(":/icons/toolbar_testnet")); - toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet")); } + toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet")); aboutAction->setIcon(QIcon(":/icons/toolbar_testnet")); } + // Create system tray menu (or setup the dock menu) that late to prevent users from calling actions, + // while the client has not yet fully loaded + if(trayIcon) + createTrayIconMenu(); + // Keep up to date with client setNumConnections(clientModel->getNumConnections()); connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); @@ -366,8 +372,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) setNumBlocks(clientModel->getNumBlocks(), clientModel->getNumBlocksOfPeers()); connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int))); - // Report errors from network/worker thread - connect(clientModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool))); + // Receive and report messages from network/worker thread + connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); overviewPage->setClientModel(clientModel); rpcConsole->setClientModel(clientModel); @@ -381,8 +387,8 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel) this->walletModel = walletModel; if(walletModel) { - // Report errors from wallet thread - connect(walletModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool))); + // Receive and report messages from wallet thread + connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); // Put transaction list in tabs transactionView->setModel(walletModel); @@ -406,16 +412,26 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel) void BitcoinGUI::createTrayIcon() { - QMenu *trayIconMenu; #ifndef Q_OS_MAC trayIcon = new QSystemTrayIcon(this); - trayIconMenu = new QMenu(this); - trayIcon->setContextMenu(trayIconMenu); + trayIcon->setToolTip(tr("Bitcoin client")); trayIcon->setIcon(QIcon(":/icons/toolbar")); + trayIcon->show(); +#endif + + notificator = new Notificator(qApp->applicationName(), trayIcon); +} + +void BitcoinGUI::createTrayIconMenu() +{ + QMenu *trayIconMenu; +#ifndef Q_OS_MAC + trayIconMenu = new QMenu(this); + trayIcon->setContextMenu(trayIconMenu); + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); - trayIcon->show(); #else // Note: On Mac, the dock icon is used to provide the tray's functionality. MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); @@ -437,8 +453,6 @@ void BitcoinGUI::createTrayIcon() trayIconMenu->addSeparator(); trayIconMenu->addAction(quitAction); #endif - - notificator = new Notificator(qApp->applicationName(), trayIcon); } #ifndef Q_OS_MAC @@ -592,15 +606,50 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) progressBar->setToolTip(tooltip); } -void BitcoinGUI::error(const QString &title, const QString &message, bool modal) +void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style) { - // Report errors from network/worker thread - if(modal) - { - QMessageBox::critical(this, title, message, QMessageBox::Ok, QMessageBox::Ok); - } else { - notificator->notify(Notificator::Critical, title, message); + QString strTitle = tr("Bitcoin") + " - "; + // Default to information icon + int nMBoxIcon = QMessageBox::Information; + int nNotifyIcon = Notificator::Information; + + // Check for usage of predefined title + switch (style) { + case CClientUIInterface::MSG_ERROR: + strTitle += tr("Error"); + break; + case CClientUIInterface::MSG_WARNING: + strTitle += tr("Warning"); + break; + case CClientUIInterface::MSG_INFORMATION: + strTitle += tr("Information"); + break; + default: + strTitle += title; // Use supplied title } + + // Check for error/warning icon + if (style & CClientUIInterface::ICON_ERROR) { + nMBoxIcon = QMessageBox::Critical; + nNotifyIcon = Notificator::Critical; + } + else if (style & CClientUIInterface::ICON_WARNING) { + nMBoxIcon = QMessageBox::Warning; + nNotifyIcon = Notificator::Warning; + } + + // Display message + if (style & CClientUIInterface::MODAL) { + // Check for buttons, use OK as default, if none was supplied + QMessageBox::StandardButton buttons; + if (!(buttons = (QMessageBox::StandardButton)(style & CClientUIInterface::BTN_MASK))) + buttons = QMessageBox::Ok; + + QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons); + mBox.exec(); + } + else + notificator->notify((Notificator::Class)nNotifyIcon, strTitle, message); } void BitcoinGUI::changeEvent(QEvent *e) @@ -648,39 +697,33 @@ void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee) *payFee = (retval == QMessageBox::Yes); } -void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end) +void BitcoinGUI::incomingTransaction(const QModelIndex& parent, int start, int /*end*/) { - if(!walletModel || !clientModel) + // Prevent balloon-spam when initial block download is in progress + if(!walletModel || !clientModel || clientModel->inInitialBlockDownload()) return; + TransactionTableModel *ttm = walletModel->getTransactionTableModel(); + + QString date = ttm->index(start, TransactionTableModel::Date, parent) + .data().toString(); qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent) - .data(Qt::EditRole).toULongLong(); - if(!clientModel->inInitialBlockDownload()) - { - // On new transaction, make an info balloon - // Unless the initial block download is in progress, to prevent balloon-spam - QString date = ttm->index(start, TransactionTableModel::Date, parent) + .data(Qt::EditRole).toULongLong(); + QString type = ttm->index(start, TransactionTableModel::Type, parent) + .data().toString(); + QString address = ttm->index(start, TransactionTableModel::ToAddress, parent) .data().toString(); - QString type = ttm->index(start, TransactionTableModel::Type, parent) - .data().toString(); - QString address = ttm->index(start, TransactionTableModel::ToAddress, parent) - .data().toString(); - QIcon icon = qvariant_cast<QIcon>(ttm->index(start, - TransactionTableModel::ToAddress, parent) - .data(Qt::DecorationRole)); - notificator->notify(Notificator::Information, - (amount)<0 ? tr("Sent transaction") : - tr("Incoming transaction"), - tr("Date: %1\n" - "Amount: %2\n" - "Type: %3\n" - "Address: %4\n") - .arg(date) - .arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true)) - .arg(type) - .arg(address), icon); - } + // On new transaction, make an info balloon + message((amount)<0 ? tr("Sent transaction") : tr("Incoming transaction"), + tr("Date: %1\n" + "Amount: %2\n" + "Type: %3\n" + "Address: %4\n") + .arg(date) + .arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true)) + .arg(type) + .arg(address), CClientUIInterface::MSG_INFORMATION); } void BitcoinGUI::gotoOverviewPage() @@ -772,7 +815,8 @@ void BitcoinGUI::dropEvent(QDropEvent *event) if (nValidUrisFound) gotoSendCoinsPage(); else - notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.")); + message(tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."), + CClientUIInterface::ICON_WARNING); } event->acceptProposedAction(); @@ -799,7 +843,8 @@ void BitcoinGUI::handleURI(QString strURI) gotoSendCoinsPage(); } else - notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.")); + message(tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."), + CClientUIInterface::ICON_WARNING); } void BitcoinGUI::setEncryptionStatus(int status) @@ -849,8 +894,12 @@ void BitcoinGUI::backupWallet() QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)")); if(!filename.isEmpty()) { if(!walletModel->backupWallet(filename)) { - QMessageBox::warning(this, tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location.")); + message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."), + CClientUIInterface::MSG_ERROR); } + else + message(tr("Backup Successful"), tr("The wallet data was successfully saved to the new location."), + CClientUIInterface::MSG_INFORMATION); } } diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 8b4607d3ed..b7afdb1c8c 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -105,8 +105,10 @@ private: void createMenuBar(); /** Create the toolbars */ void createToolBars(); - /** Create system tray (notification) icon */ + /** Create system tray icon and notification */ void createTrayIcon(); + /** Create system tray menu (or setup the dock menu) */ + void createTrayIconMenu(); public slots: /** Set number of connections shown in the UI */ @@ -119,8 +121,13 @@ public slots: */ void setEncryptionStatus(int status); - /** Notify the user of an error in the network or transaction handling code. */ - void error(const QString &title, const QString &message, bool modal); + /** Notify the user of an event from the core network or transaction handling code. + @param[in] title the message box / notification title + @param[in] message the displayed text + @param[in] style modality and style definitions (icon and used buttons - buttons only for message boxes) + @see CClientUIInterface::MessageBoxFlags + */ + void message(const QString &title, const QString &message, unsigned int style); /** Asks the user whether to pay the transaction fee or to cancel the transaction. It is currently not possible to pass a return value to another thread through BlockingQueuedConnection, so an indirected pointer is used. @@ -161,7 +168,7 @@ private slots: The new items are those between start and end inclusive, under the given parent item. */ - void incomingTransaction(const QModelIndex & parent, int start, int end); + void incomingTransaction(const QModelIndex& parent, int start, int /*end*/); /** Encrypt the wallet */ void encryptWallet(bool status); /** Backup the wallet */ diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 9b7362d757..ce112803f8 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -84,7 +84,7 @@ void ClientModel::updateAlert(const QString &hash, int status) CAlert alert = CAlert::getAlertByHash(hash_256); if(!alert.IsNull()) { - emit error(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), false); + emit message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR); } } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 7d6401ab25..1afccb7859 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -70,8 +70,8 @@ signals: void numBlocksChanged(int count, int countOfPeers); void alertsChanged(const QString &warnings); - //! Asynchronous error notification - void error(const QString &title, const QString &message, bool modal); + //! Asynchronous message notification + void message(const QString &title, const QString &message, unsigned int style); public slots: void updateTimer(); diff --git a/src/qt/notificator.h b/src/qt/notificator.h index abb47109b3..833b52cb15 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -46,11 +46,11 @@ public slots: private: QWidget *parent; enum Mode { - None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ - Freedesktop, /**< Use DBus org.freedesktop.Notifications */ - QSystemTray, /**< Use QSystemTray::showMessage */ + None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ + Freedesktop, /**< Use DBus org.freedesktop.Notifications */ + QSystemTray, /**< Use QSystemTray::showMessage */ Growl12, /**< Use the Growl 1.2 notification system (Mac only) */ - Growl13 /**< Use the Growl 1.3 notification system (Mac only) */ + Growl13 /**< Use the Growl 1.3 notification system (Mac only) */ }; QString programName; Mode mode; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index e3c9413f1b..5dac5a6c45 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -137,7 +137,11 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const case MinimizeToTray: return QVariant(fMinimizeToTray); case MapPortUPnP: +#ifdef USE_UPNP return settings.value("fUseUPnP", GetBoolArg("-upnp", true)); +#else + return QVariant(false); +#endif case MinimizeOnClose: return QVariant(fMinimizeOnClose); case ProxyUse: { diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 3568616cd3..9d5a2c04ff 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -189,7 +189,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie } return TransactionCreationFailed; } - if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString())) + if(!uiInterface.ThreadSafeAskFee(nFeeRequired)) { return Aborted; } diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 62558a49df..fd5c8c4d4f 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -147,8 +147,8 @@ signals: // this means that the unlocking failed or was cancelled. void requireUnlock(); - // Asynchronous error notification - void error(const QString &title, const QString &message, bool modal); + // Asynchronous message notification + void message(const QString &title, const QString &message, unsigned int style); public slots: /* Wallet status might have changed */ diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 3fde463cd3..5554f039a7 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -154,7 +154,7 @@ Value getblock(const Array& params, bool fHelp) CBlock block; CBlockIndex* pblockindex = mapBlockIndex[hash]; - block.ReadFromDisk(pblockindex, true); + block.ReadFromDisk(pblockindex); return blockToJSON(block, pblockindex); } diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 55d5d79e23..77cef02736 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -34,15 +34,21 @@ public: Value importprivkey(const Array& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 2) + if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( - "importprivkey <bitcoinprivkey> [label]\n" + "importprivkey <bitcoinprivkey> [label] [rescan=true]\n" "Adds a private key (as returned by dumpprivkey) to your wallet."); string strSecret = params[0].get_str(); string strLabel = ""; if (params.size() > 1) strLabel = params[1].get_str(); + + // Whether to perform rescan after import + bool fRescan = true; + if (params.size() > 2) + fRescan = params[2].get_bool(); + CBitcoinSecret vchSecret; bool fGood = vchSecret.SetString(strSecret); @@ -61,9 +67,11 @@ Value importprivkey(const Array& params, bool fHelp) if (!pwalletMain->AddKey(key)) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); - - pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true); - pwalletMain->ReacceptWalletTransactions(); + + if (fRescan) { + pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true); + pwalletMain->ReacceptWalletTransactions(); + } } return Value::null; diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 5ebab755b7..90a68f560a 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -3,14 +3,18 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <boost/assign/list_of.hpp> + #include "wallet.h" #include "walletdb.h" #include "bitcoinrpc.h" #include "init.h" #include "base58.h" -using namespace json_spirit; using namespace std; +using namespace boost; +using namespace boost::assign; +using namespace json_spirit; int64 nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; @@ -1228,7 +1232,8 @@ Value backupwallet(const Array& params, bool fHelp) "Safely copies wallet.dat to destination, which can be a directory or a path with filename."); string strDest = params[0].get_str(); - BackupWallet(*pwalletMain, strDest); + if (!BackupWallet(*pwalletMain, strDest)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); return Value::null; } @@ -1496,3 +1501,74 @@ Value validateaddress(const Array& params, bool fHelp) return ret; } +Value lockunspent(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "lockunspent unlock? [array-of-Objects]\n" + "Updates list of temporarily unspendable outputs."); + + if (params.size() == 1) + RPCTypeCheck(params, list_of(bool_type)); + else + RPCTypeCheck(params, list_of(bool_type)(array_type)); + + bool fUnlock = params[0].get_bool(); + + if (params.size() == 1) { + if (fUnlock) + pwalletMain->UnlockAllCoins(); + return true; + } + + Array outputs = params[1].get_array(); + BOOST_FOREACH(Value& output, outputs) + { + if (output.type() != obj_type) + throw JSONRPCError(-8, "Invalid parameter, expected object"); + const Object& o = output.get_obj(); + + RPCTypeCheck(o, map_list_of("txid", str_type)("vout", int_type)); + + string txid = find_value(o, "txid").get_str(); + if (!IsHex(txid)) + throw JSONRPCError(-8, "Invalid parameter, expected hex txid"); + + int nOutput = find_value(o, "vout").get_int(); + if (nOutput < 0) + throw JSONRPCError(-8, "Invalid parameter, vout must be positive"); + + COutPoint outpt(uint256(txid), nOutput); + + if (fUnlock) + pwalletMain->UnlockCoin(outpt); + else + pwalletMain->LockCoin(outpt); + } + + return true; +} + +Value listlockunspent(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 0) + throw runtime_error( + "listlockunspent\n" + "Returns list of temporarily unspendable outputs."); + + vector<COutPoint> vOutpts; + pwalletMain->ListLockedCoins(vOutpts); + + Array ret; + + BOOST_FOREACH(COutPoint &outpt, vOutpts) { + Object o; + + o.push_back(Pair("txid", outpt.hash.GetHex())); + o.push_back(Pair("vout", (int)outpt.n)); + ret.push_back(o); + } + + return ret; +} + diff --git a/src/serialize.h b/src/serialize.h index 9e14666fac..f2626281c1 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -50,10 +50,6 @@ enum SER_NETWORK = (1 << 0), SER_DISK = (1 << 1), SER_GETHASH = (1 << 2), - - // modifiers - SER_SKIPSIG = (1 << 16), - SER_BLOCKHEADERONLY = (1 << 17), }; #define IMPLEMENT_SERIALIZE(statements) \ diff --git a/src/sync.h b/src/sync.h index e80efbe001..930c9b2b80 100644 --- a/src/sync.h +++ b/src/sync.h @@ -9,15 +9,36 @@ #include <boost/thread/recursive_mutex.hpp> #include <boost/thread/locks.hpp> #include <boost/thread/condition_variable.hpp> +#include "threadsafety.h" +// Template mixin that adds -Wthread-safety locking annotations to a +// subset of the mutex API. +template <typename PARENT> +class LOCKABLE AnnotatedMixin : public PARENT +{ +public: + void lock() EXCLUSIVE_LOCK_FUNCTION() + { + PARENT::lock(); + } + void unlock() UNLOCK_FUNCTION() + { + PARENT::unlock(); + } + bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true) + { + return PARENT::try_lock(); + } +}; /** Wrapped boost mutex: supports recursive locking, but no waiting */ -typedef boost::recursive_mutex CCriticalSection; +// TODO: We should move away from using the recursive lock by default. +typedef AnnotatedMixin<boost::recursive_mutex> CCriticalSection; /** Wrapped boost mutex: supports waiting but not recursive locking */ -typedef boost::mutex CWaitableCriticalSection; +typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection; #ifdef DEBUG_LOCKORDER void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); @@ -37,46 +58,31 @@ class CMutexLock { private: boost::unique_lock<Mutex> lock; -public: void Enter(const char* pszName, const char* pszFile, int nLine) { - if (!lock.owns_lock()) - { - EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex())); + EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex())); #ifdef DEBUG_LOCKCONTENTION - if (!lock.try_lock()) - { - PrintLockContention(pszName, pszFile, nLine); + if (!lock.try_lock()) + { + PrintLockContention(pszName, pszFile, nLine); #endif - lock.lock(); + lock.lock(); #ifdef DEBUG_LOCKCONTENTION - } -#endif - } - } - - void Leave() - { - if (lock.owns_lock()) - { - lock.unlock(); - LeaveCritical(); } +#endif } bool TryEnter(const char* pszName, const char* pszFile, int nLine) { + EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true); + lock.try_lock(); if (!lock.owns_lock()) - { - EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true); - lock.try_lock(); - if (!lock.owns_lock()) - LeaveCritical(); - } + LeaveCritical(); return lock.owns_lock(); } +public: CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock) { if (fTry) @@ -95,11 +101,6 @@ public: { return lock.owns_lock(); } - - boost::unique_lock<Mutex> &GetLock() - { - return lock; - } }; typedef CMutexLock<CCriticalSection> CCriticalBlock; diff --git a/src/test/bignum_tests.cpp b/src/test/bignum_tests.cpp index 744681871f..5b898d1499 100644 --- a/src/test/bignum_tests.cpp +++ b/src/test/bignum_tests.cpp @@ -122,4 +122,57 @@ BOOST_AUTO_TEST_CASE(bignum_setint64) } } + +BOOST_AUTO_TEST_CASE(bignum_SetCompact) +{ + CBigNum num; + num.SetCompact(0); + BOOST_CHECK_EQUAL(num.GetHex(), "0"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0); + + num.SetCompact(0x00123456); + BOOST_CHECK_EQUAL(num.GetHex(), "0"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0); + + num.SetCompact(0x01123456); + BOOST_CHECK_EQUAL(num.GetHex(), "12"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000); + + // Make sure that we don't generate compacts with the 0x00800000 bit set + num = 0x80; + BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000); + + num.SetCompact(0x01fedcba); + BOOST_CHECK_EQUAL(num.GetHex(), "-7e"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x01fe0000); + + num.SetCompact(0x02123456); + BOOST_CHECK_EQUAL(num.GetHex(), "1234"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400); + + num.SetCompact(0x03123456); + BOOST_CHECK_EQUAL(num.GetHex(), "123456"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456); + + num.SetCompact(0x04123456); + BOOST_CHECK_EQUAL(num.GetHex(), "12345600"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456); + + num.SetCompact(0x04923456); + BOOST_CHECK_EQUAL(num.GetHex(), "-12345600"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x04923456); + + num.SetCompact(0x05009234); + BOOST_CHECK_EQUAL(num.GetHex(), "92340000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234); + + num.SetCompact(0x20123456); + BOOST_CHECK_EQUAL(num.GetHex(), "1234560000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456); + + num.SetCompact(0xff123456); + BOOST_CHECK_EQUAL(num.GetHex(), "123456000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0xff123456); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index e4ba0259ba..b98816d53d 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -1,10 +1,12 @@ #define BOOST_TEST_MODULE Bitcoin Test Suite #include <boost/test/unit_test.hpp> +#include <boost/filesystem.hpp> #include "db.h" #include "txdb.h" #include "main.h" #include "wallet.h" +#include "util.h" CWallet* pwalletMain; CClientUIInterface uiInterface; @@ -14,11 +16,15 @@ extern void noui_connect(); struct TestingSetup { CCoinsViewDB *pcoinsdbview; + boost::filesystem::path pathTemp; TestingSetup() { fPrintToDebugger = true; // don't want to write to debug.log file noui_connect(); bitdb.MakeMock(); + pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); + boost::filesystem::create_directories(pathTemp); + mapArgs["-datadir"] = pathTemp.string(); pblocktree = new CBlockTreeDB(1 << 20, true); pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsTip = new CCoinsViewCache(*pcoinsdbview); @@ -36,6 +42,7 @@ struct TestingSetup { delete pcoinsdbview; delete pblocktree; bitdb.Flush(true); + boost::filesystem::remove_all(pathTemp); } }; diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 3a4c035a30..c47d25bbe9 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -104,11 +104,11 @@ BOOST_AUTO_TEST_CASE(util_HexStr) BOOST_AUTO_TEST_CASE(util_DateTimeStrFormat) { /*These are platform-dependant and thus removed to avoid useless test failures - BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0), "01/01/70 00:00:00"); - BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0x7FFFFFFF), "01/19/38 03:14:07"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", 0), "1970-01-01T00:00:00"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", 0x7FFFFFFF), "2038-01-19T03:14:07"); // Formats used within Bitcoin - BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 1317425777), "09/30/11 23:36:17"); - BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M", 1317425777), "09/30/11 23:36"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", 1317425777), "2011-09-30T23:36:17"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%dT%H:%M", 1317425777), "2011-09-30T23:36"); */ } diff --git a/src/threadsafety.h b/src/threadsafety.h new file mode 100644 index 0000000000..3d3d526fd6 --- /dev/null +++ b/src/threadsafety.h @@ -0,0 +1,53 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_THREADSAFETY_H +#define BITCOIN_THREADSAFETY_H + +#ifdef __clang__ +// TL;DR Add GUARDED_BY(mutex) to member variables. The others are +// rarely necessary. Ex: int nFoo GUARDED_BY(cs_foo); +// +// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety +// for documentation. The clang compiler can do advanced static analysis +// of locking when given the -Wthread-safety option. +#define LOCKABLE __attribute__ ((lockable)) +#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable)) +#define GUARDED_BY(x) __attribute__ ((guarded_by(x))) +#define GUARDED_VAR __attribute__ ((guarded_var)) +#define PT_GUARDED_BY(x) __attribute__ ((pt_guarded_by(x))) +#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var)) +#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__))) +#define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__))) +#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__))) +#define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__))) +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__))) +#define SHARED_TRYLOCK_FUNCTION(...) __attribute__ ((shared_trylock_function(__VA_ARGS__))) +#define UNLOCK_FUNCTION(...) __attribute__ ((unlock_function(__VA_ARGS__))) +#define LOCK_RETURNED(x) __attribute__ ((lock_returned(x))) +#define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__))) +#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__ ((exclusive_locks_required(__VA_ARGS__))) +#define SHARED_LOCKS_REQUIRED(...) __attribute__ ((shared_locks_required(__VA_ARGS__))) +#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis)) +#else +#define LOCKABLE +#define SCOPED_LOCKABLE +#define GUARDED_BY(x) +#define GUARDED_VAR +#define PT_GUARDED_BY(x) +#define PT_GUARDED_VAR +#define ACQUIRED_AFTER(...) +#define ACQUIRED_BEFORE(...) +#define EXCLUSIVE_LOCK_FUNCTION(...) +#define SHARED_LOCK_FUNCTION(...) +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) +#define SHARED_TRYLOCK_FUNCTION(...) +#define UNLOCK_FUNCTION(...) +#define LOCK_RETURNED(x) +#define LOCKS_EXCLUDED(...) +#define EXCLUSIVE_LOCKS_REQUIRED(...) +#define SHARED_LOCKS_REQUIRED(...) +#define NO_THREAD_SAFETY_ANALYSIS +#endif // __GNUC__ +#endif // BITCOIN_THREADSAFETY_H diff --git a/src/ui_interface.h b/src/ui_interface.h index 0f7fdef264..703e15f095 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -29,41 +29,49 @@ public: /** Flags for CClientUIInterface::ThreadSafeMessageBox */ enum MessageBoxFlags { - YES = 0x00000002, - OK = 0x00000004, - NO = 0x00000008, - YES_NO = (YES|NO), - CANCEL = 0x00000010, - APPLY = 0x00000020, - CLOSE = 0x00000040, - OK_DEFAULT = 0x00000000, - YES_DEFAULT = 0x00000000, - NO_DEFAULT = 0x00000080, - CANCEL_DEFAULT = 0x80000000, - ICON_EXCLAMATION = 0x00000100, - ICON_HAND = 0x00000200, - ICON_WARNING = ICON_EXCLAMATION, - ICON_ERROR = ICON_HAND, - ICON_QUESTION = 0x00000400, - ICON_INFORMATION = 0x00000800, - ICON_STOP = ICON_HAND, - ICON_ASTERISK = ICON_INFORMATION, - ICON_MASK = (0x00000100|0x00000200|0x00000400|0x00000800), - FORWARD = 0x00001000, - BACKWARD = 0x00002000, - RESET = 0x00004000, - HELP = 0x00008000, - MORE = 0x00010000, - SETUP = 0x00020000, - // Force blocking, modal message box dialog (not just OS notification) - MODAL = 0x00040000 + ICON_INFORMATION = 0, + ICON_WARNING = (1U << 0), + ICON_ERROR = (1U << 1), + /** + * Mask of all available icons in CClientUIInterface::MessageBoxFlags + * This needs to be updated, when icons are changed there! + */ + ICON_MASK = (ICON_INFORMATION | ICON_WARNING | ICON_ERROR), + + /** These values are taken from qmessagebox.h "enum StandardButton" to be directly usable */ + BTN_OK = 0x00000400U, // QMessageBox::Ok + BTN_YES = 0x00004000U, // QMessageBox::Yes + BTN_NO = 0x00010000U, // QMessageBox::No + BTN_ABORT = 0x00040000U, // QMessageBox::Abort + BTN_RETRY = 0x00080000U, // QMessageBox::Retry + BTN_IGNORE = 0x00100000U, // QMessageBox::Ignore + BTN_CLOSE = 0x00200000U, // QMessageBox::Close + BTN_CANCEL = 0x00400000U, // QMessageBox::Cancel + BTN_DISCARD = 0x00800000U, // QMessageBox::Discard + BTN_HELP = 0x01000000U, // QMessageBox::Help + BTN_APPLY = 0x02000000U, // QMessageBox::Apply + BTN_RESET = 0x04000000U, // QMessageBox::Reset + /** + * Mask of all available buttons in CClientUIInterface::MessageBoxFlags + * This needs to be updated, when buttons are changed there! + */ + BTN_MASK = (BTN_OK | BTN_YES | BTN_NO | BTN_ABORT | BTN_RETRY | BTN_IGNORE | + BTN_CLOSE | BTN_CANCEL | BTN_DISCARD | BTN_HELP | BTN_APPLY | BTN_RESET), + + /** Force blocking, modal message box dialog (not just OS notification) */ + MODAL = 0x10000000U, + + /** Predefined combinations for certain default usage cases */ + MSG_INFORMATION = ICON_INFORMATION, + MSG_WARNING = (ICON_WARNING | BTN_OK | MODAL), + MSG_ERROR = (ICON_ERROR | BTN_OK | MODAL) }; /** Show message box. */ - boost::signals2::signal<void (const std::string& message, const std::string& caption, int style)> ThreadSafeMessageBox; + boost::signals2::signal<void (const std::string& message, const std::string& caption, unsigned int style)> ThreadSafeMessageBox; /** Ask the user whether they want to pay a fee or not. */ - boost::signals2::signal<bool (int64 nFeeRequired, const std::string& strCaption), boost::signals2::last_value<bool> > ThreadSafeAskFee; + boost::signals2::signal<bool (int64 nFeeRequired), boost::signals2::last_value<bool> > ThreadSafeAskFee; /** Handle a URL passed at the command line. */ boost::signals2::signal<void (const std::string& strURI)> ThreadSafeHandleURI; diff --git a/src/util.cpp b/src/util.cpp index 03014a5da0..576ba50dbb 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -64,7 +64,7 @@ bool fDebug = false; bool fDebugNet = false; bool fPrintToConsole = false; bool fPrintToDebugger = false; -bool fRequestShutdown = false; +volatile bool fRequestShutdown = false; bool fShutdown = false; bool fDaemon = false; bool fServer = false; @@ -240,7 +240,7 @@ inline int OutputDebugStringF(const char* pszFormat, ...) // Debug print useful for profiling if (fLogTimestamps && fStartedNewLine) - fprintf(fileout, "%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); + fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); if (pszFormat[strlen(pszFormat) - 1] == '\n') fStartedNewLine = true; else @@ -1248,7 +1248,7 @@ void AddTimeData(const CNetAddr& ip, int64 nTime) string strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin will not work properly."); strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); - uiInterface.ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION); + uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING); } } } @@ -1310,6 +1310,28 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) } #endif +boost::filesystem::path GetTempPath() { +#if BOOST_FILESYSTEM_VERSION == 3 + return boost::filesystem::temp_directory_path(); +#else + // TODO: remove when we don't support filesystem v2 anymore + boost::filesystem::path path; +#ifdef WIN32 + char pszPath[MAX_PATH] = ""; + + if (GetTempPathA(MAX_PATH, pszPath)) + path = boost::filesystem::path(pszPath); +#else + path = boost::filesystem::path("/tmp"); +#endif + if (path.empty() || !boost::filesystem::is_directory(path)) { + printf("GetTempPath(): failed to find temp path\n"); + return boost::filesystem::path(""); + } + return path; +#endif +} + void runCommand(std::string strCommand) { int nErr = ::system(strCommand.c_str()); diff --git a/src/util.h b/src/util.h index b798f60aa7..8bea0dd2b3 100644 --- a/src/util.h +++ b/src/util.h @@ -24,9 +24,6 @@ typedef int pid_t; /* define for Windows compatibility */ #include <boost/date_time/gregorian/gregorian_types.hpp> #include <boost/date_time/posix_time/posix_time_types.hpp> -#include <openssl/sha.h> -#include <openssl/ripemd.h> - #include "netbase.h" // for AddTimeData typedef long long int64; @@ -132,7 +129,7 @@ extern bool fDebug; extern bool fDebugNet; extern bool fPrintToConsole; extern bool fPrintToDebugger; -extern bool fRequestShutdown; +extern volatile bool fRequestShutdown; extern bool fShutdown; extern bool fDaemon; extern bool fServer; @@ -207,6 +204,7 @@ void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif +boost::filesystem::path GetTempPath(); void ShrinkDebugFile(); int GetRandInt(int nMax); uint64 GetRand(uint64 nMax); @@ -329,6 +327,12 @@ inline int64 GetTimeMillis() boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds(); } +inline int64 GetTimeMicros() +{ + return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - + boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds(); +} + inline std::string DateTimeStrFormat(const char* pszFormat, int64 nTime) { time_t n = nTime; @@ -407,109 +411,6 @@ bool SoftSetBoolArg(const std::string& strArg, bool fValue); -template<typename T1> -inline uint256 Hash(const T1 pbegin, const T1 pend) -{ - static unsigned char pblank[1]; - uint256 hash1; - SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1); - uint256 hash2; - SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); - return hash2; -} - -class CHashWriter -{ -private: - SHA256_CTX ctx; - -public: - int nType; - int nVersion; - - void Init() { - SHA256_Init(&ctx); - } - - CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) { - Init(); - } - - CHashWriter& write(const char *pch, size_t size) { - SHA256_Update(&ctx, pch, size); - return (*this); - } - - // invalidates the object - uint256 GetHash() { - uint256 hash1; - SHA256_Final((unsigned char*)&hash1, &ctx); - uint256 hash2; - SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); - return hash2; - } - - template<typename T> - CHashWriter& operator<<(const T& obj) { - // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); - return (*this); - } -}; - - -template<typename T1, typename T2> -inline uint256 Hash(const T1 p1begin, const T1 p1end, - const T2 p2begin, const T2 p2end) -{ - static unsigned char pblank[1]; - uint256 hash1; - SHA256_CTX ctx; - SHA256_Init(&ctx); - SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0])); - SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0])); - SHA256_Final((unsigned char*)&hash1, &ctx); - uint256 hash2; - SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); - return hash2; -} - -template<typename T1, typename T2, typename T3> -inline uint256 Hash(const T1 p1begin, const T1 p1end, - const T2 p2begin, const T2 p2end, - const T3 p3begin, const T3 p3end) -{ - static unsigned char pblank[1]; - uint256 hash1; - SHA256_CTX ctx; - SHA256_Init(&ctx); - SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0])); - SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0])); - SHA256_Update(&ctx, (p3begin == p3end ? pblank : (unsigned char*)&p3begin[0]), (p3end - p3begin) * sizeof(p3begin[0])); - SHA256_Final((unsigned char*)&hash1, &ctx); - uint256 hash2; - SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); - return hash2; -} - -template<typename T> -uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION) -{ - CHashWriter ss(nType, nVersion); - ss << obj; - return ss.GetHash(); -} - -inline uint160 Hash160(const std::vector<unsigned char>& vch) -{ - uint256 hash1; - SHA256(&vch[0], vch.size(), (unsigned char*)&hash1); - uint160 hash2; - RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); - return hash2; -} - - /** Median filter over a stream of values. * Returns the median of the last N numbers */ diff --git a/src/wallet.cpp b/src/wallet.cpp index 3bfb24832b..c07adff6c6 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -756,7 +756,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) while (pindex) { CBlock block; - block.ReadFromDisk(pindex, true); + block.ReadFromDisk(pindex); BOOST_FOREACH(CTransaction& tx, block.vtx) { if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate)) @@ -957,9 +957,11 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) continue; - for (unsigned int i = 0; i < pcoin->vout.size(); i++) - if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && pcoin->vout[i].nValue > 0) + for (unsigned int i = 0; i < pcoin->vout.size(); i++) { + if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && + !IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0) vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain())); + } } } } @@ -1310,7 +1312,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, return strError; } - if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired, _("Sending..."))) + if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired)) return "ABORTED"; if (!CommitTransaction(wtxNew, reservekey)) @@ -1770,3 +1772,35 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) NotifyTransactionChanged(this, hashTx, CT_UPDATED); } } + +void CWallet::LockCoin(COutPoint& output) +{ + setLockedCoins.insert(output); +} + +void CWallet::UnlockCoin(COutPoint& output) +{ + setLockedCoins.erase(output); +} + +void CWallet::UnlockAllCoins() +{ + setLockedCoins.clear(); +} + +bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const +{ + COutPoint outpt(hash, n); + + return (setLockedCoins.count(outpt) > 0); +} + +void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) +{ + for (std::set<COutPoint>::iterator it = setLockedCoins.begin(); + it != setLockedCoins.end(); it++) { + COutPoint outpt = (*it); + vOutpts.push_back(outpt); + } +} + diff --git a/src/wallet.h b/src/wallet.h index 05d60056f4..ecfdafe2eb 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -119,11 +119,18 @@ public: CPubKey vchDefaultKey; + std::set<COutPoint> setLockedCoins; + // check whether we are allowed to upgrade (or already support) to the named feature bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; } void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true) const; bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const; + bool IsLockedCoin(uint256 hash, unsigned int n) const; + void LockCoin(COutPoint& output); + void UnlockCoin(COutPoint& output); + void UnlockAllCoins(); + void ListLockedCoins(std::vector<COutPoint>& vOutpts); // keystore implementation // Generate a new key diff --git a/src/walletdb.cpp b/src/walletdb.cpp index e102df9720..4419cbb5f7 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -238,7 +238,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str()); //printf(" %12"PRI64d" %s %s %s\n", // wtx.vout[0].nValue, - // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(), + // DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", wtx.GetBlockTime()).c_str(), // wtx.hashBlock.ToString().substr(0,20).c_str(), // wtx.mapValue["message"].c_str()); } |